Cetz Manual
Cetz Manual
Zeichenpaket
Johannes Wolf
fenjalien
Version 0.2.2
1 Introduction ........................................................... 4 3.6.4 on-yz ..................................................... 33
2 Usage ....................................................................... 4 4 Coordinate Systems ........................................... 34
2.1 CeTZ Unique Argument Types .................. 4 4.1 XYZ ................................................................. 34
2.2 Anchors ............................................................ 4 4.2 Previous ......................................................... 34
2.2.1 Named ..................................................... 5 4.3 Relative ........................................................... 35
2.2.2 Border ..................................................... 5 4.4 Polar ................................................................ 35
2.2.3 Path .......................................................... 5 4.5 Barycentric .................................................... 35
3 Draw Function Reference ................................... 6 4.6 Anchor ........................................................... 36
3.1 Canvas .............................................................. 6 4.7 Tangent .......................................................... 37
3.1.1 canvas ..................................................... 6 4.8 Perpendicular ............................................... 37
3.2 Styling .............................................................. 6 4.9 Interpolation ................................................. 38
3.2.1 Marks ...................................................... 7 4.10 Function ....................................................... 39
3.3 Shapes ............................................................. 11 5 Libraries ............................................................... 40
3.3.1 circle ...................................................... 11 5.1 Tree ................................................................. 40
3.3.2 circle-through ..................................... 11 5.1.1 tree ......................................................... 40
3.3.3 arc .......................................................... 12 5.2 Plot .................................................................. 41
3.3.4 arc-through .......................................... 13 5.2.1 Types ..................................................... 41
3.3.5 mark ...................................................... 14 5.2.2 plot ......................................................... 42
3.3.6 line ......................................................... 15 5.2.3 add-anchor ........................................... 45
3.3.7 grid ........................................................ 15 5.2.4 Legends ................................................. 46
3.3.8 content .................................................. 16 5.2.5 add ......................................................... 47
3.3.9 rect ......................................................... 17 5.2.6 add-hline .............................................. 50
3.3.10 bezier ................................................... 18 5.2.7 add-vline ............................................... 50
3.3.11 bezier-through .................................. 19 5.2.8 add-fill-between .................................. 51
3.3.12 catmull ................................................ 20 5.2.9 add-contour ......................................... 52
3.3.13 hobby .................................................. 21 5.2.10 add-boxwhisker ................................ 54
3.3.14 merge-path ........................................ 22 5.2.11 add-bar ................................................ 55
3.4 Grouping ........................................................ 23 5.2.12 annotate .............................................. 56
3.4.1 hide ........................................................ 23 5.2.13 sample-fn ........................................... 56
3.4.2 intersections ........................................ 23 5.2.14 sample-fn2 ......................................... 57
3.4.3 group ..................................................... 24 5.2.15 Examples ............................................ 57
3.4.4 anchor ................................................... 25 5.2.16 Styling ................................................. 58
3.4.5 copy-anchors ....................................... 25 5.2.17 default-style ....................................... 58
3.4.6 set-ctx .................................................... 26 5.3 Chart ............................................................... 61
3.4.7 get-ctx ................................................... 26 5.3.1 barchart ................................................ 61
3.4.8 for-each-anchor .................................. 27 5.3.2 columnchart ........................................ 63
3.4.9 on-layer ................................................ 27 5.3.3 piechart ................................................. 64
3.5 Transformations ........................................... 29 5.3.4 boxwhisker .......................................... 67
3.5.1 set-transform ....................................... 29 5.3.5 Examples – Bar Chart ....................... 68
3.5.2 rotate ..................................................... 29 5.3.6 Examples – Column Chart ............... 68
3.5.3 translate ................................................ 29 5.3.7 Styling ................................................... 69
3.5.4 scale ....................................................... 30 5.4 Palette ............................................................. 70
3.5.5 set-origin .............................................. 30 5.4.1 new ........................................................ 70
3.5.6 move-to ................................................. 31 5.4.2 List of predefined palettes ................ 70
3.5.7 set-viewport ........................................ 31 5.5 Angle .............................................................. 71
3.6 Projection ...................................................... 31 5.5.1 angle ...................................................... 71
3.6.1 ortho ...................................................... 31 5.5.2 right-angle ........................................... 72
3.6.2 on-xy ..................................................... 32 5.6 Decorations ................................................... 73
3.6.3 on-xz ...................................................... 33 5.6.1 Braces .................................................... 73
5.6.2 brace ...................................................... 73
5.6.3 flat-brace .............................................. 74
5.6.4 Path Decorations ................................ 76
5.6.5 zigzag .................................................... 76
5.6.6 coil ......................................................... 77
5.6.7 wave ...................................................... 78
6 Advanced Functions .......................................... 79
6.1 Coordinate ..................................................... 79
6.1.1 resolve ................................................... 79
6.2 Styles .............................................................. 79
6.2.1 resolve ................................................... 79
6.2.2 Default Style ........................................ 81
7 Creating Custom Elements .............................. 82
8 Internals ............................................................... 82
8.1 Context ........................................................... 82
8.2 Elements ........................................................ 82
CeTZ
1 Introduction
This package provides a way to draw onto a canvas using a similar API to Processing but with relative
coordinates and anchors from TikZ. You also won’t have to worry about accidentally drawing over
other content as the canvas will automatically resize. And remember: up is positive!
The name CeTZ is a recursive acronym for “CeTZ, ein Typst Zeichenpaket” (german for “CeTZ, a Typst
drawing package”).
2 Usage
This is the minimal starting point:
#import "@preview/cetz:0.2.2"
#cetz.canvas({
import cetz.draw: *
...
})
Note that draw functions are imported inside the scope of the canvas block. This is recommended as
some draw functions override Typst’s function’s such as line.
2.2 Anchors
You can refer to a position relative to an element by using its anchors. Anchors come in several differ-
ent variations but can all be used in two different ways.
The first is by using the anchor argument on an element. When given, the element will be translated
such that the given anchor will be where the given position is. This is supported by all elements that
have the anchor argument.
The second is by using anchor coordinates. You must first give the element a name by passing a string
to its name argument, you can then use its anchors to place other elements, see Section 4.6 for more
usage. Note this is only available for elements that have a name argument.
4/83
CeTZ
Note that all anchors are transformed along with the element.
2.2.1 Named
Named anchors are normally unique to the type of element, such as a bezier curve’s control points.
Other anchor variants specify their own named anchors that are available to all elements that support
the anchor variant.
All elements also have a “default” named anchor, it always refers to another anchor on the element.
2.2.2 Border
A border anchor refers to a point on the element’s border where a ray is cast from the element’s center
at a given angle and hits the border.
They are given as angles where 0deg is towards the right and 90deg is up.
Border anchors also specify named compass directions such as “north”, “north-east”, etc. Border an-
chors also spefcify a “center” named anchor which is where the ray cast originates from.
North
160deg
0deg
2.2.3 Path
A path anchor refers to a point along the path of an element. They can be given as either a number for
an absolute distance along the path, or a ratio for a relative distance along the path.
Path anchors also specify three anchors “start”, “mid” and “end”.
100%, "end"
75%
50%, "mid"
50pt
0%, 0, "start"
5/83
CeTZ
Parameters
canvas(
length: length ratio ,
debug: bool ,
background: none color ,
body: none array element
) -> content
3.2 Styling
You can style draw elements by passing the relevant named arguments to their draw functions. All
elements that draw something have stroke and fill styling unless said otherwise.
fill: color or none Default: none
How to fill the drawn element.
stroke: none or auto or length or color or dictionary or stroke Default: 1pt + luma(0%)
How to stroke the border or the path of the draw element. See Typst’s line documentation for more
details: https://typst.app/docs/reference/visualize/line/#parameters-stroke
Instead of having to specify the same styling for each time you want to draw an element, you can
use the set-style() function to change the style for all elements after it. You can still pass styling
to a draw function to override what has been set with set-style(). You can also use the fill() and
stroke() functions as a shorthand to set the fill and stroke respectively.
6/83
CeTZ
// Sets the global style to have a fill of red and a stroke of blue
set-style(stroke: blue, fill: red)
circle((0,0))
When using a dictionary for a style, it is important to note that they update each other instead of
overriding the entire option like a non-dictionary value would do. For example, if the stroke is set to
(paint: red, thickness: 5pt) and you pass (paint: blue), the stroke would become (paint:
blue, thickness: 5pt).
You can also specify styling for each type of element. Note that dictionary values will still update with
its global value, the full hierarchy is function > element type > global. When the value of a style
is auto, it will become exactly its parent style.
set-style(
// Global fill and stroke
fill: green,
stroke: (thickness: 5pt),
// Stroke and fill for only rectangles
rect: (stroke: (dash: "dashed"), fill: blue),
)
rect((0,0), (1,1))
circle((0.5, -1.5))
rect((0,-3), (1, -4), stroke: (thickness: 1pt))
3.2.1 Marks
Marks are arrow tips that can be added to the end of path based elements that support the mark style
key, or can be directly drawn by using the mark draw function. Marks are specified by giving there
7/83
CeTZ
names as strings and have several options to customise them. You can give an array of names to have
multiple marks in a row, dictionaries can also be used in the array for per mark styling.
let c = ((rel: (0, -1)), (rel: (2, 0), update: false)) // Coordinates to draw the line, it
is not necessary to understand this for this example.
// No marks
line((), (rel: (1, 0), update: false))
// Draws a triangle mark at both ends of the line.
set-style(mark: (symbol: ">"))
line(..c)
// Overrides the end mark to be a diamond but the start is still a triangle.
set-style(mark: (end: "<>"))
line(..c)
// Draws two triangle marks at both ends but the first mark of end is still a diamond.
set-style(mark: (symbol: (">", ">")))
line(..c)
// Sets the stroke of first mark in the sequence to red but the end mark overrides it to
be blue.
set-style(mark: (symbol: ((symbol: ">", stroke: red), ">"), end: (stroke: blue)))
line(..c)
8/83
CeTZ
9/83
CeTZ
Which mark to shorten the path to when multiple marks are given. auto will shorten to the last
mark, none will shorten to the first mark (effectively disabling path shortening). An integer can be
given to select the mark’s index.
transform-shape: bool Default: true
When false marks will not be streched/affected by the current transformation, marks will be placed
after the path is transformed.
10/83
CeTZ
3.3 Shapes
3.3.1 circle
Draws a circle or ellipse.
circle((0,0))
// Draws an ellipse
circle((0,-2), radius: (0.75, 0.5))
Parameters
circle(
position: coordinate ,
name: none string ,
anchor: none string ,
..style: style
)
position: coordinate
The position to place the circle on.
Styling
Root: circle
Keys
radius: number or array Default: 1
A number that defines the size of the circle’s radius. Can also be set to a tuple of two numbers to
define the radii of an ellipse, the first number is the x radius and the second is the y radius.
Anchors
Supports border and path anchors. The “center” anchor is the default.
3.3.2 circle-through
Draws a circle through three coordinates.
11/83
CeTZ
Parameters
circle-through(
a: coordinate ,
b: coordinate ,
c: coordinate ,
name: none string ,
anchor: none string ,
..style: style
)
a: coordinate
Coordinate a.
b: coordinate
Coordinate b.
c: coordinate
Coordinate c.
Styling
Root: circle
circle-through has the same styling as circle() except for radius as the circle’s radius is calculated
by the given coordinates.
Anchors
Supports the same anchors as circle as well as:
a Coordinate a
b Coordinate b
c Coordinate c
3.3.3 arc
Draws a circular segment.
Note that two of the three angle arguments (start, stop and delta) must be set. The current position
() gets updated to the arc’s end coordinate (anchor arc-end).
Parameters
arc(
position: coordinate ,
start: auto angle ,
stop: auto angle ,
delta: auto angle ,
name: none string ,
anchor: none string ,
..style: style
)
12/83
CeTZ
position: coordinate
Position to place the arc at.
start: auto or angle Default: auto
The angle at which the arc should start. Remember that 0deg points directly towards the right and
90deg points up.
Styling
Root: arc
Keys
radius: number or array Default: 1
The radius of the arc. An elliptical arc can be created by passing a tuple of numbers where the first
element is the x radius and the second element is the y radius.
mode: string Default: "OPEN"
The options are: “OPEN” no additional lines are drawn so just the arc is shown; “CLOSE” a line is
drawn from the start to the end of the arc creating a circular segment; “PIE” lines are drawn from
the start and end of the arc to the origin creating a circular sector.
update-position: bool Default: true
Update the current canvas position to the arc’s end point (anchor "arc-end"). This overrides the
default of true, that allows chaining of (arc) elements.
Anchors
Supports border and path anchors.
arc-start The position at which the arc’s curve starts, this is the default.
arc-end The position of the arc’s curve end.
arc-center The midpoint of the arc’s curve.
center The center of the arc, this position changes depending on if the arc is closed or not.
chord-center Center of chord of the arc drawn between the start and end point.
origin The origin of the arc’s circle.
3.3.4 arc-through
Draws an arc that passes through three points a, b and c.
Note that all three points must not lie on a straight line, otherwise the function fails.
13/83
CeTZ
Parameters
arc-through(
a: coordinate ,
b: coordinate ,
c: coordinate ,
name: none string ,
..style: style
)
a: coordinate
Start position of the arc
b: coordinate
Position the arc passes through
c: coordinate
End position of the arc
Styling
Root: arc
Uses the same styling as arc()
Anchors
For anchors see arc().
3.3.5 mark
Draws a single mark pointing towards a target coordinate.
Parameters
mark(
from: coordinate ,
to: coordinate ,
..style: style
)
from: coordinate
The position to place the mark.
to: coordinate
The position the mark should point towards.
Styling
Root: mark
You can directly use the styling from Section 3.2.1.
14/83
CeTZ
3.3.6 line
Draws a line, more than two points can be given to create a line-strip.
If the first or last coordinates are given as the name of an element, that has a "default" anchor, the
intersection of that element’s border and a line from the first or last two coordinates given is used as
coordinate. This is useful to span a line between the borders of two elements.
Parameters
line(
..pts-style: coordinates style ,
close: bool ,
name: none string
)
Styling
Root: line
Supports mark styling.
Anchors
Supports path anchors.
3.3.7 grid
Draws a grid between two coordinates
// Draw a grid
grid((0,0), (2,2))
15/83
CeTZ
Parameters
grid(
from: coordinate ,
to: coordinate ,
name: none string ,
..style: style
)
from: coordinate
The top left of the grid
to: coordinate
The bottom right of the grid
Styling
Root: grid
Keys
step: number or tuple or dictionary Default: 1
Distance between grid lines. A distance of 1 means to draw a grid line every 1 length units in x- and
y-direction. If given a dictionary with x and y keys or a tuple, the step is set per axis.
help-lines: bool Default: 1
If true, force the stroke style to gray + 0.2pt
Anchors
Supports border anchors.
3.3.8 content
Positions Typst content in the canvas. Note that the content itself is not transformed only its position
is.
To put text on a line you can let the function calculate the angle between its position and a second
coordinate by passing it to angle:
16/83
CeTZ
Parameters
content(
..args-style: coordinate content style ,
angle: angle coordinate ,
anchor: none string ,
name: none string
)
Styling
Root: content
Keys
padding: number or dictionary Default: 0
Sets the spacing around content. Can be a single number to set padding on all sides or a dictionary
to specify each side specifically. The dictionary follows Typst’s pad function: https://typst.app/docs/
reference/layout/pad/
frame: string or none Default: none
Sets the frame style. Can be none, “rect” or “circle” and inherits the stroke and fill style.
Anchors
Supports border anchors.
3.3.9 rect
Draws a rectangle between two coordinates.
rect((0,0), (1,1))
rect((-.5, -.5), (rel: (2, 2)),
radius: (north-east: (100%, .5),
south-west: (100%, .5), rest: .2),
stroke: red)
rect((-1, -1), (rel: (3, 3)), radius: .5, stroke: blue)
17/83
CeTZ
Parameters
rect(
a: coordinate ,
b: coordinate ,
name: none string ,
anchor: none string ,
..style: style
)
a: coordinate
Coordinate of the bottom left corner of the rectangle.
b: coordinate
Coordinate of the top right corner of the rectangle. You can draw a rectangle with a specified width
and height by using relative coordinates for this parameter (rel: (width, height)).
Styling
Root rect
Keys
radius: number or ratio or dictionary Default: 0
The rectangles corner radius. If set to a single number, that radius is applied to all four corners of the
rectangle. If passed a dictionary you can set the radii per corner. The following keys support either
a number, ratio or an array of number, ratio for specifying a different x- and y-radius: north,
east, south, west, north-west, north-east, south-west and south-east. To set a default value for
remaining corners, the rest key can be used.
Ratio values are relative to the rects width/height.
Anchors
Supports border and path anchors.
3.3.10 bezier
Draws a quadratic or cubic bezier curve
18/83
CeTZ
let (a, b, c, d) = ((0, -1), (2, -1), (.5, -2), (1.5, 0))
line(a, c, d, b, stroke: gray)
bezier(a, b, c, d)
Parameters
bezier(
start: coordinate ,
end: coordinate ,
..ctrl-style: coordinate style ,
name: none string
)
start: coordinate
Start position
end: coordinate
End position (last coordinate)
..ctrl-style: coordinate or style
The first two positional arguments are taken as cubic bezier control points, where the first is the
start control point and the second is the end control point. One control point can be given for a
quadratic bezier curve instead. Named arguments are for styling.
Styling
Root bezier
Supports marks.
Anchors
Supports path anchors.
ctrl-n nth control point where n is an integer starting at 0
3.3.11 bezier-through
Draws a cubic bezier curve through a set of three points. See bezier for style and anchor details.
19/83
CeTZ
Parameters
bezier-through(
start: coordinate ,
pass-through: coordinate ,
end: coordinate ,
name: none string ,
..style: style
)
start: coordinate
The position to start the curve.
pass-through: coordinate
The position to pass the curve through.
end: coordinate
The position to end the curve.
3.3.12 catmull
Draws a Catmull-Rom curve through a set of points.
Parameters
catmull(
..pts-style: coordinate style ,
close: bool ,
name: none string
)
Styling
Root catmull
Supports marks.
Keys
tension: float Default: 0.5
How tight the curve should fit to the points. The higher the tension the less curvy the curve.
Anchors
Supports path anchors.
20/83
CeTZ
3.3.13 hobby
Draws a Hobby curve through a set of points.
hobby((0, 0), (1, 1), (2, -1), (3, 0), omega: 0, stroke: blue)
hobby((0, 0), (1, 1), (2, -1), (3, 0), omega: 1, stroke: red)
Parameters
hobby(
..pts-style: coordinate style ,
ta: auto array ,
tb: auto array ,
close: bool ,
name: none string
)
Styling
Root hobby
Supports marks.
Keys
omega: tuple of float Default: (1, 1)
How curly the curve should be at each endpoint. When the curl is close to zero, the spline approaches
a straight line near the endpoints. When the curl is close to one, it approaches a circular arc.
Anchors
Supports path anchors.
pt-n The nth given position (0 indexed, so “pt-0” is equal to “start”)
21/83
CeTZ
3.3.14 merge-path
Merges two or more paths by concattenating their elements. Anchors and visual styling, such as stroke
and fill, are not preserved. When an element’s path does not start at the same position the previous
element’s path ended, a straight line is drawn between them so that the final path is continuous. You
must then pay attention to the direction in which element paths are drawn.
merge-path(fill: white, {
line((0, 0), (1, 0))
bezier((), (0, 0), (1,1), (0,1))
})
body: elements
Elements with paths to be merged together.
close: bool Default: false
Close the path with a straight line from the start of the path to its end.
Anchors
Supports path anchors.
22/83
CeTZ
3.4 Grouping
3.4.1 hide
Hides an element.
Hidden elements are not drawn to the canvas, are ignored when calculating bounding boxes and dis-
carded by merge-path. All other behaviours remain the same as a non-hidden element.
set-style(radius: .5)
intersections("i", {
circle((0,0), name: "a")
circle((1,2), name: "b")
// Use a hidden line to find the border intersections
hide(line("a.center", "b.center"))
})
line("i.0", "i.1")
Parameters
hide(
body: element ,
bounds: bool
)
body: element
One or more elements to hide
bounds: bool Default: false
If true, respect the bounding box of the hidden elements for resizing the canvas
3.4.2 intersections
Calculates the intersections between multiple paths and creates one anchor per intersection point.
All resulting anchors will be named numerically, starting at 0. i.e., a call intersections("a", ...)
will generate the anchors "a.0", "a.1", "a.2" to "a.n", depending of the number of intersections.
intersections("i", {
circle((0, 0))
bezier((0,0), (3,0), (1,-1), (2,1))
line((0,-1), (0,1))
rect((1.5,-1),(2.5,1))
})
for-each-anchor("i", (name) => {
circle("i." + name, radius: .1, fill: blue)
})
23/83
CeTZ
name: string
Name to prepend to the generated anchors. (Not to be confused with other name arguments that
allow the use of anchor coordinates.)
..elements: elements or string
Elements and/or element names to calculate intersections with. Elements referred to by name are
(unlike elements passed) not drawn by the intersections function!
samples: int Default: 10
Number of samples to use for non-linear path segments. A higher sample count can give more pre-
cise results but worse performance.
3.4.3 group
Groups one or more elements together. This element acts as a scope, all state changes such as trans-
formations and styling only affect the elements in the group. Elements after the group are not affected
by the changes inside the group.
// Create group
group({
stroke(5pt)
scale(.5); rotate(45deg)
rect((-1,-1),(1,1))
})
rect((-1,-1),(1,1))
Parameters
group(
body: elements function ,
name: none string ,
anchor: none string ,
..style: style
)
Styling
Root group
24/83
CeTZ
Keys
padding: none or number or array or dictionary Default: none
How much padding to add around the group’s bounding box. none applies no padding. A number
applies padding to all sides equally. A dictionary applies padding following Typst’s pad function:
https://typst.app/docs/reference/layout/pad/. An array follows CSS like padding: (y, x), (top, x,
bottom) or (top, right, bottom, left).
Anchors
Supports border and path anchors. However they are created based on the axis aligned bounding box
of all the child elements of the group.
You can add custom anchors to the group by using the anchor element while in the scope of said group,
see anchor for more details. You can also copy over anchors from named child element by using the
copy-anchors element as they are not accessible from outside the group.
The default anchor is “center” but this can be overridden by using anchor to place a new anchor called
“default”.
Named elements within a group can also be accessed as string anchors, see Section 4.6.
3.4.4 anchor
Creates a new anchor for the current group. This element can only be used inside a group otherwise
it will panic. The new anchor will be accessible from inside the group by using just the anchor’s name
as a coordinate.
// Create group
group(name: "g", {
circle((0,0))
anchor("x", (.4, .1))
circle("x", radius: .2)
})
circle("g.x", radius: .1)
Parameters
anchor(
name: string ,
position: coordinate
)
name: string
The name of the anchor
position: coordinate
The position of the anchor
3.4.5 copy-anchors
Copies multiple anchors from one element into the current group. Panics when used outside of a group.
Copied anchors will be accessible in the same way anchors created by the anchor element are.
25/83
CeTZ
Parameters
copy-anchors(
element: string ,
filter: auto array
)
element: string
The name of the element to copy anchors from.
filter: auto or array Default: auto
When set to auto all anchors will be copied to the group. An array of anchor names can instead be
given so only the anchors that are in the element and the list will be copied over.
3.4.6 set-ctx
An advanced element that allows you to modify the current canvas context.
A context object holds the canvas’ state, such as the element dictionary, the current transformation
matrix, group and canvas unit length. The following fields are considered stable:
• length (length): Length of one canvas unit as typst length
• transform (cetz.matrix): Current 4x4 transformation matrix
• debug (bool): True if the canvas’ debug flag is set
Parameters
set-ctx(callback: function )
callback: function
A function that accepts the context dictionary and only returns a new one.
3.4.7 get-ctx
An advanced element that allows you to read the current canvas context through a callback and return
elements based on it.
26/83
CeTZ
Parameters
get-ctx(callback: function )
callback: function
A function that accepts the context dictionary and can return elements.
3.4.8 for-each-anchor
Iterates through all named anchors of an element and calls a callback for each one.
Parameters
for-each-anchor(
name: string ,
callback: function ,
exclude: array
)
name: string
The name of the element with the anchors to loop through.
callback: function
A function that takes the anchor name and can return elements.
exclude: array Default: ()
An array of anchor names to not include in the loop.
3.4.9 on-layer
Places elements on a specific layer.
A layer determines the position of an element in the draw queue. A lower layer is drawn before a
higher layer.
Layers can be used to draw behind or in front of other elements, even if the other elements were cre-
ated before or after. An example would be drawing a background behind a text, but using the text’s
calculated bounding box for positioning the background.
27/83
CeTZ
Parameters
on-layer(
layer: float integer ,
body: elements function
)
28/83
CeTZ
3.5 Transformations
All transformation functions push a transformation matrix onto the current transform stack. To apply
transformations scoped use a group(...) object.
Transformation matrices get multiplied in the following order:
𝑀world = 𝑀world ⋅ 𝑀local
3.5.1 set-transform
Sets the transformation matrix.
Parameters
set-transform(mat: none matrix )
3.5.2 rotate
Rotates the transformation matrix on the z-axis by a given angle or other axes when specified.
// Rotate on z-axis
rotate(z: 45deg)
rect((-1,-1), (1,1))
// Rotate on y-axis
rotate(y: 80deg)
circle((0,0))
Parameters
rotate(
..angles: angle ,
origin: none coordinate
)
..angles: angle
A single angle as a positional argument to rotate on the z-axis by. Named arguments of x, y or z can
be given to rotate on their respective axis. You can give named arguments of yaw, pitch or roll, too.
origin: none or coordinate Default: none
Origin to rotate around, or (0, 0, 0) if set to none.
3.5.3 translate
Translates the transformation matrix by the given vector or dictionary.
// Outer rect
rect((0, 0), (2, 2))
// Inner rect
translate(x: .5, y: .5)
rect((0, 0), (1, 1))
29/83
CeTZ
Parameters
translate(
..args: vector float length ,
pre: bool
)
3.5.4 scale
Scales the transformation matrix by the given factor(s).
Parameters
scale(
..args: float ratio ,
origin: none coordinate
)
3.5.5 set-origin
Sets the given position as the new origin (0, 0, 0)
// Outer rect
rect((0,0), (2,2), name: "r")
// Move origin to top edge
set-origin("r.north")
circle((0, 0), radius: .1)
Parameters
set-origin(origin: coordinate )
origin: coordinate
30/83
CeTZ
3.5.6 move-to
Sets the previous coordinate.
The previous coordinate can be used via () (empty coordinate). It is also used as base for relative co-
ordinates if not specified otherwise.
Parameters
move-to(pt: coordinate )
pt: coordinate
The coordinate to move to.
3.5.7 set-viewport
Span viewport between two coordinates and set-up scaling and translation
rect((0,0), (2,2))
set-viewport((0,0), (2,2), bounds: (10, 10))
circle((5,5))
Parameters
set-viewport(
from: coordinate ,
to: coordinate ,
bounds: vector
)
from: coordinate
Bottom-Left corner coordinate
to: coordinate
Top right corner coordinate
bounds: vector Default: (1, 1, 1)
Viewport bounds vector that describes the inner width, height and depth of the viewport
3.6 Projection
3.6.1 ortho
Set-up an orthographic projection environment.
This is a transformation matrix that rotates elements around the x, the y and the z axis by the parame-
ters given.
31/83
CeTZ
ortho({
on-xz({
rect((-1,-1), (1,1))
})
})
Parameters
ortho(
x: angle ,
y: angle ,
z: angle ,
reset-transform: bool ,
body: element ,
name
)
3.6.2 on-xy
Draw elements on the xy-plane with optional z value.
𝑥
All vertices of all elements will be changed in the following way: ( 𝑦 ), where 𝑧argument is the z-
𝑧argument
on-xy({
rect((-1, -1), (1, 1))
})
32/83
CeTZ
Parameters
on-xy(
z: number ,
body: element
)
z: number Default: 0
Z coordinate for all coordinates
body: element
Elements to draw
3.6.3 on-xz
Draw elements on the xz-plane with optional y value.
𝑥
All vertices of all elements will be changed in the following way: (𝑦argument ), where 𝑦argument is the y-
𝑦
value given as argument.
on-xz({
rect((-1, -1), (1, 1))
})
Parameters
on-xz(
y: number ,
body: element
)
y: number Default: 0
Y coordinate for all coordinates
body: element
Elements to draw
3.6.4 on-yz
Draw elements on the yz-plane with optional y value.
𝑥argument
All vertices of all elements will be changed in the following way: ( 𝑥 ), where 𝑥argument is the x-
𝑦
value given as argument.
on-yz({
rect((-1, -1), (1, 1))
})
33/83
CeTZ
Parameters
on-yz(
x: number ,
body: element
)
x: number Default: 0
X coordinate for all coordinates
body: element
Elements to draw
4 Coordinate Systems
A coordinate is a position on the canvas on which the picture is drawn. They take the form of dictio-
naries and the following sub-sections define the key value pairs for each system. Some systems have
a more implicit form as an array of values and CeTZ attempts to infer the system based on the element
types.
4.1 XYZ
Defines a point x units right, y units upward, and z units away.
x: number Default: 0
The number of units in the x direction.
y: number Default: 0
The number of units in the y direction.
z: number Default: 0
The number of units in the z direction.
The implicit form can be given as an array of two or three number s, as in (x,y) and (x,y,z).
// Implicit form
line((0, -2), (1, -2))
line((0, -2), (0, -1, 0))
line((0, -2), (0, -2, 1))
4.2 Previous
Use this to reference the position of the previous coordinate passed to a draw function. This will never
reference the position of a coordinate used in to define another coordinate. It takes the form of an
empty array (). The previous position initially will be (0, 0, 0).
34/83
CeTZ
4.3 Relative
Places the given coordinate relative to the previous coordinate. Or in other words, for the given coor-
dinate, the previous coordinate will be used as the origin. Another coordinate can be given to act as
the previous coordinate instead.
rel: coordinate
The coordinate to be place relative to the previous coordinate.
update: boolean Default: true
When false the previous position will not be updated.
to: coordinate Default: ()
The coordinate to treat as the previous coordinate.
In the example below, the red circle is placed one unit below the blue circle. If the blue circle was to
be moved to a different position, the red circle will move with the blue circle to stay one unit below.
4.4 Polar
Defines a point that is radius distance away from the origin at the given angle.
angle: angle
The angle of the coordinate. An angle of 0deg is to the right, a degree of 90deg is upward. See https://
typst.app/docs/reference/layout/angle/ for details.
radius: number or tuple<number>
The distance from the origin. An array can be given, in the form (x, y) to define the x and y radii
of an ellipse instead of a circle.
The implicit form is an array of the angle then the radius (angle, radius) or (angle, (x, y)).
4.5 Barycentric
In the barycentric coordinate system a point is expressed as the linear combination of multiple vectors.
The idea is that you specify vectors 𝑣1 , 𝑣2 …, 𝑣𝑛 and numbers 𝛼1 , 𝛼2 , …, 𝛼𝑛 . Then the barycentric
coordinate specified by these vectors and numbers is
𝛼1 𝑣1 + 𝛼2 𝑣1 + ⋯ + 𝛼𝑛 𝑣𝑛
𝛼1 + 𝛼2 + ⋯ + 𝛼𝑛
bary: dictionary
35/83
CeTZ
A dictionary where the key is a named element and the value is a float . The center anchor of the
named element is used as 𝑣 and the value is used as 𝑎.
for (c, a) in (
("content", "south"),
("structure", "north"),
content ("form", "north")
) {
oriented
content(c, align(center, c + [\ oriented]), padding: .1,
ASCII anchor: a)
}
4.6 Anchor
Defines a point relative to a named element using anchors, see Section 2.2.
name: string
The name of the element that you wish to use to specify a coordinate.
anchor: number or angle or string or ratio or none Default: none
The anchor of the element. Strings are named anchors, angles are border anchors and numbers and
ratios are path anchors. If not given, the default anchor will be used, on most elements this is center
but it can be different.
36/83
CeTZ
group(name: "group", {
line((0,0), (3,2), name: "line")
circle("line.end", name: "circle")
rect("line.start", "circle.east")
4.7 Tangent
This system allows you to compute the point that lies tangent to a shape. In detail, consider an element
and a point. Now draw a straight line from the point so that it “touches” the element (more formally,
so that it is tangent to this element). The point where the line touches the shape is the point referred
to by this coordinate system.
element: string
The name of the element on whose border the tangent should lie.
point: coordinate
The point through which the tangent should go.
solution: integer
Which solution should be used if there are more than one.
A special algorithm is needed in order to compute the tangent for a given shape. Currently it does this
by assuming the distance between the center and top anchor (See Section 2.2) is the radius of a circle.
4.8 Perpendicular
Can be used to find the intersection of a vertical line going through a point 𝑝 and a horizontal line
going through some other point 𝑞.
horizontal: coordinate
The coordinate through which the horizontal line passes.
vertical: coordinate
The coordinate through which the vertical line passes.
You can use the implicit syntax of (horizontal, "-|", vertical) or (vertical, "|-", horizontal)
37/83
CeTZ
4.9 Interpolation
Use this to linearly interpolate between two coordinates a and b with a given distance number. If number
is a number the position will be at the absolute distance away from a towards b, a ratio can be given
instead to be the relative distance between a and b. An angle can also be given for the general mean-
ing: “First consider the line from a to b. Then rotate this line by angle around point a. Then the two
endpoints of this line will be a and some point c. Use this point c for the subsequent computation.”
a: coordinate
The coordinate to interpolate from.
b: coordinate
The coordinate to interpolate to.
number: ratio or number
The distance between a and b. A ratio will be the relative distance between the two points, a number
will be the absolute distance between the two points.
angle: angle Default: 0deg
Angle between ⃗⃗⃗⃗⃗⃗⃗⃗⃗⃗⃗⃗
AB and ⃗⃗⃗⃗⃗⃗⃗⃗⃗⃗⃗
AP, where 𝑃 is the resulting coordinate. This can be used to get the normal
for a tangent between two points.
Can be used implicitly as an array in the form (a, number, b) or (a, number, angle, b).
38/83
CeTZ
fill(black)
stroke(none)
let n = 16
for i in range(0, n+1) {
circle(((2,2), i / 8, i * 22.5deg, (3,2)), radius: 2pt)
}
0cm
4.10 Function
An array where the first element is a function and the rest are coordinates will cause the function to
be called with the resolved coordinates. The resolved coordinates have the same format as the implicit
form of the 3-D XYZ coordinate system, Section 4.1.
The example below shows how to use this system to create an offset from an anchor, however this
could easily be replaced with a relative coordinate with the to argument set, Section 4.3.
39/83
CeTZ
5 Libraries
5.1 Tree
The tree library allows the drawing diagrams with simple tree layout algorithms
5.1.1 tree
Lays out and renders tree nodes.
For each node, the tree function creates an anchor of the format "node-<depth>-<child-index>"
that can be used to query a nodes position on the canvas.
Parameters
tree(
root: array ,
draw-node: auto function ,
draw-edge: none auto function ,
direction: string ,
parent-position: string ,
grow: float ,
spread: float ,
name: none string
)
root: array
A nested array of content that describes the structure the tree should take. Example: ([root],
[child 1], ([child 2], [grandchild 1]))
40/83
CeTZ
Nodes
A tree node is an array consisting of the nodes value at index 0 followed by its child nodes. For the
default draw-node function, the value (first item) of an node must be of type content .
Example of a list of nodes:
import cetz.tree
let data = ([\*], ([A], [A.A], [A.B]), ([B], [B.A]))
tree.tree(
data,
B B.A direction: "right",
draw-node: (node, ..) => {
* circle((), radius: .35, fill: blue, stroke: none)
A.B
content((), text(white, [#node.content]))
A },
A.A draw-edge: (from, to, ..) => {
let (a, b) = (from + ".center", to + ".center")
line((a, .4, b), (b, .4, a))
}
)
5.2 Plot
The library plot of CeTZ allows plotting data.
5.2.1 Types
Types commonly used by function of the plot library:
• domain : Tuple representing a functions domain as closed interval. Example domains are: (0, 1) for
[0, 1] or (-calc.pi, calc.pi) for [−𝜋, 𝜋].
41/83
CeTZ
• axes : Tuple of axis names. Plotting functions taking an axes tuple will use those axes as their x and
y axis for plotting. To rotate a plot, you can simply swap its axes, for example ("y", "x").
• mark : Plots feature their own set of marks. The following mark symbols are available:
+ x - | o square triangle
5.2.2 plot
Create a plot environment. Data to be plotted is given by passing it to the plot.add or other plotting
functions. The plot environment supports different axis styles to draw, see its parameter axis-style:.
import cetz.plot
plot.plot(size: (2,2), x-tick-step: none, y-tick-step: none, {
plot.add(((0,0), (1,1), (2,.5), (4,3)))
𝑦
})
To draw elements insides a plot, using the plots coordinate system, use the plot.annotate(..) func-
tion.
Parameters
plot(
body: body ,
size: array ,
axis-style: none string ,
name: string ,
plot-style: style function ,
mark-style: style function ,
fill-below: bool ,
legend: none auto coordinate ,
legend-anchor: auto string ,
legend-style: style ,
..options: any
)
body: body
Calls of plot.add or plot.add-* commands. Note that normal drawing commands like line or rect
are not allowed inside the plots body, instead wrap them in plot.annotate, which lets you select
the axes used for drawing.
size: array Default: (1, 1)
Plot size tuple of (<width>, <height>) in canvas units. This is the plots inner plotting size without
axes and labels.
axis-style: none or string Default: "scientific"
42/83
CeTZ
𝑦 𝑦
𝑦
0 𝑥
𝑥 𝑥
none "school-book" "left" "scientific"
let opts = (x-tick-step: none, y-tick-step: none, size: (2,1))
let data = cetz.plot.add(((-1,-1), (1,1),), mark: "o")
43/83
CeTZ
Options
You can use the following options to customize each axis of the plot. You must pass them as named
arguments prefixed by the axis name followed by a dash (-) they should target. Example: x-min: 0,
y-ticks: (..) or x2-label: [..].
{
−1 0 1 cetz.plot.add(domain: (0, 2 * calc.pi),
t => (calc.cos(t), calc.sin(t)))
𝑥
})
44/83
CeTZ
Like tick-step, but for minor tick marks. In contrast to ticks, minor ticks do not have labels.
ticks: none or array Default: "none"
A List of custom tick marks to additionally draw along the axis. They can be passed as an array
of float values or an array of (<float>, <content>) tuples for setting custom tick mark labels
per mark.
y-min: 1, y-max: 2,
One y-ticks: ((1, [One]), (2, [Two])),
123
{
𝑥
cetz.plot.add(((0,0),))
})
x-format: formatter,
0 1𝜋 2𝜋 {
𝑥 cetz.plot.add(((0,0),))
})
cetz.plot.plot(x-tick-step: 1, y-tick-step: 1,
2
y-minor-tick-step: .2,
1
𝑦
5.2.3 add-anchor
Add an anchor to a plot environment
45/83
CeTZ
This function is similar to draw.anchor but it takes an additional axis tuple to specify which axis co-
ordinate system to use.
import cetz.plot
import cetz.draw: *
Here plot.plot(size: (2,2), name: "plot",
x-tick-step: none, y-tick-step: none, {
plot.add(((0,0), (1,1), (2,.5), (4,3)))
𝑦
plot.add-anchor("pt", (1,1))
})
𝑥
line("plot.pt", ((), "|-", (0,1.5)), mark: (start: ">"), name: "line")
content("line.end", [Here], anchor: "south", padding: .1)
Parameters
add-anchor(
name: string ,
position: tuple ,
axes: tuple
)
name: string
Anchor name
position: tuple
Tuple of x and y values. Both values can have the special values “min” and “max”, which resolve to
the axis min/max value. Position is in axis space defined by the axes passed to axes.
axes: tuple Default: ("x", "y")
Name of the axes to use ("x", "y") as coordinate system for position. Note that both axes must
be used, as add-anchors does not create them on demand.
5.2.4 Legends
A legend for a plot will be drawn if at least one set of data with a label that is not none is given. The
following anchors are available when placing a legend on a plot:
• legend.north
• legend.south
• legend.east
• legend.west
• legend.north-east
• legend.north-west
• legend.south-east
• legend.south-west
• legend.inner-north
• legend.inner-south
• legend.inner-east
• legend.inner-west
• legend.inner-north-east
• legend.inner-north-west
• legend.inner-south-east
• legend.inner-south-west
46/83
CeTZ
import cetz.plot
plot.plot(
𝑓(𝑥) size: (3,2),
x-tick-step: none,
y-tick-step: none,
legend: "legend.north", {
𝑦
plot.add(
((-1, -1), (1, 1)),
mark: "o",
label: $ f(x) $
𝑥 )
})
Styling
Root: legend
Keys
orientation: direction Default: ttb
The direction the legend items get laid out to.
default-position: string or coordinate Default: "legend.north-east"
The default position the legend gets placed at.
layer: number Default: 1
The layer index the legend gets drawn at, see on-layer.
fill: paint Default: rgb("#ffffffc8")
The legends frame background color.
stroke: stroke Default: luma(0%)
The legends frame stroke style.
padding: float Default: 0.1
The legends frame padding, that is the distance added between its items and its frame.
offset: tuple Default: (0, 0)
An offset tuple (x and y coordinates) to add to the legends position.
spacing: number Default: 0.1
The spacing between the legend position and its frame.
item.spacing: number Default: 0.05
The spacing between two legend items in canvas units.
item.preview.width: number Default: 0.75
The width of a legend items preview picture, a small preview of the graph the legend item belongs to.
item.preview.height: number Default: 0.3
The height of a legend items preview picture.
item.preview.margin: number Default: 0.1
Margin between the preview picture and the item label.
5.2.5 add
Add data to a plot environment.
47/83
CeTZ
Note: You can use this for scatter plots by setting the stroke style to none: add(..., style: (stroke:
none)).
48/83
CeTZ
Number of times the data function gets called for sampling y-values. Only used if data is of type
function. This parameter gets passed onto sample-fn.
sample-at: array Default: ()
Array of x-values the function gets sampled at in addition to the default sampling. This parameter
gets passed to sample-fn.
line: string or dictionary Default: "linear"
Line type to use. The following types are supported:
"linear" Draw linear lines between points
"spline" Calculate a Catmull-Rom through all points
"vh" Move vertical and then horizontal
"hv" Move horizontal and then vertical
"hvh" Add a vertical step in the middle
"raw" Like linear, but without linearization taking place. This is meant as a “fallback” for either
bad performance or bugs.
If the value is a dictionary, the type must be supplied via the type key. The following extra attributes
are supported:
"samples" <int> Samples of splines
"tension" <float> Tension of splines
"mid" <float> Mid-Point of hvh lines (0 to 1)
"epsilon" <float> Linearization slope epsilon for use with "linear", defaults to 0.
import cetz.plot
let points(offset: 0) = ((0,0), (1,1), (2,0), (3,1), (4,0)).map(((x,y)) => {
(x,y + offset * 1.5)
})
plot.plot(size: (12, 3), axis-style: none, {
plot.add(points(offset: 5), line: (type: "hvh", mid: .1))
plot.add(points(offset: 4), line: "hvh")
plot.add(points(offset: 3), line: "hv")
plot.add(points(offset: 2), line: "vh")
plot.add(points(offset: 1), line: "spline")
plot.add(points(offset: 0), line: "linear")
})
49/83
CeTZ
import cetz.plot
plot.plot(size: (2, 2), axis-style: none, {
// Using an array of points:
plot.add(((0,0), (calc.pi/2,1),
(1.5*calc.pi,-1), (2*calc.pi,0)))
// Sampling a function:
plot.add(domain: (0, 2*calc.pi), calc.sin)
})
5.2.6 add-hline
Add horizontal lines at one or more y-values. Every lines start and end points are at their axis bounds.
cetz.plot.add-hline(-.5, 0, .5)
})
𝑥
Parameters
add-hline(
..y: float ,
min: auto float ,
max: auto float ,
axes: array ,
style: style ,
label: none content
)
..y: float
Y axis value(s) to add a line at
min: auto or float Default: auto
X axis minimum value or auto to take the axis minimum
max: auto or float Default: auto
X axis maximum value or auto to take the axis maximum
axes: array Default: ("x", "y")
Name of the axes to use for plotting
style: style Default: (:)
Style to use, can be used with a palette function
label: none or content Default: none
Legend label to show for this plot.
5.2.7 add-vline
Add vertical lines at one or more x-values. Every lines start and end points are at their axis bounds.
50/83
CeTZ
Parameters
add-vline(
..x: float ,
min: auto float ,
max: auto float ,
axes: array ,
style: style ,
label: none content
)
..x: float
X axis values to add a line at
min: auto or float Default: auto
Y axis minimum value or auto to take the axis minimum
max: auto or float Default: auto
Y axis maximum value or auto to take the axis maximum
axes: array Default: ("x", "y")
Name of the axes to use for plotting, note that not all plot styles are able to display a custom axis!
style: style Default: (:)
Style to use, can be used with a palette function
label: none or content Default: none
Legend label to show for this plot.
5.2.8 add-fill-between
Fill the area between two graphs. This behaves same as add but takes a pair of data instead of a single
data array/function. The area between both function plots gets filled. For a more detailed explanation
of the arguments, see add().
This can be used to display an error-band of a function.
51/83
CeTZ
Parameters
add-fill-between(
data-a: array function ,
data-b: array function ,
domain: domain ,
samples: int ,
sample-at: array ,
line: string dictionary ,
axes: array ,
label: none content ,
style: style
)
5.2.9 add-contour
Add a contour plot of a sampled function or a matrix.
52/83
CeTZ
Parameters
add-contour(
data: array function ,
label: none content ,
z: float array ,
x-domain: domain ,
y-domain: domain ,
x-samples: int ,
y-samples: int ,
interpolate: bool ,
op: auto string function ,
axes: axes ,
style: style ,
fill: bool ,
limit: int
)
53/83
CeTZ
5.2.10 add-boxwhisker
Add one or more box or whisker plots
Parameters
add-boxwhisker(
data: array dictionary ,
label: none content ,
axes: array ,
style: style ,
box-width: float ,
whisker-width: float ,
mark: string ,
mark-size: float
)
54/83
CeTZ
5.2.11 add-bar
Add a bar- or column-chart to the plot
A bar- or column-chart is a chart where values are drawn as rectangular boxes.
Parameters
add-bar(
data: array ,
mode: string ,
labels: none content array ,
bar-width: float ,
bar-position: string ,
style: dictionary ,
axes: axes
)
data: array
Array of data items. An item is an array containing a x an one or more y values. For example (0,
1) or (0, 10, 5, 30). Depending on the mode, the data items get drawn as either clustered or
stacked rects.
mode: string Default: "basic"
The mode on how to group data items into bars:
basic Add one bar per data value. If the data contains multiple values, group those bars next to
each other.
clustered Like “basic”, but take into account the maximum number of values of all items and
group each cluster of bars together having the width of the widest cluster.
stacked Stack bars of subsequent item values onto the previous bar, generating bars with the
height of the sume of all an items values.
stacked100 Like “stacked”, but scale each bar to height 100, making the different bars percent-
ages of the sum of an items values.
labels: none or content or array Default: none
A single legend label for “basic” bar-charts, or a a list of legend labels per bar category, if the mode
is one of “clustered”, “stacked” or “stacked100”.
bar-width: float Default: 1
Width of one data item on the y axis
bar-position: string Default: "center"
Positioning of data items relative to their x value.
• “start”: The lower edge of the data item is on the x value (left aligned)
55/83
CeTZ
5.2.12 annotate
Add an annotation to the plot
An annotation is a sub-canvas that uses the plots coordinates specified by its x and y axis.
import cetz.plot
plot.plot(size: (2,2), x-tick-step: none, y-tick-step: none, {
plot.add(domain: (0, 2*calc.pi), calc.sin)
Here plot.annotate({
𝑦
Bounds calculation is done naively, therefore fixed size content can grow out of the plot. You can ad-
just the padding manually to adjust for that. The feature of solving the correct bounds for fixed size
elements might be added in the future.
Parameters
annotate(
body: drawable ,
axes: axes ,
resize: bool ,
padding: none number dictionary ,
background: bool
)
body: drawable
Elements to draw
axes: axes Default: ("x", "y")
X and Y axis names
resize: bool Default: true
If true, the plots axes get adjusted to contain the annotation
padding: none or number or dictionary Default: none
Annotation padding that is used for axis adjustment
background: bool Default: false
If true, the annotation is drawn behind all plots, in the background. If false, the annotation is drawn
above all plots.
5.2.13 sample-fn
Sample the given single parameter function samples times, with values evenly spaced within the range
given by domain and return each sampled y value in an array as (x, y) tuple.
56/83
CeTZ
If the functions first return value is a tuple (x, y), then all return values must be a tuple.
Parameters
sample-fn(
fn: function ,
domain: domain ,
samples: int ,
sample-at: array
) -> array: Array of (x y) tuples
fn: function
Function to sample of the form (x) => y or (t) => (x, y), where x or t are float values within
the domain specified by domain.
domain: domain
Domain of fn used as bounding interval for the sampling points.
samples: int
Number of samples in domain.
sample-at: array Default: ()
List of x values the function gets sampled at in addition to the samples number of samples. Values
outsides the specified domain are legal.
5.2.14 sample-fn2
Samples the given two parameter function with x-samples and y-samples values evenly spaced within
the range given by x-domain and y-domain and returns each sampled output in an array.
Parameters
sample-fn2(
fn: function ,
x-domain: domain ,
y-domain: domain ,
x-samples: int ,
y-samples: int
) -> array: Array of z scalars
fn: function
Function of the form (x, y) => z with all values being numbers.
x-domain: domain
Domain used as bounding interval for sampling point’s x values.
y-domain: domain
Domain used as bounding interval for sampling point’s y values.
x-samples: int
Number of samples in the x-domain.
y-samples: int
Number of samples in the y-domain.
5.2.15 Examples
57/83
CeTZ
import cetz.plot
plot.plot(size: (3,2), x-tick-step: calc.pi, y-tick-step: 1,
x-format: v => $#{v/calc.pi} pi$, {
0
𝑦
import cetz.plot
import cetz.palette
3
2 // Let ticks point outwards by giving them negative length
set-style(axes: (tick: (length: -.2, minor-length: -.1)))
1
0
𝑦
// Plot something
plot.plot(size: (3,3), x-tick-step: 1, x-minor-tick-step: .2,
−1
y-tick-step: 1, y-minor-tick-step: .2, {
−2 let z(x, y) = {
−3 (1 - x/2 + calc.pow(x,5) + calc.pow(y,3)) * calc.exp(-(x*x) - (y*y))
}
−2 −1 0 1 2 3
plot.add-contour(x-domain: (-2, 3), y-domain: (-3, 3),
𝑥 z, z: (.1, .4, .7), fill: true)
})
5.2.16 Styling
The following style keys can be used (in addition to the standard keys) to style plot axes. Individual
axes can be styled differently by using their axis name as key below the axes root.
set-style(axes: ( /* Style for all axes */ ))
set-style(axes: (bottom: ( /* Style axis "bottom" */)))
5.2.17 default-style
Default axis style
tick-limit: int Default: 100
Upper major tick limit.
minor-tick-limit: int Default: 1000
Upper minor tick limit.
auto-tick-factors: array Default: none
List of tick factors used for automatic tick step determination.
auto-tick-count: int Default: none
Number of ticks to generate by default.
stroke: stroke Default: none
58/83
CeTZ
59/83
CeTZ
Set visibility of tick labels. A value of auto shows tick labels for all but mirrored axes.
grid.stroke: stroke Default: none
Major grid line stroke style.
minor-grid.stroke: stroke Default: none
Minor grid line stroke style.
shared-zero: bool or content Default: "$0$"
School-book style axes only: Content to display at the plots origin (0,0). If set to false, nothing is
shown. Having this set, suppresses auto-generated ticks for 0!
Parameters
default-style()
60/83
CeTZ
auto-tick-count: 11,
fill: none,
stroke: auto,
label: (offset: 2.83pt, anchor: auto, angle: auto),
axis-layer: 0,
grid-layer: 0,
background-layer: 0,
padding: 2.83pt,
tick: (
fill: none,
stroke: 1pt + luma(0%),
minor-stroke: 0.5pt + luma(0%),
offset: -50%,
minor-offset: -50%,
length: 5.67pt,
minor-length: 70%,
label: (
offset: 4.25pt,
angle: 0deg,
anchor: auto,
show: auto,
),
),
grid: (stroke: (paint: luma(83.33%), thickness: 1pt)),
minor-grid: (stroke: (paint: luma(83.33%), thickness: 0.5pt)),
x: (
stroke: auto,
fill: none,
mark: (start: none, end: "straight"),
tick: (label: (anchor: "north")),
),
y: (
stroke: auto,
fill: none,
mark: (start: none, end: "straight"),
tick: (label: (anchor: "east")),
),
origin: (label: (offset: 1.42pt)),
overshoot: 14.17pt,
shared-zero: equation(block: false, body: [0]),
)
5.3 Chart
With the chart library it is easy to draw charts.
5.3.1 barchart
Draw a bar chart. A bar chart is a chart that represents data with rectangular bars that grow from left
to right, proportional to the values they represent. For examples see Section 5.3.5.
Styling
Root: barchart.
bar-width: float Default: 0.8
Width of a single bar (basic) or a cluster of bars (clustered) in the plot.
y-inset: float Default: 1
61/83
CeTZ
Distance of the plot data to the plot’s edges on the y-axis of the plot.
You can use any plot or axes related style keys, too.
The barchart function is a wrapper of the plot API. Arguments passed to ..plot-args are passed to
the plot.plot function.
Parameters
barchart(
data: array ,
label-key: int string ,
value-key: int string ,
mode: string ,
size: array ,
bar-style: style function ,
x-label: content none ,
x-unit: content auto ,
y-label: content none ,
labels: none content ,
..plot-args: any
)
data: array
Array of data rows. A row can be of type array or dictionary, with label-key and value-key being
the keys to access a rows label and value(s).
Example
(([A], 1), ([B], 2), ([C], 3),)
62/83
CeTZ
Y axis label
labels: none or content Default: none
Legend labels per x value group
..plot-args: any
Arguments to pass to plot.plot
5.3.2 columnchart
Draw a column chart. A column chart is a chart that represents data with rectangular bars that grow
from bottom to top, proportional to the values they represent. For examples see Section 5.3.6.
Styling
Root: columnchart.
bar-width: float Default: 0.8
Width of a single bar (basic) or a cluster of bars (clustered) in the plot.
x-inset: float Default: 1
Distance of the plot data to the plot’s edges on the x-axis of the plot.
You can use any plot or axes related style keys, too.
The columnchart function is a wrapper of the plot API. Arguments passed to ..plot-args are passed
to the plot.plot function.
Parameters
columnchart(
data: array ,
label-key: int string ,
value-key: int string ,
mode: string ,
size: array ,
bar-style: style function ,
x-label: content none ,
y-unit: content auto ,
y-label: content none ,
labels: none content ,
..plot-args: any
)
data: array
Array of data rows. A row can be of type array or dictionary, with label-key and value-key being
the keys to access a rows label and value(s).
Example
(([A], 1), ([B], 2), ([C], 3),)
63/83
CeTZ
5.3.3 piechart
Draw a pie- or donut-chart
6% import cetz.chart
11%
let data = (24, 31, 18, 21, 23, 18, 27, 17, 26, 13)
12%
let colors = gradient.linear(red, blue, green, yellow)
14%
8% chart.piechart(
data,
8% radius: 1.5,
12%
slice-style: colors,
10% inner-radius: .5,
8%
11% outer-label: (content: "%",))
Styling
Root piechart
radius: number Default: 1
Outer radius of the chart.
inner-radius: number Default: 0
Inner radius of the chart slices. If greater than zero, the chart becomes a “donut-chart”.
gap: number or angle Default: 0.5deg
Gap between chart slices to leave empty. This does not increase the charts radius by pushing slices
outwards, but instead shrinks the slice. Big values can result in slices becoming invisible if no space
is left.
outset-offset: number or ratio Default: 10%
64/83
CeTZ
Absolute, or radius relative distance to push slices marked for “outsetting” outwards from the center
of the chart.
outset-offset: string Default: "OFFSET"
The mode of how to perform “outsetting” of slices:
• “OFFSET”: Offset slice position by outset-offset, increasing their gap to their siblings
• “RADIUS”: Offset slice radius by outset-offset, which scales the slice and leaves the gap un-
changed
start: angle Default: 90deg
The pie-charts start angle (ccw). You can use this to draw charts not forming a full circle.
stop: angle Default: 450deg
The pie-charts stop angle (ccw).
clockwise: bool Default: true
The pie-charts rotation direction.
outer-label.content: none or string or function Default: "LABEL"
Content to display outsides the charts slices. There are the following predefined values:
LABEL Display the slices label (see label-key)
% Display the percentage of the items value in relation to the sum of all values, rounded to the
next integer
VALUE Display the slices value
If passed a function of the format (value, label) => content, that function gets called with each
slices value and label and must return content, that gets displayed.
outer-label.radius: number or ratio Default: 125%
Absolute, or radius relative distance from the charts center to position outer labels at.
outer-label.angle: angle or auto Default: 0deg
The angle of the outer label. If passed auto, the label gets rotated, so that the baseline is parallel to
the slices secant.
outer-label.anchor: string Default: "center"
The anchor of the outer label to use for positioning.
inner-label.content: none or string or function Default: none
Content to display insides the charts slices. See outer-label.content for the possible values.
inner-label.radius: number or ratio Default: 150%
Distance of the inner label to the charts center. If passed a ratio , that ratio is relative to the mid
between the inner and outer radius (inner-radius and radius) of the chart
inner-label.angle: angle or auto Default: 0deg
See outer-label.angle.
inner-label.anchor: string Default: "center"
See outer-label.anchor.
65/83
CeTZ
Anchors
The chart places one anchor per item at the radius of it’s slice that gets named "item-<index>" (outer
radius) and "item-<index>-inner" (inner radius), where index is the index of the sclice data in data.
Parameters
piechart(
data: array ,
value-key: none int string ,
label-key: none int string ,
outset-key: none int string ,
outset: none int array ,
slice-style: function array gradient ,
name,
..style
)
data: array
Array of data items. A data item can be:
• A number: A number that is used as the fraction of the slice
• An array: An array which is read depending on value-key, label-key and outset-key
• A dictionary: A dictionary which is read depending on value-key, label-key and outset-key
value-key: none or int or string Default: none
Key of the “value” of a data item. If for example data items are passed as dictionaries, the value-key
is the key of the dictionary to access the items chart value.
label-key: none or int or string Default: none
Same as the value-key but for getting an items label content.
outset-key: none or int or string Default: none
Same as the value-key but for getting if an item should get outset (highlighted). The outset can be a
bool, float or ratio. If of type bool, the outset distance from the style gets used.
outset: none or int or array Default: none
A single or multiple indices of items that should get offset from the center to the outsides of the
chart. Only used if outset-key is none!
slice-style: function or array or gradient Default: palette.red
Slice style of the following types:
• function: A function of the form index => style that must return a style dictionary. This can be
a palette function.
• array: An array of style dictionaries or fill colors of at least one item. For each slice the style at
the slices index modulo the arrays length gets used.
• gradient: A gradient that gets sampled for each data item using the the slices index divided by the
number of slices as position on the gradient.
If one of stroke or fill is not in the style dictionary, it is taken from the charts style.
name: Default: none
..style:
66/83
CeTZ
5.3.4 boxwhisker
Add one or more box or whisker plots.
Styling
Root boxwhisker
box-width: float Default: 0.75
The width of the box. Since boxes are placed 1 unit next to each other, a width of 1 would make
neighbouring boxes touch.
whisker-width: float Default: 0.5
The width of the whisker, that is the horizontal bar on the top and bottom of the box.
mark-size: float Default: 0.15
The scaling of the mark for the boxes outlier values in canvas units.
You can use any plot or axes related style keys, too.
Parameters
boxwhisker(
data: array dictionary ,
size,
label-key: integer string ,
mark: string ,
..plot-args: any
)
67/83
CeTZ
..plot-args: any
Additional arguments are passed to plot.plot
A A A
B B B
C C C
0 2 4 6 8 10 12 14 16 18 20 0 2 4 6 8 10 12 14 16 18 20 22 0 4 8 12 16 20 24 28 32 36 40 44
import cetz.chart
// Left - Basic
let data = (("A", 10), ("B", 20), ("C", 13))
group(name: "a", {
chart.barchart(size: (4, 3), data)
})
// Center - Clustered
let data = (("A", 10, 12, 22), ("B", 20, 1, 7), ("C", 13, 8, 9))
group(name: "b", anchor: "south-west", {
anchor("default", "a.south-east")
chart.barchart(size: (4, 3), mode: "clustered", value-key: (1,2,3), data)
})
// Right - Stacked
let data = (("A", 10, 12, 22), ("B", 20, 1, 7), ("C", 13, 8, 9))
group(name: "c", anchor: "south-west", {
anchor("default", "b.south-east")
chart.barchart(size: (4, 3), mode: "stacked", value-key: (1,2,3), data)
})
68/83
CeTZ
5.3.7 Styling
Charts share their axis system with plots and therefore can be styled the same way, see Section 5.2.16.
69/83
CeTZ
anchor: "center",
),
)
5.4 Palette
A palette is a function of the form index => style that takes an index, that can be any integer and
returns a canvas style dictionary. If passed the string "len" it must return the length of its unique
styles. An example use for palette functions is the plot library, which can use palettes to apply differ-
ent styles per plot.
The palette library provides some predefined palettes.
5.4.1 new
Create a new palette based on a base style
The functions returned by this function have the following named arguments:
fill: bool Default: true
If true, the returned fill color is one of the colors from the colors list, otherwise the base styles fill
is used.
stroke: bool Default: false
If true, the returned stroke color is one of the colors from the colors list, otherwise the base styles
stroke color is used.
You can use a palette for stroking via: red.with(stroke: true).
Parameters
new(
base: style ,
colors: none array ,
dash: none array
) -> function Palette function of the form `index => style` that returns a style for an integer index
70/83
CeTZ
• indigo
• purple
• magenta
• pink
• rainbow
• tango-light
• tango
• tango-dark
5.5 Angle
The angle function of the angle module allows drawing angles with an optional label.
5.5.1 angle
Draw an angle between a and b through origin origin
Parameters
angle(
origin: coordinate ,
a: coordinate ,
b: coordinate ,
inner: bool ,
label: none content function ,
name: none string ,
..style: style
)
origin: coordinate
71/83
CeTZ
Angle origin
a: coordinate
Coordinate of side a, containing an angle between origin and b.
b: coordinate
Coordinate of side b, containing an angle between origin and a.
inner: bool Default: true
Draw the smaller (inner) angle if true, otherwise the outer angle gets drawn.
label: none or content or function Default: none
Draw a label at the angles “label” anchor. If label is a function, it gets the angle value passed as
argument. The function must be of the format angle => content.
name: none or string Default: none
Element name, used for querying anchors.
..style: style
Style key-value pairs.
5.5.2 right-angle
Draw a right angle between a and b through origin origin
72/83
CeTZ
Parameters
right-angle(
origin: coordinate ,
a: coordinate ,
b: coordinate ,
label: none content ,
name: none string ,
..style: style
)
origin: coordinate
Angle origin
a: coordinate
Coordinate of side a, containing an angle between origin and b.
b: coordinate
Coordinate of side b, containing an angle between origin and a.
label: none or content Default: "•"
Draw a label at the angles “label” anchor.
name: none or string Default: none
Element name, used for querying anchors.
..style: style
Style key-value pairs.
5.6 Decorations
Various pre-made shapes and path modifications.
5.6.1 Braces
5.6.2 brace
Draw a curly brace between two points.
cetz.decorations.brace((0,1),(2,1))
cetz.decorations.brace((0,0),(2,0),
pointiness: 45deg, outer-pointiness: 45deg)
cetz.decorations.brace((0,-1),(2,-1),
pointiness: 90deg, outer-pointiness: 90deg)
73/83
CeTZ
Sets the height of the brace, from its baseline to its middle tip.
pointiness: ratio or angle Default: 15deg
How pointy the spike should be. 0deg or 0% for maximum pointiness, 90deg or 100% for minimum.
outer-pointiness: ratio or angle Default: 15deg
How pointy the outer edges should be. 0deg or 0 for maximum pointiness (allowing for a smooth
transition to a straight line), 90deg or 1 for minimum. Setting this to auto will use the value set
for pointiness.
content-offset: number or length Default: 0.3
Offset of the "content" anchor from the spike of the brace.
Anchors:
start Where the brace starts, same as the start parameter.
end Where the brace end, same as the end parameter.
spike Point of the spike, halfway between start and end and shifted by amplitude towards the
pointing direction.
content Point to place content/text at, in front of the spike.
center Center of the enclosing rectangle.
Parameters
brace(
start: coordinate ,
end: coordinate ,
flip: bool ,
debug,
name: string none ,
..style: style
)
start: coordinate
Start point
end: coordinate
End point
flip: bool Default: false
Flip the brace around
debug: Default: false
5.6.3 flat-brace
Draw a flat curly brace between two points.
74/83
CeTZ
cetz.decorations.flat-brace((0,1),(2,1))
cetz.decorations.flat-brace((0,0),(2,0),
curves: .2,
aspect: 25%)
cetz.decorations.flat-brace((0,-1),(2,-1),
outer-curves: 0,
aspect: 75%)
This mimics the braces from TikZ’s decorations.pathreplacing library¹. In contrast to brace(), these
braces use straight line segments, resulting in better looks for long braces with a small amplitude.
Style Root: flat-brace
Style Keys:
amplitude: number Default: 0.3
Determines how much the brace rises above the base line.
aspect: ratio Default: 50%
Determines the fraction of the total length where the spike will be placed.
curves: number Default: auto
Curviness factor of the brace, a factor of 0 means no curves.
outer-curves: auto or number Default: auto
Curviness factor of the outer curves of the brace. A factor of 0 means no curves.
Anchors:
start Where the brace starts, same as the start parameter.
end Where the brace end, same as the end parameter.
spike Point of the spike’s top.
content Point to place content/text at, in front of the spike.
center Center of the enclosing rectangle.
Parameters
flat-brace(
start: coordinate ,
end: coordinate ,
flip: bool ,
debug,
name: string none ,
..style: style
)
start: coordinate
Start point
end: coordinate
End point
flip: bool Default: false
Flip the brace around
¹https://github.com/pgf-tikz/pgf/blob/6e5fd71581ab04351a89553a259b57988bc28140/tex/generic/pgf/libraries/
decorations/pgflibrarydecorations.pathreplacing.code.tex#L136-L185
75/83
CeTZ
5.6.5 zigzag
Draw a zig-zag or saw-tooth wave along a path
The number of tooths can be controlled via the segments or segment-length style key, and the width
via amplitude.
Styling
Root zigzag
Keys
factor: ratio Default: 100%
Triangle mid between its start and end. Setting this to 0% leads to a falling sawtooth shape, while
100% results in a raising sawtooth
76/83
CeTZ
Parameters
zigzag(
target: drawable ,
name: none string ,
close: auto bool ,
..style: style
)
target: drawable
Target path
name: none or string Default: none
Element name
close: auto or bool Default: auto
Close the path
..style: style
Style
5.6.6 coil
Draw a stretched coil/loop spring along a path
The number of windings can be controlled via the segments or segment-length style key, and the
width via amplitude.
Styling
Root coil
Keys
factor: ratio Default: 150%
Factor of how much the coil overextends its length to form a curl.
Parameters
coil(
target: drawable ,
close: auto bool ,
name: none string ,
..style: style
)
target: drawable
Target path
close: auto or bool Default: auto
Close the path
name: none or string Default: none
77/83
CeTZ
Element name
..style: style
Style
5.6.7 wave
Draw a wave along a path using a catmull-rom curve
The number of phases can be controlled via the segments or segment-length style key, and the width
via amplitude.
Styling
Root wave
Keys
tension: float Default: 0.5
Catmull-Rom curve tension, see catmull().
Parameters
wave(
target: drawable ,
close: auto bool ,
name: none string ,
..style: style
)
target: drawable
Target path
close: auto or bool Default: auto
Close the path
name: none or string Default: none
Element name
..style: style
Style
Styling
78/83
CeTZ
6 Advanced Functions
6.1 Coordinate
6.1.1 resolve
Resolve a list of coordinates to absolute vectors
Parameters
resolve(
ctx: context ,
..coordinates: coordinate ,
update: bool
) -> (ctx vector..) Returns a list of the new context object plus the
ctx: context
Canvas context object
..coordinates: coordinate
List of coordinates
update: bool Default: true
Update the context’s last position resolved coordinate vectors
6.2 Styles
6.2.1 resolve
You can use this to combine the style in ctx, the style given by a user for a single element and an
element’s default style.
base is first merged onto dict without overwriting existing values, and if root is given it is merged
onto that key of dict. merge is then merged onto dict but does overwrite existing entries, if root is
given it is merged onto that key of dict. Then entries in dict that are auto inherit values from their
nearest ancestor and entries of type dictionary are merged with their closest ancestor.
79/83
CeTZ
#let dict = (
stroke: "black",
fill: none,
mark: (stroke: auto, fill: "blue"),
line: (stroke: auto, mark: auto, fill: "red")
)
#styles.resolve(dict, merge: (mark: (stroke: "yellow")), root: "line")
(
stroke: "black",
mark: (stroke: "yellow", fill: "blue"),
fill: "red",
)
The following is a more detailed explanation of how the algorithm works to use as a reference if needed.
It should be updated whenever changes are made. Remember that dictionaries are recursively merged,
if an entry is any other type it is simply updated. (dict + dict = merged dict, value + dict = dict, dict +
value = value) First if base is given, it will be merged without overwriting values onto dict. If root is
given it will be merged onto that key of dict. Each level of dict is then processed with these steps. If
root is given the level with that key will be the first, otherwise the whole of dict is processed.
1. Values on the corresponding level of merge are inserted into the level if the key does not exist on the
level or if they are not both dictionaries. If they are both dictionaries their values will be inserted
in the same stage at a lower level.
2. If an entry is auto or a dictionary, the tree is travelled back up until an entry with the same key is
found. If the current entry is auto the value of the ancestor’s entry is copied. Or if the current entry
and ancestor entry is a dictionary, they are merged with the current entry overwriting any values
in it’s ancestors.
3. Each entry that is a dictionary is then resolved from step 1.
( get-ctx(ctx => {
scale: 1, // Get the current "mark" style
length: 5.67pt, content((0,0), [#cetz.styles.resolve(ctx.style, root:
width: 4.25pt, "mark")])
inset: 1.42pt, })
sep: 2.83pt,
pos: none,
offset: 0,
start: none,
end: none,
symbol: none,
xy-up: (0, 0, 1),
z-up: (0, 1, 0),
stroke: 1pt + luma(0%),
fill: none,
slant: none,
harpoon: false,
flip: false,
reverse: false,
flex: true,
position-samples: 30,
shorten-to: auto,
transform-shape: true,
)
80/83
CeTZ
Parameters
resolve(
dict: style ,
root: none str ,
merge: style ,
base: none style
)
dict: style
Current context style (ctx.style).
root: none or str Default: none
Style root element name.
merge: style Default: (:)
Style values overwriting the current style. I.e. inline styles passed with an element: line(..,
stroke: red).
81/83
CeTZ
8 Internals
8.1 Context
The state of the canvas is encoded in its context dictionary. Elements or other draw calls may return a
modified context to the canvas to change its state, e.g. modifying the transformating matrix, adding a
group or setting a style.
The context can be manually retrieved and modified using the get-ctx and set-ctx functions.
8.2 Elements
Each CeTZ element (line, bezier, circle, …) returns an array of functions for drawing to the canvas.
Such function takes the canvas’ context and must return an dictionary of the following keys:
• ctx (required): The (modified) canvas context object
• drawables: List of drawables to render to the canvas
• anchors: A function of the form (<anchor-identifier>) => <vector>
• name: The elements name
An element that does only modify the context could be implemented like the following:
82/83
CeTZ
let my-element() = {
(ctx => {
// Do something with ctx ...
(ctx: ctx)
},)
}
For drawing, elements must not use Typst native drawing functions, but output CeTZ paths. The
drawable module provides functions for path creation (path(..)), the path-util module provides
utilities for path segment creation. For demonstration, we will recreate the custmom element my-star
from Section 7:
(ctx: ctx,
drawables: cetz.drawable.apply-transform(ctx.transform, path),
)
},)
}
Using custom elements instead of groups (as in Section 7) makes sense when doing advanced compu-
tations or even applying modifications to passed in elements.
83/83