Backend#

class discopy.drawing.backend.Backend(linewidth=1)[source]#

Bases: abc.ABC

Abstract drawing backend.

draw_text(text, i, j, **params)[source]#

Draws a piece of text at a given position.

draw_node(i, j, **params)[source]#

Draws a node for a given position, color and shape.

draw_polygon(*points, facecolor=None, edgecolor=None)[source]#

Draws a polygon given a list of points.

static readable_foreground(colour, threshold=0.5)[source]#

Pick a readable foreground text colour, i.e. "white" or "black", for text drawn on top of a given background colour, using the standard luma formula for perceived brightness.

>>> Backend.readable_foreground("white")
'black'
>>> Backend.readable_foreground("black")
'white'
draw_wire(source, target, bend_out=False, bend_in=False, style=None, linewidth=None, adaptive=True)[source]#

Draws a wire from source to target, possibly with a Bezier. An adaptive wire lies on the neutral canvas, so its stroke may adapt to a dark page, see Matplotlib.dark_gid().

draw_bezier(points, adaptive=True)[source]#

Draws a cubic Bezier curve from a list of four control points.

static on_neutral_canvas(*types)[source]#

Whether wires of the given types only border white regions, i.e. the neutral canvas, so that their strokes and labels may adapt to a dark page rather than keep a static colour readable over their region.

draw_filled_shape(start, steps, color)[source]#

Fills the closed region whose boundary starts at start and follows steps, a list of either ("line", end) for a straight segment or ("curve", control1, control2, end) for a cubic Bezier. The region is filled with color and drawn without an outline, e.g. behind the wires to colour the inside of a ribbon.

static braid_strand(source, target, middle)[source]#

The four control points of the cubic Bezier drawn by draw_braid_strand(), i.e. a strand from source to target crossing the horizontal line at height middle.

static half_circle_beziers(left, right, centre, sign, depth=None)[source]#

The two Bezier control groups of the arc of a half circle (or ellipse if depth differs from the radius) from (left, centre) to (right, centre), bulging to centre + sign * depth at the apex, as drawn by draw_half_circle().

draw_half_circle(left, right, end, centre, sign, depth=None, adaptive=True)[source]#

Draws a half circle (or ellipse if depth differs from the radius) from (left, centre) to (right, centre) with vertical sides up to end, e.g. the fold of a discopy.ribbon.DualRailCup, see half_circle_beziers().

static fold_depths(xs)[source]#

The vertical depth of the outer and inner fold of a dual rail cup or cap with rails at the four positions xs, capping the half circle at RIBBON_FOLD_DEPTH so a wide cup flattens into an ellipse. The inner fold is one ribbon width shallower, keeping the width of the band constant.

fill_strand_band(first, second, middle, color, gap=0)[source]#

Fills the band between the two parallel braid strands of a ribbon, see draw_dual_rail_braid(). A non-zero gap breaks the band around the crossing, matching the broken strands, so the ribbon going under is shadowed by the one going over.

draw_braid_strand(source, target, middle, gap=0, adaptive=True)[source]#

Draws a single strand of a braid crossing the horizontal line at height middle. The strand is vertical at both ends and diagonal in between, so that two strands cross at a right angle rather than meeting flat. If gap is non-zero the strand is broken around the crossing, i.e. it goes under the other strand.

draw_spiders(graph, draw_box_labels=True, **params)[source]#

Draws a list of boxes depicted as spiders.

abstract output(path=None, show=True, **params)[source]#

Output the drawing.

abstract draw_regions(graph, **params)[source]#

Draw coloured 0-cell regions, e.g. the background of a Drawing.frame() or the wire-typed regions of a diagram.

This has no default drawing logic: backends that do not want to support coloured regions can simply inherit this no-op.

draw_legend(graph, **params)[source]#

Draw a legend of region colours when supported by the backend.

static region_colours(graph)[source]#

The distinct non-white region colours of a diagram, keyed by colour.

Returns an order-preserving mapping from each colour’s name to its monoidal.Colour, suitable for a drawing legend. White is omitted as it is the neutral background.

static region_separators(graph)[source]#

The boundaries between the regions of a drawing: a quadratic Bezier (top, control, bottom) for each non-horizontal visible edge and for both sides of each box, paired with the name of the colour of the region to its right. The Bezier control point is the one of draw_wire(), so a separator hugs the wire drawn over it. Horizontal edges bound no region on either side, so they are left out, and the left side of a box carries None since a box is a 2-cell, i.e. there is no region underneath it.

static separator_param(curve, y)[source]#

The Bezier parameter at which a separator curve from top to bottom crosses the horizontal line at height y, see region_separators(). The control point of a separator is level with one of its endpoints, so its height is monotone and the parameter has a closed form.

static region_band(separators, bottom, top)[source]#

The separators that span the height band from bottom to top, restricted to it and ordered from left to right, see region_cells(). Two separators may touch at a shared endpoint on the boundary of the band but never cross inside it, so they are ordered by their horizontal position at its middle height.

static region_cells(graph)[source]#

The exact extents of the coloured regions of a drawing, computed by trapezoidal decomposition: the canvas is subdivided at every height where a separator starts or ends and, inside each of the resulting bands, each consecutive pair of separators bounds one cell, filled with the colour that its left boundary carries – graph.dom.dom for the leftmost cell, with the sides of the canvas as outermost boundaries. White cells are left out as they are the neutral background, see region_colours(), and so are the cells underneath a box, whose left side carries no colour at all.

Returns the list of cells (left, right, colour) where left and right are quadratic Beziers (top, control, bottom) restricted to the band, ordered bottom to top then left to right.

draw_region_cell(left, right, facecolor)[source]#

Fill the cell between two quadratic Beziers left and right given as (top, control, bottom) triples spanning the same height band, see region_cells().

static visible_edges(graph)[source]#

Yield the edges of a graph that are not inside a box.

static has_boundary_sides(typ)[source]#

Whether the first or last object of a type is a frame side, i.e. it carries the frame_boundary flag set by Drawing.bubble() with draw_as_square.

static is_frame_boundary(node)[source]#

Whether a node belongs to the sides of a frame, i.e. the box drawn around the terms of an Equation with coloured boundaries.

A box carrying the frame_boundary flag is a bubble opening or closing squashed to half height, whose horizontal boundary is drawn as a wire through the box node. That boundary is hidden only for a square frame, i.e. when the left and right side types carry the flag too; a plain bubble keeps its top and bottom boundaries visible.

fill_fold(outer, inner, color)[source]#

Fills the fold of a ribbon between two concentric arcs given as pairs of Bezier control groups, see half_circle_beziers() and e.g. draw_dual_rail_cup().

draw_dual_rail_cup(positions, node, **params)[source]#

Draws a discopy.ribbon.DualRailCup as a single constant-width fold, i.e. two concentric half circles joining the outer and inner rails of two ribbons, filled with the colour of their region. A wide cup is flattened into a half ellipse, see fold_depths().

draw_dual_rail_cap(positions, node, **params)[source]#

Draws a discopy.ribbon.DualRailCap as a single constant-width fold, i.e. two concentric half circles joining the outer and inner rails of two ribbons, filled with the colour of their region. A wide cap is flattened into a half ellipse, see fold_depths().

draw_braid(positions, node)[source]#

Draws a braid or a swap as its two wires crossing diagonally, so that they meet at a right angle. A braid (over/under) breaks the wire that goes under; a symmetric swap simply crosses both wires.

draw_permutation(positions, node)[source]#

Draw a permutation as a band of crossing wires.

draw_box(positions, node, **params)[source]#

Draws a box node on a given backend.

draw_discard(positions, node, **params)[source]#

Draws a discopy.quantum.circuit.Discard box.

draw_measure(positions, node, **params)[source]#

Draws a discopy.quantum.circuit.Measure box.

draw_dual_rail_braid(positions, node, **params)[source]#

Draws a discopy.balanced.DualRailBraid, i.e. the two ribbons (0, 1) and (2, 3) crossing as a whole rather than wire by wire.

draw_dual_rail_twist(positions, node, **params)[source]#

Draws a discopy.balanced.DualRailTwist, i.e. the two rails of a ribbon crossing each other twice in quick succession.

draw_brakets(positions, node, **params)[source]#

Draws a discopy.quantum.gates.Ket box.

draw_controlled_gate(positions, node, **params)[source]#

Draws a discopy.quantum.gates.Controlled gate.