# Copyright (C) 2024 qBraid## This file is part of the qBraid-SDK## The qBraid-SDK is free software released under the GNU General Public License v3# or later. You can redistribute and/or modify it under the terms of the GPL v3.# See the LICENSE file in the project root or <https://www.gnu.org/licenses/gpl-3.0.html>.## THERE IS NO WARRANTY for the qBraid-SDK, as per Section 15 of the GPL v3."""Module for plotting historgram of measurement counts against quantum states."""fromtypingimportCallable,Optional,Unionfromqbraid_core._importimportLazyLoaderplt=LazyLoader("plt",globals(),"matplotlib.pyplot")matplotlib=LazyLoader("matplotlib",globals(),"matplotlib")# pylint: disable=too-many-arguments,unnecessary-lambdadef_counts_to_decimal(counts:dict)->dict:""" Converts a dictionary of counts to decimal form. Args: counts_dict (dict): A dictionary where keys are strings representing states and values are integers representing counts. Returns: dict: A dictionary with the same keys as the input dictionary, but with values converted to their respective decimal proportions. Raises: ValueError: If the total count is zero. TypeError: If the input dictionary contains non-integer values Example: >>> counts_to_decimal({"00": 10, "01": 15, "10": 20, "11": 5}) {"00": 0.2, "01": 0.3, "10": 0.4, "11": 0.1} """try:total_count=sum(counts.values())exceptTypeErroraserr:raiseTypeError("Counts values must be integers.")fromerriftotal_count==0:raiseValueError("Total count cannot be zero.")decimal_dict={key:value/total_countforkey,valueincounts.items()}returndecimal_dictdef_plot_data(counts:Union[list[dict],dict],legend:Optional[Union[list[str],str]]=None,colors:Optional[Union[list[str],str]]=None,title:Optional[str]=None,x_label:Optional[str]=None,y_label:Optional[str]=None,show_plot:Optional[bool]=True,save_path:Optional[str]=None,transform_fn:Optional[Callable[[dict],dict]]=None,label_format_fn:Optional[Callable[[float],str]]=lambdax:str(x),):ifnotisinstance(counts,list):counts=[counts]ifisinstance(colors,str):colors=[colors]ifisinstance(legend,str):legend=[legend]iftransform_fn:counts=[transform_fn(counts_dict)forcounts_dictincounts]all_states=sorted(set(stateforcounts_dictincountsforstateincounts_dict.keys()))num_dicts=len(counts)bar_width=0.8/num_dictsx_positions=range(len(all_states))ifcolorsisNone:cmap=matplotlib.pyplot.get_cmap("tab10")colors=[cmap(i/10)foriinrange(num_dicts)]iflen(colors)!=len(counts):raiseValueError("Number of colors must match number of datasets")ifisinstance(legend,list)andlen(legend)!=len(counts):raiseValueError("Number of legend labels must match number of datasets")fori,counts_dictinenumerate(counts):counts_iter=[counts_dict.get(state,0)forstateinall_states]default_label=f"Job {i}"ifnum_dicts>1elseNonelabel=legend[i]iflegendandi<len(legend)elsedefault_labelbars=plt.bar([x+(i*bar_width)forxinx_positions],counts_iter,width=bar_width,color=colors[i%num_dicts],label=label,align="center",)y_min,y_max=plt.gca().get_ylim()y_range=y_max-y_minoffset_percentage=0.02# Adjust this value to get the desired offsety_offset=y_range*offset_percentageforhbar,countinzip(bars,counts_iter):plt.text(hbar.get_x()+hbar.get_width()/2,hbar.get_height()++y_offset,label_format_fn(count),ha="center",va="bottom",color="black",fontsize=8,)plt.xticks(x_positions,all_states,rotation=45)y_ticks=plt.gca().get_yticks()plt.yticks(y_ticks)plt.grid(axis="y",linestyle="--",linewidth=0.7,alpha=0.7)ify_label:plt.ylabel(y_label)ifx_label:plt.xlabel(x_label)iftitle:plt.title(title)iflegendornum_dicts>1:plt.legend()ifsave_path:plt.savefig(save_path)ifshow_plot:plt.show()
[docs]defplot_distribution(counts:Union[list[dict],dict],legend:Optional[Union[list[str],str]]=None,colors:Optional[Union[list[str],str]]=None,title:Optional[str]=None,x_label:Optional[str]=None,y_label:Optional[str]=None,show_plot:Optional[bool]=True,save_path:Optional[str]=None,):""" Plots a histogram probability distribution of quantum states. Args: counts (Union[list[Dict], Dict]): Dictionary or a list of dictionaries containing the quantum states as keys and their respective counts as values. legend (Optional[Union[list[str], str]]): List of strings or a single string representing the labels of the datasets. Defaults to None, where it generates default labels. colors (Optional[Union[list[str], str]]): List of strings or a single string representing the colors for each dataset. Defaults to None, where it generates a color sequence. title (Optional[str]): String representing the title of the plot. Defaults to None. x_label (Optional[str]): String representing the label for the x-axis. Defaults to None. y_label (Optional[str]): String representing the label for the y-axis. Defaults to None. show_plot (Optional[bool]): Boolean representing whether to show the plot. Defaults to True. save_path (Optional[str]): String representing the path to save the plot. Defaults to None. Returns: None: This function does not return a value; it displays a plot. Raises: ValueError: Raises an error if input arguments do not match the expected types or formats. Example: .. code-block:: python counts_dict1 = {'00': 50, '01': 30, '10': 10, '11': 10} counts_dict2 = {'00': 20, '01': 40, '10': 30, '11': 10} plot_distribution( counts=[counts_dict1, counts_dict2], legend=['First Execution', 'Second Execution'], colors=['crimson', 'midnightblue'], title="Quantum State Probability Distribution", x_label="Quantum States", y_label="Probabilities" ) """y_label="Quasi-probabilities"ifnoty_labelelsey_label_plot_data(counts,legend,colors,title,x_label,y_label,show_plot,save_path,transform_fn=_counts_to_decimal,label_format_fn=lambdax:"{:.3f}".format(x),# pylint: disable=consider-using-f-string)
[docs]defplot_histogram(counts:Union[list[dict],dict],legend:Optional[Union[list[str],str]]=None,colors:Optional[Union[list[str],str]]=None,title:Optional[str]=None,x_label:Optional[str]=None,y_label:Optional[str]=None,show_plot:Optional[bool]=True,save_path:Optional[str]=None,):""" Plots a histogram of measurement counts against quantum states. Args: counts (Union[list[Dict], Dict]): Dictionary or a list of dictionaries containing the quantum states as keys and their respective counts as values. legend (Optional[Union[list[str], str]]): List of strings or a single string representing the labels of the datasets. Defaults to None, where it generates default labels. colors (Optional[Union[list[str], str]]): List of strings or a single string representing the colors for each dataset. Defaults to None, where it generates a color sequence. title (Optional[str]): String representing the title of the plot. Defaults to None. x_label (Optional[str]): String representing the label for the x-axis. Defaults to None. y_label (Optional[str]): String representing the label for the y-axis. Defaults to None. show_plot (Optional[bool]): Boolean representing whether to show the plot. Defaults to True. save_path (Optional[str]): String representing the path to save the plot. Defaults to None. Returns: None: This function does not return a value; it displays a plot. Raises: ValueError: Raises an error if input arguments do not match the expected types or formats. Example: .. code-block:: python counts_dict1 = {'00': 50, '01': 30, '10': 10, '11': 10} counts_dict2 = {'00': 20, '01': 40, '10': 30, '11': 10} plot_histogram( counts=[counts_dict1, counts_dict2], legend=['First Execution', 'Second Execution'], colors=['crimson', 'midnightblue'], title="Quantum State Measurement Counts", x_label="Quantum States", y_label="Counts" ) """y_label="Counts"ifnoty_labelelsey_label_plot_data(counts,legend,colors,title,x_label,y_label,show_plot,save_path,label_format_fn=lambdax:str(x),)