Customizing Elements

Reusing groups of elements

If a set of circuit elements are to be reused multiple times, they can be grouped into a single element. Create and populate a drawing, but don’t call draw on it. Instead, use the Drawing to create a new ElementDrawing, which converts the drawing into an element instance to add to other drawings.

d1 = schemdraw.Drawing()
d1.add(elm.Resistor)
d1.push()
d1.add(elm.Capacitor, d='down')
d1.add(elm.Line, d='left')
d1.pop()

d2 = schemdraw.Drawing()   # Add a second drawing
for i in range(3):
    d2.add(elm.ElementDrawing(d1))   # Add the first drawing to it 3 times
d2.draw()
../_images/customizing_1_0.svg

Defining custom elements

All elements are subclasses of schemdraw.elements.Element or schemdraw.elements.Element2Term. For elements consisting of several other already-defined elements (like a relay), schemdraw.elements.compound.ElementCompound can be used for easy combining of multiple elements. Subclasses only need to define the __init__ method in order to add lines, shapes, and text to the new element, all of which are defined using Segment classes. New Segments should be appended to the Element.segments attribute list.

Coordinates are all defined in element cooridnates, where the element begins at [0, 0] and is drawn from left to right. The drawing engine will then rotate and translate the element to its final position. A standard resistor is 1 drawing unit long, and with default lead extension will become 3 units long.

class schemdraw.segments.Segment(path, **kwargs)

A segment (path), part of an Element.

Parameters:

path (array-like) – List of [x,y] coordinates making the path

Keyword Arguments:
 
  • color (string) – Color for this segment
  • lw (float) – Line width for the segment
  • ls (string) – Line style for the segment ‘-‘, ‘–’, ‘:’, etc.
  • capstyle (string) – Capstyle for the segment: ‘round’, ‘miter’, or ‘bevel’
  • joinstyle (string) – Joinstyle for the segment: ‘round’, ‘miter’, or ‘bevel’
  • fill (string) – Color to fill if path is closed
  • zorder (int) – Z-order for segment
class schemdraw.segments.SegmentPoly(verts, **kwargs)

A polygon segment

Parameters:

xy (array-like) – List of [x,y] coordinates making the polygon

Keyword Arguments:
 
  • closed (bool) – Draw a closed polygon (default True)
  • cornerradius (float) – Round the corners to this radius (0 for no rounding)
  • color (string) – Color for this segment
  • lw (float) – Line width for the segment
  • ls (string) – Line style for the segment
  • fill (string) – Color to fill if path is closed
  • zorder (int) – Z-order for segment
class schemdraw.segments.SegmentCircle(center, radius, **kwargs)

A circle drawing segment

Parameters:
  • center ([x, y] array) – Center of the circle
  • radius (float) – Radius of the circle
Keyword Arguments:
 
  • color (string) – Color for this segment
  • lw (float) – Line width for the segment
  • ls (string) – Line style for the segment
  • fill (string) – Color to fill if path is closed
  • zorder (int) – Z-order for segment
  • ref (string) – Flip reference [‘start’, ‘end’, None].
class schemdraw.segments.SegmentArc(center, width, height, **kwargs)

An arc drawing segment

Parameters:
  • center ([x, y] array) – Center of the circle
  • width (float) – Width of the arc ellipse
  • height (float) – Height of the arc ellipse
  • reverse (bool) – Element has been reversed
Keyword Arguments:
 
  • theta1 (float) – Starting angle (degrees)
  • theta2 (float) – Ending angle (degrees)
  • angle (float) – Rotation of the ellipse defining the arc
  • arrow ([None, 'cw', 'ccw']) – Direction of arrowhead
  • color (string) – Color for this segment
  • lw (float) – Line width for the segment
  • ls (string) – Line style for the segment
  • fill (string) – Color to fill if path is closed
  • zorder (int) – Z-order for segment
class schemdraw.segments.SegmentArrow(tail, head, **kwargs)

An arrow drawing segment

Parameters:
  • start ([x, y] array) – Start coordinate of arrow
  • end ([x, y] array) – End (head) coordinate of arrow
Keyword Arguments:
 
  • headwidth (float) – Width of arrowhead
  • headlength (float) – Lenght of arrowhead
  • color (string) – Color for this segment
  • lw (float) – Line width for the segment
  • ls (string) – Line style for the segment
  • zorder (int) – Z-order for segment
class schemdraw.segments.SegmentText(pos, label, **kwargs)

A text drawing segment

Parameters:
  • pos ([x, y] array) – Coordinates for text
  • label (string) – Text to draw
Keyword Arguments:
 
  • align (tuple) – Tuple of (horizontal, vertical) alignment where horizontal is [‘center’, ‘left’, ‘right’] and vertical is [‘center’, ‘top’, ‘bottom’]
  • rotation (float) – Rotation angle (degrees)
  • rotation_mode (string) – See Matplotlib documentation. ‘anchor’ or ‘default’.
  • color (string) – Color for this segment
  • fontsize (float) – Font size
  • font (string) – Font name/family
  • zorder (int) – Z-order for segment

The Element.__init__ method takes arbitrary keyword arguments than can help define the circuit element to draw. Keyword arguments passed to the Segment instances will override the drawing defaults or kwargs passed in to the Element.__init__.

In addition to the list of Segments, named anchors and other parameters should be specified in the setup function. Anchors should be added to the Element.anchors dictionary as name: [x, y] pairs.

The Element instance maintains its own parameters dictionary in Element.params that override the default drawing parameters. Parameters are resolved by a ChainMap of user arguments to the Element instance, the Element.params attribute, then the schemdraw.Drawing parameters. A common use of setting Element.params in the setup function is to change the default position of text labels, for example Transistor elements apply labels on the right side of the element by default, so they add to the setup:

The user can still override this label position by creating, for example, Transistor(lblloc=’top’).

As an example, here’s the definition of our favorite element, the resistor:

class Resistor(Element2Term):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.segments.append(Segment([[0, 0], [0.5*reswidth, resheight],
                                      [1.5*reswidth, -resheight], [2.5*reswidth, resheight],
                                      [3.5*reswidth, -resheight], [4.5*reswidth, resheight],
                                      [5.5*reswidth, -resheight], [6*reswidth, 0]]))

The resistor is made of just one path. reswidth and resheight are constants that define the height and width of the resistor (and are referenced by several other elements too). Browse the source code in the Schemdraw.elements module to see the definitions of the other built-in elements.

Flux Capacitor Example

For an example, let’s make a flux capacitor circuit element.

Since everyone knows a flux-capacitor has three branches, we should subclass the standard schemdraw.elements.Element class instead of schemdraw.elements.Element2Term. Start by importing the Segments and define the class name and __init__ function:

from schemdraw.segments import *

class FluxCapacitor(Element):
    def __init__(self, *args, **kwargs):

We want a dot in the center of our flux capacitor, so start by adding a SegmentCircle. The fclen and radius variables could be pulled from kwargs for the user to adjust, if desired.

fclen = 0.5
radius = 0.075
self.segments.append(SegmentCircle([0, 0], radius))

Next, add the paths as Segment instances, which are drawn as lines. The flux capacitor will have three paths, all extending from the center dot:

self.segments.append(Segment([[0, 0], [0, -fclen*1.41]]))
self.segments.append(Segment([[0, 0], [fclen, fclen]]))
self.segments.append(Segment([[0, 0], [-fclen, fclen]]))

And at the end of each path is an open circle. Append three more SegmentCircle instances. By specifying fill=None the SegmentCircle will always remain unfilled regardless of any fill arguments provided to Drawing or FluxCapacitor.

self.segments.append(SegmentCircle([0, -fclen*1.41], 0.2, fill=None))
self.segments.append(SegmentCircle([fclen, fclen], 0.2, fill=None))
self.segments.append(SegmentCircle([-fclen, fclen], 0.2, fill=None))

Finally, we need to define anchor points so that other elements can be connected to the right places. Here, they’re called p1, p2, and p3 for lack of better names (what do you call the inputs to a flux capacitor?) Add these to the self.anchors dictionary.

self.anchors['p1'] = [-fclen, fclen]
self.anchors['p2'] = [fclen, fclen]
self.anchors['p3'] = [0, -fclen*1.41]

Here’s the Flux Capacitor class all in one:

class FluxCapacitor(elm.Element):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        radius = 0.075
        fclen = 0.5
        self.segments.append(SegmentCircle([0, 0], radius))
        self.segments.append(Segment([[0, 0], [0, -fclen*1.41]]))
        self.segments.append(Segment([[0, 0], [fclen, fclen]]))
        self.segments.append(Segment([[0, 0], [-fclen, fclen]]))
        self.segments.append(SegmentCircle([0, -fclen*1.41], 0.2, fill=None))
        self.segments.append(SegmentCircle([fclen, fclen], 0.2, fill=None))
        self.segments.append(SegmentCircle([-fclen, fclen], 0.2, fill=None))
        self.anchors['p1'] = [-fclen, fclen]
        self.anchors['p2'] = [fclen, fclen]
        self.anchors['p3'] = [0, -fclen*1.41]

Try it out:

FluxCapacitor()
../_images/customizing_3_0.svg

Segment objects

After an element is added to a drawing, the schemdraw.Segment objects defining it are accessible in the segments attribute list of the Element. For even more control over customizing individual pieces of an element, the parameters of a Segment can be changed.

n = d.add(logic.Nand)
n.segments[1].color = 'red'
n.segments[1].zorder = 5  # Put the bubble on top
d.draw()
../_images/customizing_5_0.svg

Matplotlib axis

As a final customization option, remember that by default schemdraw draws everything on a Matplotlib figure. A schemdraw.Figure is returned from the draw method, which contains fig and ax attributes holding the Matplotlib figure.

d = schemdraw.Drawing()
d.add(elm.Resistor)
schemfig = d.draw()
schemfig.ax.axvline(.5, color='purple', ls='--')
schemfig.ax.axvline(2.5, color='orange', ls='-', lw=3);
display(schemfig)
../_images/customizing_6_0.svg