
    z	iSB                         S r SSKJr  SSKrSSKrSSKJr  SSK	J
r
Jr  SSKJr  SSKJr  S	 r/ S
QrS\0rS\4S jr          SS jr          SS jr\R.                  R0                             SS j5       rS rS rSS jrg)z1
Visualization functions for measurement counts.
    )OrderedDictN)	optionals)QuasiDistributionProbDistribution   )VisualizationError)matplotlib_close_if_inlinec                 ~    [        U 5      [        U5      :w  a  [        S5      e[        S [        X5       5       5      $ )zCalculate the Hamming distance between two bit strings

Args:
    str1 (str): First string.
    str2 (str): Second string.
Returns:
    int: Distance between strings.
Raises:
    VisualizationError: Strings not same length
zStrings not same length.c              3   .   #    U  H  u  pX:g  v   M     g 7fN ).0s1s2s      c/home/james-whalen/.local/lib/python3.13/site-packages/qiskit/visualization/counts_visualization.py	<genexpr>#hamming_distance.<locals>.<genexpr>)   s     6oFBrxos   )lenr   sumzip)str1str2s     r   hamming_distancer      s5     4yCI !;<<6c$o666    )ascdeschammingvalue
value_descr   returnc           	          [        U [        5      (       d  U /n U  HU  n[        U[        [        45      (       d7  [        [	        [        UR                  5       5      5      [        5      (       d  MU    g   g)NTF)
isinstancelistr   r   nextitervaluesfloat)datadats     r   _is_deprecated_data_formatr*   0   sa    dD!!vc-/?@AAZcjjl#$eF
 F
 	 
 r   c                    [        U [        5      (       d  U /n SnU  HW  n[        U[        [        45      (       d7  [        [	        [        UR                  5       5      5      [        5      (       d  MU  SnMY     [        U UUUUUUUUU	U
US9$ )a  Plot a histogram of input counts data.

Args:
    data (list or dict): This is either a list of dictionaries or a single
        dict containing the values to represent (ex ``{'001': 130}``)

    figsize (tuple): Figure size in inches.
    color (list or str): String or list of strings for histogram bar colors.
    number_to_keep (int): The number of terms to plot per dataset.  The rest is made into a
        single bar called 'rest'.  If multiple datasets are given, the ``number_to_keep``
        applies to each dataset individually, which may result in more bars than
        ``number_to_keep + 1``.  The ``number_to_keep`` applies to the total values, rather than
        the x-axis sort.
    sort (string): Could be `'asc'`, `'desc'`, `'hamming'`, `'value'`, or
        `'value_desc'`. If set to `'value'` or `'value_desc'` the x axis
        will be sorted by the number of counts for each bitstring.
        Defaults to `'asc'`.
    target_string (str): Target string if 'sort' is a distance measure.
    legend(list): A list of strings to use for labels of the data.
        The number of entries must match the length of data (if data is a
        list or 1 if it's a dict)
    bar_labels (bool): Label each bar in histogram with counts value.
    title (str): A string to use for the plot title
    ax (matplotlib.axes.Axes): An optional Axes object to be used for
        the visualization output. If none is specified a new matplotlib
        Figure will be created and used. Additionally, if specified there
        will be no returned Figure since it is redundant.
    filename (str): file path to save image to.

Returns:
    matplotlib.Figure:
        A figure for the rendered histogram, if the ``ax``
        kwarg is not set.

Raises:
    MissingOptionalLibraryError: Matplotlib not available.
    VisualizationError: When legend is provided and the length doesn't
        match the input data.
    VisualizationError: Input must be Counts or a dict

Examples:
    .. plot::
       :alt: Output from the previous code.
       :include-source:

        # Plot two counts in the same figure with legends and colors specified.

        from qiskit.visualization import plot_histogram

        counts1 = {'00': 525, '11': 499}
        counts2 = {'00': 511, '11': 514}

        legend = ['First execution', 'Second execution']

        plot_histogram([counts1, counts2], legend=legend, color=['crimson','midnightblue'],
                        title="New Histogram")

        # You can sort the bitstrings using different methods.

        counts = {'001': 596, '011': 211, '010': 50, '000': 117, '101': 33, '111': 8,
                '100': 6, '110': 3}

        # Sort by the counts in descending order
        hist1 = plot_histogram(counts, sort='value_desc')

        # Sort by the hamming distance (the number of bit flips to change from
        # one bitstring to the other) from a target string.
        hist2 = plot_histogram(counts, sort='hamming', target_string='001')
countsdistributionkind)	r"   r#   r   r   r$   r%   r&   r'   _plotting_core)r(   figsizecolornumber_to_keepsorttarget_stringlegend
bar_labelstitleaxfilenamer/   r)   s                r   plot_histogramr;   ;   s    d dD!!vDc-/?@AAZcjjl#$eF
 F
 "D	 
 
 r   c                 *    [        U UUUUUUUUU	U
SS9$ )a  Plot a distribution from input sampled data.

Args:
    data (list or dict): This is either a list of dictionaries or a single
        dict containing the values to represent (ex {'001': 130})
    figsize (tuple): Figure size in inches.
    color (list or str): String or list of strings for distribution bar colors.
    number_to_keep (int): The number of terms to plot per dataset.  The rest is made into a
        single bar called 'rest'.  If multiple datasets are given, the ``number_to_keep``
        applies to each dataset individually, which may result in more bars than
        ``number_to_keep + 1``.  The ``number_to_keep`` applies to the total values, rather than
        the x-axis sort.
    sort (string): Could be `'asc'`, `'desc'`, `'hamming'`, `'value'`, or
        `'value_desc'`. If set to `'value'` or `'value_desc'` the x axis
        will be sorted by the maximum probability for each bitstring.
        Defaults to `'asc'`.
    target_string (str): Target string if 'sort' is a distance measure.
    legend(list): A list of strings to use for labels of the data.
        The number of entries must match the length of data (if data is a
        list or 1 if it's a dict)
    bar_labels (bool): Label each bar in histogram with probability value.
    title (str): A string to use for the plot title
    ax (matplotlib.axes.Axes): An optional Axes object to be used for
        the visualization output. If none is specified a new matplotlib
        Figure will be created and used. Additionally, if specified there
        will be no returned Figure since it is redundant.
    filename (str): file path to save image to.

Returns:
    matplotlib.Figure:
        A figure for the rendered distribution, if the ``ax``
        kwarg is not set.

Raises:
    MissingOptionalLibraryError: Matplotlib not available.
    VisualizationError: When legend is provided and the length doesn't
        match the input data.

Examples:
    .. plot::
       :alt: Output from the previous code.
       :include-source:

        # Plot two counts in the same figure with legends and colors specified.

        from qiskit.visualization import plot_distribution

        counts1 = {'00': 525, '11': 499}
        counts2 = {'00': 511, '11': 514}

        legend = ['First execution', 'Second execution']

        plot_distribution([counts1, counts2], legend=legend, color=['crimson','midnightblue'],
                        title="New Distribution")

        # You can sort the bitstrings using different methods.

        counts = {'001': 596, '011': 211, '010': 50, '000': 117, '101': 33, '111': 8,
                '100': 6, '110': 3}

        # Sort by the counts in descending order
        dist1 = plot_distribution(counts, sort='value_desc')

        # Sort by the hamming distance (the number of bit flips to change from
        # one bitstring to the other) from a target string.
        dist2 = plot_distribution(counts, sort='hamming', target_string='001')

r-   r.   )r0   )r(   r1   r2   r3   r4   r5   r6   r7   r8   r9   r:   s              r   plot_distributionr=      s6    b 
 r   c                 p
  ^' SS K Jn  SSKJn  U[        ;  a  [        S5      eU[        ;   a  Uc  Sn[        U5      e[        U [        5      (       a  U /n U(       a<  [        U5      [        U 5      :w  a$  [        S[        U5       S[        U 5       S35      eUc!  UR                  S   R                  5       S	   nO[        U[        5      (       a  U/nU	c  UR                  US
9u  pOS n[        [        R                   " S U [#        5       5      5      nUb  UR%                  S5        U[        ;   ak  / nU H*  nUR%                  US:w  a  [        U   " UU5      OS5        M,     ['        [        ['        UU5      S S96  Vs/ s H  n[)        U5      PM     snS   nOrSU;   al  0 m'[        U [        5      (       a  U m'O6U  H0  nU H'  nT'R+                  US5      n[-        UUU   5      T'U'   M)     M2     [        T'R/                  5       U'4S jS9n[        U 5      nS[        U 5      S-   -  n[1        U UX;S9u  nnn/ n[3        U 5       GHx  u  nnS n[3        UU   5       H[  u  nn U(       d  U(       a  UU   nU S:  d  M!  UR%                  U	R5                  UUU-  -   U UUUU[        U5      -     SS95        S nM]     US-  US-
  -  n!U	R7                  UU   U!-   5        U	R9                  UR/                  5       SSSS9  U(       d  M  U H  n"U" H  n#U#R;                  5       n$US:X  a  [=        U$S5      n$U$S:  aD  U	R?                  U#RA                  5       U#RC                  5       S-  -   SU$-  [        U$5      SSSS 9  Mo  U	R?                  U#RA                  5       U#RC                  5       S-  -   SU$-  S!SSSS 9  M     M     GM{     US":X  a  U	RE                  S#S$S%9  OU	RE                  S&S$S%9  [F        RH                  " U5      RK                  5       n%S'n&US:X  a  [M        S'[M        S( U% 5       5      5      n&U	RO                  U&[M        S)[Q        U%5      -  [-        S* U% 5       5      /5      /5        S+U;   a  U	RS                  5         U	RT                  RW                  U" S,5      5        URY                  S-S.SS/S09  U(       a  UR[                  U5        U(       a  U	R]                  S1S2SSS3S49  U(       a  [_        U5        U
c   URa                  5         U$ URe                  U
5      $ s  snf ! [b         a     U$ f = f)5Nr   )MaxNLocatorzgValue of sort option, %s, isn't a valid choice. Must be 'asc', 'desc', 'hamming', 'value', 'value_desc'z6Must define target_string when using distance measure.zLength of legend (z,) doesn't match number of input executions (z).zaxes.prop_cycler2   )r1   c                 @    U R                  UR                  5       5      $ r   )unionkeys)xys     r   <lambda> _plotting_core.<locals>.<lambda>6  s    !''!&&(2Cr   restc                     U S   $ )Nr   r   )pairs    r   rE   rF   ?  s    SWXYSZr   keyr   r   c                    > TU    $ r   r   )rK   combined_countss    r   rE   rF   I  s    PS@Tr   r.      )labelr2   zorderF   rightanchor)rotationharotation_moder-      gMbP?g       @g?centerbottom)rU   varP   0r,   Count   )fontsizezQuasi-probabilityg        c              3   ,   #    U  H
  nS U-  v   M     g7f皙?Nr   r   vals     r   r   !_plotting_core.<locals>.<genexpr>  s     >Xcc	X   ra   c              3   ,   #    U  H
  nS U-  v   M     g7fr`   r   rb   s     r   r   rd     s     8Whsshre   r      majorrD   z--)whichaxisrP   	linestylez
upper left)g)\(?g      ?T)locbbox_to_anchorncolborderaxespadframeon)3matplotlib.pyplotpyplotmatplotlib.tickerr?   VALID_SORTSr   	DIST_MEASr"   dictr   rcParamsby_keystrsubplotssorted	functoolsreducesetappendr   r#   getmaxrB   
_plot_data	enumeratebar
set_xticksset_xticklabels
get_heightroundtextget_x	get_width
set_ylabelnpconcatenateravelminset_ylimr   invert_xaxisyaxisset_major_locatorgridr8   r6   r	   tight_layoutAttributeErrorsavefig)(r(   r1   r2   r3   r4   r5   r6   r7   r8   r9   r:   r/   pltr?   err_msgfiglabelsdistitemrC   r,   count
prev_countlengthwidthlabels_dictall_pvaluesall_indsrects_rO   idxrc   
bar_centerrectrecheightall_valsmin_ylimrM   s(                                          @r   r0   r0     s'    $-; 7
 	

 y]2J ))$v#f+T*  V-YZ]^bZcYddfg
 	

 }./668A	E3			z,,w,/RI$$%CT35QRF!fyDKK	$m<TUV  $'s4/@FZ([#\]#\a$q'#\]^_`	DdD!!"O#E!0!4!4UA!>J-0VE]-KOE* $  ,,.4TUYFTQE)3D&.)\&KhET?a!+d"34HC6tQwFFdUl*##D3u:$56   	  5 aiFQJ/

htnz12
;++-wV^_:C ^^-F~-!&vq!1~IIK#--/C*?? 6MK''#$    IIK#--/C*?? 6M''#$      - #^ x
g+
)B7~~k*002HH~sC>X>>?KK3c(m 3S8Wh8W5WXYZ[~
HH{1~.HH7Q$H?		%
		& 	 	
 "3'	 
{{8$$E ^|  	
	s   T"?T' '
T54T5c                 z    [        U R                  5       S S9n[        S USU*   5       5      n[        X!* S US9$ )zUKeep only the largest values in a dictionary, and sum the rest into a new key 'rest'.c                     U S   $ )Nr   r   )ps    r   rE   %_keep_largest_items.<locals>.<lambda>  s    AaDr   rJ   c              3   *   #    U  H	  u  pUv   M     g 7fr   r   )r   rK   r   s      r   r   &_keep_largest_items.<locals>.<genexpr>  s     G'Fu'Fs   N)rG   )r{   itemsr   rv   )	executionr3   sorted_countsrG   s       r   _keep_largest_itemsr     sD    9??,.AMG}5E~o'FGGDo./d;;r   c                     [        U 5      n [        5       R                  " S U  5       6 nU Vs0 s H  o"S_M     nn/ nU  H5  nUR                  5       nUR	                  U5        UR                  U5        M7     U$ s  snf )zTMake all dictionaries in data have the same set of keys, using 0 for missing values.c              3   @   #    U  H  oR                  5       v   M     g 7fr   )rB   )r   r   s     r   r    _unify_labels.<locals>.<genexpr>  s     FI~~//s   r   )tupler~   rA   copyupdater   )r(   
all_labelsrO   baseoutr   new_executions          r   _unify_labelsr     sw    ;DFFGJ",-*1H*D-
C			Y'

=!  J .s   A;c                 J  ^ [        5       n/ n/ n[        U [        5      (       a  U /n Tb  [        U4S jU  5       5      n U  H  n/ nU H;  n	X;  a  Tc  SXI'   UR	                  S5        M"  M$  SXI'   UR	                  Xy   5        M=     US:X  a  [
        R                  " U[        S9n
O2[
        R                  " U[        S9n
U
[
        R                  " U
5      -  n
UR	                  U
5        [        U5      n[
        R                  " U5      nUR	                  U5        M     XEU4$ )a  Generate the data needed for plotting counts.

Parameters:
    data (list or dict): This is either a list of dictionaries or a single
        dict containing the values to represent (ex {'001': 130})
    labels (list): The list of bitstring labels for the plot.
    number_to_keep (int): The number of terms to plot and rest
        is made into a single bar called 'rest'.
    kind (str): One of 'counts' or 'distribution`

Returns:
    tuple: tuple containing:
        (dict): The labels actually used in the plotting.
        (list): List of ndarrays for the bars in each experiment.
        (list): Indices for the locations of the bars for each
                experiment.
c              3   <   >#    U  H  n[        UT5      v   M     g 7fr   )r   )r   r   r3   s     r   r   _plot_data.<locals>.<genexpr>  s     b]aPY0NKK]as   r   r   r,   )dtype)r   r"   rv   r   r   r   arrayintr'   r   r   arange)r(   r   r3   r/   r   r   r   r   r&   rK   pvaluesnumeleminds     `          r   r   r     s   $ -KKH$v!b]abb	C#!)'(K$MM!$ * $% in-  8hhvS1GhhvU3Grvvg&G7#f+ii % ( X--r   )
NNNr   NNTNNN)
   rg   NNr   NNTNNN)r   NNr   NNTNNNr,   )r,   )__doc__collectionsr   r|   numpyr   qiskit.utilsr   
_optionalsqiskit.resultr   r   
exceptionsr   utilsr	   r   rt   ru   boolr*   r;   r=   HAS_MATPLOTLIBrequire_in_callr0   r   r   r   r   r   r   <module>r      s    $   0 = * -7  @()	  
	
hZ 
	
^B ** 
	
	Y% +Y%x<
/.r   