Skip to content

Commit 14ec7d3

Browse files
ihincksjakelishman
andauthored
Add barrier_label_len option to circuit drawers (#15776)
* Add barrier_label_len option to circuit drawers * Switch to default value of 16 * consistency * add comment * move barrier_label_len to end * add mpl test * add ref fig * Fix comment on LaTeX spaces --------- Co-authored-by: Jake Lishman <jake@binhbar.com>
1 parent 75002e3 commit 14ec7d3

11 files changed

Lines changed: 133 additions & 2 deletions

File tree

qiskit/circuit/quantumcircuit.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3892,6 +3892,7 @@ def draw(
38923892
wire_order: list[int] | None = None,
38933893
expr_len: int = 30,
38943894
measure_arrows: bool | None = None,
3895+
barrier_label_len: int = 16,
38953896
):
38963897
r"""Draw the quantum circuit. Use the output parameter to choose the drawing format:
38973898
@@ -4003,6 +4004,9 @@ def draw(
40034004
instead place the name of the bit or register in the measure box.
40044005
Default is ``True`` unless the user config file (usually ``~/.qiskit/settings.conf``)
40054006
has an alternative value set. For example, ``circuit_measure_arrows = False``.
4007+
barrier_label_len: The number of characters to display for
4008+
:class:`.Barrier` labels in the output circuit. If this number is exceeded,
4009+
the string will be truncated at that number and '...' added to the end.
40064010
40074011
Returns:
40084012
:class:`.TextDrawing` or :class:`matplotlib.figure` or :class:`PIL.Image` or
@@ -4054,6 +4058,7 @@ def draw(
40544058
cregbundle=cregbundle,
40554059
wire_order=wire_order,
40564060
expr_len=expr_len,
4061+
barrier_label_len=barrier_label_len,
40574062
measure_arrows=measure_arrows,
40584063
)
40594064

qiskit/visualization/circuit/circuit_visualization.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ def circuit_drawer(
7575
wire_order: list[int] | None = None,
7676
expr_len: int = 30,
7777
measure_arrows: bool | None = None,
78+
barrier_label_len: int = 16,
7879
):
7980
r"""Draw the quantum circuit. Use the output parameter to choose the drawing format:
8081
@@ -187,6 +188,9 @@ def circuit_drawer(
187188
instead place the name of the bit or register in the measure box.
188189
Default is ``True`` unless the user config file (usually ``~/.qiskit/settings.conf``)
189190
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.
190194
191195
Returns:
192196
:class:`.TextDrawing` or :class:`matplotlib.figure` or :class:`PIL.Image` or
@@ -219,6 +223,7 @@ def circuit_drawer(
219223
"""
220224
image = None
221225
expr_len = max(expr_len, 0)
226+
barrier_label_len = max(barrier_label_len, 0)
222227
config = user_config.get_config()
223228
# Get default from config file else use text
224229
default_output = "text"
@@ -324,6 +329,7 @@ def check_clbit_in_inst(circuit, cregbundle):
324329
cregbundle=cregbundle,
325330
wire_order=complete_wire_order,
326331
expr_len=expr_len,
332+
barrier_label_len=barrier_label_len,
327333
measure_arrows=measure_arrows,
328334
)
329335
elif output == "latex":
@@ -340,6 +346,7 @@ def check_clbit_in_inst(circuit, cregbundle):
340346
initial_state=initial_state,
341347
cregbundle=cregbundle,
342348
wire_order=complete_wire_order,
349+
barrier_label_len=barrier_label_len,
343350
)
344351
elif output == "latex_source":
345352
return _generate_latex_source(
@@ -355,6 +362,7 @@ def check_clbit_in_inst(circuit, cregbundle):
355362
initial_state=initial_state,
356363
cregbundle=cregbundle,
357364
wire_order=complete_wire_order,
365+
barrier_label_len=barrier_label_len,
358366
)
359367
elif output == "mpl":
360368
image = _matplotlib_circuit_drawer(
@@ -406,6 +414,7 @@ def _text_circuit_drawer(
406414
wire_order=None,
407415
expr_len=30,
408416
measure_arrows=True,
417+
barrier_label_len=16,
409418
):
410419
"""Draws a circuit using ascii art.
411420
@@ -441,6 +450,8 @@ def _text_circuit_drawer(
441450
measure_arrows: If True, draw an arrow from each measure box down to the classical bit
442451
or register where the measure value is placed. If False, do not draw arrow, but
443452
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.
444455
445456
Returns:
446457
TextDrawing: An instance that, when printed, draws the circuit in ascii art.
@@ -467,6 +478,7 @@ def _text_circuit_drawer(
467478
encoding=encoding,
468479
with_layout=with_layout,
469480
expr_len=expr_len,
481+
barrier_label_len=barrier_label_len,
470482
measure_arrows=measure_arrows,
471483
)
472484
text_drawing.plotbarriers = plot_barriers
@@ -499,6 +511,7 @@ def _latex_circuit_drawer(
499511
initial_state=False,
500512
cregbundle=None,
501513
wire_order=None,
514+
barrier_label_len=16,
502515
):
503516
"""Draw a quantum circuit based on latex (Qcircuit package)
504517
@@ -525,6 +538,8 @@ def _latex_circuit_drawer(
525538
wire_order (list): Optional. A list of integers used to reorder the display
526539
of the bits. The list must have an entry for every bit with the bits
527540
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.
528543
529544
Returns:
530545
PIL.Image: an in-memory representation of the circuit diagram
@@ -552,6 +567,7 @@ def _latex_circuit_drawer(
552567
initial_state=initial_state,
553568
cregbundle=cregbundle,
554569
wire_order=wire_order,
570+
barrier_label_len=barrier_label_len,
555571
)
556572

557573
try:
@@ -618,6 +634,7 @@ def _generate_latex_source(
618634
initial_state=False,
619635
cregbundle=None,
620636
wire_order=None,
637+
barrier_label_len=16,
621638
):
622639
"""Convert QuantumCircuit to LaTeX string.
623640
@@ -641,6 +658,8 @@ def _generate_latex_source(
641658
wire_order (list): Optional. A list of integers used to reorder the display
642659
of the bits. The list must have an entry for every bit with the bits
643660
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.
644663
645664
Returns:
646665
str: Latex string appropriate for writing to file.
@@ -664,6 +683,7 @@ def _generate_latex_source(
664683
cregbundle=cregbundle,
665684
with_layout=with_layout,
666685
circuit=circuit,
686+
barrier_label_len=barrier_label_len,
667687
)
668688
latex = qcimg.latex()
669689
if filename:
@@ -695,6 +715,7 @@ def _matplotlib_circuit_drawer(
695715
wire_order=None,
696716
expr_len=30,
697717
measure_arrows=None,
718+
barrier_label_len=16,
698719
):
699720
"""Draw a quantum circuit based on matplotlib.
700721
If `%matplotlib inline` is invoked in a Jupyter notebook, it visualizes a circuit inline.
@@ -732,6 +753,8 @@ def _matplotlib_circuit_drawer(
732753
measure_arrows: If True, draw an arrow from each measure box down to the classical bit
733754
or register where the measure value is placed. If False, do not draw arrow, but
734755
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.
735758
736759
Returns:
737760
matplotlib.figure: a matplotlib figure object for the circuit diagram
@@ -764,6 +787,7 @@ def _matplotlib_circuit_drawer(
764787
cregbundle=cregbundle,
765788
with_layout=with_layout,
766789
expr_len=expr_len,
790+
barrier_label_len=barrier_label_len,
767791
measure_arrows=measure_arrows,
768792
)
769793
return qcd.draw(filename)

qiskit/visualization/circuit/latex.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ def __init__(
6363
cregbundle=None,
6464
with_layout=False,
6565
circuit=None,
66+
barrier_label_len=16,
6667
):
6768
"""QCircuitImage initializer.
6869
@@ -78,13 +79,16 @@ def __init__(
7879
initial_state (bool): Optional. Adds |0> in the beginning of the line. Default: `False`.
7980
cregbundle (bool): Optional. If set True bundle classical registers.
8081
circuit (QuantumCircuit): the circuit that's being displayed
82+
barrier_label_len (int): Optional. The number of characters to display for
83+
barrier labels. If this number is exceeded, the string will be truncated.
8184
Raises:
8285
ImportError: If pylatexenc is not installed
8386
"""
8487

8588
self._circuit = circuit
8689
self._qubits = qubits
8790
self._clbits = clbits
91+
self._barrier_label_len = barrier_label_len
8892

8993
# list of lists corresponding to layers of the circuit
9094
self._nodes = nodes
@@ -575,7 +579,10 @@ def _build_barrier(self, node, col):
575579
self._latex[pos][col - 1] += " \\barrier[0em]{" + str(last - first) + "}"
576580
if node.op.label is not None:
577581
pos = indexes[0]
578-
label = node.op.label.replace(" ", "\\,")
582+
label = node.op.label
583+
if len(label) > self._barrier_label_len:
584+
label = label[: self._barrier_label_len] + "..."
585+
label = label.replace(" ", "\\,") # \, is a LaTeX thin space
579586
self._latex[pos][col] = f"\\cds{{0}}{{^{{\\mathrm{{{label}}}}}}}"
580587

581588
def _add_controls(self, wire_list, ctrlqargs, ctrl_state, col):

qiskit/visualization/circuit/matplotlib.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ def __init__(
110110
with_layout=False,
111111
expr_len=30,
112112
measure_arrows=None,
113+
barrier_label_len=16,
113114
):
114115
self._circuit = circuit
115116
self._qubits = qubits
@@ -138,6 +139,7 @@ def __init__(
138139
self._initial_state = initial_state
139140
self._global_phase = self._circuit.global_phase
140141
self._expr_len = expr_len
142+
self._barrier_label_len = barrier_label_len
141143
self._cregbundle = cregbundle
142144
self._measure_arrows = measure_arrows
143145

@@ -1437,11 +1439,14 @@ def _barrier(self, node, node_data, glob_data):
14371439

14381440
# display the barrier label at the top if there is one
14391441
if i == 0 and node.op.label is not None:
1442+
label = node.op.label
1443+
if len(label) > self._barrier_label_len:
1444+
label = label[: self._barrier_label_len] + "..."
14401445
dir_ypos = ypos + 0.65 * HIG
14411446
self._ax.text(
14421447
xpos,
14431448
dir_ypos,
1444-
node.op.label,
1449+
label,
14451450
ha="center",
14461451
va="top",
14471452
fontsize=self._style["fs"],

qiskit/visualization/circuit/text.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -713,6 +713,7 @@ def __init__(
713713
with_layout=False,
714714
expr_len=30,
715715
measure_arrows=None,
716+
barrier_label_len=16,
716717
):
717718
self.qubits = qubits
718719
self.clbits = clbits
@@ -732,6 +733,7 @@ def __init__(
732733
self.reverse_bits = reverse_bits
733734
self.line_length = line_length
734735
self.expr_len = expr_len
736+
self.barrier_label_len = barrier_label_len
735737
self.measure_arrows = measure_arrows
736738
if vertical_compression not in ["high", "medium", "low"]:
737739
raise ValueError("Vertical compression can only be 'high', 'medium', or 'low'")
@@ -1164,6 +1166,8 @@ def add_connected_gate(node, gates, layer, current_cons, gate_wire_map):
11641166
for qubit in node.qargs:
11651167
if qubit in self.qubits:
11661168
label = op.label if qubit == top_qubit else ""
1169+
if label and len(label) > self.barrier_label_len:
1170+
label = label[: self.barrier_label_len] + "..."
11671171
layer.set_qubit(qubit, Barrier(label))
11681172

11691173
elif isinstance(op, SwapGate):
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
features_visualization:
3+
- |
4+
Added a new ``barrier_label_len`` parameter (default 16) to
5+
:meth:`.QuantumCircuit.draw` and :func:`.circuit_drawer`. When a
6+
:class:`.Barrier` label exceeds this length, it is truncated and ``"..."``
7+
is appended. This prevents very long barrier labels from making circuit
8+
diagrams unreadable. The parameter is supported by all three drawer
9+
backends (text, mpl, latex).

test/python/visualization/references/test_latex_barrier_label_truncation.tex

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/python/visualization/test_circuit_latex.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,17 @@ def test_barrier_label(self):
228228

229229
self.assertEqualToReference(filename)
230230

231+
def test_barrier_label_truncation(self):
232+
"""Test that long barrier labels are truncated"""
233+
filename = self._get_resource_path("test_latex_barrier_label_truncation.tex")
234+
circuit = QuantumCircuit(2)
235+
circuit.barrier()
236+
circuit.barrier(label="a" * 20)
237+
238+
circuit_drawer(circuit, filename=filename, output="latex_source", barrier_label_len=9)
239+
240+
self.assertEqualToReference(filename)
241+
231242
def test_big_gates(self):
232243
"""Test large gates with params"""
233244
filename = self._get_resource_path("test_latex_big_gates.tex")

test/python/visualization/test_circuit_text_drawer.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1274,6 +1274,42 @@ def test_text_barrier_label(self):
12741274
circuit.barrier(label="End Y/X")
12751275
self.assertEqual(str(circuit_drawer(circuit, output="text", initial_state=True)), expected)
12761276

1277+
def test_text_barrier_label_truncation(self):
1278+
"""Barrier labels longer than barrier_label_len are truncated"""
1279+
expected_truncated = "\n".join(
1280+
[
1281+
" ░ aaaaaaaaa... ",
1282+
"q_0: ─░───────░───────",
1283+
" ░ ░ ",
1284+
"q_1: ─░───────░───────",
1285+
" ░ ░ ",
1286+
]
1287+
)
1288+
circuit = QuantumCircuit(2)
1289+
circuit.barrier()
1290+
circuit.barrier(label="a" * 20)
1291+
self.assertEqual(
1292+
str(circuit_drawer(circuit, output="text", barrier_label_len=9)), expected_truncated
1293+
)
1294+
1295+
def test_text_barrier_label_no_truncation(self):
1296+
"""Barrier labels shorter than barrier_label_len are unchanged"""
1297+
expected = "\n".join(
1298+
[
1299+
" ░ short ",
1300+
"q_0: ─░────░───",
1301+
" ░ ░ ",
1302+
"q_1: ─░────░───",
1303+
" ░ ░ ",
1304+
]
1305+
)
1306+
circuit = QuantumCircuit(2)
1307+
circuit.barrier()
1308+
circuit.barrier(label="short")
1309+
self.assertEqual(
1310+
str(circuit_drawer(circuit, output="text", barrier_label_len=30)), expected
1311+
)
1312+
12771313
def test_text_barrier_label_reversed_bits(self):
12781314
"""Show barrier label with reversed bits"""
12791315
expected = "\n".join(
8.83 KB
Loading

0 commit comments

Comments
 (0)