qml.drawer.MPLDrawer

class MPLDrawer(n_layers, n_wires, c_wires=0, wire_options=None, figsize=None, fig=None)[source]

Bases: object

Allows easy creation of graphics representing circuits with matplotlib

Parameters
  • n_layers (int) – the number of layers

  • n_wires (int) – the number of wires

Keyword Arguments
  • c_wires=0 (int) – the number of classical wires to leave space for.

  • wire_options=None (dict) – matplotlib configuration options for drawing the wire lines

  • figsize=None (Iterable) – Allows users to specify the size of the figure manually. Defaults to scale with the size of the circuit via n_layers and n_wires.

  • fig=None (matplotlib Figure) – Allows users to specify the figure window to plot to.

Example

drawer = qml.drawer.MPLDrawer(n_wires=5, n_layers=6)

drawer.label(["0", "a", r"$|\Psi\rangle$", r"$|\theta\rangle$", "aux"])

drawer.box_gate(layer=0, wires=[0, 1, 2, 3, 4], text="Entangling Layers")
drawer.box_gate(layer=1, wires=[0, 2, 3], text="U(θ)")

drawer.box_gate(layer=1, wires=4, text="Z")

drawer.SWAP(layer=2, wires=(3,4))
drawer.CNOT(layer=2, wires=(0, 2))

drawer.ctrl(layer=3, wires=[1, 3], control_values=[True, False])
drawer.box_gate(
    layer=3, wires=2, text="H", box_options={"zorder": 4}, text_options={"zorder": 5}
)

drawer.ctrl(layer=4, wires=[1, 2])

drawer.measure(layer=5, wires=0)

drawer.fig.suptitle('My Circuit', fontsize='xx-large')
../../_images/example_basic.png

Matplotlib Integration

This class relies on matplotlib. As such, users can extend this class via interacting with the figure drawer.fig and axes drawer.ax objects manually. For instance, the example circuit manipulates the figure to set a title using drawer.fig.suptitle. Users can save the image using plt.savefig or via the figure method drawer.fig.savefig.

As described in the next section, the figure supports both global styling and individual styling of elements with matplotlib styles, configuration, and keywords.

Formatting

PennyLane has inbuilt styles for controlling the appearance of the circuit drawings. All available styles can be determined by evaluating qml.drawer.available_styles(). Any available string can then be passed to qml.drawer.use_style.

qml.drawer.use_style('black_white')
../../_images/black_white_style.png

You can also control the appearance with matplotlib’s provided tools, see the matplotlib docs . For example, we can customize plt.rcParams:

plt.rcParams['patch.facecolor'] = 'mistyrose'
plt.rcParams['patch.edgecolor'] = 'maroon'
plt.rcParams['text.color'] = 'maroon'
plt.rcParams['font.weight'] = 'bold'
plt.rcParams['patch.linewidth'] = 4
plt.rcParams['patch.force_edgecolor'] = True
plt.rcParams['lines.color'] = 'indigo'
plt.rcParams['lines.linewidth'] = 5
plt.rcParams['figure.facecolor'] = 'ghostwhite'
../../_images/example_rcParams.png

You can also manually control the styles of individual plot elements via the drawer class. All accept dictionaries of keyword-values pairs for matplotlib object components. Acceptable keywords differ based on what’s being drawn. For example, you cannot pass "fontsize" to the dictionary controlling how to format a rectangle. For the control-type gates CNOT and ctrl the options dictionary can only contain 'linewidth', 'color', or 'zorder' keys.

This example demonstrates the different ways you can format the individual elements:

wire_options = {"color": "indigo", "linewidth": 4}
drawer = MPLDrawer(n_wires=2, n_layers=4, wire_options=wire_options)

label_options = {"fontsize": "x-large", 'color': 'indigo'}
drawer.label(["0", "a"], text_options=label_options)

box_options = {'facecolor': 'lightcoral', 'edgecolor': 'maroon', 'linewidth': 5}
text_options = {'fontsize': 'xx-large', 'color': 'maroon'}
drawer.box_gate(layer=0, wires=0, text="Z", box_options=box_options, text_options=text_options)

swap_options = {'linewidth': 4, 'color': 'darkgreen'}
drawer.SWAP(layer=1, wires=(0, 1), options=swap_options)

ctrl_options = {'linewidth': 4, 'color': 'teal'}
drawer.CNOT(layer=2, wires=(0, 1), options=ctrl_options)
drawer.ctrl(layer=3, wires=(0, 1), options=ctrl_options)


measure_box = {'facecolor': 'white', 'edgecolor': 'indigo'}
measure_lines = {'edgecolor': 'indigo', 'facecolor': 'plum', 'linewidth': 2}
for wire in range(2):
    drawer.measure(layer=4, wires=wire, box_options=measure_box, lines_options=measure_lines)

drawer.fig.suptitle('My Circuit', fontsize='xx-large')
../../_images/example_formatted.png

Positioning

Each gate takes arguments in order of layer followed by wires. These translate to x and y coordinates in the graph. Layer number (x) increases as you go right, and wire number (y) increases as you go down; the y-axis is inverted. You can pass non-integer values to either keyword. If you have a long label, the gate can span multiple layers and have extra width:

drawer = MPLDrawer(2, 2)
drawer.box_gate(layer=0, wires=1, text="X")
drawer.box_gate(layer=1, wires=1, text="Y")

# Gate between two layers
drawer.box_gate(layer=0.5, wires=0, text="Big Gate", extra_width=0.5)
../../_images/float_layer.png

ax

Matplotlib axes

fig

Matplotlib figure

fontsize

Default fontsize for text.

ax

Matplotlib axes

fig

Matplotlib figure

fontsize

Default fontsize for text. Defaults to 14.

CNOT(layer, wires[, control_values, options])

Draws a CNOT gate.

SWAP(layer, wires[, options])

Draws a SWAP gate

box_gate(layer, wires[, text, box_options, …])

Draws a box and adds label text to its center.

classical_wire(layers, wires)

Draw a classical control line.

cond(layer, measured_layer, wires, wires_target)

Add classical communication double-lines for conditional operations

ctrl(layer, wires[, wires_target, …])

Add an arbitrary number of control wires

cwire_join(layer, wire[, erase_right])

Erase the horizontal edges of an intersection between classical wires.

erase_wire(layer, wire, length)

Erases a portion of a wire by adding a rectangle that matches the background.

label(labels[, text_options])

Label each wire.

measure(layer, wires[, text, box_options, …])

Draw a Measurement graphic at designated layer, wire combination.

CNOT(layer, wires, control_values=None, options=None)[source]

Draws a CNOT gate.

Parameters
  • layer (int) – layer to draw in

  • control_values=None (Union[bool, Iterable[bool]]) – for each control wire, denotes whether to control on False=0 or True=1

  • wires (Union[int, Iterable[int]]) – wires to use. Last wire is the target.

Keyword Arguments

options=None – Matplotlib options. The only supported keys are 'color', 'linewidth', and 'zorder'.

Example

drawer = MPLDrawer(n_wires=2, n_layers=2)

drawer.CNOT(0, (0, 1))

options = {'color': 'indigo', 'linewidth': 4}
drawer.CNOT(1, (1, 0), options=options)
../../_images/cnot.png
SWAP(layer, wires, options=None)[source]

Draws a SWAP gate

Parameters
  • layer (int) – layer to draw on

  • wires (Tuple[int, int]) – two wires the SWAP acts on

Keyword Arguments

options=None (dict) – matplotlib keywords for Line2D objects

Example

The options keyword can accept any Line2D compatible keywords in a dictionary.

drawer = MPLDrawer(n_wires=2, n_layers=2)

drawer.SWAP(0, (0, 1))

swap_options = {"linewidth": 2, "color": "indigo"}
drawer.SWAP(1, (0, 1), options=swap_options)
../../_images/SWAP.png
box_gate(layer, wires, text='', box_options=None, text_options=None, **kwargs)[source]

Draws a box and adds label text to its center.

Parameters
  • layer (int) – x coordinate for the box center

  • wires (Union[int, Iterable[int]]) – y locations to include inside the box. Only min and max of an Iterable affect the output

  • text (str) – string to print at the box’s center

Keyword Arguments
  • box_options=None (dict) – any matplotlib keywords for the plt.Rectangle patch

  • text_options=None (dict) – any matplotlib keywords for the text

  • extra_width (float) – extra box width

  • autosize (bool) – whether to rotate and shrink text to fit within the box

  • active_wire_notches (bool) – whether or not to add notches indicating active wires. Defaults to True.

Example

drawer = MPLDrawer(n_wires=2, n_layers=1)

drawer.box_gate(layer=0, wires=(0, 1), text="CY")
../../_images/box_gates.png

This method can accept two different sets of design keywords. box_options takes Rectangle keywords , and text_options accepts Matplotlib Text keywords .

box_options = {'facecolor': 'lightcoral', 'edgecolor': 'maroon', 'linewidth': 5}
text_options = {'fontsize': 'xx-large', 'color': 'maroon'}

drawer = MPLDrawer(n_wires=2, n_layers=1)

drawer.box_gate(layer=0, wires=(0, 1), text="CY",
    box_options=box_options, text_options=text_options)
../../_images/box_gates_formatted.png

By default, text is rotated and/or shrunk to fit within the box. This behavior can be turned off with the autosize=False keyword.

drawer = MPLDrawer(n_layers=4, n_wires=2)

drawer.box_gate(layer=0, wires=0, text="A longer label")
drawer.box_gate(layer=0, wires=1, text="Label")

drawer.box_gate(layer=1, wires=(0,1), text="long multigate label")

drawer.box_gate(layer=3, wires=(0,1), text="Not autosized label", autosize=False)
../../_images/box_gates_autosized.png
classical_wire(layers, wires)[source]

Draw a classical control line.

Parameters
  • layers – a list of x coordinates for the classical wire

  • wires – a list of y coordinates for the classical wire. Wire numbers greater than the number of quantum wires will be scaled as classical wires.

cond(layer, measured_layer, wires, wires_target, options=None)[source]

Add classical communication double-lines for conditional operations

Parameters
  • layer (int) – the layer to draw vertical lines in, containing the target operation

  • measured_layer (int) – the layer where the mid-circuit measurements are

  • wires (Union[int, Iterable[int]]) – set of wires to control on

  • wires_target (Union[int, Iterable[int]]) – target wires. Used to determine where to terminate the vertical double-line

Keyword Arguments

options=None (dict) – Matplotlib keywords passed to plt.Line2D

Example

drawer = MPLDrawer(n_wires=3, n_layers=4)

drawer.cond(layer=1, measured_layer=0, wires=[0], wires_target=[1])

options = {'color': "indigo", 'linewidth': 1.5}
drawer.cond(layer=3, measured_layer=2, wires=(1,), wires_target=(2,), options=options)
../../_images/cond.png
ctrl(layer, wires, wires_target=None, control_values=None, options=None)[source]

Add an arbitrary number of control wires

Parameters
  • layer (int) – the layer to draw the object in

  • wires (Union[int, Iterable[int]]) – set of wires to control on

Keyword Arguments
  • wires_target=None (Union[int, Iterable[int]]) – target wires. Used to determine min and max wires for the vertical line

  • control_values=None (Union[bool, Iterable[bool]]) – for each control wire, denotes whether to control on False=0 or True=1

  • options=None (dict) – Matplotlib keywords. The only supported keys are 'color', 'linewidth', and 'zorder'.

Example

drawer = MPLDrawer(n_wires=2, n_layers=3)

drawer.ctrl(layer=0, wires=0, wires_target=1)
drawer.ctrl(layer=1, wires=(0, 1), control_values=[0, 1])

options = {'color': "indigo", 'linewidth': 4}
drawer.ctrl(layer=2, wires=(0, 1), control_values=[1, 0], options=options)
../../_images/ctrl.png
cwire_join(layer, wire, erase_right=False)[source]

Erase the horizontal edges of an intersection between classical wires. By default, erases only the left edge.

Parameters
  • layer – the x-coordinate for the classical wire intersection

  • wire – the classical wire y-coordinate for the intersection

  • erase_right=False (bool) – whether or not to erase the right side of the intersection in addition to the left.

erase_wire(layer, wire, length)[source]

Erases a portion of a wire by adding a rectangle that matches the background.

Parameters
  • layer (int) – starting x coordinate for erasing the wire

  • wire (int) – y location to erase the wire from

  • length (float, int) – horizontal distance from layer to erase the background.

label(labels, text_options=None)[source]

Label each wire.

Parameters

labels (Iterable[str]) – Iterable of labels for the wires

Keyword Arguments

text_options (dict) – any matplotlib keywords for a text object, such as font or size

Example

drawer = MPLDrawer(n_wires=2, n_layers=1)
drawer.label(["a", "b"])
../../_images/labels.png

You can also pass any Matplotlib Text keywords as a dictionary to the text_options keyword:

drawer = MPLDrawer(n_wires=2, n_layers=1)
drawer.label(["a", "b"], text_options={"color": "indigo", "fontsize": "xx-large"})
../../_images/labels_formatted.png
measure(layer, wires, text=None, box_options=None, lines_options=None)[source]

Draw a Measurement graphic at designated layer, wire combination.

Parameters
  • layer (int) – layer to draw on

  • wires (int) – wire to draw on

Keyword Arguments
  • text=None (str) – an annotation for the lower right corner.

  • box_options=None (dict) – dictionary to format a matplotlib rectangle

  • lines_options=None (dict) – dictionary to format matplotlib arc and arrow

Example

This method accepts two different formatting dictionaries. box_options edits the rectangle while lines_options edits the arc and arrow.

drawer = MPLDrawer(n_wires=2, n_layers=1)
drawer.measure(layer=0, wires=0)

measure_box = {'facecolor': 'white', 'edgecolor': 'indigo'}
measure_lines = {'edgecolor': 'indigo', 'facecolor': 'plum', 'linewidth': 2}
drawer.measure(layer=0, wires=1, box_options=measure_box, lines_options=measure_lines)
../../_images/measure.png