Shapes¶
Rect¶
Rect draws a filled rectangle. Set its size with .size(width, height), fill color with
.color(), and position with .xy(x, y). By default the rect has zero size and is placed
according to the parent's layout (centered for the default layout).
Output image
Stroke¶
Add an outline with .stroke_color() and .stroke_width(). Setting a fill color to None
gives a hollow shape.
Output image
Positioning¶
See Positioning for .xy(), .align_x(), .align_y(), and .move().
Ellipse¶
Ellipse draws an ellipse. When width == height it becomes a circle. Its API is identical
to Rect.
Output image
with Scene():
Ellipse().size(80, 80).color("orchid").xy(30, 60)
Ellipse().size(80, 40).color("gold").xy(130, 80)
Ellipse().size(40, 80).color("steelblue").xy(220, 60)
Output image
Path¶
Path draws an arbitrary vector shape from a sequence of commands. Use .stroke_color() to
set the line color and .stroke_width() for line thickness. Like Rect, it can also be
filled with .color().
Line segments¶
with Scene():
p = Path()
p.stroke_color("darkslateblue").stroke_width(3).color("lavender")
p.move_to().xy(30, 100)
p.line_to().xy(150, 40)
p.line_to().xy(270, 100)
p.line_to().xy(150, 160)
p.close()
Output image
Cubic Bézier curves¶
.cubic_to() appends a cubic Bézier segment. Use .c1_xy(dx, dy) and .c2_xy(dx, dy) to
set the two control point offsets (relative to the segment start and end respectively).
with Scene():
p = Path()
p.stroke_color("darkorange").stroke_width(3)
p.move_to().xy(40, 150)
p.cubic_to().xy(260, 150).c1_xy(60, -130).c2_xy(-60, -130)
Output image
Arrows¶
.triangle_arrow() adds a filled arrowhead at the end of a path. Pass "start" to place it
at the beginning instead. The arrowhead is automatically sized to match the stroke width.
with Scene():
p = Path()
p.stroke_color("steelblue").stroke_width(3)
p.move_to().xy(40, 100)
p.line_to().xy(260, 100)
p.triangle_arrow()
p.triangle_arrow("start").color("tomato")
Output image
The arrowhead inherits the path's stroke color by default. Call .color() on the returned arrow object to override it independently — as shown above with the red start arrow.
The arrowhead scales automatically with stroke width. Pass length and width to triangle_arrow() to override the size explicitly — length is the tip-to-base distance, width is the base width (both default to 3 × stroke_width):
with Scene():
# top: automatic size (stroke_width=8 → arrow 24×24)
p = Path()
p.stroke_color("steelblue").stroke_width(8)
p.move_to().xy(40, 60)
p.line_to().xy(250, 60)
p.triangle_arrow()
# bottom: same stroke but arrow manually set to length=40, width=20
q = Path()
q.stroke_color("steelblue").stroke_width(8)
q.move_to().xy(40, 140)
q.line_to().xy(250, 140)
q.triangle_arrow(length=40, width=20)
Output image
Path cropping¶
crop_start and crop_end trim the path from either end. Values are in [0.0, 1.0] where
0.0 is the full extent. This is mainly used to animate paths drawing themselves in.
with Scene():
p = Path()
p.stroke_color("mediumseagreen").stroke_width(4)
p.move_to().xy(30, 100)
p.cubic_to().xy(150, 40).c1_xy(50, -60).c2_xy(-50, -60)
p.cubic_to().xy(270, 100).c1_xy(50, 60).c2_xy(-50, 60)
p.crop_end(0.5)
Output image