Commands

reset()

Syntax

reset()

Description

Resets the current transform to its default state (the identity matrix).

Transformations in PlotDevice build up an incremental state. For example, once rotate(90) is called, all subsequent shapes, paths, text, and images are rotated 90 degrees (i.e., the rotation ‘state’ is 90°). If called again – e.g., rotate(30) – the rotation state becomes 120 degrees (90+30).

Once reset() is called, the rotation state becomes 0 degrees (the default rotation) again. Since reset() affects the entire transform state, it will also wipe out any previously applied translations, skews, and scale-factors.

Context Manager

As with the other transform commands, reset() can be used in a with statement to limit its scope to drawing commands within the following block of code.

Tutorial

Example

GCD
font(14), fill(0.2)

rotate(90)
text("one", 30, 80)
text("two", 45, 80)

reset()
text("three", 70, 80)

rotate()

Syntax

rotate(amount) # amount to rotate (in default unit)
rotate(percent=0.5) # 0 ... 1.0
rotate(degrees=180) # 0 ... 360
rotate(radians=pi)  # 0 ... 2*pi (a.k.a. tau)

Description

Rotates all subsequent drawing commands. The rotate() command accepts one parameter to specify the angle (in degrees by default). The angle-unit can be changed by calling geometry() with DEGREES, RADIANS, or PERCENT. Subsequent calls to rotate() will then be interpreted in the chosen units.

Alternatively, a rotation can specify its units explicitly by using a keyword argument. For example, you can use radians to flip the canvas upside down (regardless of the current geometry-unit) wtih:

rotate(radians=tau/2) 

Like other transform operations, the rotate() command works incrementally: if you call rotate(30), and later on call rotate(60), all commands following that second rotate() will be rotated 90° (30+60).

Context Manager

As with the other transform commands, rotate() can be used in a with statement to limit its scope to drawing commands within the indented block of code.

Tutorial

Example

fill(0.2)
rotate(-45)
rect(30, 30, 40, 40)

scale()

Syntax

scale(x, y=None)

Description

Increases, decreases, or streches the size of all subsequent drawing commands. The first parameter sets the horizontal scale and the optional second parameter the vertical scale. You can also call scale() with a single parameter that sets both the horizontal and vertical scale. Scale values are specified as floating-point (decimal) numbers with 1.0 corresponding to 100%.

The scale() command works incrementally: if you call scale(0.5), and later on call scale(0.2), all subsequent drawing commands will be sized to 10% (0.2 of 0.5).

Context Manager

As with the other transform commands, scale() can be used in a with statement to limit its scope to drawing commands within the following block of code.

Tutorial

Example

fill(0.2)
poly(30,30, 20)
scale(0.5)
poly(70,30, 20)

skew()

Syntax

skew(x, y=None)

Description

Slants the direction of all subsequent drawing commands. The first parameter sets the horizontal skew. The second parameter is optional and sets the vertical skew.

Skew values are expressed as angles using the current geometry() unit (DEGREES by default). The skew() command works incrementally: if you call skew(10), and later on call skew(20), all subsequent drawing commands will be skewed by 30° (10+20).

Context Manager

As with the other transform commands, skew() can be used in a with statement to limit its scope to drawing commands within the indented block of code.

Tutorial

Example

fill(0.2)
skew(10.0)
rect(20, 10, 40, 40)

transform()

Syntax

transform(mode)

Set the current transform mode (to CENTER or CORNER)

transform(matrix=[m11, m21, m12, m22, tX, tY])

Overwrite the current transform matrix with a new one

with transform(mode=None, matrix=None):
    ... # drawing & transformation commands

Restore the transformation state at the end of the indented block (and optionally change the transform mode/matrix for the duration)

Description

The mode parameter sets the registration point – the offset for rotate(), scale() and skew() commands. By default, primitives, text, and images rotate around their own centerpoints. But if you call transform() with CORNER as its mode parameter, transformations will be applied relative to canvas’s ‘origin point’ rather than being relative to the objects’ centerpoint origins.

In addition to changing the mode, the transform() command also allows you to overwrite the underlying transformation matrix with a new set of values. Pass a 6-element list or tuple as the matrix argument to update the current transform (see Apple’s docs for all the math-y details). Note that you can omit the mode arg when setting a new matrix if you don’t want the transformation origin to change.

Context Manager

When called as part of a with block, transform() will ensure that any subsequent transformation commands will apply only within the block. At the end of the block, the transformation state will be reset to what it was before the transform() call. This is equivalent to calling push() and pop() at the beginning and end of the block respectively, though transform() will also reset the mode on exit.

with transform(CORNER):
    translate(100,20)
    line(0,0, 40,0)

is equivalent to:

oldmode = CENTER
transform(CORNER)
push()
translate(100,20)
line(0,0, 40,0)
pop()
transform(oldmode)

Returns

a Transform object with the canvas’s ‘current’ state. You can use this object’s apply() method with Points or Beziers to calculate the ‘screen coordinates’ that would result from drawing with the current transformation state.

Tutorial

Examples

fill(0.2)
fontsize(14)
rotate(90)
text("one", 40, 80)

with transform():
    rotate(-90)
    text("two", 40, 40)

text("three", 50, 80)

translate()

Syntax

translate(x, y)

Description

Shifts the origin used when interpreting drawing commands’ coordinates. The first parameter sets the horizontal offset, the second parameter the vertical offset. Translating is the same as dragging something across the screen. Or the same as moving the canvas registration point, which is situated in the upper left corner by default.

After calling translate(), all subsequent drawing commands are shifted by the specified offsets. This can be useful when positioning groups of multiple elements.

Context Manager

As with the other transform commands, translate() can be used in a with statement to limit its scope to drawing commands within the following block of code.

Tutorial

Example

fill(0.2)
arc(10,10, 20)
translate(50, 50)
arc(10,10, 20)

Objects

Point

Syntax

Point(x, y)

Description

A pair of x & y coordinates wrapped into a single value. You can access its properties by name in addition to using the object as a ‘normal’ tuple. Point objects support basic arithmetic and provide utility methods for geometry calculations.

PlotDevice commands that take separate x & y arguments (e.g., poly(), arc(), text()) will typically also accept a Point object in their place.

Properties

pt.x
pt.y

Methods

pt.angle(point)

Returns the angle from the object to a target Point or pair of (x,y) coordinates. By default, the angle will be represented in degrees, but this can be altered by setting an alternate unit with the geometry() command.

src = Point(25,75)
dst = Point(75,25)
theta = src.angle(dst)
arc(src, 4, fill='red')
arc(dst, 4, fill='orange')
with pen(dash=5), stroke(.5), nofill():
    arc(src, 32, range=theta)
print(theta)
>>> -45.0
pt.distance(point)

Returns the linear distance between the object and a second Point or pair of (x,y) coordinates.

src = Point(25,25)
dst = Point(100,100)
length = src.distance(dst)
arc(src, 4, fill='red')
arc(dst, 4, fill='orange')
with pen(dash=5), stroke(.8):
    line(src, dst)
print(length)
>>> 106.066017178
pt.reflect(point, d=1.0, a=180)

Uses the object as an ‘origin’ and returns a Point containing the reflection of a target Point or pair of (x,y) coordinates. The optional d parameter is a magnification factor relative to the distance between the mirror and the target point.

The a parameter controls the angle of reflection. When set to 180° (the default), the reflected point will be directly opposite the target, but other values will allow you to ‘ricochet’ the target point off of the mirror instead.

origin = Point(50,50)
src = Point(25,40)
dst = origin.reflect(src, d=2.0)
arc(src, 4, fill='red')
arc(dst, 4, fill='orange')
arc(origin, 4, fill=.7)
pt.coordinates(distance, angle)

Uses the object as the ‘origin’ of a polar coordinate system and returns a Point at a given distance and orientation relative to the origin. The distance parameter uses the current canvas size() unit and the angle should be expressed in the current geometry() unit.

origin = Point(50,50)
dst = origin.coordinates(50, 45)
arc(origin, 4, fill=.7)
arc(dst, 4, fill='orange')
with pen(dash=3), stroke(.5), nofill():
    arc(origin, 25, range=45)

If you’d prefer to work with raw numbers rather than Point objects, you can also import the numerical versions of these methods for use in your scripts:

from plotdevice.lib.pathmatics import angle, distance, coordinates, reflect

Tutorial

Geometry

Region

Syntax

Region(x, y, w, h)
Region(Point, Size)

Description

An origin Point and a Size which together describe a rectangular region. Region objects have properties to read and modify the rectangle geometry. Methods allow you to generate new regions from combinations of old ones or by systematically shifting their values.

PlotDevice commands that take x/y/w/h arguments (e.g., rect(), oval(), image()) will also accept a Region object in their place.

Geometry Properties

r.x, r.y # position
r.w, r.h # dimensions
r.origin # Point(r.x, r.y)
r.size   # Size(r.w, r.h)

Convenience Properties

r.top, r.bottom, r.left, r.right # edge positions
r.w/h/t/b/l/r # shorthand aliases

Methods

r.intersect(region)

return a new Region describing the overlapping portions of the existing Region object and a second Region

r1 = Region(20,20, 40,30)
r2 = Region(40,40, 30,40)
overlap = r1.intersect(r2)
with nofill(), stroke(.7):
    rect(r1)
    rect(r2)
    rect(overlap, stroke='red', dash=3)
r.union(region)

return a new Region that contains the combined bounds of the existing Region object and a second Region

r1 = Region(20,20, 40,30)
r2 = Region(40,40, 30,40)
union = r1.union(r2)
with nofill(), stroke(.7):
    rect(r1)
    rect(r2)
    rect(union, stroke='red', dash=3)
r.shift(point)

return a copy of the Region with its origin shifted by a Point

r = Region(20,20, 40,30)
shifted = r.shift(20,15)
nofill()
rect(r, stroke=.7)
rect(shifted, stroke='red', dash=3)
r.inset(dx, dy)

return a copy of the Region whose horizontal dimensions have been shrunk by dx and vertical by dy. If dy is omitted, shrink both dimensions by dx. Passing a negative value for dx or dy will enlarge the dimension rather than shrinking it.

r = Region(30,40, 60,40)
shrunk = r.inset(20,5)
grown = r.inset(-20)
nofill()
rect(r, stroke=.7)
rect(shrunk, stroke='orange', dash=3)
rect(grown, stroke='red', dash=3)

Tutorial

Geometry

Size

Syntax

Size(width, height)

Description

A pair of width & height values wrapped into a single object. Size objects are very similar to Points and arithmetic between the two types is supported.

Properties

s.width
s.height
s.w, s.h # shorthand aliases

Tutorial

Geometry

Transform

Syntax

Transform()

Description

A local transformation state (independent of the global, canvas transform). You can use Transform objects to apply translation, rotation, scaling and skewing to a path before drawing it.

Methods

t.translate(x=0, y=0)
t.rotate(degrees=0, radians=0)
t.scale(x=1, y=None)
t.skew(x=0, y=0)
t.invert()
t.append(t)
t.prepend(t)
t.apply(path_or_point)
t.copy()

See the tutorial on paths to learn more about the methods.

The apply() method returns a new Bezier or Point with the defined transformations applied to it.

Legacy Commands

push() & pop()

Syntax

push()
pop()

Description

PlotDevice is a so-called state-machine in which certain types of modifications are cumulative. For example, once rotate(45) is called, all subsequent shapes, paths, text and images are rotated 45 degrees – the rotation ‘state’ has been set to 45°.

All transformations, such as rotate() and skew(), defined between a push() and pop() call last only until pop() is called. Thereafter the previous state is used. For example, a rotate(-30) within a rotate(45) means a rotation state of 15° until pop() is called and the rotation state becomes 45 degrees again.

PlotDevice Equivalent

While push() & pop() allow your script to save and restore the state manually (and leave it up to you to ensure that a call to one is balanced by a call to the other). The transform() command provides a context manager to limit the scope of these state changes to an indented block of code.

Tutorial

Example

fill(0.2)
fontsize(14)
rotate(90)
text("one", 40, 80)

push()
rotate(-90)
text("two", 40, 40)
pop()

text("three", 50, 80)