Update plot_gate_map() family to leverage graphviz for visualization (#10208)
* Update gate_map.py Update the gate_map.py to migrate the visualization modules from matplotlib to rustworkx.graphviz * Removed has_rustworkx instances * Added release notes * Update test_gate_map.py Updated tests for the modified gate_map.py file * Formatted gate_map.py * Format test_gate_map.py * Added release notes for the fix of #9031 * Update gate_map.py * Update test_gate_map.py Test file updated so that all tests can be passed. * Update test_gate_map.py * Update gate_map.py for rerunning tests. * Update test_clifford.py * Update gate_map.py to reuse rx.draw_graphiz * Update test_gate_map.py to omit qubit_visualization * Update test_gate_map.py to fix formatting changes * Update gate_map.py * Update gate_map.py * Update gate_map.py * Update test_gate_map.py * Update test_gate_map.py * Update gate_map.py * Update gate_map.py * Update gate_map.py * Update gate_map.py * Update gate_map.py * Update gate_map.py * Update gate_map.py * Update test_gate_map.py * Update test_gate_map.py to add rx import * Update test_gate_map.py * Update test_gate_map.py * Update test_gate_map.py to fix imports * Update test_gate_map.py to add HAS_GRAPHVIZ to all tests * Update test_graph_matplotlib_drawer.py to have HAS_GRAPHVIZ * Update test_graph_matplotlib_drawer.py to add HAS_GRAPHVIZ import to test_font_color function * Update test_graph_matplotlib_drawer.py to add GRAPHVIZ check to the class * Update test_graph_matplotlib_drawer.py to add HAS_GRAPHVIZ to both gate_plot_map and test_gate_plot_map import to test_font_color function * Update test_graph_matplotlib_drawer.py * Update test_graph_matplotlib_drawer.py * Update test_graph_matplotlib_drawer.py * Fixed the `font_color` parameter in `gate_map.py/plot_gate_map()` The font_color parameter can now accept hex values as well. * Modify color_edge function to increase speed * Update gate_map.py to fix formatting * Update gate_map.py to shift seaborn import to `plot_error_map` * Add HAS_SEABORN to test_plot_error_map * Reformat gate_map.py * Fixed node autoscaling in `gate_map.py` graphs * Add return type to `test_from_gate_with_cyclic_definition ` in `test_clifford.py` * Update update-gate_map-visualizations-6ea907a0502fdc1a.yaml * Rename update-gate_map-visualizations-6ea907a0502fdc1a.yaml to update-gate-map-visualizations-6ea907a0502fdc1a.yaml * Update update-gate-map-visualizations-6ea907a0502fdc1a.yaml * Update update-gate-map-visualizations-6ea907a0502fdc1a.yaml * Update pauli_op.py to use np.prod `np.product` is deprecated and is causing test fails. * Update operator.py to use np.prod `np.product` is deprecated and is causing test fails. * Update pauli_sum_op.py to use np.prod `np.product` is deprecated and is causing test fails. * Update random.py to use np.product `np.product` is deprecated and is causing test fails. * Update chi.py to use np.prod `np.product` is deprecated and is causing test fails. * Replace np.product with np.prod `np.product` is deprecated and is causing test fails. * Update ptm.py to use np.prod `np.product` is deprecated and is causing test fails. * Update stinespring.py to use np.prod `np.product` is deprecated and is causing test fails. * Update superop.py to use np.prod `np.product` is deprecated and is causing test fails. * Update transformations.py to use np.prod `np.product` is deprecated and is causing test fails. * Update densitymatrix.py to use np.prod `np.product` is deprecated and is causing test fails. * Update random.py to use np.prod `np.product` is deprecated and is causing test fails. * Update statevector.py to use np.prod `np.product` is deprecated and is causing test fails. * Update local_readout_mitigator.py to use np.prod `np.product` is deprecated and is causing test fails. * Update unitary_synthesis.py to use np.prod `np.product` is deprecated and is causing test fails. * Update test_random.py to use np.prod `np.product` is deprecated and is causing test fails. * Update test_scalar_op.py to use np.prod `np.product` is deprecated and is causing test fails. * Update test_random.py to use np.prod `np.product` is deprecated and is causing test fails. * Update test_clifford.py to remove debugging code * Move matplotlib imports to occur at run time * Apply suggestions from code review * Move matplotlib_close_if_inline to runtime import too * Flatten parallel edges Co-authored-by: Matthew Treinish <mtreinish@kortar.org> * Fix 1 qubit backend handling * Fix qubit label and font sizes * new reference images * Adjust font scaling * Update reference images * Remove unrelated reference file update * Improve formatting * Adjust pixel scaling factor * Update reference images with formatting changes --------- Co-authored-by: Matthew Treinish <mtreinish@kortar.org> Co-authored-by: Luciano Bello <bel@zurich.ibm.com>
|
@ -17,12 +17,13 @@ from typing import List
|
|||
|
||||
import numpy as np
|
||||
import rustworkx as rx
|
||||
from rustworkx.visualization import graphviz_draw
|
||||
|
||||
from qiskit.exceptions import QiskitError
|
||||
from qiskit.utils import optionals as _optionals
|
||||
from qiskit.providers.exceptions import BackendPropertyError
|
||||
from qiskit.transpiler.coupling import CouplingMap
|
||||
from .exceptions import VisualizationError
|
||||
from .utils import matplotlib_close_if_inline
|
||||
|
||||
|
||||
def _get_backend_interface_version(backend):
|
||||
|
@ -42,7 +43,7 @@ def plot_gate_map(
|
|||
qubit_color=None,
|
||||
qubit_labels=None,
|
||||
line_color=None,
|
||||
font_color="w",
|
||||
font_color="white",
|
||||
ax=None,
|
||||
filename=None,
|
||||
qubit_coordinates=None,
|
||||
|
@ -93,8 +94,6 @@ def plot_gate_map(
|
|||
"""
|
||||
qubit_coordinates_map = {}
|
||||
|
||||
qubit_coordinates_map[1] = [[0, 0]]
|
||||
|
||||
qubit_coordinates_map[5] = [[1, 0], [0, 1], [1, 1], [1, 2], [2, 1]]
|
||||
|
||||
qubit_coordinates_map[7] = [[0, 0], [0, 1], [0, 2], [1, 1], [2, 0], [2, 1], [2, 2]]
|
||||
|
@ -912,8 +911,6 @@ def plot_gate_map(
|
|||
|
||||
backend_version = _get_backend_interface_version(backend)
|
||||
if backend_version <= 1:
|
||||
from qiskit.transpiler.coupling import CouplingMap
|
||||
|
||||
if backend.configuration().simulator:
|
||||
raise QiskitError("Requires a device backend, not simulator.")
|
||||
config = backend.configuration()
|
||||
|
@ -927,31 +924,12 @@ def plot_gate_map(
|
|||
if qubit_coordinates is None and ("ibm" in name or "fake" in name):
|
||||
qubit_coordinates = qubit_coordinates_map.get(num_qubits, None)
|
||||
|
||||
if qubit_coordinates is None:
|
||||
# Replace with planar_layout() when rustworkx offers it
|
||||
qubit_coordinates_rx = rx.spring_layout(coupling_map.graph, seed=1234)
|
||||
scaling_factor = 10 ** int(math.log10(num_qubits) + 1)
|
||||
qubit_coordinates = [
|
||||
(
|
||||
int(scaling_factor * qubit_coordinates_rx[i][0]),
|
||||
int(scaling_factor * qubit_coordinates_rx[i][1]),
|
||||
if qubit_coordinates:
|
||||
if len(qubit_coordinates) != num_qubits:
|
||||
raise QiskitError(
|
||||
f"The number of specified qubit coordinates {len(qubit_coordinates)} "
|
||||
f"does not match the device number of qubits: {num_qubits}"
|
||||
)
|
||||
for i in range(num_qubits)
|
||||
]
|
||||
|
||||
if any(x[0] < 0 or x[1] < 0 for x in qubit_coordinates):
|
||||
min_entry = min(qubit_coordinates, key=lambda x: min(x[0], x[1]))
|
||||
negative_offset = 0 - min(min_entry)
|
||||
qubit_coordinates = [
|
||||
(x[0] + negative_offset, x[1] + negative_offset) for x in qubit_coordinates
|
||||
]
|
||||
|
||||
if len(qubit_coordinates) != num_qubits:
|
||||
raise QiskitError(
|
||||
f"The number of specified qubit coordinates {len(qubit_coordinates)} "
|
||||
f"does not match the device number of qubits: {num_qubits}"
|
||||
)
|
||||
|
||||
return plot_coupling_map(
|
||||
num_qubits,
|
||||
qubit_coordinates,
|
||||
|
@ -972,6 +950,7 @@ def plot_gate_map(
|
|||
|
||||
|
||||
@_optionals.HAS_MATPLOTLIB.require_in_call
|
||||
@_optionals.HAS_GRAPHVIZ.require_in_call
|
||||
def plot_coupling_map(
|
||||
num_qubits: int,
|
||||
qubit_coordinates: List[List[int]],
|
||||
|
@ -985,7 +964,7 @@ def plot_coupling_map(
|
|||
qubit_color=None,
|
||||
qubit_labels=None,
|
||||
line_color=None,
|
||||
font_color="w",
|
||||
font_color="white",
|
||||
ax=None,
|
||||
filename=None,
|
||||
):
|
||||
|
@ -1014,7 +993,7 @@ def plot_coupling_map(
|
|||
Figure: A Matplotlib figure instance.
|
||||
|
||||
Raises:
|
||||
MissingOptionalLibraryError: if matplotlib not installed.
|
||||
MissingOptionalLibraryError: If matplotlib or graphviz is not installed.
|
||||
QiskitError: If length of qubit labels does not match number of qubits.
|
||||
|
||||
Example:
|
||||
|
@ -1030,20 +1009,14 @@ def plot_coupling_map(
|
|||
plot_coupling_map(num_qubits, qubit_coordinates, coupling_map)
|
||||
"""
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib.patches as mpatches
|
||||
from .utils import matplotlib_close_if_inline
|
||||
|
||||
input_axes = False
|
||||
if ax:
|
||||
input_axes = True
|
||||
|
||||
if font_size is None:
|
||||
font_size = 12
|
||||
|
||||
if qubit_size is None:
|
||||
qubit_size = 24
|
||||
if num_qubits > 20:
|
||||
qubit_size = 28
|
||||
font_size = 10
|
||||
qubit_size = 30
|
||||
|
||||
if qubit_labels is None:
|
||||
qubit_labels = list(range(num_qubits))
|
||||
|
@ -1051,128 +1024,96 @@ def plot_coupling_map(
|
|||
if len(qubit_labels) != num_qubits:
|
||||
raise QiskitError("Length of qubit labels does not equal number of qubits.")
|
||||
|
||||
if qubit_coordinates is not None:
|
||||
grid_data = qubit_coordinates
|
||||
else:
|
||||
if not input_axes:
|
||||
fig, ax = plt.subplots(figsize=(5, 5))
|
||||
ax.axis("off")
|
||||
if filename:
|
||||
fig.savefig(filename)
|
||||
return fig
|
||||
|
||||
x_max = max(d[1] for d in grid_data)
|
||||
y_max = max(d[0] for d in grid_data)
|
||||
max_dim = max(x_max, y_max)
|
||||
|
||||
if figsize is None:
|
||||
if num_qubits == 1 or (x_max / max_dim > 0.33 and y_max / max_dim > 0.33):
|
||||
figsize = (5, 5)
|
||||
else:
|
||||
figsize = (9, 3)
|
||||
|
||||
if ax is None:
|
||||
fig, ax = plt.subplots(figsize=figsize)
|
||||
ax.axis("off")
|
||||
if not label_qubits:
|
||||
qubit_labels = [""] * num_qubits
|
||||
|
||||
# set coloring
|
||||
if qubit_color is None:
|
||||
qubit_color = ["#648fff"] * num_qubits
|
||||
if line_color is None:
|
||||
line_color = ["#648fff"] * len(coupling_map) if coupling_map else []
|
||||
line_color = ["#648fff"] * len(coupling_map)
|
||||
|
||||
# Add lines for couplings
|
||||
if num_qubits != 1:
|
||||
for ind, edge in enumerate(coupling_map):
|
||||
is_symmetric = False
|
||||
if edge[::-1] in coupling_map:
|
||||
is_symmetric = True
|
||||
y_start = grid_data[edge[0]][0]
|
||||
x_start = grid_data[edge[0]][1]
|
||||
y_end = grid_data[edge[1]][0]
|
||||
x_end = grid_data[edge[1]][1]
|
||||
if num_qubits == 1:
|
||||
graph = rx.PyDiGraph()
|
||||
graph.add_node(0)
|
||||
else:
|
||||
graph = CouplingMap(coupling_map).graph
|
||||
|
||||
if is_symmetric:
|
||||
if y_start == y_end:
|
||||
x_end = (x_end - x_start) / 2 + x_start
|
||||
if not plot_directed:
|
||||
graph = graph.to_undirected(multigraph=False)
|
||||
|
||||
elif x_start == x_end:
|
||||
y_end = (y_end - y_start) / 2 + y_start
|
||||
for node in graph.node_indices():
|
||||
graph[node] = node
|
||||
|
||||
else:
|
||||
x_end = (x_end - x_start) / 2 + x_start
|
||||
y_end = (y_end - y_start) / 2 + y_start
|
||||
ax.add_artist(
|
||||
plt.Line2D(
|
||||
[x_start, x_end],
|
||||
[-y_start, -y_end],
|
||||
color=line_color[ind],
|
||||
linewidth=line_width,
|
||||
zorder=0,
|
||||
)
|
||||
)
|
||||
if plot_directed:
|
||||
dx = x_end - x_start
|
||||
dy = y_end - y_start
|
||||
if is_symmetric:
|
||||
x_arrow = x_start + dx * 0.95
|
||||
y_arrow = -y_start - dy * 0.95
|
||||
dx_arrow = dx * 0.01
|
||||
dy_arrow = -dy * 0.01
|
||||
head_width = 0.15
|
||||
else:
|
||||
x_arrow = x_start + dx * 0.5
|
||||
y_arrow = -y_start - dy * 0.5
|
||||
dx_arrow = dx * 0.2
|
||||
dy_arrow = -dy * 0.2
|
||||
head_width = 0.2
|
||||
ax.add_patch(
|
||||
mpatches.FancyArrow(
|
||||
x_arrow,
|
||||
y_arrow,
|
||||
dx_arrow,
|
||||
dy_arrow,
|
||||
head_width=head_width,
|
||||
length_includes_head=True,
|
||||
edgecolor=None,
|
||||
linewidth=0,
|
||||
facecolor=line_color[ind],
|
||||
zorder=1,
|
||||
)
|
||||
)
|
||||
for edge_index in graph.edge_indices():
|
||||
graph.update_edge_by_index(edge_index, edge_index)
|
||||
|
||||
# Add circles for qubits
|
||||
for var, idx in enumerate(grid_data):
|
||||
_idx = [idx[1], -idx[0]]
|
||||
ax.add_artist(
|
||||
mpatches.Ellipse(
|
||||
_idx,
|
||||
qubit_size / 48,
|
||||
qubit_size / 48, # This is here so that the changes
|
||||
color=qubit_color[var],
|
||||
zorder=1,
|
||||
)
|
||||
) # to how qubits are plotted does
|
||||
if label_qubits: # not affect qubit size kwarg.
|
||||
ax.text(
|
||||
*_idx,
|
||||
s=qubit_labels[var],
|
||||
horizontalalignment="center",
|
||||
verticalalignment="center",
|
||||
color=font_color,
|
||||
size=font_size,
|
||||
weight="bold",
|
||||
)
|
||||
ax.set_xlim([-1, x_max + 1])
|
||||
ax.set_ylim([-(y_max + 1), 1])
|
||||
ax.set_aspect("equal")
|
||||
# pixel-to-inch conversion
|
||||
px = 1.15 / plt.rcParams["figure.dpi"]
|
||||
|
||||
if qubit_coordinates:
|
||||
qubit_coordinates = [coordinates[::-1] for coordinates in qubit_coordinates]
|
||||
|
||||
if font_size is None:
|
||||
max_characters = max(1, max(len(str(x)) for x in qubit_labels))
|
||||
font_size = max(int(20 / max_characters), 1)
|
||||
|
||||
def color_node(node):
|
||||
if qubit_coordinates:
|
||||
out_dict = {
|
||||
"label": str(qubit_labels[node]),
|
||||
"color": f'"{qubit_color[node]}"',
|
||||
"fillcolor": f'"{qubit_color[node]}"',
|
||||
"style": "filled",
|
||||
"shape": "circle",
|
||||
"pos": f'"{qubit_coordinates[node][0]},{qubit_coordinates[node][1]}"',
|
||||
"pin": "True",
|
||||
}
|
||||
else:
|
||||
out_dict = {
|
||||
"label": str(qubit_labels[node]),
|
||||
"color": f'"{qubit_color[node]}"',
|
||||
"fillcolor": f'"{qubit_color[node]}"',
|
||||
"style": "filled",
|
||||
"shape": "circle",
|
||||
}
|
||||
out_dict["fontcolor"] = f'"{font_color}"'
|
||||
out_dict["fontsize"] = str(font_size)
|
||||
out_dict["height"] = str(qubit_size * px)
|
||||
out_dict["fixedsize"] = "True"
|
||||
out_dict["fontname"] = '"DejaVu Sans"'
|
||||
return out_dict
|
||||
|
||||
def color_edge(edge):
|
||||
out_dict = {
|
||||
"color": f'"{line_color[edge]}"',
|
||||
"fillcolor": f'"{line_color[edge]}"',
|
||||
"penwidth": str(line_width),
|
||||
}
|
||||
return out_dict
|
||||
|
||||
plot = graphviz_draw(
|
||||
graph,
|
||||
method="neato",
|
||||
node_attr_fn=color_node,
|
||||
edge_attr_fn=color_edge,
|
||||
filename=filename,
|
||||
)
|
||||
|
||||
if filename:
|
||||
return None
|
||||
|
||||
if not input_axes:
|
||||
if figsize is None:
|
||||
width, height = plot.size
|
||||
figsize = (width * px, height * px)
|
||||
fig, ax = plt.subplots(figsize=figsize)
|
||||
ax.axis("off")
|
||||
ax.imshow(plot)
|
||||
|
||||
if not input_axes:
|
||||
matplotlib_close_if_inline(fig)
|
||||
if filename:
|
||||
fig.savefig(filename)
|
||||
return fig
|
||||
return None
|
||||
|
||||
|
||||
def plot_circuit_layout(circuit, backend, view="virtual", qubit_coordinates=None):
|
||||
|
@ -1232,7 +1173,7 @@ def plot_circuit_layout(circuit, backend, view="virtual", qubit_coordinates=None
|
|||
cmap_len = cmap.graph.num_edges()
|
||||
|
||||
qubits = []
|
||||
qubit_labels = [None] * num_qubits
|
||||
qubit_labels = [""] * num_qubits
|
||||
|
||||
bit_locations = {
|
||||
bit: {"register": register, "index": index}
|
||||
|
@ -1248,27 +1189,27 @@ def plot_circuit_layout(circuit, backend, view="virtual", qubit_coordinates=None
|
|||
bit_register = bit_locations[key]["register"]
|
||||
if bit_register is None or bit_register.name != "ancilla":
|
||||
qubits.append(val)
|
||||
qubit_labels[val] = bit_locations[key]["index"]
|
||||
qubit_labels[val] = str(bit_locations[key]["index"])
|
||||
|
||||
elif view == "physical":
|
||||
for key, val in circuit._layout.initial_layout.get_physical_bits().items():
|
||||
bit_register = bit_locations[val]["register"]
|
||||
if bit_register is None or bit_register.name != "ancilla":
|
||||
qubits.append(key)
|
||||
qubit_labels[key] = key
|
||||
qubit_labels[key] = str(key)
|
||||
|
||||
else:
|
||||
raise VisualizationError("Layout view must be 'virtual' or 'physical'.")
|
||||
|
||||
qcolors = ["#648fff"] * num_qubits
|
||||
for k in qubits:
|
||||
qcolors[k] = "k"
|
||||
qcolors[k] = "black"
|
||||
|
||||
lcolors = ["#648fff"] * cmap_len
|
||||
|
||||
for idx, edge in enumerate(cmap):
|
||||
if edge[0] in qubits and edge[1] in qubits:
|
||||
lcolors[idx] = "k"
|
||||
lcolors[idx] = "black"
|
||||
|
||||
fig = plot_gate_map(
|
||||
backend,
|
||||
|
@ -1282,7 +1223,7 @@ def plot_circuit_layout(circuit, backend, view="virtual", qubit_coordinates=None
|
|||
|
||||
@_optionals.HAS_MATPLOTLIB.require_in_call
|
||||
@_optionals.HAS_SEABORN.require_in_call
|
||||
def plot_error_map(backend, figsize=(12, 9), show_title=True, qubit_coordinates=None):
|
||||
def plot_error_map(backend, figsize=(15, 12), show_title=True, qubit_coordinates=None):
|
||||
"""Plots the error map of a given backend.
|
||||
|
||||
Args:
|
||||
|
@ -1300,7 +1241,7 @@ def plot_error_map(backend, figsize=(12, 9), show_title=True, qubit_coordinates=
|
|||
|
||||
Raises:
|
||||
VisualizationError: The backend does not provide gate errors for the 'sx' gate.
|
||||
MissingOptionalLibraryError: If seaborn is not installed
|
||||
MissingOptionalLibraryError: If matplotlib or seaborn is not installed.
|
||||
|
||||
Example:
|
||||
.. plot::
|
||||
|
@ -1313,10 +1254,11 @@ def plot_error_map(backend, figsize=(12, 9), show_title=True, qubit_coordinates=
|
|||
backend = FakeVigoV2()
|
||||
plot_error_map(backend)
|
||||
"""
|
||||
import seaborn as sns
|
||||
import matplotlib
|
||||
import matplotlib.pyplot as plt
|
||||
from matplotlib import gridspec, ticker
|
||||
import seaborn as sns
|
||||
from .utils import matplotlib_close_if_inline
|
||||
|
||||
color_map = sns.cubehelix_palette(reverse=True, as_cmap=True)
|
||||
|
||||
|
@ -1406,7 +1348,7 @@ def plot_error_map(backend, figsize=(12, 9), show_title=True, qubit_coordinates=
|
|||
single_norm = matplotlib.colors.Normalize(
|
||||
vmin=min(single_gate_errors), vmax=max(single_gate_errors)
|
||||
)
|
||||
q_colors = [color_map(single_norm(err)) for err in single_gate_errors]
|
||||
q_colors = [matplotlib.colors.to_hex(color_map(single_norm(err))) for err in single_gate_errors]
|
||||
|
||||
directed = False
|
||||
line_colors = []
|
||||
|
@ -1417,7 +1359,7 @@ def plot_error_map(backend, figsize=(12, 9), show_title=True, qubit_coordinates=
|
|||
avg_cx_err = np.mean(cx_errors)
|
||||
|
||||
cx_norm = matplotlib.colors.Normalize(vmin=min(cx_errors), vmax=max(cx_errors))
|
||||
line_colors = [color_map(cx_norm(err)) for err in cx_errors]
|
||||
line_colors = [matplotlib.colors.to_hex(color_map(cx_norm(err))) for err in cx_errors]
|
||||
|
||||
read_err = 100 * np.asarray(read_err)
|
||||
avg_read_err = np.mean(read_err)
|
||||
|
@ -1450,6 +1392,7 @@ def plot_error_map(backend, figsize=(12, 9), show_title=True, qubit_coordinates=
|
|||
ax=main_ax,
|
||||
qubit_coordinates=qubit_coordinates,
|
||||
)
|
||||
|
||||
main_ax.axis("off")
|
||||
main_ax.set_aspect(1)
|
||||
if cmap:
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
---
|
||||
features:
|
||||
- |
|
||||
The visualizations from the :func:`~.plot_gate_map`, :func:`~.plot_coupling_map`.
|
||||
:func:`~.plot_error_map`, and :func:`~.plot_circuit_layout` functions have been significantly
|
||||
improved for rendering layouts of backends with large numbers of qubits. This was accomplished
|
||||
by leveraging `graphviz <https://graphviz.org/>`__ through rustworkx's ``graphviz_draw()`` function
|
||||
to perform a more sophisticated algorithmic graph layout that scales for large numbers of
|
||||
qubits.
|
||||
|
||||
upgrade:
|
||||
- |
|
||||
The visualization functions: :func:`~.plot_gate_map`, :func:`~.plot_coupling_map`.
|
||||
:func:`~.plot_error_map`, and :func:`~.plot_circuit_layout` now depend on
|
||||
`graphviz <https://graphviz.org/>`__ being installed to function. This change was
|
||||
necessary to enable visualizing backends with larger numbers of qubits. This
|
||||
additional external requirement is in addition to the existing optional dependencies
|
||||
these functions previously required. You find details on how to install
|
||||
graphviz here: https://graphviz.org/download/
|
|
@ -55,6 +55,8 @@ class TestGateMap(QiskitVisualizationTestCase):
|
|||
)
|
||||
|
||||
@data(*backends)
|
||||
@unittest.skipIf(not optionals.HAS_MATPLOTLIB, "matplotlib not available.")
|
||||
@unittest.skipUnless(optionals.HAS_GRAPHVIZ, "Graphviz not installed")
|
||||
def test_plot_gate_map(self, backend):
|
||||
"""tests plotting of gate map of a device (20 qubit, 16 qubit, 14 qubit and 5 qubit)"""
|
||||
n = backend.configuration().n_qubits
|
||||
|
@ -67,6 +69,8 @@ class TestGateMap(QiskitVisualizationTestCase):
|
|||
plt.close(fig)
|
||||
|
||||
@data(*backends)
|
||||
@unittest.skipIf(not optionals.HAS_MATPLOTLIB, "matplotlib not available.")
|
||||
@unittest.skipUnless(optionals.HAS_GRAPHVIZ, "Graphviz not installed")
|
||||
def test_plot_circuit_layout(self, backend):
|
||||
"""tests plot_circuit_layout for each device"""
|
||||
layout_length = int(backend._configuration.n_qubits / 2)
|
||||
|
@ -83,9 +87,11 @@ class TestGateMap(QiskitVisualizationTestCase):
|
|||
with BytesIO() as img_buffer:
|
||||
fig.savefig(img_buffer, format="png")
|
||||
img_buffer.seek(0)
|
||||
self.assertImagesAreEqual(Image.open(img_buffer), img_ref, 0.1)
|
||||
self.assertImagesAreEqual(Image.open(img_buffer), img_ref, 0.2)
|
||||
plt.close(fig)
|
||||
|
||||
@unittest.skipIf(not optionals.HAS_MATPLOTLIB, "matplotlib not available.")
|
||||
@unittest.skipUnless(optionals.HAS_GRAPHVIZ, "Graphviz not installed")
|
||||
def test_plot_gate_map_no_backend(self):
|
||||
"""tests plotting of gate map without a device"""
|
||||
n_qubits = 8
|
||||
|
@ -101,6 +107,9 @@ class TestGateMap(QiskitVisualizationTestCase):
|
|||
self.assertImagesAreEqual(Image.open(img_buffer), img_ref, 0.2)
|
||||
plt.close(fig)
|
||||
|
||||
@unittest.skipIf(not optionals.HAS_MATPLOTLIB, "matplotlib not available.")
|
||||
@unittest.skipUnless(optionals.HAS_GRAPHVIZ, "Graphviz not installed")
|
||||
@unittest.skipUnless(optionals.HAS_SEABORN, "Seaborn not installed")
|
||||
def test_plot_error_map_backend_v1(self):
|
||||
"""Test plotting error map with fake backend v1."""
|
||||
backend = FakeKolkata()
|
||||
|
@ -112,6 +121,9 @@ class TestGateMap(QiskitVisualizationTestCase):
|
|||
self.assertImagesAreEqual(Image.open(img_buffer), img_ref, 0.2)
|
||||
plt.close(fig)
|
||||
|
||||
@unittest.skipIf(not optionals.HAS_MATPLOTLIB, "matplotlib not available.")
|
||||
@unittest.skipUnless(optionals.HAS_GRAPHVIZ, "Graphviz not installed")
|
||||
@unittest.skipUnless(optionals.HAS_SEABORN, "Seaborn not installed")
|
||||
def test_plot_error_map_backend_v2(self):
|
||||
"""Test plotting error map with fake backend v2."""
|
||||
backend = FakeKolkataV2()
|
||||
|
@ -123,6 +135,9 @@ class TestGateMap(QiskitVisualizationTestCase):
|
|||
self.assertImagesAreEqual(Image.open(img_buffer), img_ref, 0.2)
|
||||
plt.close(fig)
|
||||
|
||||
@unittest.skipIf(not optionals.HAS_MATPLOTLIB, "matplotlib not available.")
|
||||
@unittest.skipUnless(optionals.HAS_GRAPHVIZ, "Graphviz not installed")
|
||||
@unittest.skipUnless(optionals.HAS_SEABORN, "Seaborn not installed")
|
||||
def test_plot_error_map_over_100_qubit(self):
|
||||
"""Test plotting error map with large fake backend."""
|
||||
backend = FakeWashington()
|
||||
|
@ -134,6 +149,9 @@ class TestGateMap(QiskitVisualizationTestCase):
|
|||
self.assertImagesAreEqual(Image.open(img_buffer), img_ref, 0.2)
|
||||
plt.close(fig)
|
||||
|
||||
@unittest.skipIf(not optionals.HAS_MATPLOTLIB, "matplotlib not available.")
|
||||
@unittest.skipUnless(optionals.HAS_GRAPHVIZ, "Graphviz not installed")
|
||||
@unittest.skipUnless(optionals.HAS_SEABORN, "Seaborn not installed")
|
||||
def test_plot_error_map_over_100_qubit_backend_v2(self):
|
||||
"""Test plotting error map with large fake backendv2."""
|
||||
backend = FakeWashingtonV2()
|
||||
|
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 5.7 KiB |