• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Qiskit / qiskit / 23548889554

25 Mar 2026 03:22PM UTC coverage: 87.191% (-0.04%) from 87.235%
23548889554

Pull #15836

github

web-flow
Merge 4df6d9082 into 3e8032600
Pull Request #15836: Use `np.bitwise_count` in `BitArray.bitcount`

1 of 5 new or added lines in 1 file covered. (20.0%)

1085 existing lines in 41 files now uncovered.

103626 of 118850 relevant lines covered (87.19%)

1001189.12 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

74.83
/qiskit/visualization/circuit/circuit_visualization.py
1
# This code is part of Qiskit.
2
#
3
# (C) Copyright IBM 2017, 2018.
4
#
5
# This code is licensed under the Apache License, Version 2.0. You may
6
# obtain a copy of this license in the LICENSE.txt file in the root directory
7
# of this source tree or at https://www.apache.org/licenses/LICENSE-2.0.
8
#
9
# Any modifications or derivative works of this code must retain this
10
# copyright notice, and modified files need to carry a notice indicating
11
# that they have been altered from the originals.
12

13
"""
14
Module for the primary interface to the circuit drawers.
15

16
This module contains the end user facing API for drawing quantum circuits.
17
There are 3 available drawer backends:
18

19
 0. ASCII art
20
 1. LaTeX
21
 2. Matplotlib
22

23
This provides a single function entry point to drawing a circuit object with
24
any of the backends.
25
"""
26

27
from __future__ import annotations
1✔
28

29
import logging
1✔
30
import os
1✔
31
import shutil
1✔
32
import subprocess
1✔
33
import tempfile
1✔
34
import typing
1✔
35
from warnings import warn
1✔
36

37
from qiskit import user_config
1✔
38
from qiskit.circuit import ControlFlowOp, Measure
1✔
39
from qiskit.utils import optionals as _optionals
1✔
40

41
from ..exceptions import VisualizationError
1✔
42
from ..utils import _trim as trim_image
1✔
43
from . import _utils
1✔
44
from . import latex as _latex
1✔
45
from . import matplotlib as _matplotlib
1✔
46
from . import text as _text
1✔
47

48
if typing.TYPE_CHECKING:
49
    from typing import Any
50
    from qiskit.circuit import QuantumCircuit
51

52

53
logger = logging.getLogger(__name__)
1✔
54

55

56
def circuit_drawer(
1✔
57
    circuit: QuantumCircuit,
58
    scale: float | None = None,
59
    filename: str | None = None,
60
    style: dict | str | None = None,
61
    output: str | None = None,
62
    interactive: bool = False,
63
    plot_barriers: bool = True,
64
    reverse_bits: bool | None = None,
65
    justify: str | None = None,
66
    vertical_compression: str | None = "medium",
67
    idle_wires: bool | str | None = None,
68
    with_layout: bool = True,
69
    fold: int | None = None,
70
    # The type of ax is matplotlib.axes.Axes, but this is not a fixed dependency, so cannot be
71
    # safely forward-referenced.
72
    ax: Any | None = None,
73
    initial_state: bool = False,
74
    cregbundle: bool | None = None,
75
    wire_order: list[int] | None = None,
76
    expr_len: int = 30,
77
    measure_arrows: bool | None = None,
78
    barrier_label_len: int = 16,
79
):
80
    r"""Draw the quantum circuit. Use the output parameter to choose the drawing format:
81

82
    ``text``
83
        ASCII art TextDrawing that can be printed in the console.
84

85
    ``mpl``
86
        Images with color rendered purely in Python using matplotlib.
87

88
    ``latex``
89
        High-quality images compiled via LaTeX.
90

91
        .. warning::
92
            This will call an installed system version of ``pdflatex`` on arbitrary user input by
93
            design (such as to render custom code in :attr:`.Instruction.label`), so should only be
94
            used on trusted data.
95

96
    ``latex_source``
97
        Raw uncompiled LaTeX output.  This is the source of what would be rendered by the
98
        ``latex`` drawer.
99

100
    .. warning::
101

102
        Support for :class:`~.expr.Expr` nodes in conditions and :attr:`.SwitchCaseOp.target`
103
        fields is preliminary and incomplete.  The ``text`` and ``mpl`` drawers will make a
104
        best-effort attempt to show data dependencies, but the LaTeX-based drawers will skip
105
        these completely.
106

107
    Args:
108
        circuit: The circuit to visualize.
109
        scale: Scale of image to draw (shrink if ``< 1.0``). Only used by
110
            the ``mpl``, ``latex`` and ``latex_source`` outputs. Defaults to ``1.0``.
111
        filename: File path to save image to. Defaults to ``None`` (result not saved in a file).
112
        style: Style name, file name of style JSON file, or a dictionary specifying the style.
113

114
            * The supported style names are ``"iqp"`` (default), ``"iqp-dark"``, ``"clifford"``,
115
                ``"textbook"`` and ``"bw"``.
116
            * If given a JSON file, e.g. ``my_style.json`` or ``my_style`` (the ``.json``
117
                extension may be omitted), this function attempts to load the style dictionary
118
                from that location. Note, that the JSON file must completely specify the
119
                visualization specifications. The file is searched for in
120
                ``qiskit/visualization/circuit/styles``, the current working directory, and
121
                the location specified in ``~/.qiskit/settings.conf``.
122
            * If a dictionary, every entry overrides the default configuration. If the
123
                ``"name"`` key is given, the default configuration is given by that style.
124
                For example, ``{"name": "textbook", "subfontsize": 5}`` loads the ``"textbook"``
125
                style and sets the subfontsize (e.g. the gate angles) to ``5``.
126
            * If ``None`` the default style ``"iqp"`` is used or, if given, the default style
127
                specified in ``~/.qiskit/settings.conf``.
128

129
        output: Select the output method to use for drawing the circuit.
130
            Valid choices are ``text``, ``mpl``, ``latex``, ``latex_source``.
131
            By default, the ``text`` drawer is used unless the user config file
132
            (usually ``~/.qiskit/settings.conf``) has an alternative backend set
133
            as the default. For example, ``circuit_drawer = latex``. If the output
134
            kwarg is set, that backend will always be used over the default in
135
            the user config file.
136
        interactive: When set to ``True``, show the circuit in a new window
137
            (for ``mpl`` this depends on the matplotlib backend being used
138
            supporting this). Note when used with either the `text` or the
139
            ``latex_source`` output type this has no effect and will be silently
140
            ignored. Defaults to ``False``.
141
        reverse_bits: When set to ``True``, reverse the bit order inside
142
            registers for the output visualization. Defaults to ``False`` unless the
143
            user config file (usually ``~/.qiskit/settings.conf``) has an
144
            alternative value set. For example, ``circuit_reverse_bits = True``.
145
        plot_barriers: Enable/disable drawing barriers in the output
146
            circuit. Defaults to ``True``.
147
        justify: Options are ``"left"``, ``"right"`` or ``"none"`` (str).
148
            If anything else is supplied, left justified will be used instead.
149
            It refers to where gates should be placed in the output circuit if
150
            there is an option. ``none`` results in each gate being placed in
151
            its own column. Defaults to ``left``.
152
        vertical_compression: ``high``, ``medium`` or ``low``. It
153
            merges the lines generated by the `text` output so the drawing
154
            will take less vertical room.  Default is ``medium``. Only used by
155
            the ``text`` output, will be silently ignored otherwise.
156
        idle_wires: Include (or not) idle wires (wires with no circuit elements)
157
            in output visualization. The string ``"auto"`` is also possible, in which
158
            case idle wires are show except that the circuit has a layout attached.
159
            Default is ``"auto"`` unless the
160
            user config file (usually ``~/.qiskit/settings.conf``) has an
161
            alternative value set. For example, ``circuit_idle_wires = False``.
162
        with_layout: Include layout information, with labels on the
163
            physical layout. Default is ``True``.
164
        fold: Sets pagination. It can be disabled using -1. In ``text``,
165
            sets the length of the lines. This is useful when the drawing does
166
            not fit in the console. If None (default), it will try to guess the
167
            console width using ``shutil.get_terminal_size()``. However, if
168
            running in jupyter, the default line length is set to 80 characters.
169
            In ``mpl``, it is the number of (visual) layers before folding.
170
            Default is 25.
171
        ax: Only used by the `mpl` backend. An optional ``matplotlib.axes.Axes``
172
            object to be used for the visualization output. If none is
173
            specified, a new matplotlib Figure will be created and used.
174
            Additionally, if specified there will be no returned Figure since
175
            it is redundant.
176
        initial_state: Adds :math:`|0\rangle` in the beginning of the qubit wires and
177
            :math:`0` to classical wires. Default is ``False``.
178
        cregbundle: If set to ``True``, bundle classical registers.
179
            Default is ``True``, except for when ``output`` is set to  ``"text"``.
180
        wire_order: A list of integers used to reorder the display
181
            of the bits. The list must have an entry for every bit with the bits
182
            in the range 0 to (``num_qubits`` + ``num_clbits``).
183
        expr_len: The number of characters to display if an :class:`~.expr.Expr`
184
            is used for the condition in a :class:`.ControlFlowOp`. If this number is exceeded,
185
            the string will be truncated at that number and '...' added to the end.
186
        measure_arrows: If True, draw an arrow from each measure box down to the classical bit
187
            or register where the measure value is placed. If False, do not draw arrow, but
188
            instead place the name of the bit or register in the measure box.
189
            Default is ``True`` unless the user config file (usually ``~/.qiskit/settings.conf``)
190
            has an alternative value set. For example, ``circuit_measure_arrows = False``.
191
        barrier_label_len: The number of characters to display for
192
            :class:`.Barrier` labels in the output circuit. If this number is exceeded,
193
            the string will be truncated at that number and '...' added to the end.
194

195
    Returns:
196
        :class:`.TextDrawing` or :class:`matplotlib.figure` or :class:`PIL.Image` or
197
        :class:`str`:
198

199
        * ``TextDrawing`` (if ``output='text'``)
200
            A drawing that can be printed as ascii art.
201
        * ``matplotlib.figure.Figure`` (if ``output='mpl'``)
202
            A matplotlib figure object for the circuit diagram.
203
        * ``PIL.Image`` (if ``output='latex``')
204
            An in-memory representation of the image of the circuit diagram.
205
        * ``str`` (if ``output='latex_source'``)
206
            The LaTeX source code for visualizing the circuit diagram.
207

208
    Raises:
209
        VisualizationError: when an invalid output method is selected
210
        ImportError: when the output methods requires non-installed libraries.
211

212
    Example:
213
        .. plot::
214
            :alt: Circuit diagram output by the previous code.
215
            :include-source:
216

217
            from qiskit import QuantumCircuit
218
            from qiskit.visualization import circuit_drawer
219
            qc = QuantumCircuit(1, 1)
220
            qc.h(0)
221
            qc.measure(0, 0)
222
            circuit_drawer(qc, output="mpl", style={"backgroundcolor": "#EEEEEE"})
223
    """
224
    image = None
1✔
225
    expr_len = max(expr_len, 0)
1✔
226
    barrier_label_len = max(barrier_label_len, 0)
1✔
227
    config = user_config.get_config()
1✔
228
    # Get default from config file else use text
229
    default_output = "text"
1✔
230
    default_reverse_bits = False
1✔
231
    default_idle_wires = config.get("circuit_idle_wires", "auto")
1✔
232
    default_measure_arrows = config.get("circuit_measure_arrows", True)
1✔
233
    if config:
1✔
234
        default_output = config.get("circuit_drawer", "text")
1✔
235
        if default_output == "auto":
1✔
236
            if _optionals.HAS_MATPLOTLIB:
1✔
237
                default_output = "mpl"
1✔
238
            else:
239
                default_output = "text"
1✔
240
        if wire_order is None:
1✔
241
            default_reverse_bits = config.get("circuit_reverse_bits", False)
1✔
242
    if output is None:
1✔
243
        output = default_output
1✔
244

245
    if reverse_bits is None:
1✔
246
        reverse_bits = default_reverse_bits
1✔
247

248
    if idle_wires is None:
1✔
249
        idle_wires = default_idle_wires
1✔
250
    if isinstance(idle_wires, str):
1✔
251
        if idle_wires == "auto":
1✔
252
            idle_wires = hasattr(circuit, "_layout") and circuit._layout is None
1✔
253
        else:
UNCOV
254
            raise VisualizationError(f"Parameter idle_wires={idle_wires} unrecognized.")
×
255

256
    if measure_arrows is None:
1✔
257
        measure_arrows = default_measure_arrows
1✔
258

259
    if wire_order is not None and reverse_bits:
1✔
260
        raise VisualizationError(
1✔
261
            "The wire_order option cannot be set when the reverse_bits option is True."
262
        )
263

264
    complete_wire_order = wire_order
1✔
265
    if wire_order is not None:
1✔
266
        wire_order_len = len(wire_order)
1✔
267
        total_wire_len = circuit.num_qubits + circuit.num_clbits
1✔
268
        if wire_order_len not in [circuit.num_qubits, total_wire_len]:
1✔
UNCOV
269
            raise VisualizationError(
×
270
                f"The wire_order list (length {wire_order_len}) should as long as "
271
                f"the number of qubits ({circuit.num_qubits}) or the "
272
                f"total numbers of qubits and classical bits {total_wire_len}."
273
            )
274

275
        if len(set(wire_order)) != len(wire_order):
1✔
276
            raise VisualizationError("The wire_order list should not have repeated elements.")
1✔
277

278
        if wire_order_len == circuit.num_qubits:
1✔
279
            complete_wire_order = wire_order + list(range(circuit.num_qubits, total_wire_len))
1✔
280

281
    if (
1✔
282
        circuit.clbits
283
        and (reverse_bits or wire_order is not None)
284
        and not set(wire_order or []).issubset(set(range(circuit.num_qubits)))
285
    ):
286
        if cregbundle:
1✔
287
            warn(
1✔
288
                "cregbundle set to False since either reverse_bits or wire_order "
289
                "(over classical bit) has been set.",
290
                RuntimeWarning,
291
                2,
292
            )
293
        cregbundle = False
1✔
294

295
    def check_clbit_in_inst(circuit, cregbundle):
1✔
296
        if cregbundle is False:
1✔
297
            return False
1✔
298
        for inst in circuit.data:
1✔
299
            if isinstance(inst.operation, ControlFlowOp):
1✔
300
                for block in inst.operation.blocks:
1✔
301
                    if check_clbit_in_inst(block, cregbundle) is False:
1✔
UNCOV
302
                        return False
×
303
            elif inst.clbits and not isinstance(inst.operation, Measure):
1✔
304
                if cregbundle is not False:
1✔
305
                    warn(
1✔
306
                        "Cregbundle set to False since an instruction needs to refer"
307
                        " to individual classical wire",
308
                        RuntimeWarning,
309
                        3,
310
                    )
311
                return False
1✔
312

313
        return True
1✔
314

315
    cregbundle = check_clbit_in_inst(circuit, cregbundle)
1✔
316

317
    if output == "text":
1✔
318
        return _text_circuit_drawer(
1✔
319
            circuit,
320
            filename=filename,
321
            reverse_bits=reverse_bits,
322
            plot_barriers=plot_barriers,
323
            justify=justify,
324
            vertical_compression=vertical_compression,
325
            idle_wires=idle_wires,
326
            with_layout=with_layout,
327
            fold=fold,
328
            initial_state=initial_state,
329
            cregbundle=cregbundle,
330
            wire_order=complete_wire_order,
331
            expr_len=expr_len,
332
            barrier_label_len=barrier_label_len,
333
            measure_arrows=measure_arrows,
334
        )
335
    elif output == "latex":
1✔
UNCOV
336
        image = _latex_circuit_drawer(
×
337
            circuit,
338
            filename=filename,
339
            scale=scale,
340
            style=style,
341
            plot_barriers=plot_barriers,
342
            reverse_bits=reverse_bits,
343
            justify=justify,
344
            idle_wires=idle_wires,
345
            with_layout=with_layout,
346
            initial_state=initial_state,
347
            cregbundle=cregbundle,
348
            wire_order=complete_wire_order,
349
            barrier_label_len=barrier_label_len,
350
        )
351
    elif output == "latex_source":
1✔
352
        return _generate_latex_source(
1✔
353
            circuit,
354
            filename=filename,
355
            scale=scale,
356
            style=style,
357
            plot_barriers=plot_barriers,
358
            reverse_bits=reverse_bits,
359
            justify=justify,
360
            idle_wires=idle_wires,
361
            with_layout=with_layout,
362
            initial_state=initial_state,
363
            cregbundle=cregbundle,
364
            wire_order=complete_wire_order,
365
            barrier_label_len=barrier_label_len,
366
        )
367
    elif output == "mpl":
1✔
368
        image = _matplotlib_circuit_drawer(
1✔
369
            circuit,
370
            scale=scale,
371
            filename=filename,
372
            style=style,
373
            plot_barriers=plot_barriers,
374
            reverse_bits=reverse_bits,
375
            justify=justify,
376
            idle_wires=idle_wires,
377
            with_layout=with_layout,
378
            fold=fold,
379
            ax=ax,
380
            initial_state=initial_state,
381
            cregbundle=cregbundle,
382
            wire_order=complete_wire_order,
383
            expr_len=expr_len,
384
            measure_arrows=measure_arrows,
385
        )
386
    else:
UNCOV
387
        raise VisualizationError(
×
388
            f"Invalid output type {output} selected. The only valid choices "
389
            "are text, latex, latex_source, and mpl"
390
        )
391
    if image and interactive:
1✔
UNCOV
392
        image.show()
×
393
    return image
1✔
394

395

396
# -----------------------------------------------------------------------------
397
# _text_circuit_drawer
398
# -----------------------------------------------------------------------------
399

400

401
def _text_circuit_drawer(
1✔
402
    circuit,
403
    filename=None,
404
    reverse_bits=False,
405
    plot_barriers=True,
406
    justify=None,
407
    vertical_compression="high",
408
    idle_wires=True,
409
    with_layout=True,
410
    fold=None,
411
    initial_state=True,
412
    cregbundle=None,
413
    encoding=None,
414
    wire_order=None,
415
    expr_len=30,
416
    measure_arrows=True,
417
    barrier_label_len=16,
418
):
419
    """Draws a circuit using ascii art.
420

421
    Args:
422
        circuit (QuantumCircuit): Input circuit
423
        filename (str): Optional filename to write the result
424
        reverse_bits (bool): Rearrange the bits in reverse order.
425
        plot_barriers (bool): Draws the barriers when they are there.
426
        justify (str) : `left`, `right` or `none`. Defaults to `left`. Says how
427
            the circuit should be justified.
428
        vertical_compression (string): `high`, `medium`, or `low`. It merges the
429
            lines so the drawing will take less vertical room. Default is `high`.
430
        idle_wires (bool): Include idle wires. Default is True.
431
        with_layout (bool): Include layout information with labels on the physical
432
            layout. Default: True
433
        fold (int): Optional. Breaks the circuit drawing to this length. This
434
            is useful when the drawing does not fit in the console. If
435
            None (default), it will try to guess the console width using
436
            `shutil.get_terminal_size()`. If you don't want pagination
437
            at all, set `fold=-1`.
438
        initial_state (bool): Optional. Adds |0> in the beginning of the line.
439
            Default: `False`.
440
        cregbundle (bool): Optional. If set True, bundle classical registers.
441
            Default: ``True``.
442
        encoding (str): Optional. Sets the encoding preference of the output.
443
            Default: ``sys.stdout.encoding``.
444
        wire_order (list): Optional. A list of integers used to reorder the display
445
            of the bits. The list must have an entry for every bit with the bits
446
            in the range 0 to (num_qubits + num_clbits).
447
        expr_len (int): Optional. The number of characters to display if an :class:`~.expr.Expr`
448
            is used for the condition in a :class:`.ControlFlowOp`. If this number is exceeded,
449
            the string will be truncated at that number and '...' added to the end.
450
        measure_arrows: If True, draw an arrow from each measure box down to the classical bit
451
            or register where the measure value is placed. If False, do not draw arrow, but
452
            instead place the name of the bit or register in the measure box.
453
        barrier_label_len (int): Optional. The number of characters to display for
454
            :class:`.Barrier` labels. If this number is exceeded, the string will be truncated.
455

456
    Returns:
457
        TextDrawing: An instance that, when printed, draws the circuit in ascii art.
458

459
    Raises:
460
        VisualizationError: When the filename extension is not .txt.
461
    """
462
    qubits, clbits, nodes = _utils._get_layered_instructions(
1✔
463
        circuit,
464
        reverse_bits=reverse_bits,
465
        justify=justify,
466
        idle_wires=idle_wires,
467
        wire_order=wire_order,
468
        measure_arrows=measure_arrows,
469
    )
470
    text_drawing = _text.TextDrawing(
1✔
471
        qubits,
472
        clbits,
473
        nodes,
474
        circuit,
475
        reverse_bits=reverse_bits,
476
        initial_state=initial_state,
477
        cregbundle=cregbundle,
478
        encoding=encoding,
479
        with_layout=with_layout,
480
        expr_len=expr_len,
481
        barrier_label_len=barrier_label_len,
482
        measure_arrows=measure_arrows,
483
    )
484
    text_drawing.plotbarriers = plot_barriers
1✔
485
    text_drawing.line_length = fold
1✔
486
    text_drawing.vertical_compression = vertical_compression
1✔
487

488
    if filename:
1✔
489
        text_drawing.dump(filename, encoding=encoding)
1✔
490
    return text_drawing
1✔
491

492

493
# -----------------------------------------------------------------------------
494
# latex_circuit_drawer
495
# -----------------------------------------------------------------------------
496

497

498
@_optionals.HAS_PDFLATEX.require_in_call("LaTeX circuit drawing")
1✔
499
@_optionals.HAS_PDFTOCAIRO.require_in_call("LaTeX circuit drawing")
1✔
500
@_optionals.HAS_PIL.require_in_call("LaTeX circuit drawing")
1✔
501
def _latex_circuit_drawer(
1✔
502
    circuit,
503
    scale=0.7,
504
    style=None,
505
    filename=None,
506
    plot_barriers=True,
507
    reverse_bits=False,
508
    justify=None,
509
    idle_wires=True,
510
    with_layout=True,
511
    initial_state=False,
512
    cregbundle=None,
513
    wire_order=None,
514
    barrier_label_len=16,
515
):
516
    """Draw a quantum circuit based on latex (Qcircuit package)
517

518
    Requires version >=2.6.0 of the qcircuit LaTeX package.
519

520
    Args:
521
        circuit (QuantumCircuit): a quantum circuit
522
        scale (float): scaling factor
523
        style (dict or str): dictionary of style or file name of style file
524
        filename (str): file path to save image to
525
        reverse_bits (bool): When set to True reverse the bit order inside
526
            registers for the output visualization.
527
        plot_barriers (bool): Enable/disable drawing barriers in the output
528
            circuit. Defaults to True.
529
        justify (str) : `left`, `right` or `none`. Defaults to `left`. Says how
530
            the circuit should be justified.
531
        idle_wires (bool): Include idle wires. Default is True.
532
        with_layout (bool): Include layout information, with labels on the physical
533
            layout. Default: True
534
        initial_state (bool): Optional. Adds |0> in the beginning of the line.
535
            Default: `False`.
536
        cregbundle (bool): Optional. If set True, bundle classical registers.  On by default, if
537
            this is possible for the given circuit, otherwise off.
538
        wire_order (list): Optional. A list of integers used to reorder the display
539
            of the bits. The list must have an entry for every bit with the bits
540
            in the range 0 to (num_qubits + num_clbits).
541
        barrier_label_len (int): Optional. The number of characters to display for
542
            :class:`.Barrier` labels. If this number is exceeded, the string will be truncated.
543

544
    Returns:
545
        PIL.Image: an in-memory representation of the circuit diagram
546

547
    Raises:
548
        MissingOptionalLibraryError: if pillow, pdflatex, or poppler are not installed
549
        VisualizationError: if one of the conversion utilities failed for some internal or
550
            file-access reason.
551
    """
UNCOV
552
    from PIL import Image
×
553

UNCOV
554
    tmpfilename = "circuit"
×
UNCOV
555
    with tempfile.TemporaryDirectory() as tmpdirname:
×
UNCOV
556
        tmppath = os.path.join(tmpdirname, tmpfilename + ".tex")
×
557
        _generate_latex_source(
×
558
            circuit,
559
            filename=tmppath,
560
            scale=scale,
561
            style=style,
562
            plot_barriers=plot_barriers,
563
            reverse_bits=reverse_bits,
564
            justify=justify,
565
            idle_wires=idle_wires,
566
            with_layout=with_layout,
567
            initial_state=initial_state,
568
            cregbundle=cregbundle,
569
            wire_order=wire_order,
570
            barrier_label_len=barrier_label_len,
571
        )
572

573
        try:
×
574
            subprocess.run(
×
575
                [
576
                    "pdflatex",
577
                    "-halt-on-error",
578
                    f"-output-directory={tmpdirname}",
579
                    f"{tmpfilename + '.tex'}",
580
                ],
581
                stdout=subprocess.PIPE,
582
                stderr=subprocess.DEVNULL,
583
                check=True,
584
            )
585
        except OSError as exc:
×
586
            # OSError should generally not occur, because it's usually only triggered if `pdflatex`
587
            # doesn't exist as a command, but we've already checked that.
UNCOV
588
            raise VisualizationError("`pdflatex` command could not be run.") from exc
×
589
        except subprocess.CalledProcessError as exc:
×
590
            with open("latex_error.log", "wb") as error_file:
×
591
                error_file.write(exc.stdout)
×
592
            logger.warning(
×
593
                "Unable to compile LaTeX. Perhaps you are missing the `qcircuit` package."
594
                " The output from the `pdflatex` command is in `latex_error.log`."
595
            )
596
            raise VisualizationError(
×
597
                "`pdflatex` call did not succeed: see `latex_error.log`."
598
            ) from exc
599
        base = os.path.join(tmpdirname, tmpfilename)
×
600
        try:
×
601
            subprocess.run(
×
602
                ["pdftocairo", "-singlefile", "-png", "-q", base + ".pdf", base],
603
                check=True,
604
            )
605
        except (OSError, subprocess.CalledProcessError) as exc:
×
UNCOV
606
            message = "`pdftocairo` failed to produce an image."
×
UNCOV
607
            logger.warning(message)
×
UNCOV
608
            raise VisualizationError(message) from exc
×
UNCOV
609
        image = Image.open(base + ".png")
×
UNCOV
610
        image = trim_image(image)
×
UNCOV
611
        if filename:
×
UNCOV
612
            if filename.endswith(".pdf"):
×
UNCOV
613
                shutil.move(base + ".pdf", filename)
×
614
            else:
UNCOV
615
                try:
×
UNCOV
616
                    image.save(filename)
×
UNCOV
617
                except (ValueError, OSError) as exc:
×
UNCOV
618
                    raise VisualizationError(
×
619
                        f"Pillow could not write the image file '{filename}'."
620
                    ) from exc
UNCOV
621
        return image
×
622

623

624
def _generate_latex_source(
1✔
625
    circuit,
626
    filename=None,
627
    scale=0.7,
628
    style=None,
629
    reverse_bits=False,
630
    plot_barriers=True,
631
    justify=None,
632
    idle_wires=True,
633
    with_layout=True,
634
    initial_state=False,
635
    cregbundle=None,
636
    wire_order=None,
637
    barrier_label_len=16,
638
):
639
    """Convert QuantumCircuit to LaTeX string.
640

641
    Args:
642
        circuit (QuantumCircuit): a quantum circuit
643
        scale (float): scaling factor
644
        style (dict or str): dictionary of style or file name of style file
645
        filename (str): optional filename to write latex
646
        reverse_bits (bool): When set to True reverse the bit order inside
647
            registers for the output visualization.
648
        plot_barriers (bool): Enable/disable drawing barriers in the output
649
            circuit. Defaults to True.
650
        justify (str) : `left`, `right` or `none`. Defaults to `left`. Says how
651
            the circuit should be justified.
652
        idle_wires (bool): Include idle wires. Default is True.
653
        with_layout (bool): Include layout information, with labels on the physical
654
            layout. Default: True
655
        initial_state (bool): Optional. Adds |0> in the beginning of the line.
656
            Default: `False`.
657
        cregbundle (bool): Optional. If set True, bundle classical registers.
658
        wire_order (list): Optional. A list of integers used to reorder the display
659
            of the bits. The list must have an entry for every bit with the bits
660
            in the range 0 to (num_qubits + num_clbits).
661
        barrier_label_len (int): Optional. The number of characters to display for
662
            :class:`.Barrier` labels. If this number is exceeded, the string will be truncated.
663

664
    Returns:
665
        str: Latex string appropriate for writing to file.
666
    """
667
    qubits, clbits, nodes = _utils._get_layered_instructions(
1✔
668
        circuit,
669
        reverse_bits=reverse_bits,
670
        justify=justify,
671
        idle_wires=idle_wires,
672
        wire_order=wire_order,
673
    )
674
    qcimg = _latex.QCircuitImage(
1✔
675
        qubits,
676
        clbits,
677
        nodes,
678
        scale,
679
        style=style,
680
        reverse_bits=reverse_bits,
681
        plot_barriers=plot_barriers,
682
        initial_state=initial_state,
683
        cregbundle=cregbundle,
684
        with_layout=with_layout,
685
        circuit=circuit,
686
        barrier_label_len=barrier_label_len,
687
    )
688
    latex = qcimg.latex()
1✔
689
    if filename:
1✔
690
        with open(filename, "w") as latex_file:
1✔
691
            latex_file.write(latex)
1✔
692

693
    return latex
1✔
694

695

696
# -----------------------------------------------------------------------------
697
# matplotlib_circuit_drawer
698
# -----------------------------------------------------------------------------
699

700

701
def _matplotlib_circuit_drawer(
1✔
702
    circuit,
703
    scale=None,
704
    filename=None,
705
    style=None,
706
    plot_barriers=True,
707
    reverse_bits=False,
708
    justify=None,
709
    idle_wires=True,
710
    with_layout=True,
711
    fold=None,
712
    ax=None,
713
    initial_state=False,
714
    cregbundle=None,
715
    wire_order=None,
716
    expr_len=30,
717
    measure_arrows=None,
718
    barrier_label_len=16,
719
):
720
    """Draw a quantum circuit based on matplotlib.
721
    If `%matplotlib inline` is invoked in a Jupyter notebook, it visualizes a circuit inline.
722
    We recommend `%config InlineBackend.figure_format = 'svg'` for the inline visualization.
723

724
    Args:
725
        circuit (QuantumCircuit): a quantum circuit
726
        scale (float): scaling factor
727
        filename (str): file path to save image to
728
        style (dict or str): dictionary of style or file name of style file
729
        reverse_bits (bool): When set to True, reverse the bit order inside
730
            registers for the output visualization.
731
        plot_barriers (bool): Enable/disable drawing barriers in the output
732
            circuit. Defaults to True.
733
        justify (str): `left`, `right` or `none`. Defaults to `left`. Says how
734
            the circuit should be justified.
735
        idle_wires (bool): Include idle wires. Default is True.
736
        with_layout (bool): Include layout information, with labels on the physical
737
            layout. Default: True.
738
        fold (int): Number of vertical layers allowed before folding. Default is 25.
739
        ax (matplotlib.axes.Axes): An optional Axes object to be used for
740
            the visualization output. If none is specified, a new matplotlib
741
            Figure will be created and used. Additionally, if specified there
742
            will be no returned Figure since it is redundant.
743
        initial_state (bool): Optional. Adds |0> in the beginning of the line.
744
            Default: `False`.
745
        cregbundle (bool): Optional. If set True bundle classical registers.
746
            Default: ``True``.
747
        wire_order (list): Optional. A list of integers used to reorder the display
748
            of the bits. The list must have an entry for every bit with the bits
749
            in the range 0 to (num_qubits + num_clbits).
750
        expr_len (int): Optional. The number of characters to display if an :class:`~.expr.Expr`
751
            is used for the condition in a :class:`.ControlFlowOp`. If this number is exceeded,
752
            the string will be truncated at that number and '...' added to the end.
753
        measure_arrows: If True, draw an arrow from each measure box down to the classical bit
754
            or register where the measure value is placed. If False, do not draw arrow, but
755
            instead place the name of the bit or register in the measure box.
756
        barrier_label_len (int): Optional. The number of characters to display for
757
            :class:`.Barrier` labels. If this number is exceeded, the string will be truncated.
758

759
    Returns:
760
        matplotlib.figure: a matplotlib figure object for the circuit diagram
761
            if the ``ax`` kwarg is not set.
762
    """
763

764
    qubits, clbits, nodes = _utils._get_layered_instructions(
1✔
765
        circuit,
766
        reverse_bits=reverse_bits,
767
        justify=justify,
768
        idle_wires=idle_wires,
769
        wire_order=wire_order,
770
        measure_arrows=measure_arrows,
771
    )
772
    if fold is None:
1✔
773
        fold = 25
1✔
774

775
    qcd = _matplotlib.MatplotlibDrawer(
1✔
776
        qubits,
777
        clbits,
778
        nodes,
779
        circuit,
780
        scale=scale,
781
        style=style,
782
        reverse_bits=reverse_bits,
783
        plot_barriers=plot_barriers,
784
        fold=fold,
785
        ax=ax,
786
        initial_state=initial_state,
787
        cregbundle=cregbundle,
788
        with_layout=with_layout,
789
        expr_len=expr_len,
790
        barrier_label_len=barrier_label_len,
791
        measure_arrows=measure_arrows,
792
    )
793
    return qcd.draw(filename)
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc