qml.drawer.draw_mpl

draw_mpl(qnode, wire_order=None, show_all_wires=False, decimals=None, style=None, *, fig=None, level='gradient', **kwargs)[source]

Draw a qnode with matplotlib

Parameters
  • qnode (QNode or Callable) – the input QNode/quantum function that is to be drawn.

  • wire_order (Sequence[Any]) – the order (from top to bottom) to print the wires of the circuit. If not provided, the wire order defaults to the device wires. If device wires are not available, the circuit wires are sorted if possible.

  • show_all_wires (bool) – If True, all wires, including empty wires, are printed.

  • decimals (int) – How many decimal points to include when formatting operation parameters. Default None will omit parameters from operation labels.

  • style (str) – visual style of plot. Valid strings are {'black_white', 'black_white_dark', 'sketch', 'pennylane', 'pennylane_sketch', 'sketch_dark', 'solarized_light', 'solarized_dark', 'default'}. If no style is specified, the global style set with use_style() will be used, and the initial default is ‘black_white’. If you would like to use your environment’s current rcParams, set style to “rcParams”. Setting style does not modify matplotlib global plotting settings.

Keyword Arguments
  • fig (None or matplotlib.Figure) – Matplotlib figure to plot onto. If None, then create a new figure

  • fontsize (float or str) – fontsize for text. Valid strings are {'xx-small', 'x-small', 'small', 'medium', large', 'x-large', 'xx-large'}. Default is 14.

  • wire_options (dict) – matplotlib formatting options for the wire lines

  • label_options (dict) – matplotlib formatting options for the wire labels

  • show_wire_labels (bool) – Whether or not to show the wire labels.

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

  • level (None, str, int, slice) – An indication of what transforms to apply before drawing. Check get_transform_program() for more information on the allowed values and usage details of this argument.

Returns

A function that has the same argument signature as qnode. When called, the function will draw the QNode as a tuple of (matplotlib.figure.Figure, matplotlib.axes._axes.Axes)

Warning

Unlike draw(), this function can not draw the full result of a tape-splitting transform. In such cases, only the tape generated first will be plotted.

Example:

dev = qml.device('lightning.qubit', wires=(0,1,2,3))

@qml.qnode(dev)
def circuit(x, z):
    qml.QFT(wires=(0,1,2,3))
    qml.IsingXX(1.234, wires=(0,2))
    qml.Toffoli(wires=(0,1,2))
    mcm = qml.measure(1)
    mcm_out = qml.measure(2)
    qml.CSWAP(wires=(0,2,3))
    qml.RX(x, wires=0)
    qml.cond(mcm, qml.RY)(np.pi / 4, wires=3)
    qml.CRZ(z, wires=(3,0))
    return qml.expval(qml.Z(0)), qml.probs(op=mcm_out)


fig, ax = qml.draw_mpl(circuit)(1.2345,1.2345)
fig.show()
../../_images/main_example.png

Decimals:

The keyword decimals controls how many decimal points to include when labelling the operations. The default value None omits parameters for brevity.

@qml.qnode(dev)
def circuit2(x, y):
    qml.RX(x, wires=0)
    qml.Rot(*y, wires=0)
    return qml.expval(qml.Z(0))

fig, ax = qml.draw_mpl(circuit2, decimals=2)(1.23456, [1.2345,2.3456,3.456])
fig.show()
../../_images/decimals.png

Wires:

The keywords wire_order and show_all_wires control the location of wires from top to bottom.

fig, ax = qml.draw_mpl(circuit, wire_order=[3,2,1,0])(1.2345,1.2345)
fig.show()
../../_images/wire_order.png

If a wire is in wire_order, but not in the tape, it will be omitted by default. Only by selecting show_all_wires=True will empty wires be displayed.

fig, ax = qml.draw_mpl(circuit, wire_order=["aux"], show_all_wires=True)(1.2345,1.2345)
fig.show()
../../_images/show_all_wires.png

Integration with matplotlib:

This function returns matplotlib figure and axes objects. Using these objects, users can perform further customization of the graphic.

fig, ax = qml.draw_mpl(circuit)(1.2345,1.2345)
fig.suptitle("My Circuit", fontsize="xx-large")

options = {'facecolor': "white", 'edgecolor': "#f57e7e", "linewidth": 6, "zorder": -1}
box1 = plt.Rectangle((-0.5, -0.5), width=3.0, height=4.0, **options)
ax.add_patch(box1)

ax.annotate("CSWAP", xy=(5, 2.5), xycoords='data', xytext=(5.8,1.5), textcoords='data',
            arrowprops={'facecolor': 'black'}, fontsize=14)

ax.annotate("classical control flow", xy=(3.5, 4.2), xycoords='data', xytext=(0.8,4.2),
            textcoords='data', arrowprops={'facecolor': 'blue'}, fontsize=14,
            va="center")
fig.show()
../../_images/postprocessing.png

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 via the kwarg style to change the settings for that plot. This will not affect style settings for subsequent matplotlib plots.

fig, ax = qml.draw_mpl(circuit, style='sketch')(1.2345,1.2345)
fig.show()
../../_images/sketch_style.png

You can also control the appearance with matplotlib’s provided tools, see the matplotlib docs . For example, we can customize plt.rcParams. To use a customized appearance based on matplotlib’s plt.rcParams, qml.draw_mpl must be run with style="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'] = 2
plt.rcParams['figure.facecolor'] = 'ghostwhite'

fig, ax = qml.draw_mpl(circuit, style="rcParams")(1.2345,1.2345)
fig.show()
../../_images/rcparams.png

The wires and wire labels can be manually formatted by passing in dictionaries of keyword-value pairs of matplotlib options. wire_options accepts options for lines, and label_options accepts text options.

fig, ax = qml.draw_mpl(circuit, wire_options={'color':'teal', 'linewidth': 5},
            label_options={'size': 20})(1.2345,1.2345)
fig.show()
../../_images/wires_labels.png

Levels:

The level keyword argument allows one to select a subset of the transforms to apply on the QNode before carrying out any drawing. Take, for example, this circuit:

@qml.transforms.merge_rotations
@qml.transforms.cancel_inverses
@qml.qnode(qml.device("default.qubit"), diff_method="parameter-shift")
def circ():
    qml.RandomLayers([[1.0, 20]], wires=(0, 1))
    qml.Permute([2, 1, 0], wires=(0, 1, 2))
    qml.PauliX(0)
    qml.PauliX(0)
    qml.RX(0.1, wires=0)
    qml.RX(-0.1, wires=0)
    return qml.expval(qml.PauliX(0))

One can plot the circuit without any transforms applied by passing level="top" or level=0:

fig, ax = qml.draw_mpl(circ, level="top")()
fig.show()
../../_images/level_top.png

Or plot the circuit after applying the transforms manually applied on the QNode (merge_rotations and cancel_inverses):

fig, ax = qml.draw_mpl(circ, level="user")()
fig.show()
../../_images/level_user.png

To apply all of the transforms, including those carried out by the differentiation method and the device, use level=None:

fig, ax = qml.draw_mpl(circ, level=None)()
fig.show()
../../_images/level_none.png

Slices can also be passed to the level argument. So one can, for example, request that only the merge_rotations transform is applied:

fig, ax = qml.draw_mpl(circ, level=slice(1, 2))()
fig.show()
../../_images/level_slice.png