Source code for qiskit.visualization.gate_map
# This code is part of Qiskit.
#
# (C) Copyright IBM 2017, 2018.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.
"""A module for visualizing device coupling maps"""
import math
import numpy as np
from qiskit.exceptions import QiskitError, MissingOptionalLibraryError
from .matplotlib import HAS_MATPLOTLIB
from .exceptions import VisualizationError
from .utils import matplotlib_close_if_inline
[docs]def plot_gate_map(
backend,
figsize=None,
plot_directed=False,
label_qubits=True,
qubit_size=None,
line_width=4,
font_size=None,
qubit_color=None,
qubit_labels=None,
line_color=None,
font_color="w",
ax=None,
):
"""Plots the gate map of a device.
Args:
backend (BaseBackend): A backend instance,
figsize (tuple): Output figure size (wxh) in inches.
plot_directed (bool): Plot directed coupling map.
label_qubits (bool): Label the qubits.
qubit_size (float): Size of qubit marker.
line_width (float): Width of lines.
font_size (int): Font size of qubit labels.
qubit_color (list): A list of colors for the qubits
qubit_labels (list): A list of qubit labels
line_color (list): A list of colors for each line from coupling_map.
font_color (str): The font color for the qubit labels.
ax (Axes): A Matplotlib axes instance.
Returns:
Figure: A Matplotlib figure instance.
Raises:
QiskitError: if tried to pass a simulator.
MissingOptionalLibraryError: if matplotlib not installed.
Example:
.. jupyter-execute::
:hide-code:
:hide-output:
from qiskit.test.ibmq_mock import mock_get_backend
mock_get_backend('FakeVigo')
.. jupyter-execute::
from qiskit import QuantumCircuit, execute, IBMQ
from qiskit.visualization import plot_gate_map
%matplotlib inline
provider = IBMQ.load_account()
accountProvider = IBMQ.get_provider(hub='ibm-q')
backend = accountProvider.get_backend('ibmq_vigo')
plot_gate_map(backend)
"""
if not HAS_MATPLOTLIB:
raise MissingOptionalLibraryError(
libname="Matplotlib",
name="plot_gate_map",
pip_install="pip install matplotlib",
)
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
if backend.configuration().simulator:
raise QiskitError("Requires a device backend, not simulator.")
input_axes = False
if ax:
input_axes = True
mpl_data = {}
mpl_data[1] = [[0, 0]]
mpl_data[5] = [[1, 0], [0, 1], [1, 1], [1, 2], [2, 1]]
mpl_data[7] = [[0, 0], [0, 1], [0, 2], [1, 1], [2, 0], [2, 1], [2, 2]]
mpl_data[20] = [
[0, 0],
[0, 1],
[0, 2],
[0, 3],
[0, 4],
[1, 0],
[1, 1],
[1, 2],
[1, 3],
[1, 4],
[2, 0],
[2, 1],
[2, 2],
[2, 3],
[2, 4],
[3, 0],
[3, 1],
[3, 2],
[3, 3],
[3, 4],
]
mpl_data[15] = [
[0, 0],
[0, 1],
[0, 2],
[0, 3],
[0, 4],
[0, 5],
[0, 6],
[1, 7],
[1, 6],
[1, 5],
[1, 4],
[1, 3],
[1, 2],
[1, 1],
[1, 0],
]
mpl_data[16] = [
[1, 0],
[1, 1],
[2, 1],
[3, 1],
[1, 2],
[3, 2],
[0, 3],
[1, 3],
[3, 3],
[4, 3],
[1, 4],
[3, 4],
[1, 5],
[2, 5],
[3, 5],
[1, 6],
]
mpl_data[27] = [
[1, 0],
[1, 1],
[2, 1],
[3, 1],
[1, 2],
[3, 2],
[0, 3],
[1, 3],
[3, 3],
[4, 3],
[1, 4],
[3, 4],
[1, 5],
[2, 5],
[3, 5],
[1, 6],
[3, 6],
[0, 7],
[1, 7],
[3, 7],
[4, 7],
[1, 8],
[3, 8],
[1, 9],
[2, 9],
[3, 9],
[3, 10],
]
mpl_data[28] = [
[0, 2],
[0, 3],
[0, 4],
[0, 5],
[0, 6],
[1, 2],
[1, 6],
[2, 0],
[2, 1],
[2, 2],
[2, 3],
[2, 4],
[2, 5],
[2, 6],
[2, 7],
[2, 8],
[3, 0],
[3, 4],
[3, 8],
[4, 0],
[4, 1],
[4, 2],
[4, 3],
[4, 4],
[4, 5],
[4, 6],
[4, 7],
[4, 8],
]
mpl_data[53] = [
[0, 2],
[0, 3],
[0, 4],
[0, 5],
[0, 6],
[1, 2],
[1, 6],
[2, 0],
[2, 1],
[2, 2],
[2, 3],
[2, 4],
[2, 5],
[2, 6],
[2, 7],
[2, 8],
[3, 0],
[3, 4],
[3, 8],
[4, 0],
[4, 1],
[4, 2],
[4, 3],
[4, 4],
[4, 5],
[4, 6],
[4, 7],
[4, 8],
[5, 2],
[5, 6],
[6, 0],
[6, 1],
[6, 2],
[6, 3],
[6, 4],
[6, 5],
[6, 6],
[6, 7],
[6, 8],
[7, 0],
[7, 4],
[7, 8],
[8, 0],
[8, 1],
[8, 2],
[8, 3],
[8, 4],
[8, 5],
[8, 6],
[8, 7],
[8, 8],
[9, 2],
[9, 6],
]
mpl_data[65] = [
[0, 0],
[0, 1],
[0, 2],
[0, 3],
[0, 4],
[0, 5],
[0, 6],
[0, 7],
[0, 8],
[0, 9],
[1, 0],
[1, 4],
[1, 8],
[2, 0],
[2, 1],
[2, 2],
[2, 3],
[2, 4],
[2, 5],
[2, 6],
[2, 7],
[2, 8],
[2, 9],
[2, 10],
[3, 2],
[3, 6],
[3, 10],
[4, 0],
[4, 1],
[4, 2],
[4, 3],
[4, 4],
[4, 5],
[4, 6],
[4, 7],
[4, 8],
[4, 9],
[4, 10],
[5, 0],
[5, 4],
[5, 8],
[6, 0],
[6, 1],
[6, 2],
[6, 3],
[6, 4],
[6, 5],
[6, 6],
[6, 7],
[6, 8],
[6, 9],
[6, 10],
[7, 2],
[7, 6],
[7, 10],
[8, 1],
[8, 2],
[8, 3],
[8, 4],
[8, 5],
[8, 6],
[8, 7],
[8, 8],
[8, 9],
[8, 10],
]
config = backend.configuration()
num_qubits = config.n_qubits
cmap = config.coupling_map
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
if qubit_labels is None:
qubit_labels = list(range(num_qubits))
else:
if len(qubit_labels) != num_qubits:
raise QiskitError("Length of qubit labels " "does not equal number " "of qubits.")
if num_qubits in mpl_data.keys():
grid_data = mpl_data[num_qubits]
else:
if not input_axes:
fig, ax = plt.subplots(figsize=(5, 5))
ax.axis("off")
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")
# set coloring
if qubit_color is None:
qubit_color = ["#648fff"] * config.n_qubits
if line_color is None:
line_color = ["#648fff"] * len(cmap) if cmap else []
# Add lines for couplings
if num_qubits != 1:
for ind, edge in enumerate(cmap):
is_symmetric = False
if edge[::-1] in cmap:
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 is_symmetric:
if y_start == y_end:
x_end = (x_end - x_start) / 2 + x_start
elif x_start == x_end:
y_end = (y_end - y_start) / 2 + y_start
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,
)
)
# 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")
if not input_axes:
matplotlib_close_if_inline(fig)
return fig
return None
[docs]def plot_circuit_layout(circuit, backend, view="virtual"):
"""Plot the layout of a circuit transpiled for a given
target backend.
Args:
circuit (QuantumCircuit): Input quantum circuit.
backend (BaseBackend): Target backend.
view (str): Layout view: either 'virtual' or 'physical'.
Returns:
Figure: A matplotlib figure showing layout.
Raises:
QiskitError: Invalid view type given.
VisualizationError: Circuit has no layout attribute.
Example:
.. jupyter-execute::
:hide-code:
:hide-output:
from qiskit.test.ibmq_mock import mock_get_backend
mock_get_backend('FakeVigo')
.. jupyter-execute::
import numpy as np
from qiskit import QuantumCircuit, IBMQ, transpile
from qiskit.visualization import plot_histogram, plot_gate_map, plot_circuit_layout
from qiskit.tools.monitor import job_monitor
import matplotlib.pyplot as plt
%matplotlib inline
IBMQ.load_account()
ghz = QuantumCircuit(3, 3)
ghz.h(0)
for idx in range(1,3):
ghz.cx(0,idx)
ghz.measure(range(3), range(3))
provider = IBMQ.get_provider(hub='ibm-q')
backend = provider.get_backend('ibmq_vigo')
new_circ_lv3 = transpile(ghz, backend=backend, optimization_level=3)
plot_circuit_layout(new_circ_lv3, backend)
"""
if circuit._layout is None:
raise QiskitError("Circuit has no layout. " "Perhaps it has not been transpiled.")
num_qubits = backend.configuration().n_qubits
qubits = []
qubit_labels = [None] * num_qubits
bit_locations = {
bit: {"register": register, "index": index}
for register in circuit._layout.get_registers()
for index, bit in enumerate(register)
}
for index, qubit in enumerate(circuit._layout.get_virtual_bits()):
if qubit not in bit_locations:
bit_locations[qubit] = {"register": None, "index": index}
if view == "virtual":
for key, val in circuit._layout.get_virtual_bits().items():
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"]
elif view == "physical":
for key, val in circuit._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
else:
raise VisualizationError("Layout view must be 'virtual' or 'physical'.")
qcolors = ["#648fff"] * num_qubits
for k in qubits:
qcolors[k] = "k"
cmap = backend.configuration().coupling_map
lcolors = ["#648fff"] * len(cmap)
for idx, edge in enumerate(cmap):
if edge[0] in qubits and edge[1] in qubits:
lcolors[idx] = "k"
fig = plot_gate_map(backend, qubit_color=qcolors, qubit_labels=qubit_labels, line_color=lcolors)
return fig
[docs]def plot_error_map(backend, figsize=(12, 9), show_title=True):
"""Plots the error map of a given backend.
Args:
backend (IBMQBackend): Given backend.
figsize (tuple): Figure size in inches.
show_title (bool): Show the title or not.
Returns:
Figure: A matplotlib figure showing error map.
Raises:
VisualizationError: Input is not IBMQ backend.
MissingOptionalLibraryError: If seaborn is not installed
Example:
.. jupyter-execute::
:hide-code:
:hide-output:
from qiskit.test.ibmq_mock import mock_get_backend
mock_get_backend('FakeVigo')
.. jupyter-execute::
from qiskit import QuantumCircuit, execute, IBMQ
from qiskit.visualization import plot_error_map
%matplotlib inline
IBMQ.load_account()
provider = IBMQ.get_provider(hub='ibm-q')
backend = provider.get_backend('ibmq_vigo')
plot_error_map(backend)
"""
try:
import seaborn as sns
except ImportError as ex:
raise MissingOptionalLibraryError(
libname="seaborn",
name="plot_error_map",
pip_install="pip install seaborn",
) from ex
if not HAS_MATPLOTLIB:
raise MissingOptionalLibraryError(
libname="Matplotlib",
name="plot_error_map",
pip_install="pip install matplotlib",
)
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
from matplotlib import ticker
color_map = sns.cubehelix_palette(reverse=True, as_cmap=True)
props = backend.properties().to_dict()
config = backend.configuration().to_dict()
num_qubits = config["n_qubits"]
# U2 error rates
single_gate_errors = [0] * num_qubits
for gate in props["gates"]:
if gate["gate"] == "u2":
_qubit = gate["qubits"][0]
single_gate_errors[_qubit] = gate["parameters"][0]["value"]
# Convert to percent
single_gate_errors = 100 * np.asarray(single_gate_errors)
avg_1q_err = np.mean(single_gate_errors)
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]
cmap = config["coupling_map"]
directed = False
line_colors = []
if cmap:
directed = False
if num_qubits < 20:
for edge in cmap:
if not [edge[1], edge[0]] in cmap:
directed = True
break
cx_errors = []
for line in cmap:
for item in props["gates"]:
if item["qubits"] == line:
cx_errors.append(item["parameters"][0]["value"])
break
else:
continue
# Convert to percent
cx_errors = 100 * np.asarray(cx_errors)
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]
# Measurement errors
read_err = []
for qubit in range(num_qubits):
for item in props["qubits"][qubit]:
if item["name"] == "readout_error":
read_err.append(item["value"])
read_err = 100 * np.asarray(read_err)
avg_read_err = np.mean(read_err)
max_read_err = np.max(read_err)
fig = plt.figure(figsize=figsize)
gridspec.GridSpec(nrows=2, ncols=3)
grid_spec = gridspec.GridSpec(
12, 12, height_ratios=[1] * 11 + [0.5], width_ratios=[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2]
)
left_ax = plt.subplot(grid_spec[2:10, :1])
main_ax = plt.subplot(grid_spec[:11, 1:11])
right_ax = plt.subplot(grid_spec[2:10, 11:])
bleft_ax = plt.subplot(grid_spec[-1, :5])
if cmap:
bright_ax = plt.subplot(grid_spec[-1, 7:])
qubit_size = 28
if num_qubits <= 5:
qubit_size = 20
plot_gate_map(
backend,
qubit_color=q_colors,
line_color=line_colors,
qubit_size=qubit_size,
line_width=5,
plot_directed=directed,
ax=main_ax,
)
main_ax.axis("off")
main_ax.set_aspect(1)
if cmap:
single_cb = matplotlib.colorbar.ColorbarBase(
bleft_ax, cmap=color_map, norm=single_norm, orientation="horizontal"
)
tick_locator = ticker.MaxNLocator(nbins=5)
single_cb.locator = tick_locator
single_cb.update_ticks()
single_cb.update_ticks()
bleft_ax.set_title(f"H error rate (%) [Avg. = {round(avg_1q_err, 3)}]")
if cmap is None:
bleft_ax.axis("off")
bleft_ax.set_title(f"H error rate (%) = {round(avg_1q_err, 3)}")
if cmap:
cx_cb = matplotlib.colorbar.ColorbarBase(
bright_ax, cmap=color_map, norm=cx_norm, orientation="horizontal"
)
tick_locator = ticker.MaxNLocator(nbins=5)
cx_cb.locator = tick_locator
cx_cb.update_ticks()
bright_ax.set_title(f"CNOT error rate (%) [Avg. = {round(avg_cx_err, 3)}]")
if num_qubits < 10:
num_left = num_qubits
num_right = 0
else:
num_left = math.ceil(num_qubits / 2)
num_right = num_qubits - num_left
left_ax.barh(range(num_left), read_err[:num_left], align="center", color="#DDBBBA")
left_ax.axvline(avg_read_err, linestyle="--", color="#212121")
left_ax.set_yticks(range(num_left))
left_ax.set_xticks([0, round(avg_read_err, 2), round(max_read_err, 2)])
left_ax.set_yticklabels([str(kk) for kk in range(num_left)], fontsize=12)
left_ax.invert_yaxis()
left_ax.set_title("Readout Error (%)", fontsize=12)
for spine in left_ax.spines.values():
spine.set_visible(False)
if num_right:
right_ax.barh(
range(num_left, num_qubits), read_err[num_left:], align="center", color="#DDBBBA"
)
right_ax.axvline(avg_read_err, linestyle="--", color="#212121")
right_ax.set_yticks(range(num_left, num_qubits))
right_ax.set_xticks([0, round(avg_read_err, 2), round(max_read_err, 2)])
right_ax.set_yticklabels([str(kk) for kk in range(num_left, num_qubits)], fontsize=12)
right_ax.invert_yaxis()
right_ax.invert_xaxis()
right_ax.yaxis.set_label_position("right")
right_ax.yaxis.tick_right()
right_ax.set_title("Readout Error (%)", fontsize=12)
else:
right_ax.axis("off")
for spine in right_ax.spines.values():
spine.set_visible(False)
if show_title:
fig.suptitle(f"{backend.name()} Error Map", fontsize=24, y=0.9)
matplotlib_close_if_inline(fig)
return fig