diff --git a/qiskit/visualization/gate_map.py b/qiskit/visualization/gate_map.py index 52c4ff39ab29..e48f7d7df2f2 100644 --- a/qiskit/visualization/gate_map.py +++ b/qiskit/visualization/gate_map.py @@ -20,6 +20,7 @@ from qiskit.exceptions import QiskitError from qiskit.utils import optionals as _optionals +from qiskit.providers.exceptions import BackendPropertyError from .exceptions import VisualizationError from .utils import matplotlib_close_if_inline @@ -910,14 +911,16 @@ def plot_error_map(backend, figsize=(12, 9), show_title=True, qubit_coordinates= backend_version = _get_backend_interface_version(backend) if backend_version <= 1: + backend_name = backend.name() num_qubits = backend.configuration().n_qubits cmap = backend.configuration().coupling_map - props = backend.properties().to_dict() + props = backend.properties() + props_dict = props.to_dict() single_gate_errors = [0] * num_qubits read_err = [0] * num_qubits cx_errors = [] # sx error rates - for gate in props["gates"]: + for gate in props_dict["gates"]: if gate["gate"] == "sx": _qubit = gate["qubits"][0] for param in gate["parameters"]: @@ -937,16 +940,18 @@ def plot_error_map(backend, figsize=(12, 9), show_title=True, qubit_coordinates= break for line in cmap: - for item in props["gates"]: + for item in props_dict["gates"]: if item["qubits"] == line: cx_errors.append(item["parameters"][0]["value"]) break for qubit in range(num_qubits): - for item in props["qubits"][qubit]: - if item["name"] == "readout_error": - read_err.append(item["value"]) + try: + read_err[qubit] = props.readout_error(qubit) + except BackendPropertyError: + pass else: + backend_name = backend.name num_qubits = backend.num_qubits cmap = backend.coupling_map two_q_error_map = {} @@ -977,7 +982,7 @@ def plot_error_map(backend, figsize=(12, 9), show_title=True, qubit_coordinates= if not [edge[1], edge[0]] in cmap: directed = True break - for line in cmap: + for line in cmap.get_edges(): err = two_q_error_map.get(tuple(line), 0) cx_errors.append(err) @@ -1095,6 +1100,6 @@ def plot_error_map(backend, figsize=(12, 9), show_title=True, qubit_coordinates= spine.set_visible(False) if show_title: - fig.suptitle(f"{backend.name()} Error Map", fontsize=24, y=0.9) + fig.suptitle(f"{backend_name} Error Map", fontsize=24, y=0.9) matplotlib_close_if_inline(fig) return fig diff --git a/releasenotes/notes/fix-plot-error-map-f3b4cc754b589d8f.yaml b/releasenotes/notes/fix-plot-error-map-f3b4cc754b589d8f.yaml new file mode 100644 index 000000000000..a1feedab8521 --- /dev/null +++ b/releasenotes/notes/fix-plot-error-map-f3b4cc754b589d8f.yaml @@ -0,0 +1,8 @@ +--- +fixes: + - | + Fixed an issue with the :class:`~.plot_error_map` visualization function + which prevented it from working when run with a backend that had readout + error defined in the provided backend's :class:`~.BackendProperties` or + when running with a :class:`~.BackendV2` backend. + Fixed `#7879 `__ diff --git a/test/python/visualization/references/kolkata_error.png b/test/python/visualization/references/kolkata_error.png new file mode 100644 index 000000000000..2c10258e5d42 Binary files /dev/null and b/test/python/visualization/references/kolkata_error.png differ diff --git a/test/python/visualization/references/kolkata_v2_error.png b/test/python/visualization/references/kolkata_v2_error.png new file mode 100644 index 000000000000..2c10258e5d42 Binary files /dev/null and b/test/python/visualization/references/kolkata_v2_error.png differ diff --git a/test/python/visualization/references/washington_error.png b/test/python/visualization/references/washington_error.png new file mode 100644 index 000000000000..c5991313013a Binary files /dev/null and b/test/python/visualization/references/washington_error.png differ diff --git a/test/python/visualization/references/washington_v2_error.png b/test/python/visualization/references/washington_v2_error.png new file mode 100644 index 000000000000..c5991313013a Binary files /dev/null and b/test/python/visualization/references/washington_v2_error.png differ diff --git a/test/python/visualization/test_gate_map.py b/test/python/visualization/test_gate_map.py index c4a6e4e96c15..99541fe37564 100644 --- a/test/python/visualization/test_gate_map.py +++ b/test/python/visualization/test_gate_map.py @@ -18,7 +18,18 @@ from PIL import Image from ddt import ddt, data from qiskit.test.mock import FakeProvider -from qiskit.visualization.gate_map import plot_gate_map, plot_coupling_map, plot_circuit_layout +from qiskit.providers.fake_provider import ( + FakeKolkata, + FakeWashington, + FakeKolkataV2, + FakeWashingtonV2, +) +from qiskit.visualization.gate_map import ( + plot_gate_map, + plot_coupling_map, + plot_circuit_layout, + plot_error_map, +) from qiskit.utils import optionals from qiskit import QuantumRegister, QuantumCircuit from qiskit.transpiler import Layout @@ -93,6 +104,54 @@ def test_plot_gate_map_no_backend(self): self.assertImagesAreEqual(Image.open(img_buffer), img_ref, 0.2) plt.close(fig) + @unittest.skipIf(not optionals.HAS_MATPLOTLIB, "matplotlib not available.") + def test_plot_error_map_backend_v1(self): + """Test plotting error map with fake backend v1.""" + backend = FakeKolkata() + img_ref = path_to_diagram_reference("kolkata_error.png") + fig = plot_error_map(backend) + with BytesIO() as img_buffer: + fig.savefig(img_buffer, format="png") + img_buffer.seek(0) + self.assertImagesAreEqual(Image.open(img_buffer), img_ref, 0.2) + plt.close(fig) + + @unittest.skipIf(not optionals.HAS_MATPLOTLIB, "matplotlib not available.") + def test_plot_error_map_backend_v2(self): + """Test plotting error map with fake backend v2.""" + backend = FakeKolkataV2() + img_ref = path_to_diagram_reference("kolkata_v2_error.png") + fig = plot_error_map(backend) + with BytesIO() as img_buffer: + fig.savefig(img_buffer, format="png") + img_buffer.seek(0) + self.assertImagesAreEqual(Image.open(img_buffer), img_ref, 0.2) + plt.close(fig) + + @unittest.skipIf(not optionals.HAS_MATPLOTLIB, "matplotlib not available.") + def test_plot_error_map_over_100_qubit(self): + """Test plotting error map with large fake backend.""" + backend = FakeWashington() + img_ref = path_to_diagram_reference("washington_error.png") + fig = plot_error_map(backend) + with BytesIO() as img_buffer: + fig.savefig(img_buffer, format="png") + img_buffer.seek(0) + self.assertImagesAreEqual(Image.open(img_buffer), img_ref, 0.2) + plt.close(fig) + + @unittest.skipIf(not optionals.HAS_MATPLOTLIB, "matplotlib not available.") + def test_plot_error_map_over_100_qubit_backend_v2(self): + """Test plotting error map with large fake backendv2.""" + backend = FakeWashingtonV2() + img_ref = path_to_diagram_reference("washington_v2_error.png") + fig = plot_error_map(backend) + with BytesIO() as img_buffer: + fig.savefig(img_buffer, format="png") + img_buffer.seek(0) + self.assertImagesAreEqual(Image.open(img_buffer), img_ref, 0.2) + plt.close(fig) + if __name__ == "__main__": unittest.main(verbosity=2)