Skip to content

Commit

Permalink
Conform iplot_histogram and plot_histogram
Browse files Browse the repository at this point in the history
This commit fixes the inconsistencies between the 2 histogram plot
functions iplot_histogram (for an interactive js plot) and
plot_histogram (for a matplotlib generated plot). Both functions perform
the same function just using different tools. To make them
interchangeable this commit addresses the differences between the 2 and
makes the interface the same between the 2. However, because of
backwards compat concerns with plot_histogram (which has been present in
several releases already) there is a some duplication of number_to_keep
kwarg and the options dict. This deprecates the number_to_keep parameter
so users can migrate off of it and then we can remove it from both
plot_histogram and iplot_histogram.

With the interfaces to both functions being the same this commit also
updates the __init__ module to leverage iplot_histogram by default if
qiskit.tools.visualization.plot_histogram() is called and we're running
under jupyter and have a network connection to download the necessary
js.

Fixes #864
  • Loading branch information
mtreinish committed Sep 5, 2018
1 parent f4303a5 commit 39ca802
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 37 deletions.
6 changes: 5 additions & 1 deletion qiskit/tools/visualization/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,18 @@

from ._circuit_visualization import circuit_drawer, plot_circuit, generate_latex_source,\
latex_circuit_drawer, matplotlib_circuit_drawer, qx_color_scheme
from ._counts_visualization import plot_histogram

if ('ipykernel' in sys.modules) and ('spyder' not in sys.modules):
import requests
if requests.get(
'https://qvisualization.mybluemix.net/').status_code == 200:
from .interactive._iplot_state import iplot_state as plot_state
from .interactive._iplot_histogram import iplot_histogram as \
plot_histogram
else:
from ._state_visualization import plot_state
from ._counts_visualization import plot_histogram

else:
from ._state_visualization import plot_state
from ._counts_visualization import plot_histogram
87 changes: 60 additions & 27 deletions qiskit/tools/visualization/_counts_visualization.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,35 +17,68 @@
import matplotlib.pyplot as plt


def plot_histogram(data, number_to_keep=False):
def plot_histogram(data, number_to_keep=False, legend=None, options=None):
"""Plot a histogram of data.
data is a dictionary of {'000': 5, '010': 113, ...}
number_to_keep is the number of terms to plot and rest is made into a
single bar called other values
Args:
data (list or dict): This is either a list of dictionaries containing:
values to represent (ex {'001': 130})
number_to_keep (int): DEPRECATED the number of terms to plot and rest
is made into a single bar called other values
legend(list): A list of strings to use for labels of the data.
The number of entries must match the lenght of data (if data is a
list or 1 if it's a dict)
options (dict): Representation settings containing
- number_to_keep (integer): groups max values
- show_legend (bool): show legend of graph content
Raises:
Exception: When legend is provided and the length doesn't match the
input data
"""
if number_to_keep is not False:
data_temp = dict(Counter(data).most_common(number_to_keep))
data_temp["rest"] = sum(data.values()) - sum(data_temp.values())
data = data_temp

labels = sorted(data)
values = np.array([data[key] for key in labels], dtype=float)
pvalues = values / sum(values)
numelem = len(values)
ind = np.arange(numelem) # the x locations for the groups
width = 0.35 # the width of the bars
if options is None:
options = {}

if isinstance(data, dict):
data = [data]
if legend and len(legend) != 1:
raise Exception("Length of legendL %s doesn't match number of "
"input executions: %s" % (len(legend), 1))
else:
if legend and len(legend) != len(data):
raise Exception("Length of legendL %s doesn't match number of "
"input executions: %s" % (len(legend), len(data)))

_, ax = plt.subplots()
rects = ax.bar(ind, pvalues, width, color='seagreen')
# add some text for labels, title, and axes ticks
ax.set_ylabel('Probabilities', fontsize=12)
ax.set_xticks(ind)
ax.set_xticklabels(labels, fontsize=12, rotation=70)
ax.set_ylim([0., min([1.2, max([1.2 * val for val in pvalues])])])
# attach some text labels
for rect in rects:
height = rect.get_height()
ax.text(rect.get_x() + rect.get_width() / 2., 1.05 * height,
'%f' % float(height),
ha='center', va='bottom')
for item, execution in enumerate(data):
if number_to_keep is not False or (
'number_to_keep' in options and options['number_to_keep']):
data_temp = dict(Counter(execution).most_common(number_to_keep))
data_temp["rest"] = sum(execution.values()) - sum(data_temp.values())
execution = data_temp

labels = sorted(execution)
values = np.array([execution[key] for key in labels], dtype=float)
pvalues = values / sum(values)
numelem = len(values)
ind = np.arange(numelem) # the x locations for the groups
width = 0.35 # the width of the bars
label = None
if legend:
label = legend[item]
adj = width * item
rects = ax.bar(ind+adj, pvalues, width, label=label)
# add some text for labels, title, and axes ticks
ax.set_ylabel('Probabilities', fontsize=12)
ax.set_xticks(ind)
ax.set_xticklabels(labels, fontsize=12, rotation=70)
ax.set_ylim([0., min([1.2, max([1.2 * val for val in pvalues])])])
# attach some text labels
for rect in rects:
height = rect.get_height()
ax.text(rect.get_x() + rect.get_width() / 2., 1.05 * height,
'%f' % float(height),
ha='center', va='bottom')
if legend and (
'show_legend' not in options or options['show_legend'] is True):
plt.legend()
plt.show()
39 changes: 30 additions & 9 deletions qiskit/tools/visualization/interactive/_iplot_histogram.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,24 +48,29 @@ def process_data(data, number_to_keep):
return result


def iplot_histogram(executions_results, options=None):
def iplot_histogram(data, number_to_keep=False, options=None, legend=None):
""" Create a histogram representation.
Graphical representation of the input array using a vertical bars
style graph.
Args:
executions_results (array): Array of dictionaries containing
- data (dict): values to represent (ex. {'001' : 130})
- name (string): name to show in the legend
- device (string): Could be 'real' or 'simulated'
data (list or dict): This is either a list of dicts or a single
dict containing the values to represent (ex. {'001' : 130})
number_to_keep (int): DEPRECATED the number of terms to plot and
rest is made into a single bar called other values
legend (list): A list of strings to use for labels of the data.
The number of entries must match the length of data.
options (dict): Representation settings containing
- width (integer): graph horizontal size
- height (integer): graph vertical size
- slider (bool): activate slider
- number_to_keep (integer): groups max values
- show_legend (bool): show legend of graph content
- sort (string): Could be 'asc' or 'desc'
Raises:
Exception: When legend is provided and the length doesn't match the
input data
"""

# HTML
Expand Down Expand Up @@ -111,12 +116,28 @@ def iplot_histogram(executions_results, options=None):
options['show_legend'] = 1

if 'number_to_keep' not in options:
options['number_to_keep'] = 0
if number_to_keep is False:
options['number_to_keep'] = 0
elif number_to_keep:
options['number_to_keep'] = number_to_keep

data_to_plot = []
for execution in executions_results:
data = process_data(execution['data'], options['number_to_keep'])
data_to_plot.append({'data': data})
if isinstance(data, dict):
data = [data]
if legend and len(legend) != 1:
raise Exception("Length of legendL %s doesn't match number of "
"input executions: %s" % (len(legend), 1))
else:
if legend and len(legend) != len(data):
raise Exception("Length of legendL %s doesn't match number of "
"input executions: %s" % (len(legend), len(data)))

for item, execution in enumerate(data):
exec_data = process_data(execution, options['number_to_keep'])
out_dict = {'data': exec_data}
if legend:
out_dict['name'] = legend[item]
data_to_plot.append(out_dict)

html = html_template.substitute({
'divNumber': div_number
Expand Down

0 comments on commit 39ca802

Please sign in to comment.