Skip to content

Commit

Permalink
"fold" option unified across circuit drawers (#3108)
Browse files Browse the repository at this point in the history
* test

* cast in insinstance

* style

* layouts are already layouts :)

* style['plotbarrier'] is being deprecated

* internal param for text drawer renamed to plot_barriers

* error when style contains unknown options

* better error message

* deprecated style option

* mp karg fold

* text fold

* lint

* docstring

* cregbundle text option

* Revert "cregbundle text option"

This reverts commit bba055f.

* revert 3100

* new pickles

* cleaning up the diff

* docstring

* pickles
  • Loading branch information
Luciano authored Oct 4, 2019
1 parent 7ac8f89 commit 00e434c
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 47 deletions.
12 changes: 9 additions & 3 deletions qiskit/circuit/quantumcircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -560,8 +560,8 @@ def qasm(self):

def draw(self, scale=0.7, filename=None, style=None, output=None,
interactive=False, line_length=None, plot_barriers=True,
reverse_bits=False, justify=None, vertical_compression='medium', idle_wires=True,
with_layout=True):
reverse_bits=False, justify=None, idle_wires=True, vertical_compression='medium',
with_layout=True, fold=None):
"""Draw the quantum circuit
Using the output parameter you can specify the format. The choices are:
Expand Down Expand Up @@ -604,6 +604,12 @@ def draw(self, scale=0.7, filename=None, style=None, output=None,
idle_wires (bool): Include idle wires. 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 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 amount of operations before folding. Default is 25.
Returns:
PIL.Image or matplotlib.figure or str or TextDrawing:
* PIL.Image: (output `latex`) an in-memory representation of the
Expand All @@ -629,7 +635,7 @@ def draw(self, scale=0.7, filename=None, style=None, output=None,
justify=justify,
vertical_compression=vertical_compression,
idle_wires=idle_wires,
with_layout=with_layout)
with_layout=with_layout, fold=fold)

def size(self):
"""Returns total number of gate operations in circuit.
Expand Down
54 changes: 33 additions & 21 deletions qiskit/visualization/circuit_visualization.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

# TODO: Remove after 0.7 and the deprecated methods are removed


"""
Two quantum circuit drawers based on:
Expand All @@ -27,6 +25,7 @@
import os
import subprocess
import tempfile
from warnings import warn

try:
from PIL import Image
Expand Down Expand Up @@ -56,7 +55,8 @@ def circuit_drawer(circuit,
justify=None,
vertical_compression='medium',
idle_wires=True,
with_layout=True):
with_layout=True,
fold=None):
"""Draw a quantum circuit to different formats (set by output parameter):
0. text: ASCII art TextDrawing that can be printed in the console.
1. latex: high-quality images, but heavy external software dependencies
Expand All @@ -81,12 +81,7 @@ def circuit_drawer(circuit,
supporting this). Note when used with either the `text` or the
`latex_source` output type this has no effect and will be silently
ignored.
line_length (int): Sets the length of the lines generated by `text`
output type. 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 you're running in
jupyter the default line length is set to 80 characters. If you
don't want pagination at all, set `line_length=-1`.
line_length (int): Deprecated. See `fold`.
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
Expand All @@ -102,6 +97,12 @@ def circuit_drawer(circuit,
idle_wires (bool): Include idle wires. Default is True.
with_layout (bool): Include layout information, with labels on the physical
layout.
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` is the amount of operations before folding. Default is 25.
Returns:
PIL.Image: (output `latex`) an in-memory representation of the image
of the circuit diagram.
Expand Down Expand Up @@ -229,7 +230,8 @@ def circuit_drawer(circuit,
justify=justify,
vertical_compression=vertical_compression,
idle_wires=idle_wires,
with_layout=with_layout)
with_layout=with_layout,
fold=fold)
elif output == 'latex':
image = _latex_circuit_drawer(circuit, scale=scale,
filename=filename, style=style,
Expand All @@ -254,7 +256,8 @@ def circuit_drawer(circuit,
reverse_bits=reverse_bits,
justify=justify,
idle_wires=idle_wires,
with_layout=with_layout)
with_layout=with_layout,
fold=fold)
else:
raise exceptions.VisualizationError(
'Invalid output type %s selected. The only valid choices '
Expand Down Expand Up @@ -342,17 +345,13 @@ def qx_color_scheme():

def _text_circuit_drawer(circuit, filename=None, line_length=None, reverse_bits=False,
plot_barriers=True, justify=None, vertical_compression='high',
idle_wires=True, with_layout=True):
idle_wires=True, with_layout=True, fold=None,):
"""
Draws a circuit using ascii art.
Args:
circuit (QuantumCircuit): Input circuit
filename (str): optional filename to write the result
line_length (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 line_length=-1.
line_length (int): Deprecated. See `fold`.
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
Expand All @@ -362,6 +361,11 @@ def _text_circuit_drawer(circuit, filename=None, line_length=None, reverse_bits=
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): 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`.
Returns:
TextDrawing: An instances that, when printed, draws the circuit in ascii art.
"""
Expand All @@ -373,9 +377,12 @@ def _text_circuit_drawer(circuit, filename=None, line_length=None, reverse_bits=
layout = circuit._layout
else:
layout = None
if line_length:
warn('The parameter "line_length" is being replaced by "fold"', DeprecationWarning, 3)
fold = line_length
text_drawing = _text.TextDrawing(qregs, cregs, ops, layout=layout)
text_drawing.plotbarriers = plot_barriers
text_drawing.line_length = line_length
text_drawing.line_length = fold
text_drawing.vertical_compression = vertical_compression

if filename:
Expand Down Expand Up @@ -530,7 +537,8 @@ def _matplotlib_circuit_drawer(circuit,
reverse_bits=False,
justify=None,
idle_wires=True,
with_layout=True):
with_layout=True,
fold=None):
"""Draw a quantum circuit based on matplotlib.
If `%matplotlib inline` is invoked in a Jupyter notebook, it visualizes a circuit inline.
We recommend `%config InlineBackend.figure_format = 'svg'` for the inline visualization.
Expand All @@ -544,11 +552,12 @@ def _matplotlib_circuit_drawer(circuit,
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
justify (str): `left`, `right` or `none`. Defaults to `left`. Says how
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.
fold (int): amount ops allowed before folding. Default is 25.
Returns:
matplotlib.figure: a matplotlib figure object for the circuit diagram
"""
Expand All @@ -562,7 +571,10 @@ def _matplotlib_circuit_drawer(circuit,
else:
layout = None

if fold is None:
fold = 25

qcd = _matplotlib.MatplotlibDrawer(qregs, cregs, ops, scale=scale, style=style,
plot_barriers=plot_barriers,
reverse_bits=reverse_bits, layout=layout)
reverse_bits=reverse_bits, layout=layout, fold=fold)
return qcd.draw(filename)
28 changes: 16 additions & 12 deletions qiskit/visualization/matplotlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ def get_index(self):
class MatplotlibDrawer:
def __init__(self, qregs, cregs, ops,
scale=1.0, style=None, plot_barriers=True,
reverse_bits=False, layout=None):
reverse_bits=False, layout=None, fold=25):

if not HAS_MATPLOTLIB:
raise ImportError('The class MatplotlibDrawer needs matplotlib. '
Expand Down Expand Up @@ -146,6 +146,10 @@ def __init__(self, qregs, cregs, ops,
dic = json.load(infile)
self._style.set_style(dic)

self.fold = self._style.fold or fold # self._style.fold should be removed after 0.10
if self.fold < 2:
self.fold = -1

self.figure = plt.figure()
self.figure.patch.set_facecolor(color=self._style.bg)
self.ax = self.figure.add_subplot(111)
Expand Down Expand Up @@ -457,8 +461,8 @@ def _barrier(self, config, anc):
y_reg.append(qreg['y'])
x0 = xys[0][0]

box_y0 = min(y_reg) - int(anc / self._style.fold) * (self._cond['n_lines'] + 1) - 0.5
box_y1 = max(y_reg) - int(anc / self._style.fold) * (self._cond['n_lines'] + 1) + 0.5
box_y0 = min(y_reg) - int(anc / self.fold) * (self._cond['n_lines'] + 1) - 0.5
box_y1 = max(y_reg) - int(anc / self.fold) * (self._cond['n_lines'] + 1) + 0.5
box = patches.Rectangle(xy=(x0 - 0.3 * WID, box_y0),
width=0.6 * WID, height=box_y1 - box_y0,
fc=self._style.bc, ec=None, alpha=0.6,
Expand Down Expand Up @@ -616,7 +620,7 @@ def _draw_regs_sub(self, n_fold, feedline_l=False, feedline_r=False):

# lf line
if feedline_r:
self._linefeed_mark((self._style.fold + 1 - 0.1,
self._linefeed_mark((self.fold + 1 - 0.1,
- n_fold * (self._cond['n_lines'] + 1)))
if feedline_l:
self._linefeed_mark((0.1,
Expand All @@ -633,12 +637,12 @@ def _draw_ops(self, verbose=False):
for key, qreg in self._qreg_dict.items():
q_anchors[key] = Anchor(reg_num=self._cond['n_lines'],
yind=qreg['y'],
fold=self._style.fold)
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._style.fold)
fold=self.fold)
#
# draw gates
#
Expand Down Expand Up @@ -947,10 +951,10 @@ def _draw_ops(self, verbose=False):
max_anc = max(anchors)
else:
max_anc = 0
n_fold = max(0, max_anc - 1) // self._style.fold
n_fold = max(0, max_anc - 1) // self.fold
# window size
if max_anc > self._style.fold > 0:
self._cond['xmax'] = self._style.fold + 1 + self.x_offset
if max_anc > self.fold > 0:
self._cond['xmax'] = self.fold + 1 + self.x_offset
self._cond['ymax'] = (n_fold + 1) * (self._cond['n_lines'] + 1) - 1
else:
self._cond['xmax'] = max_anc + 1 + self.x_offset
Expand All @@ -963,9 +967,9 @@ def _draw_ops(self, verbose=False):
# draw gate number
if self._style.index:
for ii in range(max_anc):
if self._style.fold > 0:
x_coord = ii % self._style.fold + 1
y_coord = - (ii // self._style.fold) * (self._cond['n_lines'] + 1) + 0.7
if self.fold > 0:
x_coord = ii % self.fold + 1
y_coord = - (ii // self.fold) * (self._cond['n_lines'] + 1) + 0.7
else:
x_coord = ii + 1
y_coord = 0.7
Expand Down
30 changes: 19 additions & 11 deletions qiskit/visualization/qcstyle.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ def __init__(self):
'meas': non_gate_color
}
self.latexmode = False
self.fold = 25
self.fold = None # To be removed after 0.10 is released
self.bundle = True
self.index = False
self.figwidth = -1
Expand All @@ -113,18 +113,22 @@ def set_style(self, style_dic):
self.disptex = dic.pop('displaytext', self.disptex)
self.dispcol = dic.pop('displaycolor', self.dispcol)
self.latexmode = dic.pop('latexdrawerstyle', self.latexmode)
self.fold = dic.pop('fold', self.fold)
if self.fold < 2:
self.fold = -1
self.bundle = dic.pop('cregbundle', self.bundle)
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 'fold' in dic:
warn('The key "fold" in the argument "style" is being replaced by the argument "fold"',
DeprecationWarning, 5)
self.fold = dic.pop('fold', self.fold)
if self.fold < 2:
self.fold = -1

if dic:
warn('style option/s ({}) is/are not '
'supported'.format(', '.join(dic.keys())), DeprecationWarning, 2)
warn('style option/s ({}) is/are not supported'.format(', '.join(dic.keys())),
DeprecationWarning, 2)


class BWStyle:
Expand Down Expand Up @@ -213,15 +217,19 @@ def set_style(self, style_dic):
self.dispcol[key] = self.gc
self.dispcol = dic.pop('displaycolor', self.dispcol)
self.latexmode = dic.pop('latexdrawerstyle', self.latexmode)
self.fold = dic.pop('fold', self.fold)
if self.fold < 2:
self.fold = -1
self.bundle = dic.pop('cregbundle', self.bundle)
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 'fold' in dic:
warn('The key "fold" in the argument "style" is being replaced by the argument "fold"',
DeprecationWarning, 5)
self.fold = dic.pop('fold', self.fold)
if self.fold < 2:
self.fold = -1

if dic:
warn('style option/s ({}) is/are not '
'supported'.format(', '.join(dic.keys())), DeprecationWarning, 2)
warn('style option/s ({}) is/are not supported'.format(', '.join(dic.keys())),
DeprecationWarning, 2)

0 comments on commit 00e434c

Please sign in to comment.