From 8c40b0250a35293ea923cddc23949c1d8628f512 Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Thu, 29 Oct 2020 15:26:39 -0700 Subject: [PATCH] Make all mpl styles json loads and update visualization code and docs (#5223) * Convert default in qcstyle to dict * Convert styles to all dict and begin file loads * Created bw and iqx json files, styles dir, and cleanup * Finish json load and cleanup * Consolidate json load and remove copy in qcstyle * Update docs and cleanup style dict * Update docs and adjust barrier and measure * Fixing doc strings * Docstrings * Set up path for styles json and added tests * Testing paths * Update docs, use warn in user_config, and new test * Finalize drawer docstrings * Lint * More lint * QC doc fix * QC doc fix2 * QC doc fix3 * QC doc fix4 * Updated partial_layout.png reference image * Doc updates, path delimeter, and mpl changes * Lint * Docstring fix * Release note * Subfont fix, bad style var warn, and for-else * Fix italic c * Fix path and bw.png * Debug path in binder * Debug2 * Debug3 * Debug4 * Update path * Update path pkgutil * Update2 * Use exists * Listdir * Listdir minus 1 * install locally * Cleanup and return to sanity * Lint * Doc error * Fix style selection * new refs * debug * edit * install style jsons * remove debuging print * references! Co-authored-by: Luciano Bello --- MANIFEST.in | 1 + postBuild | 1 + qiskit/circuit/quantumcircuit.py | 313 ++++---- qiskit/user_config.py | 35 +- qiskit/visualization/__init__.py | 2 +- qiskit/visualization/circuit_visualization.py | 428 +++++------ qiskit/visualization/latex.py | 20 +- qiskit/visualization/matplotlib.py | 677 +++++++++--------- qiskit/visualization/qcstyle.py | 542 ++++---------- qiskit/visualization/styles/bw.json | 213 ++++++ qiskit/visualization/styles/default.json | 213 ++++++ qiskit/visualization/styles/iqx.json | 213 ++++++ ...ser-style-json-files-823590b03f015e4b.yaml | 23 + test/ipynb/mpl/references/bw.png | Bin 0 -> 27362 bytes test/ipynb/mpl/references/iqx_color.png | Bin 51329 -> 51329 bytes test/ipynb/mpl/references/partial_layout.png | Bin 11271 -> 17168 bytes test/ipynb/mpl/references/reverse_bits.png | Bin 0 -> 9281 bytes test/ipynb/mpl/references/subfont.png | Bin 0 -> 9929 bytes test/ipynb/mpl/references/user_style.png | Bin 0 -> 56602 bytes .../mpl/test_circuit_matplotlib_drawer.py | 66 +- test/ipynb/mpl/user_style.json | 213 ++++++ test/python/test_user_config.py | 8 +- 22 files changed, 1828 insertions(+), 1140 deletions(-) create mode 100644 qiskit/visualization/styles/bw.json create mode 100644 qiskit/visualization/styles/default.json create mode 100644 qiskit/visualization/styles/iqx.json create mode 100644 releasenotes/notes/load-user-style-json-files-823590b03f015e4b.yaml create mode 100644 test/ipynb/mpl/references/bw.png create mode 100644 test/ipynb/mpl/references/reverse_bits.png create mode 100644 test/ipynb/mpl/references/subfont.png create mode 100644 test/ipynb/mpl/references/user_style.png create mode 100644 test/ipynb/mpl/user_style.json diff --git a/MANIFEST.in b/MANIFEST.in index 07c56801a3a2..47fe2fa2830a 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -4,6 +4,7 @@ include qiskit/schemas/*.json include qiskit/VERSION.txt include qiskit/transpiler/passes/routing/cython/stochastic_swap/*.pyx include qiskit/transpiler/passes/routing/cython/stochastic_swap/*.pxd +include qiskit/visualization/styles/*.json recursive-include qiskit/test/mock/backends *.json # Include the tests files. diff --git a/postBuild b/postBuild index ddc9f0449702..15e7fe0a1827 100644 --- a/postBuild +++ b/postBuild @@ -8,6 +8,7 @@ # - pillow: for image comparison # - appmode: jupyter extension for executing the notebook pip install matplotlib pylatexenc pillow appmode +pip install . # Activation of appmode extension jupyter nbextension enable --py --sys-prefix appmode diff --git a/qiskit/circuit/quantumcircuit.py b/qiskit/circuit/quantumcircuit.py index ae43316052a3..eafe5e26fe6b 100644 --- a/qiskit/circuit/quantumcircuit.py +++ b/qiskit/circuit/quantumcircuit.py @@ -1128,172 +1128,223 @@ def draw(self, output=None, scale=None, filename=None, style=None, interactive=False, plot_barriers=True, reverse_bits=False, justify=None, vertical_compression='medium', idle_wires=True, with_layout=True, fold=None, ax=None, initial_state=False, cregbundle=True): - """Draw the quantum circuit. + """Draw the quantum circuit. Use the output parameter to choose the drawing format: **text**: ASCII art TextDrawing that can be printed in the console. - **latex**: high-quality images compiled via LaTeX. + **matplotlib**: images with color rendered purely in Python. - **latex_source**: raw uncompiled LaTeX output. + **latex**: high-quality images compiled via latex. - **matplotlib**: images with color rendered purely in Python. + **latex_source**: raw uncompiled latex output. Args: - output (str): Select the output method to use for drawing the - circuit. Valid choices are ``text``, ``latex``, - ``latex_source``, or ``mpl``. By default the `'text`' drawer is - used unless a user config file has an alternative backend set - as the default. If the output kwarg is set, that backend - will always be used over the default in a user config file. - scale (float): scale of image to draw (shrink if < 1) - filename (str): file path to save image to - style (dict or str): dictionary of style or file name of style - file. This option is only used by the ``mpl`` output type. If a - str is passed in that is the path to a json file which contains - a dictionary of style, then that will be opened, parsed, and used - as the input dict. See: :ref:`Style Dict Doc ` for more + output (str): select the output method to use for drawing the circuit. + Valid choices are ``text``, ``mpl``, ``latex``, ``latex_source``. + By default the `text` drawer is used unless the user config file + (usually ``~/.qiskit/settings.conf``) has an alternative backend set + as the default. For example, ``circuit_drawer = latex``. If the output + kwarg is set, that backend will always be used over the default in + the user config file. + scale (float): scale of image to draw (shrink if < 1.0). Only used by + the `mpl`, `latex` and `latex_source` outputs. Defaults to 1.0. + filename (str): file path to save image to. Defaults to None. + style (dict or str): dictionary of style or file name of style json file. + This option is only used by the `mpl` output type. If a str, it + is used as the path to a json file which contains a style dict. + The file will be opened, parsed, and then any style elements in the + dict will replace the default values in the input dict. A file to + be loaded must end in ``.json``, but the name entered here can omit + ``.json``. For example, ``style='iqx.json'`` or ``style='iqx'``. + If `style` is a dict and the ``'name'`` key is set, that name + will be used to load a json file, followed by loading the other + items in the style dict. For example, ``style={'name': 'iqx'}``. + If `style` is not a str and `name` is not a key in the style dict, + then the default value from the user config file (usually + ``~/.qiskit/settings.conf``) will be used, for example, + ``circuit_mpl_style = iqx``. + If none of these are set, the `default` style will be used. + The search path for style json files can be specified in the user + config, for example, + ``circuit_mpl_style_path = /home/user/styles:/home/user``. + See: :ref:`Style Dict Doc ` for more information on the contents. - interactive (bool): when set true show the circuit in a new window + interactive (bool): when set to true, show the circuit in a new window (for `mpl` this depends on the matplotlib backend being used supporting this). Note when used with either the `text` or the - `latex_source` output type this has no effect and will be - silently ignored. - reverse_bits (bool): When set to True, reverse the bit order inside - registers for the output visualization. - plot_barriers (bool): Enable/disable drawing barriers in the output + `latex_source` output type this has no effect and will be silently + ignored. Defaults to False. + reverse_bits (bool): when set to True, reverse the bit order inside + registers for the output visualization. Defaults to False. + plot_barriers (bool): enable/disable drawing barriers in the output circuit. Defaults to True. - justify (string): Options are ``left``, ``right`` or - ``none``. If anything else is supplied it defaults to left - justified. It refers to where gates should be placed in the - output circuit if there is an option. ``none`` results in - each gate being placed in its own column. + justify (string): options are ``left``, ``right`` or ``none``. If + anything else is supplied, it defaults to left justified. It refers + to where gates should be placed in the output circuit if there is + an option. ``none`` results in each gate being placed in its own + column. vertical_compression (string): ``high``, ``medium`` or ``low``. It - merges the lines generated by the ``text`` output so the - drawing will take less vertical room. Default is ``medium``. - Only used by the ``text`` output, will be silently ignored - otherwise. - idle_wires (bool): Include idle wires (wires with no circuit - elements) in output visualization. Default is True. - with_layout (bool): Include layout information, with labels on the + merges the lines generated by the `text` output so the drawing + will take less vertical room. Default is ``medium``. Only used by + the `text` output, will be silently ignored otherwise. + idle_wires (bool): include idle wires (wires with no circuit elements) + in output visualization. Default is True. + with_layout (bool): include layout information, with labels on the physical layout. Default is True. - fold (int): Sets pagination. It can be disabled using -1. - In `text`, sets the length of the lines. This is useful when the - drawing does not fit in the console. If None (default), it will - try to guess the console width using ``shutil. - get_terminal_size()``. However, if running in jupyter, the - default line length is set to 80 characters. In ``mpl`` is the - number of (visual) layers before folding. Default is 25. - ax (matplotlib.axes.Axes): An optional Axes object to be used for - the visualization output. If none is specified, a new matplotlib - Figure will be created and used. Additionally, if specified, - there will be no returned Figure since it is redundant. This is - only used when the ``output`` kwarg is set to use the ``mpl`` - backend. It will be silently ignored with all other outputs. - initial_state (bool): Optional. Adds ``|0>`` in the beginning of the wire. - Only used by the ``text``, ``latex`` and ``latex_source`` outputs. - Default: ``False``. - cregbundle (bool): Optional. If set True bundle classical registers. Not used by - the ``matplotlib`` output. Default: ``True``. + fold (int): sets pagination. It can be disabled using -1. In `text`, + sets the length of the lines. This is useful when the drawing does + not fit in the console. If None (default), it will try to guess the + console width using ``shutil.get_terminal_size()``. However, if + running in jupyter, the default line length is set to 80 characters. + In `mpl`, it is the number of (visual) layers before folding. + Default is 25. + ax (matplotlib.axes.Axes): Only used by the `mpl` backend. An optional + Axes object to be used for the visualization output. If none is + specified, a new matplotlib Figure will be created and used. + Additionally, if specified there will be no returned Figure since + it is redundant. + initial_state (bool): optional. Adds ``|0>`` in the beginning of the wire. + Default is False. + cregbundle (bool): optional. If set True, bundle classical registers. + Default is True. Returns: - :class:`PIL.Image` or :class:`matplotlib.figure` or :class:`str` or - :class:`TextDrawing`: + :class:`TextDrawing` or :class:`matplotlib.figure` or :class:`PIL.Image` or + :class:`str`: - * `PIL.Image` (output='latex') - an in-memory representation of the image of the circuit - diagram. + * `TextDrawing` (output='text') + A drawing that can be printed as ascii art. * `matplotlib.figure.Figure` (output='mpl') - a matplotlib figure object for the circuit diagram. + A matplotlib figure object for the circuit diagram. + * `PIL.Image` (output='latex') + An in-memory representation of the image of the circuit diagram. * `str` (output='latex_source') The LaTeX source code for visualizing the circuit diagram. - * `TextDrawing` (output='text') - A drawing that can be printed as ASCII art. Raises: VisualizationError: when an invalid output method is selected - ImportError: when the output methods require non-installed - libraries + ImportError: when the output methods requires non-installed libraries. - .. _style-dict-circ-doc: + .. _style-dict-doc: **Style Dict Details** - The style dict kwarg contains numerous options that define the style of - the output circuit visualization. The style dict is only used by the - ``mpl`` output. The options available in the style dict are defined - below: + The style dict kwarg contains numerous options that define the style of the + output circuit visualization. The style dict is only used by the `mpl` + output. The options available in the style dict are defined below: Args: - name (str): The name of the style. The name can be set to 'iqx', - 'bw', or 'default'. This overrides the setting in the - '~/.qiskit/settings.conf' file. - textcolor (str): The color code to use for text. Defaults to - `'#000000'` - subtextcolor (str): The color code to use for subtext. Defaults to - `'#000000'` - linecolor (str): The color code to use for lines. Defaults to - `'#000000'` - creglinecolor (str): The color code to use for classical register - lines. Defaults to `'#778899'` - gatetextcolor (str): The color code to use for gate text. Defaults - to `'#000000'` - gatefacecolor (str): The color code to use for gates. Defaults to - `'#ffffff'` - barrierfacecolor (str): The color code to use for barriers. - Defaults to `'#bdbdbd'` - backgroundcolor (str): The color code to use for the background. - Defaults to `'#ffffff'` - fontsize (int): The font size to use for text. Defaults to 13. - subfontsize (int): The font size to use for subtext. Defaults to 8. - displaytext (dict): A dictionary of the text to use for each - element type in the output visualization. The default values - are:: + name (str): the name of the style. The name can be set to ``iqx``, + ``bw``, ``default``, or the name of a user-created json file. This + overrides the setting in the user config file (usually + ``~/.qiskit/settings.conf``). + textcolor (str): the color code to use for all text not inside a gate. + Defaults to ``#000000`` + subtextcolor (str): the color code to use for subtext. Defaults to + ``#000000`` + linecolor (str): the color code to use for lines. Defaults to + ``#000000`` + creglinecolor (str): the color code to use for classical register + lines. Defaults to ``#778899`` + gatetextcolor (str): the color code to use for gate text. Defaults to + ``#000000`` + gatefacecolor (str): the color code to use for a gate if no color + specified in the 'displaycolor' dict. Defaults to ``#BB8BFF`` + barrierfacecolor (str): the color code to use for barriers. Defaults to + ``#BDBDBD`` + backgroundcolor (str): the color code to use for the background. + Defaults to ``#FFFFFF`` + edgecolor (str): the color code to use for gate edges when using the + `bw` style. Defaults to ``#000000``. + fontsize (int): the font size to use for text. Defaults to 13. + subfontsize (int): the font size to use for subtext. Defaults to 8. + showindex (bool): if set to True, show the index numbers at the top. + Defaults to False. + figwidth (int): the maximum width (in inches) for the output figure. + If set to -1, the maximum displayable width will be used. + Defaults to -1. + dpi (int): the DPI to use for the output image. Defaults to 150. + margin (list): a list of margin values to adjust spacing around output + image. Takes a list of 4 ints: [x left, x right, y bottom, y top]. + Defaults to [2.0, 0.1, 0.1, 0.3]. + creglinestyle (str): The style of line to use for classical registers. + Choices are ``solid``, ``doublet``, or any valid matplotlib + `linestyle` kwarg value. Defaults to ``doublet``. + displaytext (dict): a dictionary of the text to use for certain element + types in the output visualization. These items allow the use of + LaTeX formatting for gate names. The 'displaytext' dict can contain + any number of elements from one to the entire dict above.The default + values are (`default.json`):: { - 'id': 'id', - 'u0': 'U_0', - 'u1': 'U_1', - 'u2': 'U_2', - 'u3': 'U_3', + 'u1': '$\\mathrm{U}_1$', + 'u2': '$\\mathrm{U}_2$', + 'u3': '$\\mathrm{U}_3$', + 'u': 'U', + 'p': 'P', + 'id': 'I', 'x': 'X', 'y': 'Y', 'z': 'Z', 'h': 'H', 's': 'S', - 'sdg': 'S^\\dagger', + 'sdg': '$\\mathrm{S}^\\dagger$', + 'sx': '$\\sqrt{\\mathrm{X}}$', + 'sxdg': '$\\sqrt{\\mathrm{X}}^\\dagger$', 't': 'T', - 'tdg': 'T^\\dagger', - 'rx': 'R_x', - 'ry': 'R_y', - 'rz': 'R_z', - 'reset': '\\left|0\\right\\rangle' + 'tdg': '$\\mathrm{T}^\\dagger$', + 'dcx': 'Dcx', + 'iswap': 'Iswap', + 'ms': 'MS', + 'r': 'R', + 'rx': '$\\mathrm{R}_\\mathrm{X}$', + 'ry': '$\\mathrm{R}_\\mathrm{Y}$', + 'rz': '$\\mathrm{R}_\\mathrm{Z}$', + 'rxx': '$\\mathrm{R}_{\\mathrm{XX}}$', + 'ryy': '$\\mathrm{R}_{\\mathrm{YY}}$', + 'rzx': '$\\mathrm{R}_{\\mathrm{ZX}}$', + 'rzz': '$\\mathrm{R}_{\\mathrm{ZZ}}$', + 'reset': '$\\left|0\\right\\rangle$', + 'initialize': '$|\\psi\\rangle$' } - You must specify all the necessary values if using this. There - is no provision for passing an incomplete dict in. - displaycolor (dict): The color codes to use for each circuit - element in the form (gate_color, text_color). - The default values are:: + displaycolor (dict): the color codes to use for each circuit element in + the form (gate_color, text_color). Colors can also be entered without + the text color, such as 'u1': '#FA74A6', in which case the text color + will always be `gatetextcolor`. The `displaycolor` dict can contain + any number of elements from one to the entire dict above. The default + values are (`default.json`):: { 'u1': ('#FA74A6', '#000000'), 'u2': ('#FA74A6', '#000000'), 'u3': ('#FA74A6', '#000000'), 'id': ('#05BAB6', '#000000'), + 'u': ('#BB8BFF', '#000000'), + 'p': ('#BB8BFF', '#000000'), 'x': ('#05BAB6', '#000000'), 'y': ('#05BAB6', '#000000'), 'z': ('#05BAB6', '#000000'), 'h': ('#6FA4FF', '#000000'), 'cx': ('#6FA4FF', '#000000'), + 'ccx': ('#BB8BFF', '#000000'), + 'mcx': ('#BB8BFF', '#000000'), + 'mcx_gray': ('#BB8BFF', '#000000), 'cy': ('#6FA4FF', '#000000'), 'cz': ('#6FA4FF', '#000000'), 'swap': ('#6FA4FF', '#000000'), - 's': ('#6FA4FF', '#000000'), - 'sdg': ('#6FA4FF', '#000000'), + 'cswap': ('#BB8BFF', '#000000'), + 'ccswap': ('#BB8BFF', '#000000'), 'dcx': ('#6FA4FF', '#000000'), + 'cdcx': ('#BB8BFF', '#000000'), + 'ccdcx': ('#BB8BFF', '#000000'), 'iswap': ('#6FA4FF', '#000000'), + 's': ('#6FA4FF', '#000000'), + 'sdg': ('#6FA4FF', '#000000'), 't': ('#BB8BFF', '#000000'), 'tdg': ('#BB8BFF', '#000000'), + 'sx': ('#BB8BFF', '#000000'), + 'sxdg': ('#BB8BFF', '#000000') 'r': ('#BB8BFF', '#000000'), 'rx': ('#BB8BFF', '#000000'), 'ry': ('#BB8BFF', '#000000'), @@ -1304,39 +1355,19 @@ def draw(self, output=None, scale=None, filename=None, style=None, 'reset': ('#000000', #FFFFFF'), 'target': ('#FFFFFF, '#FFFFFF'), 'measure': ('#000000', '#FFFFFF'), - 'ccx': ('#BB8BFF', '#000000'), - 'cdcx': ('#BB8BFF', '#000000'), - 'ccdcx': ('#BB8BFF', '#000000'), - 'cswap': ('#BB8BFF', '#000000'), - 'ccswap': ('#BB8BFF', '#000000'), - 'mcx': ('#BB8BFF', '#000000'), - 'mcx_gray': ('#BB8BFF', '#000000), - 'u': ('#BB8BFF', '#000000'), - 'p': ('#BB8BFF', '#000000'), - 'sx': ('#BB8BFF', '#000000'), - 'sxdg': ('#BB8BFF', '#000000') } - Colors can also be entered without the text color, such as - 'u1': '#FA74A6', in which case the text color will always - be 'gatetextcolor'. The 'displaycolor' dict can contain any - number of elements from one to the entire dict above. - latexdrawerstyle (bool): When set to True, enable LaTeX mode, which - will draw gates like the `latex` output modes. - usepiformat (bool): When set to True, use radians for output. - fold (int): The number of circuit elements to fold the circuit at. - Defaults to 20. - cregbundle (bool): If set True, bundle classical registers - showindex (bool): If set True, draw an index. - compress (bool): If set True, draw a compressed circuit. - figwidth (int): The maximum width (in inches) for the output figure. - dpi (int): The DPI to use for the output image. Defaults to 150. - margin (list): A list of margin values to adjust spacing around - output image. Takes a list of 4 ints: - [x left, x right, y bottom, y top]. - creglinestyle (str): The style of line to use for classical - registers. Choices are `'solid'`, `'doublet'`, or any valid - matplotlib `linestyle` kwarg value. Defaults to `doublet` + Example: + .. jupyter-execute:: + + from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit + from qiskit.tools.visualization import circuit_drawer + q = QuantumRegister(1) + c = ClassicalRegister(1) + qc = QuantumCircuit(q, c) + qc.h(q) + qc.measure(q, c) + qc.draw('mpl', style={'showindex': True}) """ # pylint: disable=cyclic-import diff --git a/qiskit/user_config.py b/qiskit/user_config.py index bd1bf6e2b404..e46a3762a8bc 100644 --- a/qiskit/user_config.py +++ b/qiskit/user_config.py @@ -14,6 +14,7 @@ import configparser import os +from warnings import warn from qiskit import exceptions @@ -29,6 +30,9 @@ class UserConfig: [default] circuit_drawer = mpl circuit_mpl_style = default + circuit_mpl_style_path = ~/.qiskit: + transpile_optimization_level = 1 + suppress_packaging_warnings = False """ def __init__(self, filename=None): @@ -36,7 +40,7 @@ def __init__(self, filename=None): Args: filename (str): The path to the user config file. If one isn't - specified ~/.qiskit/settings.conf is used. + specified, ~/.qiskit/settings.conf is used. """ if filename is None: self.filename = DEFAULT_FILENAME @@ -60,21 +64,35 @@ def read_config_file(self): 'latex_source', 'auto']: raise exceptions.QiskitUserConfigError( "%s is not a valid circuit drawer backend. Must be " - "either 'text', 'mpl', 'latex', 'auto', or " - "'latex_source'" + "either 'text', 'mpl', 'latex', 'latex_source', or " + "'auto'." % circuit_drawer) self.settings['circuit_drawer'] = circuit_drawer + # Parse circuit_mpl_style circuit_mpl_style = self.config_parser.get('default', 'circuit_mpl_style', fallback=None) if circuit_mpl_style: - if circuit_mpl_style not in ['default', 'iqx', 'bw']: - raise exceptions.QiskitUserConfigError( - "%s is not a valid mpl circuit style. Must be " - "either 'default', 'iqx', or bw'" - % circuit_mpl_style) + if not isinstance(circuit_mpl_style, str): + warn("%s is not a valid mpl circuit style. Must be " + "a text string. Will not load style." + % circuit_mpl_style, UserWarning, 2) self.settings['circuit_mpl_style'] = circuit_mpl_style + + # Parse circuit_mpl_style_path + circuit_mpl_style_path = self.config_parser.get('default', + 'circuit_mpl_style_path', + fallback=None) + if circuit_mpl_style_path: + cpath_list = circuit_mpl_style_path.split(':') + for path in cpath_list: + if not os.path.exists(os.path.expanduser(path)): + warn("%s is not a valid circuit mpl style path." + " Correct the path in ~/.qiskit/settings.conf." + % path, UserWarning, 2) + self.settings['circuit_mpl_style_path'] = cpath_list + # Parse transpile_optimization_level transpile_optimization_level = self.config_parser.getint( 'default', 'transpile_optimization_level', fallback=-1) @@ -86,6 +104,7 @@ def read_config_file(self): "0, 1, 2, or 3.") self.settings['transpile_optimization_level'] = ( transpile_optimization_level) + # Parse package warnings package_warnings = self.config_parser.getboolean( 'default', 'suppress_packaging_warnings', fallback=False) diff --git a/qiskit/visualization/__init__.py b/qiskit/visualization/__init__.py index 242932f37df2..a35dbb9f6152 100644 --- a/qiskit/visualization/__init__.py +++ b/qiskit/visualization/__init__.py @@ -113,7 +113,7 @@ plot_state_qsphere) from qiskit.visualization.transition_visualization import visualize_transition -from .circuit_visualization import circuit_drawer, qx_color_scheme +from .circuit_visualization import circuit_drawer from .dag_visualization import dag_drawer from .exceptions import VisualizationError from .gate_map import plot_gate_map, plot_circuit_layout, plot_error_map diff --git a/qiskit/visualization/circuit_visualization.py b/qiskit/visualization/circuit_visualization.py index c7207c2b2ee5..897308c24890 100644 --- a/qiskit/visualization/circuit_visualization.py +++ b/qiskit/visualization/circuit_visualization.py @@ -30,7 +30,6 @@ import os import subprocess import tempfile -from warnings import warn try: from PIL import Image @@ -64,85 +63,99 @@ def circuit_drawer(circuit, ax=None, initial_state=False, cregbundle=True): - """Draw a quantum circuit to different formats (set by output parameter): + """Draw the quantum circuit. Use the output parameter to choose the drawing format: **text**: ASCII art TextDrawing that can be printed in the console. + **matplotlib**: images with color rendered purely in Python. + **latex**: high-quality images compiled via latex. **latex_source**: raw uncompiled latex output. - **matplotlib**: images with color rendered purely in Python. - Args: circuit (QuantumCircuit): the quantum circuit to draw - scale (float): scale of image to draw (shrink if < 1). Only used by the ``mpl``, - ``latex``, and ``latex_source`` outputs. - filename (str): file path to save image to - style (dict or str): dictionary of style or file name of style file. - This option is only used by the ``mpl`` output type. If a str is - passed in that is the path to a json file which contains that will - be open, parsed, and then used just as the input dict. See: - :ref:`Style Dict Doc ` for more information on the - contents. - output (str): Select the output method to use for drawing the circuit. - Valid choices are ``text``, ``latex``, ``latex_source``, ``mpl``. - By default the `'text`' drawer is used unless a user config file - has an alternative backend set as the default. If the output kwarg - is set, that backend will always be used over the default in a user - config file. - interactive (bool): when set true show the circuit in a new window + scale (float): scale of image to draw (shrink if < 1.0). Only used by + the `mpl`, `latex` and `latex_source` outputs. Defaults to 1.0. + filename (str): file path to save image to. Defaults to None. + style (dict or str): dictionary of style or file name of style json file. + This option is only used by the `mpl` output type. If a str, it + is used as the path to a json file which contains a style dict. + The file will be opened, parsed, and then any style elements in the + dict will replace the default values in the input dict. A file to + be loaded must end in ``.json``, but the name entered here can omit + ``.json``. For example, ``style='iqx.json'`` or ``style='iqx'``. + If `style` is a dict and the ``'name'`` key is set, that name + will be used to load a json file, followed by loading the other + items in the style dict. For example, ``style={'name': 'iqx'}``. + If `style` is not a str and `name` is not a key in the style dict, + then the default value from the user config file (usually + ``~/.qiskit/settings.conf``) will be used, for example, + ``circuit_mpl_style = iqx``. + If none of these are set, the `default` style will be used. + The search path for style json files can be specified in the user + config, for example, + ``circuit_mpl_style_path = /home/user/styles:/home/user``. + See: :ref:`Style Dict Doc ` for more + information on the contents. + output (str): select the output method to use for drawing the circuit. + Valid choices are ``text``, ``mpl``, ``latex``, ``latex_source``. + By default the `text` drawer is used unless the user config file + (usually ``~/.qiskit/settings.conf``) has an alternative backend set + as the default. For example, ``circuit_drawer = latex``. If the output + kwarg is set, that backend will always be used over the default in + the user config file. + interactive (bool): when set to true, show the circuit in a new window (for `mpl` this depends on the matplotlib backend being used supporting this). Note when used with either the `text` or the `latex_source` output type this has no effect and will be silently - ignored. - reverse_bits (bool): When set to True reverse the bit order inside - registers for the output visualization. - plot_barriers (bool): Enable/disable drawing barriers in the output + ignored. Defaults to False. + reverse_bits (bool): when set to True, reverse the bit order inside + registers for the output visualization. Defaults to False. + plot_barriers (bool): enable/disable drawing barriers in the output circuit. Defaults to True. - justify (string): Options are ``left``, ``right`` or ``none``, if - anything else is supplied it defaults to left justified. It refers + justify (string): options are ``left``, ``right`` or ``none``. If + anything else is supplied, it defaults to left justified. It refers to where gates should be placed in the output circuit if there is an option. ``none`` results in each gate being placed in its own column. vertical_compression (string): ``high``, ``medium`` or ``low``. It - merges the lines generated by the ``text`` output so the drawing + merges the lines generated by the `text` output so the drawing will take less vertical room. Default is ``medium``. Only used by - the ``text`` output, will be silently ignored otherwise. - idle_wires (bool): Include idle wires (wires with no circuit elements) + the `text` output, will be silently ignored otherwise. + idle_wires (bool): include idle wires (wires with no circuit elements) in output visualization. Default is True. - with_layout (bool): Include layout information, with labels on the + with_layout (bool): include layout information, with labels on the physical layout. Default is True. - fold (int): Sets pagination. It can be disabled using -1. - In `text`, sets the length of the lines. This useful when the - drawing does not fit in the console. If None (default), it will try - to guess the console width using ``shutil.get_terminal_size()``. - However, if running in jupyter, the default line length is set to - 80 characters. In ``mpl`` it is the number of (visual) layers before - folding. Default is 25. - ax (matplotlib.axes.Axes): An optional Axes object to be used for - the visualization output. If none is specified a new matplotlib - Figure will be created and used. Additionally, if specified there - will be no returned Figure since it is redundant. This is only used - when the ``output`` kwarg is set to use the ``mpl`` backend. It - will be silently ignored with all other outputs. - initial_state (bool): Optional. Adds ``|0>`` in the beginning of the wire. - Default: ``False``. - cregbundle (bool): Optional. If set True bundle classical registers. - Default: ``True``. + fold (int): sets pagination. It can be disabled using -1. In `text`, + sets the length of the lines. This is useful when the drawing does + not fit in the console. If None (default), it will try to guess the + console width using ``shutil.get_terminal_size()``. However, if + running in jupyter, the default line length is set to 80 characters. + In `mpl`, it is the number of (visual) layers before folding. + Default is 25. + ax (matplotlib.axes.Axes): Only used by the `mpl` backend. An optional + Axes object to be used for the visualization output. If none is + specified, a new matplotlib Figure will be created and used. + Additionally, if specified there will be no returned Figure since + it is redundant. + initial_state (bool): optional. Adds ``|0>`` in the beginning of the wire. + Default is False. + cregbundle (bool): optional. If set True, bundle classical registers. + Default is True. Returns: - :class:`PIL.Image` or :class:`matplotlib.figure` or :class:`str` or - :class:`TextDrawing`: + :class:`TextDrawing` or :class:`matplotlib.figure` or :class:`PIL.Image` or + :class:`str`: - * `PIL.Image` (output='latex') - an in-memory representation of the image of the circuit diagram. + * `TextDrawing` (output='text') + A drawing that can be printed as ascii art. * `matplotlib.figure.Figure` (output='mpl') - a matplotlib figure object for the circuit diagram. + A matplotlib figure object for the circuit diagram. + * `PIL.Image` (output='latex') + An in-memory representation of the image of the circuit diagram. * `str` (output='latex_source') The LaTeX source code for visualizing the circuit diagram. - * `TextDrawing` (output='text') - A drawing that can be printed as ascii art Raises: VisualizationError: when an invalid output method is selected @@ -153,79 +166,121 @@ def circuit_drawer(circuit, **Style Dict Details** The style dict kwarg contains numerous options that define the style of the - output circuit visualization. The style dict is only used by the ``mpl`` + output circuit visualization. The style dict is only used by the `mpl` output. The options available in the style dict are defined below: Args: - name (str): The name of the style. The name can be set to 'iqx', - 'bw', or 'default'. This overrides the setting in the - '~/.qiskit/settings.conf' file. - textcolor (str): The color code to use for text. Defaults to - `'#000000'` - subtextcolor (str): The color code to use for subtext. Defaults to - `'#000000'` - linecolor (str): The color code to use for lines. Defaults to - `'#000000'` - creglinecolor (str): The color code to use for classical register - lines. Defaults to `'#778899'` - gatetextcolor (str): The color code to use for gate text. Defaults to - `'#000000'` - gatefacecolor (str): The color code to use for gates. Defaults to - `'#ffffff'` - barrierfacecolor (str): The color code to use for barriers. Defaults to - `'#bdbdbd'` - backgroundcolor (str): The color code to use for the background. - Defaults to `'#ffffff'` - fontsize (int): The font size to use for text. Defaults to 13 - subfontsize (int): The font size to use for subtext. Defaults to 8 - displaytext (dict): A dictionary of the text to use for each element - type in the output visualization. The default values are:: + name (str): the name of the style. The name can be set to ``iqx``, + ``bw``, ``default``, or the name of a user-created json file. This + overrides the setting in the user config file (usually + ``~/.qiskit/settings.conf``). + textcolor (str): the color code to use for all text not inside a gate. + Defaults to ``#000000`` + subtextcolor (str): the color code to use for subtext. Defaults to + ``#000000`` + linecolor (str): the color code to use for lines. Defaults to + ``#000000`` + creglinecolor (str): the color code to use for classical register + lines. Defaults to ``#778899`` + gatetextcolor (str): the color code to use for gate text. Defaults to + ``#000000`` + gatefacecolor (str): the color code to use for a gate if no color + specified in the 'displaycolor' dict. Defaults to ``#BB8BFF`` + barrierfacecolor (str): the color code to use for barriers. Defaults to + ``#BDBDBD`` + backgroundcolor (str): the color code to use for the background. + Defaults to ``#FFFFFF`` + edgecolor (str): the color code to use for gate edges when using the + `bw` style. Defaults to ``#000000``. + fontsize (int): the font size to use for text. Defaults to 13. + subfontsize (int): the font size to use for subtext. Defaults to 8. + showindex (bool): if set to True, show the index numbers at the top. + Defaults to False. + figwidth (int): the maximum width (in inches) for the output figure. + If set to -1, the maximum displayable width will be used. + Defaults to -1. + dpi (int): the DPI to use for the output image. Defaults to 150. + margin (list): a list of margin values to adjust spacing around output + image. Takes a list of 4 ints: [x left, x right, y bottom, y top]. + Defaults to [2.0, 0.1, 0.1, 0.3]. + creglinestyle (str): The style of line to use for classical registers. + Choices are ``solid``, ``doublet``, or any valid matplotlib + `linestyle` kwarg value. Defaults to ``doublet``. + displaytext (dict): a dictionary of the text to use for certain element + types in the output visualization. These items allow the use of + LaTeX formatting for gate names. The 'displaytext' dict can contain + any number of elements from one to the entire dict above.The default + values are (`default.json`):: { - 'id': 'id', - 'u0': 'U_0', - 'u1': 'U_1', - 'u2': 'U_2', - 'u3': 'U_3', + 'u1': '$\\mathrm{U}_1$', + 'u2': '$\\mathrm{U}_2$', + 'u3': '$\\mathrm{U}_3$', + 'u': 'U', + 'p': 'P', + 'id': 'I', 'x': 'X', 'y': 'Y', 'z': 'Z', 'h': 'H', 's': 'S', - 'sdg': 'S^\\dagger', + 'sdg': '$\\mathrm{S}^\\dagger$', + 'sx': '$\\sqrt{\\mathrm{X}}$', + 'sxdg': '$\\sqrt{\\mathrm{X}}^\\dagger$', 't': 'T', - 'tdg': 'T^\\dagger', - 'rx': 'R_x', - 'ry': 'R_y', - 'rz': 'R_z', - 'reset': '\\left|0\\right\\rangle' + 'tdg': '$\\mathrm{T}^\\dagger$', + 'dcx': 'Dcx', + 'iswap': 'Iswap', + 'ms': 'MS', + 'r': 'R', + 'rx': '$\\mathrm{R}_\\mathrm{X}$', + 'ry': '$\\mathrm{R}_\\mathrm{Y}$', + 'rz': '$\\mathrm{R}_\\mathrm{Z}$', + 'rxx': '$\\mathrm{R}_{\\mathrm{XX}}$', + 'ryy': '$\\mathrm{R}_{\\mathrm{YY}}$', + 'rzx': '$\\mathrm{R}_{\\mathrm{ZX}}$', + 'rzz': '$\\mathrm{R}_{\\mathrm{ZZ}}$', + 'reset': '$\\left|0\\right\\rangle$', + 'initialize': '$|\\psi\\rangle$' } - You must specify all the necessary values if using this. There is - no provision for passing an incomplete dict in. - displaycolor (dict): The color codes to use for each circuit - element in the form (gate_color, text_color). - The default values are:: + displaycolor (dict): the color codes to use for each circuit element in + the form (gate_color, text_color). Colors can also be entered without + the text color, such as 'u1': '#FA74A6', in which case the text color + will always be `gatetextcolor`. The `displaycolor` dict can contain + any number of elements from one to the entire dict above. The default + values are (`default.json`):: { 'u1': ('#FA74A6', '#000000'), 'u2': ('#FA74A6', '#000000'), 'u3': ('#FA74A6', '#000000'), 'id': ('#05BAB6', '#000000'), + 'u': ('#BB8BFF', '#000000'), + 'p': ('#BB8BFF', '#000000'), 'x': ('#05BAB6', '#000000'), 'y': ('#05BAB6', '#000000'), 'z': ('#05BAB6', '#000000'), 'h': ('#6FA4FF', '#000000'), 'cx': ('#6FA4FF', '#000000'), + 'ccx': ('#BB8BFF', '#000000'), + 'mcx': ('#BB8BFF', '#000000'), + 'mcx_gray': ('#BB8BFF', '#000000), 'cy': ('#6FA4FF', '#000000'), 'cz': ('#6FA4FF', '#000000'), 'swap': ('#6FA4FF', '#000000'), - 's': ('#6FA4FF', '#000000'), - 'sdg': ('#6FA4FF', '#000000'), + 'cswap': ('#BB8BFF', '#000000'), + 'ccswap': ('#BB8BFF', '#000000'), 'dcx': ('#6FA4FF', '#000000'), + 'cdcx': ('#BB8BFF', '#000000'), + 'ccdcx': ('#BB8BFF', '#000000'), 'iswap': ('#6FA4FF', '#000000'), + 's': ('#6FA4FF', '#000000'), + 'sdg': ('#6FA4FF', '#000000'), 't': ('#BB8BFF', '#000000'), 'tdg': ('#BB8BFF', '#000000'), + 'sx': ('#BB8BFF', '#000000'), + 'sxdg': ('#BB8BFF', '#000000') 'r': ('#BB8BFF', '#000000'), 'rx': ('#BB8BFF', '#000000'), 'ry': ('#BB8BFF', '#000000'), @@ -236,39 +291,8 @@ def circuit_drawer(circuit, 'reset': ('#000000', #FFFFFF'), 'target': ('#FFFFFF, '#FFFFFF'), 'measure': ('#000000', '#FFFFFF'), - 'ccx': ('#BB8BFF', '#000000'), - 'cdcx': ('#BB8BFF', '#000000'), - 'ccdcx': ('#BB8BFF', '#000000'), - 'cswap': ('#BB8BFF', '#000000'), - 'ccswap': ('#BB8BFF', '#000000'), - 'mcx': ('#BB8BFF', '#000000'), - 'mcx_gray': ('#BB8BFF', '#000000), - 'u': ('#BB8BFF', '#000000'), - 'p': ('#BB8BFF', '#000000'), - 'sx': ('#BB8BFF', '#000000'), - 'sxdg': ('#BB8BFF', '#000000') } - Colors can also be entered without the text color, such as - 'u1': '#FA74A6', in which case the text color will always - be 'gatetextcolor'. The 'displaycolor' dict can contain any - number of elements from one to the entire dict above. - latexdrawerstyle (bool): When set to True enable latex mode which will - draw gates like the `latex` output modes. - usepiformat (bool): When set to True use radians for output - fold (int): The number of circuit elements to fold the circuit at. - Defaults to 20 - cregbundle (bool): If set True bundle classical registers - showindex (bool): If set True draw an index. - compress (bool): If set True draw a compressed circuit - figwidth (int): The maximum width (in inches) for the output figure. - dpi (int): The DPI to use for the output image. Defaults to 150 - margin (list): A list of margin values to adjust spacing around output - image. Takes a list of 4 ints: [x left, x right, y bottom, y top]. - creglinestyle (str): The style of line to use for classical registers. - Choices are `'solid'`, `'doublet'`, or any valid matplotlib - `linestyle` kwarg value. Defaults to `doublet` - Example: .. jupyter-execute:: @@ -279,7 +303,7 @@ def circuit_drawer(circuit, qc = QuantumCircuit(q, c) qc.h(q) qc.measure(q, c) - circuit_drawer(qc) + circuit_drawer(qc, output='mpl', style={'showindex': True}) """ image = None config = user_config.get_config() @@ -307,8 +331,8 @@ def circuit_drawer(circuit, initial_state=initial_state, cregbundle=cregbundle) elif output == 'latex': - image = _latex_circuit_drawer(circuit, scale=scale, - filename=filename, style=style, + image = _latex_circuit_drawer(circuit, + filename=filename, scale=scale, plot_barriers=plot_barriers, reverse_bits=reverse_bits, justify=justify, @@ -319,7 +343,6 @@ def circuit_drawer(circuit, elif output == 'latex_source': return _generate_latex_source(circuit, filename=filename, scale=scale, - style=style, plot_barriers=plot_barriers, reverse_bits=reverse_bits, justify=justify, @@ -342,86 +365,12 @@ def circuit_drawer(circuit, else: raise exceptions.VisualizationError( 'Invalid output type %s selected. The only valid choices ' - 'are latex, latex_source, text, and mpl' % output) + 'are text, latex, latex_source, and mpl' % output) if image and interactive: image.show() return image -# ----------------------------------------------------------------------------- -# Plot style sheet option -# ----------------------------------------------------------------------------- -def qx_color_scheme(): - """Return default style for matplotlib_circuit_drawer (IBM QX style).""" - warn('The qx_color_scheme function is deprecated as of 0.11, and ' - 'will be removed no earlier than 3 months after that release ' - 'date.', DeprecationWarning, stacklevel=2) - return { - "comment": "Style file for matplotlib_circuit_drawer (IBM QX Composer style)", - "textcolor": "#000000", - "gatetextcolor": "#000000", - "subtextcolor": "#000000", - "linecolor": "#000000", - "creglinecolor": "#b9b9b9", - "gatefacecolor": "#ffffff", - "barrierfacecolor": "#bdbdbd", - "backgroundcolor": "#ffffff", - "fold": 20, - "fontsize": 13, - "subfontsize": 8, - "figwidth": -1, - "dpi": 150, - "displaytext": { - "id": "id", - "u0": "U_0", - "u1": "U_1", - "u2": "U_2", - "u3": "U_3", - "x": "X", - "y": "Y", - "z": "Z", - "h": "H", - "s": "S", - "sdg": "S^\\dagger", - "t": "T", - "tdg": "T^\\dagger", - "rx": "R_x", - "ry": "R_y", - "rz": "R_z", - "reset": "\\left|0\\right\\rangle" - }, - "displaycolor": { - "id": "#ffca64", - "u0": "#f69458", - "u1": "#f69458", - "u2": "#f69458", - "u3": "#f69458", - "x": "#a6ce38", - "y": "#a6ce38", - "z": "#a6ce38", - "h": "#00bff2", - "s": "#00bff2", - "sdg": "#00bff2", - "t": "#ff6666", - "tdg": "#ff6666", - "rx": "#ffca64", - "ry": "#ffca64", - "rz": "#ffca64", - "reset": "#d7ddda", - "target": "#00bff2", - "meas": "#f070aa" - }, - "latexdrawerstyle": True, - "usepiformat": False, - "cregbundle": False, - "showindex": False, - "compress": True, - "margin": [2.0, 0.0, 0.0, 0.3], - "creglinestyle": "solid", - "reversebits": False - } - - # ----------------------------------------------------------------------------- # _text_circuit_drawer # ----------------------------------------------------------------------------- @@ -435,27 +384,30 @@ def _text_circuit_drawer(circuit, filename=None, reverse_bits=False, Args: circuit (QuantumCircuit): Input circuit - filename (str): optional filename to write the result + filename (str): Optional filename to write the result reverse_bits (bool): Rearrange the bits in reverse order. plot_barriers (bool): Draws the barriers when they are there. justify (str) : `left`, `right` or `none`. Defaults to `left`. Says how - the circuit should be justified. + the circuit should be justified. vertical_compression (string): `high`, `medium`, or `low`. It merges the lines so the drawing will take less vertical room. Default is `high`. idle_wires (bool): Include idle wires. Default is True. - with_layout (bool): Include layout information, with labels on the physical + with_layout (bool): Include layout information with labels on the physical layout. Default: True fold (int): Optional. Breaks the circuit drawing to this length. This - useful when the drawing does not fit in the console. If - None (default), it will try to guess the console width using - `shutil.get_terminal_size()`. If you don't want pagination - at all, set `fold=-1`. - initial_state (bool): Optional. Adds |0> in the beginning of the line. Default: `True`. - cregbundle (bool): Optional. If set True bundle classical registers. Default: ``False``. + is useful when the drawing does not fit in the console. If + None (default), it will try to guess the console width using + `shutil.get_terminal_size()`. If you don't want pagination + at all, set `fold=-1`. + initial_state (bool): Optional. Adds |0> in the beginning of the line. + Default: `False`. + cregbundle (bool): Optional. If set True, bundle classical registers. + Default: ``True``. encoding (str): Optional. Sets the encoding preference of the output. - Default: ``sys.stdout.encoding``. + Default: ``sys.stdout.encoding``. + Returns: - TextDrawing: An instances that, when printed, draws the circuit in ascii art. + TextDrawing: An instance that, when printed, draws the circuit in ascii art. """ qregs, cregs, ops = utils._get_layered_instructions(circuit, reverse_bits=reverse_bits, @@ -486,7 +438,6 @@ def _text_circuit_drawer(circuit, filename=None, reverse_bits=False, def _latex_circuit_drawer(circuit, scale=0.7, filename=None, - style=None, plot_barriers=True, reverse_bits=False, justify=None, @@ -502,18 +453,18 @@ def _latex_circuit_drawer(circuit, circuit (QuantumCircuit): a quantum circuit scale (float): scaling factor filename (str): file path to save image to - style (dict or str): dictionary of style or file name of style file reverse_bits (bool): When set to True reverse the bit order inside registers for the output visualization. plot_barriers (bool): Enable/disable drawing barriers in the output circuit. Defaults to True. justify (str) : `left`, `right` or `none`. Defaults to `left`. Says how - the circuit should be justified. + the circuit should be justified. idle_wires (bool): Include idle wires. Default is True. with_layout (bool): Include layout information, with labels on the physical layout. Default: True - initial_state (bool): Optional. Adds |0> in the beginning of the line. Default: `False`. - cregbundle (bool): Optional. If set True bundle classical registers. + initial_state (bool): Optional. Adds |0> in the beginning of the line. + Default: `False`. + cregbundle (bool): Optional. If set True, bundle classical registers. Default: ``False``. Returns: @@ -522,14 +473,13 @@ def _latex_circuit_drawer(circuit, Raises: OSError: usually indicates that ```pdflatex``` or ```pdftocairo``` is missing. - CalledProcessError: usually points errors during diagram creation. + CalledProcessError: usually points to errors during diagram creation. ImportError: if pillow is not installed """ tmpfilename = 'circuit' with tempfile.TemporaryDirectory() as tmpdirname: tmppath = os.path.join(tmpdirname, tmpfilename + '.tex') - _generate_latex_source(circuit, filename=tmppath, - scale=scale, style=style, + _generate_latex_source(circuit, filename=tmppath, scale=scale, plot_barriers=plot_barriers, reverse_bits=reverse_bits, justify=justify, idle_wires=idle_wires, with_layout=with_layout, @@ -578,27 +528,27 @@ def _latex_circuit_drawer(circuit, def _generate_latex_source(circuit, filename=None, - scale=0.7, style=None, reverse_bits=False, + scale=0.7, reverse_bits=False, plot_barriers=True, justify=None, idle_wires=True, with_layout=True, initial_state=False, cregbundle=False): """Convert QuantumCircuit to LaTeX string. Args: - circuit (QuantumCircuit): input circuit - scale (float): image scaling + circuit (QuantumCircuit): a quantum circuit + scale (float): scaling factor filename (str): optional filename to write latex - style (dict or str): dictionary of style or file name of style file reverse_bits (bool): When set to True reverse the bit order inside registers for the output visualization. plot_barriers (bool): Enable/disable drawing barriers in the output circuit. Defaults to True. justify (str) : `left`, `right` or `none`. Defaults to `left`. Says how - the circuit should be justified. + the circuit should be justified. idle_wires (bool): Include idle wires. Default is True. with_layout (bool): Include layout information, with labels on the physical layout. Default: True - initial_state (bool): Optional. Adds |0> in the beginning of the line. Default: `False`. - cregbundle (bool): Optional. If set True bundle classical registers. + initial_state (bool): Optional. Adds |0> in the beginning of the line. + Default: `False`. + cregbundle (bool): Optional. If set True, bundle classical registers. Default: ``False``. Returns: @@ -613,9 +563,8 @@ def _generate_latex_source(circuit, filename=None, layout = None global_phase = circuit.global_phase if hasattr(circuit, 'global_phase') else None - qcimg = _latex.QCircuitImage(qregs, cregs, ops, scale, style=style, - plot_barriers=plot_barriers, - reverse_bits=reverse_bits, layout=layout, + qcimg = _latex.QCircuitImage(qregs, cregs, ops, scale, + plot_barriers=plot_barriers, layout=layout, initial_state=initial_state, cregbundle=cregbundle, global_phase=global_phase) @@ -655,7 +604,7 @@ def _matplotlib_circuit_drawer(circuit, scale (float): scaling factor filename (str): file path to save image to style (dict or str): dictionary of style or file name of style file - reverse_bits (bool): When set to True reverse the bit order inside + reverse_bits (bool): When set to True, reverse the bit order inside registers for the output visualization. plot_barriers (bool): Enable/disable drawing barriers in the output circuit. Defaults to True. @@ -664,9 +613,9 @@ def _matplotlib_circuit_drawer(circuit, idle_wires (bool): Include idle wires. Default is True. with_layout (bool): Include layout information, with labels on the physical layout. Default: True. - fold (int): amount ops allowed before folding. Default is 25. + fold (int): Number of vertical layers allowed before folding. Default is 25. ax (matplotlib.axes.Axes): An optional Axes object to be used for - the visualization output. If none is specified a new matplotlib + the visualization output. If none is specified, a new matplotlib Figure will be created and used. Additionally, if specified there will be no returned Figure since it is redundant. initial_state (bool): Optional. Adds |0> in the beginning of the line. @@ -693,8 +642,7 @@ def _matplotlib_circuit_drawer(circuit, global_phase = circuit.global_phase if hasattr(circuit, 'global_phase') else None qcd = _matplotlib.MatplotlibDrawer(qregs, cregs, ops, scale=scale, style=style, - plot_barriers=plot_barriers, - reverse_bits=reverse_bits, layout=layout, + plot_barriers=plot_barriers, layout=layout, fold=fold, ax=ax, initial_state=initial_state, cregbundle=cregbundle, global_phase=global_phase) return qcd.draw(filename) diff --git a/qiskit/visualization/latex.py b/qiskit/visualization/latex.py index 2a4aa56c9a53..fb63d3430205 100644 --- a/qiskit/visualization/latex.py +++ b/qiskit/visualization/latex.py @@ -16,14 +16,12 @@ import collections import io -import json import math import re import numpy as np from qiskit.circuit.controlledgate import ControlledGate from qiskit.circuit.parameterexpression import ParameterExpression -from qiskit.visualization import qcstyle as _qcstyle from qiskit.visualization import exceptions from qiskit.circuit.tools.pi_check import pi_check from .utils import generate_latex_label @@ -38,8 +36,8 @@ class QCircuitImage: Thanks to Eric Sabo for the initial implementation for Qiskit. """ - def __init__(self, qubits, clbits, ops, scale, style=None, - plot_barriers=True, reverse_bits=False, layout=None, initial_state=False, + def __init__(self, qubits, clbits, ops, scale, + plot_barriers=True, layout=None, initial_state=False, cregbundle=False, global_phase=None): """QCircuitImage initializer. @@ -48,9 +46,6 @@ def __init__(self, qubits, clbits, ops, scale, style=None, clbits (list[Clbit]): list of clbits ops (list[list[DAGNode]]): list of circuit instructions, grouped by layer scale (float): image scaling - style (dict or str): dictionary of style or file name of style file - reverse_bits (bool): When set to True reverse the bit order inside - registers for the output visualization. plot_barriers (bool): Enable/disable drawing barriers in the output circuit. Defaults to True. layout (Layout or None): If present, the layout information will be @@ -61,16 +56,6 @@ def __init__(self, qubits, clbits, ops, scale, style=None, Raises: ImportError: If pylatexenc is not installed """ - # style sheet - self._style = _qcstyle.BWStyle() - if style: - if isinstance(style, dict): - self._style.set_style(style) - elif isinstance(style, str): - with open(style) as infile: - dic = json.load(infile) - self._style.set_style(dic) - # list of lists corresponding to layers of the circuit self.ops = ops @@ -113,7 +98,6 @@ def __init__(self, qubits, clbits, ops, scale, style=None, # presence of "box" or "target" determines row spacing self.has_box = False self.has_target = False - self.reverse_bits = reverse_bits self.layout = layout self.initial_state = initial_state self.plot_barriers = plot_barriers diff --git a/qiskit/visualization/matplotlib.py b/qiskit/visualization/matplotlib.py index 3c95522fa2df..5b1e9f92b31a 100644 --- a/qiskit/visualization/matplotlib.py +++ b/qiskit/visualization/matplotlib.py @@ -10,7 +10,7 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. -# pylint: disable=invalid-name,missing-docstring,inconsistent-return-statements +# pylint: disable=invalid-name,inconsistent-return-statements """mpl circuit visualization backend.""" @@ -19,6 +19,7 @@ import json import logging import re +import os from warnings import warn import numpy as np @@ -40,7 +41,7 @@ HAS_PYLATEX = False from qiskit.circuit import ControlledGate -from qiskit.visualization.qcstyle import DefaultStyle, IQXStyle, BWStyle +from qiskit.visualization.qcstyle import DefaultStyle, set_style from qiskit.circuit import Delay from qiskit import user_config from qiskit.circuit.tools.pi_check import pi_check @@ -61,6 +62,7 @@ class Anchor: + """Locate the anchors for the gates""" def __init__(self, reg_num, yind, fold): self.__yind = yind self.__fold = fold @@ -69,6 +71,7 @@ def __init__(self, reg_num, yind, fold): self.gate_anchor = 0 def plot_coord(self, index, gate_width, x_offset): + """Set the coord positions for an index""" h_pos = index % self.__fold + 1 # check folding if self.__fold > 0: @@ -85,6 +88,7 @@ def plot_coord(self, index, gate_width, x_offset): return x_pos + x_offset, y_pos def is_locatable(self, index, gate_width): + """Determine if a gate has been placed""" hold = [index + i for i in range(gate_width)] for p in hold: if p in self.__gate_placed: @@ -92,6 +96,7 @@ def is_locatable(self, index, gate_width): return True def set_index(self, index, gate_width): + """Set the index for a gate""" if self.__fold < 2: _index = index else: @@ -106,128 +111,75 @@ def set_index(self, index, gate_width): self.__gate_placed.sort() def get_index(self): + """Getter for the index""" if self.__gate_placed: return self.__gate_placed[-1] + 1 return 0 class MatplotlibDrawer: + """Matplotlib drawer class called from circuit_drawer""" def __init__(self, qregs, cregs, ops, scale=None, style=None, plot_barriers=True, - reverse_bits=False, layout=None, fold=25, ax=None, - initial_state=False, cregbundle=True, global_phase=None): + layout=None, fold=25, ax=None, initial_state=False, + cregbundle=True, global_phase=None): if not HAS_MATPLOTLIB: raise ImportError('The class MatplotlibDrawer needs matplotlib. ' 'To install, run "pip install matplotlib".') - if not HAS_PYLATEX: raise ImportError('The class MatplotlibDrawer needs pylatexenc. ' 'to install, run "pip install pylatexenc".') - - self._ast = None - self._scale = 1.0 if scale is None else scale self._creg = [] self._qreg = [] self._registers(cregs, qregs) - self._ops = ops - self.global_phase = global_phase - self._qreg_dict = collections.OrderedDict() self._creg_dict = collections.OrderedDict() - self._cond = { - 'n_lines': 0, - 'xmax': 0, - 'ymax': 0, - } - if isinstance(style, dict) and 'name' in style.keys(): - if style['name'] == 'iqx': - self._style = IQXStyle() - elif style['name'] == 'bw': - self._style = BWStyle() - else: - self._style = DefaultStyle() - else: - config = user_config.get_config() - if config: - config_style = config.get('circuit_mpl_style', 'default') - if config_style == 'iqx': - self._style = IQXStyle() - elif config_style == 'bw': - self._style = BWStyle() - else: - self._style = DefaultStyle() - elif style is False: - self._style = BWStyle() - else: - self._style = DefaultStyle() - - if style: - if isinstance(style, dict): - self._style.set_style(style) - elif isinstance(style, str): - try: - with open(style) as infile: - dic = json.load(infile) - self._style.set_style(dic) - except FileNotFoundError: - warn("Style JSON file '{}' not found. Will use default style.".format(style), - UserWarning, 2) - except json.JSONDecodeError as e: - warn("Could not decode JSON in file '{}': {}. ".format(style, str(e)) - + "Will use default style.", UserWarning, 2) - except OSError: - warn("Error loading JSON file '{}'. Will use default style.".format(style), - UserWarning, 2) - - self.plot_barriers = plot_barriers - self.reverse_bits = reverse_bits - self.layout = layout - self.initial_state = initial_state - if isinstance(style, dict) and 'cregbundle' in style.keys(): - self.cregbundle = style['cregbundle'] - del style['cregbundle'] - warn("The style dictionary key 'cregbundle' has been deprecated and will be removed" - " in a future release. cregbundle is now a parameter to draw()." - " Example: circuit.draw(output='mpl', cregbundle=False)", DeprecationWarning, 2) - else: - self.cregbundle = cregbundle - + self._ops = ops + self._scale = 1.0 if scale is None else scale + self._style = self._load_style(style) + self._plot_barriers = plot_barriers + self._layout = layout + self._fold = fold + if self._fold < 2: + self._fold = -1 if ax is None: - self.return_fig = True - self.figure = plt.figure() - self.figure.patch.set_facecolor(color=self._style.bg) - self.ax = self.figure.add_subplot(111) + self._return_fig = True + self._figure = plt.figure() + self._figure.patch.set_facecolor(color=self._style['bg']) + self._ax = self._figure.add_subplot(111) else: - self.return_fig = False - self.ax = ax - self.figure = ax.get_figure() + self._return_fig = False + self._ax = ax + self._figure = ax.get_figure() + self._ax.axis('off') + self._ax.set_aspect('equal') + self._ax.tick_params(labelbottom=False, labeltop=False, + labelleft=False, labelright=False) + self._initial_state = initial_state + self._cregbundle = cregbundle + self._global_phase = global_phase - self.x_offset = 0 + self._ast = None + self._n_lines = 0 + self._xmax = 0 + self._ymax = 0 + self._x_offset = 0 self._reg_long_text = 0 + self._style['fs'] *= self._scale + self._style['sfs'] *= self._scale + self._lwidth15 = 1.5 * self._scale + self._lwidth2 = 2.0 * self._scale # default is to use character table for text width, # but get_renderer will work with some mpl backends """fig = plt.figure() if hasattr(fig.canvas, 'get_renderer'): - self.renderer = fig.canvas.get_renderer() + self._renderer = fig.canvas.get_renderer() else: - self.renderer = None""" - self.renderer = None - - self.fold = fold - if self.fold < 2: - self.fold = -1 - - self.ax.axis('off') - self.ax.set_aspect('equal') - self.ax.tick_params(labelbottom=False, labeltop=False, - labelleft=False, labelright=False) - - self._style.fs *= self._scale - self._style.sfs *= self._scale - self._lwidth15 = 1.5 * self._scale - self._lwidth2 = 2.0 * self._scale + self._renderer = None""" + self._renderer = None + self._mathmode_regex = re.compile(r"(?' - initial_cbit = ' 0' - else: - initial_qbit = '' - initial_cbit = '' + longest_reg_name_width = 0 + initial_qbit = ' |0>' if self._initial_state else '' + initial_cbit = ' 0' if self._initial_state else '' - def _fix_double_script(label): - words = label.split(' ') + def _fix_double_script(reg_name): + words = reg_name.split(' ') words = [word.replace('_', r'\_') if word.count('_') > 1 else word for word in words] words = [word.replace('^', r'\^{\ }') if word.count('^') > 1 else word for word in words] - label = ' '.join(words).replace(' ', '\\;') - return label + reg_name = ' '.join(words).replace(' ', '\\;') + return reg_name # quantum register + fs = self._style['fs'] for ii, reg in enumerate(self._qreg): if len(self._qreg) > 1: - if self.layout is None: - label = '${{{name}}}_{{{index}}}$'.format(name=reg.register.name, - index=reg.index) - label = _fix_double_script(label) + initial_qbit - text_width = self._get_text_width(label, self._style.fs) + if self._layout is None: + qreg_name = '${{{name}}}_{{{index}}}$'.format(name=reg.register.name, + index=reg.index) else: - if self.layout[reg.index]: - label = '${{{name}}}_{{{index}}} \\mapsto {{{physical}}}$'.format( - name=self.layout[reg.index].register.name, - index=self.layout[reg.index].index, physical=reg.index) + if self._layout[reg.index]: + qreg_name = '${{{name}}}_{{{index}}} \\mapsto {{{physical}}}$'.format( + name=self._layout[reg.index].register.name, + index=self._layout[reg.index].index, physical=reg.index) else: - label = '${{{physical}}}$'.format(physical=reg.index) - label = _fix_double_script(label) + initial_qbit - text_width = self._get_text_width(label, self._style.fs) + qreg_name = '${{{physical}}}$'.format(physical=reg.index) else: - label = '{name}'.format(name=reg.register.name) - label = _fix_double_script(label) + initial_qbit - text_width = self._get_text_width(label, self._style.fs) - - text_width = text_width * 1.15 # to account for larger font used - if text_width > longest_label_width: - longest_label_width = text_width + qreg_name = '{name}'.format(name=reg.register.name) + qreg_name = _fix_double_script(qreg_name) + initial_qbit + text_width = self._get_text_width(qreg_name, fs) * 1.15 + if text_width > longest_reg_name_width: + longest_reg_name_width = text_width pos = -ii self._qreg_dict[ii] = { - 'y': pos, 'label': label, 'index': reg.index, 'group': reg.register} - self._cond['n_lines'] += 1 + 'y': pos, 'reg_name': qreg_name, 'index': reg.index, 'group': reg.register} + self._n_lines += 1 # classical register if self._creg: @@ -682,81 +694,82 @@ def _fix_double_script(label): y_off = -len(self._qreg) for ii, (reg, nreg) in enumerate(itertools.zip_longest(self._creg, n_creg)): pos = y_off - idx - if self.cregbundle: - label = '{}'.format(reg.register.name) - label = _fix_double_script(label) + initial_cbit - text_width = self._get_text_width(reg.register.name, self._style.fs) * 1.15 - if text_width > longest_label_width: - longest_label_width = text_width - self._creg_dict[ii] = {'y': pos, 'label': label, 'index': reg.index, + if self._cregbundle: + creg_name = '{}'.format(reg.register.name) + creg_name = _fix_double_script(creg_name) + initial_cbit + text_width = self._get_text_width(reg.register.name, fs) * 1.15 + if text_width > longest_reg_name_width: + longest_reg_name_width = text_width + self._creg_dict[ii] = {'y': pos, 'reg_name': creg_name, 'index': reg.index, 'group': reg.register} if not (not nreg or reg.register != nreg.register): continue else: - label = '${}_{{{}}}$'.format(reg.register.name, reg.index) - label = _fix_double_script(label) + initial_cbit - text_width = self._get_text_width(reg.register.name, self._style.fs) * 1.15 - if text_width > longest_label_width: - longest_label_width = text_width - self._creg_dict[ii] = {'y': pos, 'label': label, 'index': reg.index, + creg_name = '${}_{{{}}}$'.format(reg.register.name, reg.index) + creg_name = _fix_double_script(creg_name) + initial_cbit + text_width = self._get_text_width(reg.register.name, fs) * 1.15 + if text_width > longest_reg_name_width: + longest_reg_name_width = text_width + self._creg_dict[ii] = {'y': pos, 'reg_name': creg_name, 'index': reg.index, 'group': reg.register} - self._cond['n_lines'] += 1 + self._n_lines += 1 idx += 1 - self._reg_long_text = longest_label_width - self.x_offset = -1.2 + self._reg_long_text + self._reg_long_text = longest_reg_name_width + self._x_offset = -1.2 + self._reg_long_text def _draw_regs_sub(self, n_fold, feedline_l=False, feedline_r=False): # quantum register + fs = self._style['fs'] for qreg in self._qreg_dict.values(): - label = qreg['label'] - y = qreg['y'] - n_fold * (self._cond['n_lines'] + 1) - self.ax.text(self.x_offset - 0.2, y, label, ha='right', va='center', - fontsize=1.25 * self._style.fs, color=self._style.tc, - clip_on=True, zorder=PORDER_TEXT) - self._line([self.x_offset, y], [self._cond['xmax'], y], + qreg_name = qreg['reg_name'] + y = qreg['y'] - n_fold * (self._n_lines + 1) + self._ax.text(self._x_offset - 0.2, y, qreg_name, ha='right', va='center', + fontsize=1.25 * fs, color=self._style['tc'], + clip_on=True, zorder=PORDER_TEXT) + self._line([self._x_offset, y], [self._xmax, y], zorder=PORDER_REGLINE) # classical register this_creg_dict = {} for creg in self._creg_dict.values(): - label = creg['label'] - y = creg['y'] - n_fold * (self._cond['n_lines'] + 1) + creg_name = creg['reg_name'] + y = creg['y'] - n_fold * (self._n_lines + 1) if y not in this_creg_dict.keys(): - this_creg_dict[y] = {'val': 1, 'label': label} + this_creg_dict[y] = {'val': 1, 'reg_name': creg_name} else: this_creg_dict[y]['val'] += 1 for y, this_creg in this_creg_dict.items(): # cregbundle if this_creg['val'] > 1: - self.ax.plot([self.x_offset + 0.2, self.x_offset + 0.3], [y - 0.1, y + 0.1], - color=self._style.cc, zorder=PORDER_LINE) - self.ax.text(self.x_offset + 0.1, y + 0.1, str(this_creg['val']), ha='left', - va='bottom', fontsize=0.8 * self._style.fs, - color=self._style.tc, clip_on=True, zorder=PORDER_TEXT) - self.ax.text(self.x_offset - 0.2, y, this_creg['label'], ha='right', va='center', - fontsize=1.25 * self._style.fs, color=self._style.tc, - clip_on=True, zorder=PORDER_TEXT) - self._line([self.x_offset, y], [self._cond['xmax'], y], lc=self._style.cc, - ls=self._style.cline, zorder=PORDER_REGLINE) + self._ax.plot([self._x_offset + 0.2, self._x_offset + 0.3], [y - 0.1, y + 0.1], + color=self._style['cc'], zorder=PORDER_LINE) + self._ax.text(self._x_offset + 0.1, y + 0.1, str(this_creg['val']), ha='left', + va='bottom', fontsize=0.8 * fs, + color=self._style['tc'], clip_on=True, zorder=PORDER_TEXT) + self._ax.text(self._x_offset - 0.2, y, this_creg['reg_name'], ha='right', va='center', + fontsize=1.25 * fs, color=self._style['tc'], + clip_on=True, zorder=PORDER_TEXT) + self._line([self._x_offset, y], [self._xmax, y], lc=self._style['cc'], + ls=self._style['cline'], zorder=PORDER_REGLINE) # lf vertical line at either end if feedline_l or feedline_r: - xpos_l = self.x_offset - 0.01 - xpos_r = self.fold + self.x_offset + 0.1 - ypos1 = -n_fold * (self._cond['n_lines'] + 1) - ypos2 = -(n_fold + 1) * (self._cond['n_lines']) - n_fold + 1 + xpos_l = self._x_offset - 0.01 + xpos_r = self._fold + self._x_offset + 0.1 + ypos1 = -n_fold * (self._n_lines + 1) + ypos2 = -(n_fold + 1) * (self._n_lines) - n_fold + 1 if feedline_l: - self.ax.plot([xpos_l, xpos_l], [ypos1, ypos2], - color=self._style.lc, linewidth=self._lwidth15, zorder=PORDER_LINE) + self._ax.plot([xpos_l, xpos_l], [ypos1, ypos2], color=self._style['lc'], + linewidth=self._lwidth15, zorder=PORDER_LINE) if feedline_r: - self.ax.plot([xpos_r, xpos_r], [ypos1, ypos2], - color=self._style.lc, linewidth=self._lwidth15, zorder=PORDER_LINE) + self._ax.plot([xpos_r, xpos_r], [ypos1, ypos2], color=self._style['lc'], + linewidth=self._lwidth15, zorder=PORDER_LINE) def _draw_ops(self, verbose=False): _standard_1q_gates = ['x', 'y', 'z', 'id', 'h', 'r', 's', 'sdg', 't', 'tdg', 'rx', 'ry', - 'rz', 'rxx', 'ryy', 'rzx', 'u1', 'u2', 'u3', 'swap', 'reset', 'sx', - 'sxdg', 'p'] + 'rz', 'rxx', 'ryy', 'rzx', 'u1', 'u2', 'u3', 'u', 'swap', 'reset', + 'sx', 'sxdg', 'p'] _barrier_gates = ['barrier', 'snapshot', 'load', 'save', 'noise'] _barriers = {'coord': [], 'group': []} @@ -765,16 +778,18 @@ def _draw_ops(self, verbose=False): # q_anchors = {} for key, qreg in self._qreg_dict.items(): - q_anchors[key] = Anchor(reg_num=self._cond['n_lines'], - yind=qreg['y'], fold=self.fold) + q_anchors[key] = Anchor(reg_num=self._n_lines, + yind=qreg['y'], fold=self._fold) c_anchors = {} for key, creg in self._creg_dict.items(): - c_anchors[key] = Anchor(reg_num=self._cond['n_lines'], - yind=creg['y'], fold=self.fold) + c_anchors[key] = Anchor(reg_num=self._n_lines, + yind=creg['y'], fold=self._fold) # # draw the ops # prev_anc = -1 + fs = self._style['fs'] + sfs = self._style['sfs'] for layer in self._ops: widest_box = 0.0 # @@ -795,17 +810,17 @@ def _draw_ops(self, verbose=False): # small increments at end of the 3 _get_text_width calls are for small # spacing adjustments between gates - ctrl_width = self._get_text_width(ctrl_text, fontsize=self._style.sfs) - 0.05 + ctrl_width = self._get_text_width(ctrl_text, fontsize=sfs) - 0.05 # get param_width, but 0 for gates with array params if (hasattr(op.op, 'params') and not any([isinstance(param, np.ndarray) for param in op.op.params]) and len(op.op.params) > 0): - param = self.param_parse(op.op.params) + param = self._param_parse(op.op.params) if op.name == 'initialize': param = '[%s]' % param param = "${}$".format(param) - param_width = self._get_text_width(param, fontsize=self._style.sfs, + param_width = self._get_text_width(param, fontsize=sfs, param=True) + 0.08 else: param_width = 0.0 @@ -813,15 +828,15 @@ def _draw_ops(self, verbose=False): if op.name == 'cu1' or op.name == 'rzz' or base_name == 'rzz': tname = 'U1' if op.name == 'cu1' else 'zz' gate_width = (self._get_text_width(tname + ' ()', - fontsize=self._style.sfs) + fontsize=sfs) + param_width) * 1.5 else: - gate_width = self._get_text_width(gate_text, fontsize=self._style.fs) + 0.10 + gate_width = self._get_text_width(gate_text, fontsize=fs) + 0.10 # add .21 for the qubit numbers on the left of the multibit gates if (op.name not in _standard_1q_gates and base_name not in _standard_1q_gates): gate_width += 0.21 - box_width = max((gate_width, ctrl_width, param_width, WID)) + box_width = max(gate_width, ctrl_width, param_width, WID) if box_width > widest_box: widest_box = box_width @@ -856,15 +871,15 @@ def _draw_ops(self, verbose=False): # only add the gate to the anchors if it is going to be plotted. # this prevents additional blank wires at the end of the line if # the last instruction is a barrier type - if self.plot_barriers or op.name not in _barrier_gates: + if self._plot_barriers or op.name not in _barrier_gates: for ii in q_idxs: q_anchors[ii].set_index(this_anc, layer_width) # qreg coordinate - q_xy = [q_anchors[ii].plot_coord(this_anc, layer_width, self.x_offset) + q_xy = [q_anchors[ii].plot_coord(this_anc, layer_width, self._x_offset) for ii in q_idxs] # creg coordinate - c_xy = [c_anchors[ii].plot_coord(this_anc, layer_width, self.x_offset) + c_xy = [c_anchors[ii].plot_coord(this_anc, layer_width, self._x_offset) for ii in c_idxs] # bottom and top point of qreg qreg_b = min(q_xy, key=lambda xy: xy[1]) @@ -879,13 +894,13 @@ def _draw_ops(self, verbose=False): # load param if (op.type == 'op' and hasattr(op.op, 'params') and len(op.op.params) > 0 and not any([isinstance(param, np.ndarray) for param in op.op.params])): - param = "{}".format(self.param_parse(op.op.params)) + param = "{}".format(self._param_parse(op.op.params)) else: param = '' # conditional gate if op.condition: - c_xy = [c_anchors[ii].plot_coord(this_anc, layer_width, self.x_offset) for + c_xy = [c_anchors[ii].plot_coord(this_anc, layer_width, self._x_offset) for ii in self._creg_dict] mask = 0 for index, cbit in enumerate(self._creg): @@ -904,19 +919,19 @@ def _draw_ops(self, verbose=False): for xy, m in zip(c_xy, cmask): if m == '1': if xy not in xy_plot: - if vlist[v_ind] == '1' or self.cregbundle: - self._conds(xy, istrue=True) + if vlist[v_ind] == '1' or self._cregbundle: + self._conditional(xy, istrue=True) else: - self._conds(xy, istrue=False) + self._conditional(xy, istrue=False) xy_plot.append(xy) v_ind += 1 creg_b = sorted(xy_plot, key=lambda xy: xy[1])[0] xpos, ypos = creg_b - self.ax.text(xpos, ypos - 0.3 * HIG, hex(val), ha='center', va='top', - fontsize=self._style.sfs, color=self._style.tc, - clip_on=True, zorder=PORDER_TEXT) - self._line(qreg_t, creg_b, lc=self._style.cc, - ls=self._style.cline) + self._ax.text(xpos, ypos - 0.3 * HIG, hex(val), ha='center', va='top', + fontsize=sfs, color=self._style['tc'], + clip_on=True, zorder=PORDER_TEXT) + self._line(qreg_t, creg_b, lc=self._style['cc'], + ls=self._style['cline']) # # draw special gates # @@ -931,7 +946,7 @@ def _draw_ops(self, verbose=False): if q_group not in _barriers['group']: _barriers['group'].append(q_group) _barriers['coord'].append(q_xy[index]) - if self.plot_barriers: + if self._plot_barriers: self._barrier(_barriers) elif op.name == 'initialize': @@ -962,7 +977,7 @@ def _draw_ops(self, verbose=False): num_ctrl_qubits = op.op.num_ctrl_qubits self._set_ctrl_bits(op.op.ctrl_state, num_ctrl_qubits, q_xy, ec=ec, tc=tc, text=ctrl_text, qargs=op.qargs) - tgt_color = self._style.dispcol['target'] + tgt_color = self._style['dispcol']['target'] tgt = tgt_color if isinstance(tgt_color, str) else tgt_color[0] self._x_tgt_qubit(q_xy[num_ctrl_qubits], ec=ec, ac=tgt) self._line(qreg_b, qreg_t, lc=lc) @@ -984,7 +999,7 @@ def _draw_ops(self, verbose=False): self._ctrl_qubit(q_xy[num_ctrl_qubits], fc=ec, ec=ec, tc=tc) if op.name != 'cu1': self._ctrl_qubit(q_xy[num_ctrl_qubits + 1], fc=ec, ec=ec, tc=tc) - stext = self._style.disptex['u1'] if op.name == 'cu1' else 'zz' + stext = self._style['disptex']['u1'] if op.name == 'cu1' else 'zz' self._sidetext(qreg_b, tc=tc, text='{}'.format(stext) + ' ' + '({})'.format(param)) self._line(qreg_b, qreg_t, lc=lc) @@ -1025,7 +1040,7 @@ def _draw_ops(self, verbose=False): # adjust the column if there have been barriers encountered, but not plotted barrier_offset = 0 - if not self.plot_barriers: + if not self._plot_barriers: # only adjust if everything in the layer wasn't plotted barrier_offset = -1 if all([op.name in _barrier_gates for op in layer]) else 0 @@ -1035,15 +1050,15 @@ def _draw_ops(self, verbose=False): # anchors = [q_anchors[ii].get_index() for ii in self._qreg_dict] max_anc = max(anchors) if anchors else 0 - n_fold = max(0, max_anc - 1) // self.fold if self.fold > 0 else 0 + n_fold = max(0, max_anc - 1) // self._fold if self._fold > 0 else 0 # window size - if max_anc > self.fold > 0: - self._cond['xmax'] = self.fold + 1 + self.x_offset - 0.9 - self._cond['ymax'] = (n_fold + 1) * (self._cond['n_lines'] + 1) - 1 + if max_anc > self._fold > 0: + self._xmax = self._fold + 1 + self._x_offset - 0.9 + self._ymax = (n_fold + 1) * (self._n_lines + 1) - 1 else: - self._cond['xmax'] = max_anc + 1 + self.x_offset - 0.9 - self._cond['ymax'] = self._cond['n_lines'] + self._xmax = max_anc + 1 + self._x_offset - 0.9 + self._ymax = self._n_lines # add horizontal lines for ii in range(n_fold + 1): @@ -1052,14 +1067,14 @@ def _draw_ops(self, verbose=False): self._draw_regs_sub(ii, feedline_l, feedline_r) # draw anchor index number - if self._style.index: + if self._style['index']: for ii in range(max_anc): - if self.fold > 0: - x_coord = ii % self.fold + self._reg_long_text - 0.67 - y_coord = - (ii // self.fold) * (self._cond['n_lines'] + 1) + 0.7 + if self._fold > 0: + x_coord = ii % self._fold + self._reg_long_text - 0.67 + y_coord = - (ii // self._fold) * (self._n_lines + 1) + 0.7 else: x_coord = ii + self._reg_long_text - 0.67 y_coord = 0.7 - self.ax.text(x_coord, y_coord, str(ii + 1), ha='center', - va='center', fontsize=self._style.sfs, - color=self._style.tc, clip_on=True, zorder=PORDER_TEXT) + self._ax.text(x_coord, y_coord, str(ii + 1), ha='center', + va='center', fontsize=sfs, + color=self._style['tc'], clip_on=True, zorder=PORDER_TEXT) diff --git a/qiskit/visualization/qcstyle.py b/qiskit/visualization/qcstyle.py index b70f924490c4..7df1cfd6b289 100644 --- a/qiskit/visualization/qcstyle.py +++ b/qiskit/visualization/qcstyle.py @@ -10,9 +10,8 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. -# pylint: disable=invalid-name,missing-docstring +"""mpl circuit visualization style.""" -from copy import copy from warnings import warn @@ -20,401 +19,152 @@ class DefaultStyle: """IBM Design Style colors """ def __init__(self): - # Set colors - basis_color = '#FA74A6' # Red - clifford_color = '#6FA4FF' # Blue - non_gate_color = '#000000' # Black - other_color = '#BB8BFF' # Purple - pauli_color = '#05BAB6' # Green - iden_color = '#05BAB6' # Green - - black_font = '#000000' # Black font color - white_font = '#ffffff' # White font color - - self.name = 'default' - self.tc = '#000000' - self.sc = '#000000' - self.lc = '#000000' - self.not_gate_lc = '#ffffff' - self.cc = '#778899' # Medium Gray - self.gc = other_color - self.gt = '#000000' - self.bc = '#bdbdbd' # Dark Gray - self.bg = '#ffffff' - self.edge_color = None - self.math_fs = 15 - self.fs = 13 - self.sfs = 8 - self.disptex = { - 'id': 'I', - 'p': 'P', - 'u': 'U', - 'u1': '$\\mathrm{U}_1$', - 'u2': '$\\mathrm{U}_2$', - 'u3': '$\\mathrm{U}_3$', - 'x': 'X', - 'y': 'Y', - 'z': 'Z', - 'h': 'H', - 's': 'S', - 'sdg': '$\\mathrm{S}^\\dagger$', - 'sx': '$\\sqrt{\\mathrm{X}}$', - 'sxdg': '$\\sqrt{\\mathrm{X}}^\\dagger$', - 't': 'T', - 'tdg': '$\\mathrm{T}^\\dagger$', - 'iswap': 'Iswap', - 'dcx': 'Dcx', - 'ms': 'MS', - 'diagonal': 'Diagonal', - 'unitary': 'Unitary', - 'r': 'R', - 'rx': '$\\mathrm{R}_\\mathrm{X}$', - 'ry': '$\\mathrm{R}_\\mathrm{Y}$', - 'rz': '$\\mathrm{R}_\\mathrm{Z}$', - 'rxx': '$\\mathrm{R}_{\\mathrm{XX}}$', - 'ryy': '$\\mathrm{R}_{\\mathrm{YY}}$', - 'rzx': '$\\mathrm{R}_{\\mathrm{ZX}}$', - 'rzz': '$\\mathrm{R}_{\\mathrm{ZZ}}$', - 'reset': '$\\left|0\\right\\rangle$', - 'initialize': '$|\\psi\\rangle$' - } - self.dispcol = { - 'u1': (basis_color, black_font), - 'u2': (basis_color, black_font), - 'u3': (basis_color, black_font), - 'id': (iden_color, black_font), - 'x': (pauli_color, black_font), - 'y': (pauli_color, black_font), - 'z': (pauli_color, black_font), - 'h': (clifford_color, black_font), - 'cx': (clifford_color, black_font), - 'cy': (clifford_color, black_font), - 'cz': (clifford_color, black_font), - 'swap': (clifford_color, black_font), - 's': (clifford_color, black_font), - 'sdg': (clifford_color, black_font), - 'dcx': (clifford_color, black_font), - 'iswap': (clifford_color, black_font), - 't': (other_color, black_font), - 'tdg': (other_color, black_font), - 'r': (other_color, black_font), - 'rx': (other_color, black_font), - 'ry': (other_color, black_font), - 'rz': (other_color, black_font), - 'rxx': (other_color, black_font), - 'ryy': (other_color, black_font), - 'rzx': (other_color, black_font), - 'reset': (non_gate_color, white_font), - 'target': ('#ffffff', white_font), - 'measure': (non_gate_color, white_font), - 'ccx': (other_color, black_font), - 'cdcx': (other_color, black_font), - 'ccdcx': (other_color, black_font), - 'cswap': (other_color, black_font), - 'ccswap': (other_color, black_font), - 'mcx': (other_color, black_font), - 'mcx_gray': (other_color, black_font), - 'u': (other_color, black_font), - 'p': (other_color, black_font), - 'sx': (other_color, black_font), - 'sxdg': (other_color, black_font) - } - self.latexmode = False - self.index = False - self.figwidth = -1 - self.dpi = 150 - self.margin = [2.0, 0.1, 0.1, 0.3] - self.cline = 'doublet' - - def set_style(self, style_dic): - dic = copy(style_dic) - self.name = dic.pop('name', self.name) - self.tc = dic.pop('textcolor', self.tc) - self.sc = dic.pop('subtextcolor', self.sc) - self.lc = dic.pop('linecolor', self.lc) - self.cc = dic.pop('creglinecolor', self.cc) - self.gt = dic.pop('gatetextcolor', self.gt) - self.gc = dic.pop('gatefacecolor', self.gc) - self.bc = dic.pop('barrierfacecolor', self.bc) - self.bg = dic.pop('backgroundcolor', self.bg) - self.fs = dic.pop('fontsize', self.fs) - self.sfs = dic.pop('subfontsize', self.sfs) - self.disptex = dic.pop('displaytext', self.disptex) - dcol = dic.pop('displaycolor', self.dispcol) - for col in dcol.keys(): - if col in self.dispcol.keys(): - self.dispcol[col] = dcol[col] - self.latexmode = dic.pop('latexdrawerstyle', self.latexmode) - self.index = dic.pop('showindex', self.index) - self.figwidth = dic.pop('figwidth', self.figwidth) - self.dpi = dic.pop('dpi', self.dpi) - self.margin = dic.pop('margin', self.margin) - self.cline = dic.pop('creglinestyle', self.cline) - - if dic: - warn('style option/s ({}) is/are not supported'.format(', '.join(dic.keys())), - DeprecationWarning, 2) - - -class BWStyle: - def __init__(self): - face_gate_color = '#ffffff' # White face color - - self.name = 'bw' - self.tc = '#000000' - self.sc = '#000000' - self.lc = '#000000' - self.not_gate_lc = '#000000' - self.cc = '#778899' - self.gc = '#ffffff' - self.gt = '#000000' - self.bc = '#bdbdbd' - self.bg = '#ffffff' - self.edge_color = '#000000' - self.fs = 13 - self.math_fs = 15 - self.sfs = 8 - self.disptex = { - 'id': 'I', - 'p': 'P', - 'u': 'U', - 'u1': '$\\mathrm{U}_1$', - 'u2': '$\\mathrm{U}_2$', - 'u3': '$\\mathrm{U}_3$', - 'x': 'X', - 'y': 'Y', - 'z': 'Z', - 'h': 'H', - 's': 'S', - 'sdg': '$\\mathrm{S}^\\dagger$', - 't': 'T', - 'tdg': '$\\mathrm{T}^\\dagger$', - 'iswap': 'Iswap', - 'dcx': 'Dcx', - 'ms': 'MS', - 'diagonal': 'Diagonal', - 'unitary': 'Unitary', - 'r': 'R', - 'rx': '$\\mathrm{R}_\\mathrm{X}$', - 'ry': '$\\mathrm{R}_\\mathrm{Y}$', - 'rz': '$\\mathrm{R}_\\mathrm{Z}$', - 'rxx': '$\\mathrm{R}_{\\mathrm{XX}}$', - 'ryy': '$\\mathrm{R}_{\\mathrm{YY}}$', - 'rzx': '$\\mathrm{R}_{\\mathrm{ZX}}$', - 'rzz': '$\\mathrm{R}_{\\mathrm{ZZ}}$', - 'reset': '$\\left|0\\right\\rangle$', - 'initialize': '$|\\psi\\rangle$' + """Creates a Default Style dictionary + """ + colors = { + '### Default Colors': 'Default Colors', + 'basis': '#FA74A6', # Red + 'clifford': '#6FA4FF', # Light Blue + 'pauli': '#05BAB6', # Green + 'def_other': '#BB8BFF', # Purple + '### IQX Colors': 'IQX Colors', + 'classical': '#002D9C', # Dark Blue + 'phase': '#33B1FF', # Cyan + 'hadamard': '#FA4D56', # Light Red + 'non_unitary': '#A8A8A8', # Medium Gray + 'iqx_other': '#9F1853', # Dark Red + '### B/W': 'B/W', + 'black': '#000000', + 'white': '#FFFFFF', + 'dark_gray': '#778899', + 'light_gray': '#BDBDBD' } - self.dispcol = { - 'u1': (face_gate_color, '#000000'), - 'u2': (face_gate_color, '#000000'), - 'u3': (face_gate_color, '#000000'), - 'id': (face_gate_color, '#000000'), - 'x': (face_gate_color, '#000000'), - 'y': (face_gate_color, '#000000'), - 'z': (face_gate_color, '#000000'), - 'h': (face_gate_color, '#000000'), - 'cx': (face_gate_color, '#000000'), - 'cy': (face_gate_color, '#000000'), - 'cz': (face_gate_color, '#000000'), - 'swap': (face_gate_color, '#000000'), - 's': (face_gate_color, '#000000'), - 'sdg': (face_gate_color, '#000000'), - 'dcx': (face_gate_color, '#000000'), - 'iswap': (face_gate_color, '#000000'), - 't': (face_gate_color, '#000000'), - 'tdg': (face_gate_color, '#000000'), - 'r': (face_gate_color, '#000000'), - 'rx': (face_gate_color, '#000000'), - 'ry': (face_gate_color, '#000000'), - 'rz': (face_gate_color, '#000000'), - 'rxx': (face_gate_color, '#000000'), - 'ryy': (face_gate_color, '#000000'), - 'rzx': (face_gate_color, '#000000'), - 'reset': (face_gate_color, '#000000'), - 'target': (face_gate_color, '#000000'), - 'measure': (face_gate_color, '#000000'), - 'ccx': (face_gate_color, '#000000'), - 'cdcx': (face_gate_color, '#000000'), - 'ccdcx': (face_gate_color, '#000000'), - 'cswap': (face_gate_color, '#000000'), - 'ccswap': (face_gate_color, '#000000'), - 'mcx': (face_gate_color, '#000000'), - 'mcx_gray': (face_gate_color, '#000000'), - 'u': (face_gate_color, '#000000'), - 'p': (face_gate_color, '#000000'), - 'sx': (face_gate_color, '#000000'), - 'sxdg': (face_gate_color, '#000000') + self.style = { + 'name': 'default', + 'tc': colors['black'], # Non-gate Text Color + 'gt': colors['black'], # Gate Text Color + 'sc': colors['black'], # Gate Subtext Color + 'lc': colors['black'], # Line Color + 'cc': colors['dark_gray'], # creg Line Color + 'gc': colors['def_other'], # Default Gate Color + 'bc': colors['light_gray'], # Barrier Color + 'bg': colors['white'], # Background Color + 'ec': None, # Edge Color (B/W only) + 'fs': 13, # Gate Font Size + 'sfs': 8, # Subtext Font Size + 'index': False, + 'figwidth': -1, + 'dpi': 150, + 'margin': [2.0, 0.1, 0.1, 0.3], + 'cline': 'doublet', + + 'disptex': { + 'u1': '$\\mathrm{U}_1$', + 'u2': '$\\mathrm{U}_2$', + 'u3': '$\\mathrm{U}_3$', + 'u': 'U', + 'p': 'P', + 'id': 'I', + 'x': 'X', + 'y': 'Y', + 'z': 'Z', + 'h': 'H', + 's': 'S', + 'sdg': '$\\mathrm{S}^\\dagger$', + 'sx': '$\\sqrt{\\mathrm{X}}$', + 'sxdg': '$\\sqrt{\\mathrm{X}}^\\dagger$', + 't': 'T', + 'tdg': '$\\mathrm{T}^\\dagger$', + 'dcx': 'Dcx', + 'iswap': 'Iswap', + 'ms': 'MS', + 'r': 'R', + 'rx': '$\\mathrm{R}_\\mathrm{X}$', + 'ry': '$\\mathrm{R}_\\mathrm{Y}$', + 'rz': '$\\mathrm{R}_\\mathrm{Z}$', + 'rxx': '$\\mathrm{R}_{\\mathrm{XX}}$', + 'ryy': '$\\mathrm{R}_{\\mathrm{YY}}$', + 'rzx': '$\\mathrm{R}_{\\mathrm{ZX}}$', + 'rzz': '$\\mathrm{R}_{\\mathrm{ZZ}}$', + 'reset': '$\\left|0\\right\\rangle$', + 'initialize': '$|\\psi\\rangle$' + }, + 'dispcol': { + 'u1': (colors['basis'], colors['black']), + 'u2': (colors['basis'], colors['black']), + 'u3': (colors['basis'], colors['black']), + 'u': (colors['def_other'], colors['black']), + 'p': (colors['def_other'], colors['black']), + 'id': (colors['pauli'], colors['black']), + 'x': (colors['pauli'], colors['black']), + 'y': (colors['pauli'], colors['black']), + 'z': (colors['pauli'], colors['black']), + 'h': (colors['clifford'], colors['black']), + 'cx': (colors['clifford'], colors['black']), + 'ccx': (colors['def_other'], colors['black']), + 'mcx': (colors['def_other'], colors['black']), + 'mcx_gray': (colors['def_other'], colors['black']), + 'cy': (colors['clifford'], colors['black']), + 'cz': (colors['clifford'], colors['black']), + 'swap': (colors['clifford'], colors['black']), + 'cswap': (colors['def_other'], colors['black']), + 'ccswap': (colors['def_other'], colors['black']), + 'dcx': (colors['clifford'], colors['black']), + 'cdcx': (colors['def_other'], colors['black']), + 'ccdcx': (colors['def_other'], colors['black']), + 'iswap': (colors['clifford'], colors['black']), + 's': (colors['clifford'], colors['black']), + 'sdg': (colors['clifford'], colors['black']), + 't': (colors['def_other'], colors['black']), + 'tdg': (colors['def_other'], colors['black']), + 'sx': (colors['def_other'], colors['black']), + 'sxdg': (colors['def_other'], colors['black']), + 'r': (colors['def_other'], colors['black']), + 'rx': (colors['def_other'], colors['black']), + 'ry': (colors['def_other'], colors['black']), + 'rz': (colors['def_other'], colors['black']), + 'rxx': (colors['def_other'], colors['black']), + 'ryy': (colors['def_other'], colors['black']), + 'rzx': (colors['def_other'], colors['black']), + 'reset': (colors['black'], colors['white']), + 'target': (colors['white'], colors['white']), + 'measure': (colors['black'], colors['white']) + } } - self.latexmode = False - self.index = False - self.figwidth = -1 - self.dpi = 150 - self.margin = [2.0, 0.1, 0.1, 0.3] - self.cline = 'doublet' - def set_style(self, style_dic): - dic = copy(style_dic) - self.name = dic.pop('name', self.name) - self.tc = dic.pop('textcolor', self.tc) - self.sc = dic.pop('subtextcolor', self.sc) - self.lc = dic.pop('linecolor', self.lc) - self.cc = dic.pop('creglinecolor', self.cc) - self.gt = dic.pop('gatetextcolor', self.gt) - self.gc = dic.pop('gatefacecolor', self.gc) - self.bc = dic.pop('barrierfacecolor', self.bc) - self.bg = dic.pop('backgroundcolor', self.bg) - self.fs = dic.pop('fontsize', self.fs) - self.sfs = dic.pop('subfontsize', self.sfs) - self.disptex = dic.pop('displaytext', self.disptex) - dcol = dic.pop('displaycolor', self.dispcol) - for col in dcol.keys(): - if col in self.dispcol.keys(): - self.dispcol[col] = dcol[col] - self.latexmode = dic.pop('latexdrawerstyle', self.latexmode) - self.index = dic.pop('showindex', self.index) - self.figwidth = dic.pop('figwidth', self.figwidth) - self.dpi = dic.pop('dpi', self.dpi) - self.margin = dic.pop('margin', self.margin) - self.cline = dic.pop('creglinestyle', self.cline) - if dic: - warn('style option/s ({}) is/are not supported'.format(', '.join(dic.keys())), - DeprecationWarning, 2) - - -class IQXStyle: - def __init__(self): - # Set colors - classical_gate_color = '#002D9C' # Dark Blue - phase_gate_color = '#33B1FF' # Cyan - hadamard_color = '#FA4D56' # Red - other_quantum_gate = '#9F1853' # Dark Red - non_unitary_gate = '#A8A8A8' # Grey - - black_font = '#000000' # Black font color - white_font = '#ffffff' # White font color - - self.name = 'iqx' - self.tc = '#000000' - self.sc = '#ffffff' - self.lc = '#000000' - self.not_gate_lc = '#ffffff' - self.cc = '#778899' # Medium Gray - self.gc = other_quantum_gate - self.gt = '#ffffff' - self.bc = non_unitary_gate # Dark Gray - self.bg = '#ffffff' - self.edge_color = None - self.math_fs = 15 - self.fs = 13 - self.sfs = 8 - self.disptex = { - 'id': 'I', - 'p': 'P', - 'u': 'U', - 'u1': '$\\mathrm{U}_1$', - 'u2': '$\\mathrm{U}_2$', - 'u3': '$\\mathrm{U}_3$', - 'x': 'X', - 'y': 'Y', - 'z': 'Z', - 'h': 'H', - 's': 'S', - 'sdg': '$\\mathrm{S}^\\dagger$', - 'sx': '$\\sqrt{\\mathrm{X}}$', - 'sxdg': '$\\sqrt{\\mathrm{X}}^\\dagger$', - 't': 'T', - 'tdg': '$\\mathrm{T}^\\dagger$', - 'iswap': 'Iswap', - 'dcx': 'Dcx', - 'ms': 'MS', - 'diagonal': 'Diagonal', - 'unitary': 'Unitary', - 'r': 'R', - 'rx': '$\\mathrm{R}_\\mathrm{X}$', - 'ry': '$\\mathrm{R}_\\mathrm{Y}$', - 'rz': '$\\mathrm{R}_\\mathrm{Z}$', - 'rxx': '$\\mathrm{R}_{\\mathrm{XX}}$', - 'ryy': '$\\mathrm{R}_{\\mathrm{YY}}$', - 'rzx': '$\\mathrm{R}_{\\mathrm{ZX}}$', - 'rzz': '$\\mathrm{R}_{\\mathrm{ZZ}}$', - 'reset': '$\\left|0\\right\\rangle$', - 'initialize': '$|\\psi\\rangle$' - } - self.dispcol = { - 'u1': (phase_gate_color, black_font), - 'u2': (other_quantum_gate, white_font), - 'u3': (other_quantum_gate, white_font), - 'id': (classical_gate_color, white_font), - 'x': (classical_gate_color, white_font), - 'y': (other_quantum_gate, white_font), - 'z': (phase_gate_color, black_font), - 'h': (hadamard_color, black_font), - 'cx': (classical_gate_color, white_font), - 'cy': (other_quantum_gate, white_font), - 'cz': (other_quantum_gate, white_font), - 'swap': (classical_gate_color, white_font), - 's': (phase_gate_color, black_font), - 'sdg': (phase_gate_color, black_font), - 'dcx': (classical_gate_color, white_font), - 'iswap': (phase_gate_color, black_font), - 't': (phase_gate_color, black_font), - 'tdg': (phase_gate_color, black_font), - 'r': (other_quantum_gate, white_font), - 'rx': (other_quantum_gate, white_font), - 'ry': (other_quantum_gate, white_font), - 'rz': (other_quantum_gate, white_font), - 'rxx': (other_quantum_gate, white_font), - 'ryy': (other_quantum_gate, white_font), - 'rzx': (other_quantum_gate, white_font), - 'reset': (non_unitary_gate, black_font), - 'target': ('#ffffff', '#ffffff'), - 'measure': (non_unitary_gate, black_font), - 'ccx': (classical_gate_color, white_font), - 'cdcx': (classical_gate_color, white_font), - 'ccdcx': (classical_gate_color, white_font), - 'cswap': (classical_gate_color, white_font), - 'ccswap': (classical_gate_color, white_font), - 'mcx': (classical_gate_color, white_font), - 'mcx_gray': (classical_gate_color, white_font), - 'u': (other_quantum_gate, white_font), - 'p': (phase_gate_color, black_font), - 'sx': (other_quantum_gate, white_font), - 'sxdg': (other_quantum_gate, white_font), - } - self.latexmode = False - self.index = False - self.figwidth = -1 - self.dpi = 150 - self.margin = [2.0, 0.1, 0.1, 0.3] - self.cline = 'doublet' - - def set_style(self, style_dic): - dic = copy(style_dic) - self.name = dic.pop('name', self.name) - self.tc = dic.pop('textcolor', self.tc) - self.sc = dic.pop('subtextcolor', self.sc) - self.lc = dic.pop('linecolor', self.lc) - self.cc = dic.pop('creglinecolor', self.cc) - self.gt = dic.pop('gatetextcolor', self.gt) - self.gc = dic.pop('gatefacecolor', self.gc) - self.bc = dic.pop('barrierfacecolor', self.bc) - self.bg = dic.pop('backgroundcolor', self.bg) - self.fs = dic.pop('fontsize', self.fs) - self.sfs = dic.pop('subfontsize', self.sfs) - self.disptex = dic.pop('displaytext', self.disptex) - dcol = dic.pop('displaycolor', self.dispcol) - for col in dcol.keys(): - if col in self.dispcol.keys(): - self.dispcol[col] = dcol[col] - self.latexmode = dic.pop('latexdrawerstyle', self.latexmode) - self.index = dic.pop('showindex', self.index) - self.figwidth = dic.pop('figwidth', self.figwidth) - self.dpi = dic.pop('dpi', self.dpi) - self.margin = dic.pop('margin', self.margin) - self.cline = dic.pop('creglinestyle', self.cline) - - if dic: - warn('style option/s ({}) is/are not supported'.format(', '.join(dic.keys())), - DeprecationWarning, 2) +def set_style(current_style, new_style): + """Utility function to take elements in new_style and + write them into current_style. + """ + current_style['name'] = new_style.pop('name', current_style['name']) + current_style['tc'] = new_style.pop('textcolor', current_style['tc']) + current_style['gt'] = new_style.pop('gatetextcolor', current_style['gt']) + current_style['sc'] = new_style.pop('subtextcolor', current_style['sc']) + current_style['lc'] = new_style.pop('linecolor', current_style['lc']) + current_style['cc'] = new_style.pop('creglinecolor', current_style['cc']) + current_style['gc'] = new_style.pop('gatefacecolor', current_style['gc']) + current_style['bc'] = new_style.pop('barrierfacecolor', current_style['bc']) + current_style['bg'] = new_style.pop('backgroundcolor', current_style['bg']) + current_style['ec'] = new_style.pop('edgecolor', current_style['ec']) + current_style['fs'] = new_style.pop('fontsize', current_style['fs']) + current_style['sfs'] = new_style.pop('subfontsize', current_style['sfs']) + current_style['index'] = new_style.pop('showindex', current_style['index']) + current_style['figwidth'] = new_style.pop('figwidth', current_style['figwidth']) + current_style['dpi'] = new_style.pop('dpi', current_style['dpi']) + current_style['margin'] = new_style.pop('margin', current_style['margin']) + current_style['cline'] = new_style.pop('creglinestyle', current_style['cline']) + dtex = new_style.pop('displaytext', current_style['disptex']) + for tex in dtex.keys(): + if tex in current_style['disptex'].keys(): + current_style['disptex'][tex] = dtex[tex] + dcol = new_style.pop('displaycolor', current_style['dispcol']) + for col in dcol.keys(): + if col in current_style['dispcol'].keys(): + current_style['dispcol'][col] = dcol[col] + + if new_style: + warn('style option/s ({}) is/are not supported'.format(', '.join(new_style.keys())), + DeprecationWarning, 2) + + return current_style diff --git a/qiskit/visualization/styles/bw.json b/qiskit/visualization/styles/bw.json new file mode 100644 index 000000000000..ece05efa37ba --- /dev/null +++ b/qiskit/visualization/styles/bw.json @@ -0,0 +1,213 @@ +{ + "name": "bw", + "textcolor": "#000000", + "gatetextcolor": "#000000", + "subtextcolor": "#000000", + "linecolor": "#000000", + "creglinecolor": "#778899", + "gatefacecolor": "#FFFFFF", + "barrierfacecolor": "#BDBDBD", + "backgroundcolor": "#FFFFFF", + "edgecolor": "#000000", + "fontsize": 13, + "subfontsize": 8, + "showindex": false, + "figwidth": -1, + "dpi": 150, + "margin": [ + 2.0, + 0.1, + 0.1, + 0.3 + ], + "creglinestyle": "doublet", + "displaytext": { + "u1": "$\\mathrm{U}_1$", + "u2": "$\\mathrm{U}_2$", + "u3": "$\\mathrm{U}_3$", + "u": "U", + "p": "P", + "id": "I", + "x": "X", + "y": "Y", + "z": "Z", + "h": "H", + "s": "S", + "sdg": "$\\mathrm{S}^\\dagger$", + "sx": "$\\sqrt{\\mathrm{X}}$", + "sxdg": "$\\sqrt{\\mathrm{X}}^\\dagger$", + "t": "T", + "tdg": "$\\mathrm{T}^\\dagger$", + "dcx": "Dcx", + "iswap": "Iswap", + "ms": "MS", + "r": "R", + "rx": "$\\mathrm{R}_\\mathrm{X}$", + "ry": "$\\mathrm{R}_\\mathrm{Y}$", + "rz": "$\\mathrm{R}_\\mathrm{Z}$", + "rxx": "$\\mathrm{R}_{\\mathrm{XX}}$", + "ryy": "$\\mathrm{R}_{\\mathrm{YY}}$", + "rzx": "$\\mathrm{R}_{\\mathrm{ZX}}$", + "rzz": "$\\mathrm{R}_{\\mathrm{ZZ}}$", + "reset": "$\\left|0\\right\\rangle$", + "initialize": "$|\\psi\\rangle$" + }, + "displaycolor": { + "u1": [ + "#FFFFFF", + "#000000" + ], + "u2": [ + "#FFFFFF", + "#000000" + ], + "u3": [ + "#FFFFFF", + "#000000" + ], + "u": [ + "#FFFFFF", + "#000000" + ], + "p": [ + "#FFFFFF", + "#000000" + ], + "id": [ + "#FFFFFF", + "#000000" + ], + "x": [ + "#FFFFFF", + "#000000" + ], + "y": [ + "#FFFFFF", + "#000000" + ], + "z": [ + "#FFFFFF", + "#000000" + ], + "h": [ + "#FFFFFF", + "#000000" + ], + "cx": [ + "#FFFFFF", + "#000000" + ], + "ccx": [ + "#FFFFFF", + "#000000" + ], + "mcx": [ + "#FFFFFF", + "#000000" + ], + "mcx_gray": [ + "#FFFFFF", + "#000000" + ], + "cy": [ + "#FFFFFF", + "#000000" + ], + "cz": [ + "#FFFFFF", + "#000000" + ], + "swap": [ + "#FFFFFF", + "#000000" + ], + "cswap": [ + "#FFFFFF", + "#000000" + ], + "ccswap": [ + "#FFFFFF", + "#000000" + ], + "dcx": [ + "#FFFFFF", + "#000000" + ], + "cdcx": [ + "#FFFFFF", + "#000000" + ], + "ccdcx": [ + "#FFFFFF", + "#000000" + ], + "iswap": [ + "#FFFFFF", + "#000000" + ], + "s": [ + "#FFFFFF", + "#000000" + ], + "sdg": [ + "#FFFFFF", + "#000000" + ], + "t": [ + "#FFFFFF", + "#000000" + ], + "tdg": [ + "#FFFFFF", + "#000000" + ], + "sx": [ + "#FFFFFF", + "#000000" + ], + "sxdg": [ + "#FFFFFF", + "#000000" + ], + "r": [ + "#FFFFFF", + "#000000" + ], + "rx": [ + "#FFFFFF", + "#000000" + ], + "ry": [ + "#FFFFFF", + "#000000" + ], + "rz": [ + "#FFFFFF", + "#000000" + ], + "rxx": [ + "#FFFFFF", + "#000000" + ], + "ryy": [ + "#FFFFFF", + "#000000" + ], + "rzx": [ + "#FFFFFF", + "#000000" + ], + "reset": [ + "#000000", + "#FFFFFF" + ], + "target": [ + "#FFFFFF", + "#FFFFFF" + ], + "measure": [ + "#000000", + "#FFFFFF" + ] + } +} \ No newline at end of file diff --git a/qiskit/visualization/styles/default.json b/qiskit/visualization/styles/default.json new file mode 100644 index 000000000000..734ae2a7a77b --- /dev/null +++ b/qiskit/visualization/styles/default.json @@ -0,0 +1,213 @@ +{ + "name": "default", + "textcolor": "#000000", + "gatetextcolor": "#000000", + "subtextcolor": "#000000", + "linecolor": "#000000", + "creglinecolor": "#778899", + "gatefacecolor": "#BB8BFF", + "barrierfacecolor": "#BDBDBD", + "backgroundcolor": "#FFFFFF", + "edgecolor": null, + "fontsize": 13, + "subfontsize": 8, + "showindex": false, + "figwidth": -1, + "dpi": 150, + "margin": [ + 2.0, + 0.1, + 0.1, + 0.3 + ], + "creglinestyle": "doublet", + "displaytext": { + "u1": "$\\mathrm{U}_1$", + "u2": "$\\mathrm{U}_2$", + "u3": "$\\mathrm{U}_3$", + "u": "U", + "p": "P", + "id": "I", + "x": "X", + "y": "Y", + "z": "Z", + "h": "H", + "s": "S", + "sdg": "$\\mathrm{S}^\\dagger$", + "sx": "$\\sqrt{\\mathrm{X}}$", + "sxdg": "$\\sqrt{\\mathrm{X}}^\\dagger$", + "t": "T", + "tdg": "$\\mathrm{T}^\\dagger$", + "dcx": "Dcx", + "iswap": "Iswap", + "ms": "MS", + "r": "R", + "rx": "$\\mathrm{R}_\\mathrm{X}$", + "ry": "$\\mathrm{R}_\\mathrm{Y}$", + "rz": "$\\mathrm{R}_\\mathrm{Z}$", + "rxx": "$\\mathrm{R}_{\\mathrm{XX}}$", + "ryy": "$\\mathrm{R}_{\\mathrm{YY}}$", + "rzx": "$\\mathrm{R}_{\\mathrm{ZX}}$", + "rzz": "$\\mathrm{R}_{\\mathrm{ZZ}}$", + "reset": "$\\left|0\\right\\rangle$", + "initialize": "$|\\psi\\rangle$" + }, + "displaycolor": { + "u1": [ + "#FA74A6", + "#000000" + ], + "u2": [ + "#FA74A6", + "#000000" + ], + "u3": [ + "#FA74A6", + "#000000" + ], + "u": [ + "#BB8BFF", + "#000000" + ], + "p": [ + "#BB8BFF", + "#000000" + ], + "id": [ + "#05BAB6", + "#000000" + ], + "x": [ + "#05BAB6", + "#000000" + ], + "y": [ + "#05BAB6", + "#000000" + ], + "z": [ + "#05BAB6", + "#000000" + ], + "h": [ + "#6FA4FF", + "#000000" + ], + "cx": [ + "#6FA4FF", + "#000000" + ], + "ccx": [ + "#BB8BFF", + "#000000" + ], + "mcx": [ + "#BB8BFF", + "#000000" + ], + "mcx_gray": [ + "#BB8BFF", + "#000000" + ], + "cy": [ + "#6FA4FF", + "#000000" + ], + "cz": [ + "#6FA4FF", + "#000000" + ], + "swap": [ + "#6FA4FF", + "#000000" + ], + "cswap": [ + "#BB8BFF", + "#000000" + ], + "ccswap": [ + "#BB8BFF", + "#000000" + ], + "dcx": [ + "#6FA4FF", + "#000000" + ], + "cdcx": [ + "#BB8BFF", + "#000000" + ], + "ccdcx": [ + "#BB8BFF", + "#000000" + ], + "iswap": [ + "#6FA4FF", + "#000000" + ], + "s": [ + "#6FA4FF", + "#000000" + ], + "sdg": [ + "#6FA4FF", + "#000000" + ], + "t": [ + "#BB8BFF", + "#000000" + ], + "tdg": [ + "#BB8BFF", + "#000000" + ], + "sx": [ + "#BB8BFF", + "#000000" + ], + "sxdg": [ + "#BB8BFF", + "#000000" + ], + "r": [ + "#BB8BFF", + "#000000" + ], + "rx": [ + "#BB8BFF", + "#000000" + ], + "ry": [ + "#BB8BFF", + "#000000" + ], + "rz": [ + "#BB8BFF", + "#000000" + ], + "rxx": [ + "#BB8BFF", + "#000000" + ], + "ryy": [ + "#BB8BFF", + "#000000" + ], + "rzx": [ + "#BB8BFF", + "#000000" + ], + "reset": [ + "#000000", + "#FFFFFF" + ], + "target": [ + "#FFFFFF", + "#FFFFFF" + ], + "measure": [ + "#000000", + "#FFFFFF" + ] + } +} \ No newline at end of file diff --git a/qiskit/visualization/styles/iqx.json b/qiskit/visualization/styles/iqx.json new file mode 100644 index 000000000000..b9fc41ee6baa --- /dev/null +++ b/qiskit/visualization/styles/iqx.json @@ -0,0 +1,213 @@ +{ + "name": "iqx", + "textcolor": "#000000", + "gatetextcolor": "#FFFFFF", + "subtextcolor": "#FFFFFF", + "linecolor": "#000000", + "creglinecolor": "#778899", + "gatefacecolor": "#9F1853", + "barrierfacecolor": "#A8A8A8", + "backgroundcolor": "#FFFFFF", + "edgecolor": null, + "fontsize": 13, + "subfontsize": 8, + "showindex": false, + "figwidth": -1, + "dpi": 150, + "margin": [ + 2.0, + 0.1, + 0.1, + 0.3 + ], + "creglinestyle": "doublet", + "displaytext": { + "u1": "$\\mathrm{U}_1$", + "u2": "$\\mathrm{U}_2$", + "u3": "$\\mathrm{U}_3$", + "u": "U", + "p": "P", + "id": "I", + "x": "X", + "y": "Y", + "z": "Z", + "h": "H", + "s": "S", + "sdg": "$\\mathrm{S}^\\dagger$", + "sx": "$\\sqrt{\\mathrm{X}}$", + "sxdg": "$\\sqrt{\\mathrm{X}}^\\dagger$", + "t": "T", + "tdg": "$\\mathrm{T}^\\dagger$", + "dcx": "Dcx", + "iswap": "Iswap", + "ms": "MS", + "r": "R", + "rx": "$\\mathrm{R}_\\mathrm{X}$", + "ry": "$\\mathrm{R}_\\mathrm{Y}$", + "rz": "$\\mathrm{R}_\\mathrm{Z}$", + "rxx": "$\\mathrm{R}_{\\mathrm{XX}}$", + "ryy": "$\\mathrm{R}_{\\mathrm{YY}}$", + "rzx": "$\\mathrm{R}_{\\mathrm{ZX}}$", + "rzz": "$\\mathrm{R}_{\\mathrm{ZZ}}$", + "reset": "$\\left|0\\right\\rangle$", + "initialize": "$|\\psi\\rangle$" + }, + "displaycolor": { + "u1": [ + "#33B1FF", + "#000000" + ], + "u2": [ + "#9F1853", + "#FFFFFF" + ], + "u3": [ + "#9F1853", + "#FFFFFF" + ], + "u": [ + "#9F1853", + "#FFFFFF" + ], + "p": [ + "#33B1FF", + "#000000" + ], + "id": [ + "#002D9C", + "#FFFFFF" + ], + "x": [ + "#002D9C", + "#FFFFFF" + ], + "y": [ + "#9F1853", + "#FFFFFF" + ], + "z": [ + "#33B1FF", + "#000000" + ], + "h": [ + "#FA4D56", + "#000000" + ], + "cx": [ + "#002D9C", + "#000000" + ], + "ccx": [ + "#002D9C", + "#000000" + ], + "mcx": [ + "#002D9C", + "#000000" + ], + "mcx_gray": [ + "#002D9C", + "#000000" + ], + "cy": [ + "#9F1853", + "#FFFFFF" + ], + "cz": [ + "#9F1853", + "#FFFFFF" + ], + "swap": [ + "#002D9C", + "#000000" + ], + "cswap": [ + "#002D9C", + "#000000" + ], + "ccswap": [ + "#002D9C", + "#000000" + ], + "dcx": [ + "#002D9C", + "#FFFFFF" + ], + "cdcx": [ + "#002D9C", + "#FFFFFF" + ], + "ccdcx": [ + "#002D9C", + "#FFFFFF" + ], + "iswap": [ + "#33B1FF", + "#000000" + ], + "s": [ + "#33B1FF", + "#000000" + ], + "sdg": [ + "#33B1FF", + "#000000" + ], + "t": [ + "#33B1FF", + "#000000" + ], + "tdg": [ + "#33B1FF", + "#000000" + ], + "sx": [ + "#9F1853", + "#FFFFFF" + ], + "sxdg": [ + "#9F1853", + "#FFFFFF" + ], + "r": [ + "#9F1853", + "#FFFFFF" + ], + "rx": [ + "#9F1853", + "#FFFFFF" + ], + "ry": [ + "#9F1853", + "#FFFFFF" + ], + "rz": [ + "#9F1853", + "#FFFFFF" + ], + "rxx": [ + "#9F1853", + "#FFFFFF" + ], + "ryy": [ + "#9F1853", + "#FFFFFF" + ], + "rzx": [ + "#9F1853", + "#FFFFFF" + ], + "reset": [ + "#A8A8A8", + "#000000" + ], + "target": [ + "#FFFFFF", + "#FFFFFF" + ], + "measure": [ + "#A8A8A8", + "#000000" + ] + } +} \ No newline at end of file diff --git a/releasenotes/notes/load-user-style-json-files-823590b03f015e4b.yaml b/releasenotes/notes/load-user-style-json-files-823590b03f015e4b.yaml new file mode 100644 index 000000000000..728198e5b8f5 --- /dev/null +++ b/releasenotes/notes/load-user-style-json-files-823590b03f015e4b.yaml @@ -0,0 +1,23 @@ +--- +fixes: + - | + The documentation for the :class:`~qiskit.circuit.QuantumCircuit` method + :meth:`~qiskit.circuit.QuantumCircuit.draw` and the + :func:`~qiskit.visualization.circuit_drawer` function were out-of-sync with + the state of the code. The documentation has been brought up-to-date. As + part of this update, 3 elements of the `mpl` drawer `style` parameter dictionary + have been removed since they were not implemented in the code and not needed. + These are `latexdrawerstyle`, `usepiformat`, and `compress`. +features: + - | + In previous versions of qiskit, there was a rudimentary functionality that + allowed users to load an `mpl` drawer `style` dictionary from a JSON file in + order to customize the colors and other display features of the `mpl` drawer. + This capability has now been expanded so that all `style` dictionaries are + loaded from JSON files, and users can copy and customize the standard style + JSON files included with qiskit - `default.json`, `iqx.json`, and `bw.json`. + Users can indicate the path to be searched for any user style JSON files by + setting ``circuit_mpl_style_path`` under the [Default] heading in the file + ``settings.conf`` in the ``~/.qiskit`` directory. Path entries should be + separated by `:`. For example, + ``circuit_mpl_style_path = ~/.qiskit:~/user_styles`` diff --git a/test/ipynb/mpl/references/bw.png b/test/ipynb/mpl/references/bw.png new file mode 100644 index 0000000000000000000000000000000000000000..56b2ce75abd2a75ef618b141348451ec6ef1030b GIT binary patch literal 27362 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 UJZ{*#lg7l^>DY(m2mBNM1ChTFQ2+n{ literal 0 HcmV?d00001 diff --git a/test/ipynb/mpl/references/iqx_color.png b/test/ipynb/mpl/references/iqx_color.png index 2bf9909993a82360477cc674e8185969b190eba5..7f7201c65b4ad98425c85112510fdc8f5a7f3877 100644 GIT binary patch delta 43 ycmZpi$lN%Qd4h+Wk&Z$}Nl8JmmA-y%Vo5J=@S4&=MNSD delta 43 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 literal 11271 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 z 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