diff --git a/qiskit/visualization/bloch.py b/qiskit/visualization/bloch.py index ac5dd8c3e72..e7b4cb96817 100644 --- a/qiskit/visualization/bloch.py +++ b/qiskit/visualization/bloch.py @@ -149,7 +149,9 @@ class Bloch: Positions of +z and -z labels respectively. """ - def __init__(self, fig=None, axes=None, view=None, figsize=None, background=False): + def __init__( + self, fig=None, axes=None, view=None, figsize=None, background=False, font_size=20 + ): # Figure and axes self._ext_fig = False @@ -194,7 +196,7 @@ def __init__(self, fig=None, axes=None, view=None, figsize=None, background=Fals # Color of fonts, default = 'black' self.font_color = plt.rcParams["axes.labelcolor"] # Size of fonts, default = 20 - self.font_size = 20 + self.font_size = font_size # ---vector options--- # List of colors for Bloch vectors, default = ['b','g','r','y'] diff --git a/qiskit/visualization/state_visualization.py b/qiskit/visualization/state_visualization.py index 98122585b14..7dae6433ee9 100644 --- a/qiskit/visualization/state_visualization.py +++ b/qiskit/visualization/state_visualization.py @@ -187,7 +187,9 @@ def plot_state_hinton( @_optionals.HAS_MATPLOTLIB.require_in_call -def plot_bloch_vector(bloch, title="", ax=None, figsize=None, coord_type="cartesian"): +def plot_bloch_vector( + bloch, title="", ax=None, figsize=None, coord_type="cartesian", font_size=None +): """Plot the Bloch sphere. Plot a Bloch sphere with the specified coordinates, that can be given in both @@ -204,6 +206,7 @@ def plot_bloch_vector(bloch, title="", ax=None, figsize=None, coord_type="cartes figsize (tuple): Figure size in inches. Has no effect is passing ``ax``. coord_type (str): a string that specifies coordinate type for bloch (Cartesian or spherical), default is Cartesian + font_size (float): Font size. Returns: Figure: A matplotlib figure instance if ``ax = None``. @@ -234,7 +237,7 @@ def plot_bloch_vector(bloch, title="", ax=None, figsize=None, coord_type="cartes if figsize is None: figsize = (5, 5) - B = Bloch(axes=ax) + B = Bloch(axes=ax, font_size=font_size) if coord_type == "spherical": r, theta, phi = bloch[0], bloch[1], bloch[2] bloch[0] = r * np.sin(theta) * np.cos(phi) @@ -253,7 +256,16 @@ def plot_bloch_vector(bloch, title="", ax=None, figsize=None, coord_type="cartes @deprecate_arguments({"rho": "state"}, since="0.15.1") @_optionals.HAS_MATPLOTLIB.require_in_call def plot_bloch_multivector( - state, title="", figsize=None, *, rho=None, reverse_bits=False, filename=None + state, + title="", + figsize=None, + *, + rho=None, + reverse_bits=False, + filename=None, + font_size=None, + title_font_size=None, + title_pad=1, ): r"""Plot a Bloch sphere for each qubit. @@ -266,8 +278,11 @@ def plot_bloch_multivector( Args: state (Statevector or DensityMatrix or ndarray): an N-qubit quantum state. title (str): a string that represents the plot title - figsize (tuple): Has no effect, here for compatibility only. + figsize (tuple): size of each individual Bloch sphere figure, in inches. reverse_bits (bool): If True, plots qubits following Qiskit's convention [Default:False]. + font_size (float): Font size for the Bloch ball figures. + title_font_size (float): Font size for the title. + title_pad (float): Padding for the title (suptitle `y` position is `y=1+title_pad/100`). Returns: matplotlib.Figure: @@ -324,13 +339,21 @@ def plot_bloch_multivector( _bloch_multivector_data(state)[::-1] if reverse_bits else _bloch_multivector_data(state) ) num = len(bloch_data) - width, height = plt.figaspect(1 / num) + if figsize is not None: + width, height = figsize + width *= num + else: + width, height = plt.figaspect(1 / num) + default_title_font_size = font_size if font_size is not None else 16 + title_font_size = title_font_size if title_font_size is not None else default_title_font_size fig = plt.figure(figsize=(width, height)) for i in range(num): pos = num - 1 - i if reverse_bits else i ax = fig.add_subplot(1, num, i + 1, projection="3d") - plot_bloch_vector(bloch_data[i], "qubit " + str(pos), ax=ax, figsize=figsize) - fig.suptitle(title, fontsize=16, y=1.01) + plot_bloch_vector( + bloch_data[i], "qubit " + str(pos), ax=ax, figsize=figsize, font_size=font_size + ) + fig.suptitle(title, fontsize=title_font_size, y=1.0 + title_pad / 100) matplotlib_close_if_inline(fig) if filename is None: return fig diff --git a/releasenotes/notes/update-state-visualization-6836bd53e3a24891.yaml b/releasenotes/notes/update-state-visualization-6836bd53e3a24891.yaml new file mode 100644 index 00000000000..a348d96dccd --- /dev/null +++ b/releasenotes/notes/update-state-visualization-6836bd53e3a24891.yaml @@ -0,0 +1,23 @@ +--- +features: + - | + The ``figsize`` argument of + :obj:`~qiskit.visualization.plot_bloch_multivector` can now be used to + set a size for individual Bloch ball sub-plots: if there are ``num`` + qubits and ``(w, h)`` is passed to ``figsize``, then the overall figure + width is set to ``num*w``, while the overall height is set to ``h``. + - | + A new ``font_size`` keyword argument for + :obj:`~qiskit.visualization.plot_bloch_multivector` can be used to + control the font size in Bloch ball sub-plots. + - | + New ``title_font_size`` and ``title_pad`` keyword arguments + for :obj:`~qiskit.visualization.plot_bloch_multivector` can be used to + control the font size of the overall title and its padding. +fixes: + - | + Previous to this release, the ``figsize`` argument of + :obj:`~qiskit.visualization.plot_bloch_multivector` was not used by the + visualization, making it impossible to change its size (e.g. to shrink + it for single-qubit states). This release fixes it by introducing a use + for the ``figsize`` argument. \ No newline at end of file diff --git a/test/ipynb/mpl/graph/references/bloch_multivector_figsize_improvements.png b/test/ipynb/mpl/graph/references/bloch_multivector_figsize_improvements.png new file mode 100644 index 00000000000..c7e8b102ea0 Binary files /dev/null and b/test/ipynb/mpl/graph/references/bloch_multivector_figsize_improvements.png differ diff --git a/test/ipynb/mpl/graph/test_graph_matplotlib_drawer.py b/test/ipynb/mpl/graph/test_graph_matplotlib_drawer.py index 23f676da228..962c905ffd7 100644 --- a/test/ipynb/mpl/graph/test_graph_matplotlib_drawer.py +++ b/test/ipynb/mpl/graph/test_graph_matplotlib_drawer.py @@ -370,6 +370,31 @@ def test_plot_coupling_map(self): filename="coupling_map.png", ) + def test_plot_bloch_multivector_figsize_improvements(self): + """test bloch sphere figsize, font_size, title_font_size and title_pad + See https://github.com/Qiskit/qiskit-terra/issues/7263 + and https://github.com/Qiskit/qiskit-terra/pull/7264. + """ + circuit = QuantumCircuit(3) + circuit.h(1) + circuit.sxdg(2) + + # getting the state using backend + backend = BasicAer.get_backend("statevector_simulator") + result = execute(circuit, backend).result() + state = result.get_statevector(circuit) + + self.graph_state_drawer( + state=state, + output="bloch", + figsize=(3, 2), + font_size=10, + title="|0+R> state", + title_font_size=14, + title_pad=8, + filename="bloch_multivector_figsize_improvements.png", + ) + if __name__ == "__main__": unittest.main(verbosity=1)