Aesthetic specifications
This document is a translation of the ggplot2 aesthetic specification.
Color and fill
Almost every geom has either color, fill, or both. Colors and fills can be specified in the following ways:
A name, e.g.,
"red"
. TODO: how do you list colors?. https://matplotlib.org/stable/gallery/color/named_colors.html#css-colorsAn rgb specification, with a string of the form
"#RRGGBB"
where each of the pairsRR
,GG
,BB
consists of two hexadecimal digits giving a value in the range00
toFF
You can optionally make the color transparent by using the form
"#RRGGBBAA"
.A missing value (e.g. None, np.nan, pd.NA), for a completely transparent colour.
- https://github.com/has2k1/plotnine/issues/791
TODO: continuous colormaps – https://matplotlib.org/stable/users/explain/colors/colormaps.html
Lines
As well as colour
, the appearance of a line is affected by linewidth
, linetype
, linejoin
and lineend
.
Line type
Line types can be specified with:
A name: solid, dashed, dotted, dashdot, as shown below:
The lengths of on/off stretches of line. This is done with a string containing 2, 4, 6, or 8 hexadecimal digits which give the lengths of consecutive lengths. For example, the string
"33"
specifies three units on followed by three off and"3313"
specifies three units on followed by three off followed by one on and finally three off. TODO: this likely isn’t implemented? (but tuple syntax is(0, (1, 5))
)
The five standard dash-dot line types described above correspond to 44, 13, 1343, 73, and 2262.
Linewidth
Due to a historical error, the unit of linewidth is roughly 0.75 mm. Making it exactly 1 mm would change a very large number of existing plots, so we’re stuck with this mistake.
Line end/join parameters
The appearance of the line end is controlled by the
lineend
paramter, and can be one of “round”, “butt” (the default), or “square”.= pd.DataFrame({"x": [1,2,3], "y": [4, 1, 9]}) df = ggplot(df, aes("x", "y")) + xlim(0.5, 3.5) + ylim(0, 10) base (+ base = 10) + geom_path(size = 1, colour = "red") geom_path(size ) (+ base = 10, lineend = "round") + geom_path(size = 1, colour = "red") geom_path(size ) (+ base = 10, lineend = "square") + geom_path(size = 1, colour = "red") geom_path(size )
The appearance of line joins is controlled by
linejoin
and can be one of “round” (the default), “mitre”, or “bevel”.= pd.DataFrame({"x": [1,2,3], "y": [9, 1, 9]}) df = ggplot(df, aes("x", "y")) + ylim(0, 10) base (+ base = 10) + geom_path(size = 1, colour = "red") geom_path(size ) (+ base = 10, linejoin = "mitre") + geom_path(size = 1, colour = "red") geom_path(size ) (+ base = 10, linejoin = "bevel") + geom_path(size = 1, colour = "red") geom_path(size )
Mitre joins are automatically converted to bevel joins whenever the angle is too small (which would create a very long bevel). This is controlled by the linemitre
parameter which specifies the maximum ratio between the line width and the length of the mitre.
Polygons
The border of the polygon is controlled by the colour
, linetype
, and linewidth
aesthetics as described above. The inside is controlled by fill
.
Point
Shape
Shapes take five types of values:
A string for a point type, as specified in matplotlib.markers:
None
to draw nothing. (TODO: does not work)
Colour and fill
While colour
applies to all shapes, fill
only applies to shapes with red fill in the plot above. The size of the filled part is controlled by size
, the size of the stroke is controlled by stroke
. Each is measured in mm, and the total size of the point is the sum of the two. Note that the size is constant along the diagonal in the following figure.
= (
sizes "size": [0, 2, 4, 6]})
pd.DataFrame({
.merge("stroke": [0, 2, 4, 6]}), how="cross"
pd.DataFrame({
)
)
("size", "stroke", size = "size", stroke = "stroke")) +
ggplot(sizes, aes(= -1, intercept = 6, colour = "white", size = 6) +
geom_abline(slope = "o", fill = "red") +
geom_point(shape =None)
scale_size_identity(guide )
Text
Font family
There are only three fonts that are guaranteed to work everywhere: “sans” (the default), “serif”, or “mono” (TODO: this doesn’t work):
# TODO: add cursive and 🧚♀️ fantasy
= pd.DataFrame({"x": 1, "y": [3, 2, 1], "family": ["sans-serif", "serif", "monospace"]})
df
("x", "y")) +
ggplot(df, aes(= "family", family="family"), size=20)
geom_text(aes(label )
findfont: Generic family 'serif' not found because none of the following families were found: Times, Palatino, New Century Schoolbook, Bookman, Computer Modern Roman, Times New Roman
findfont: Generic family 'serif' not found because none of the following families were found: Times, Palatino, New Century Schoolbook, Bookman, Computer Modern Roman, Times New Roman
findfont: Generic family 'serif' not found because none of the following families were found: Times, Palatino, New Century Schoolbook, Bookman, Computer Modern Roman, Times New Roman
You should be able to use any fonts installed on your system. TODO: find something to link out to for installing new fonts.
showtext
makes GD-independent plots by rendering all text as polygons. (TODO: svg_usefont; trade-off, paths are hard to edit quickly vs fonts eg in inkscape)
Font weight
TODO: update plotnine and re-run; see geom_text docs
= pd.DataFrame({"x": [1, 2, 3, 4], "fontweight": ["light", "normal", "bold", "extra bold"]})
df
(1, "x")) +
ggplot(df, aes(= "fontweight"), fontweight="bold")
geom_text(aes(label )
Font style
Font size
The size
of text is measured in mm by default. This is unusual, but makes the size of text consistent with the size of lines and points. Typically you specify font size using points (or pt for short), where 1 pt = 0.35mm. In geom_text()
and geom_label()
, you can set size.unit = "pt"
to use points instead of millimeters. In addition, ggplot2 provides a conversion factor as the variable .pt
, so if you want to draw 12pt text, you can also set size = 12 / .pt
.
Justification
Horizontal and vertical justification have the same parameterisation, either a string (“top”, “middle”, “bottom”, “left”, “center”, “right”) or a number between 0 and 1:
- top = 1, middle = 0.5, bottom = 0
- left = 0, center = 0.5, right = 1
= pd.DataFrame({"hjust": ["center", "right", "left"], "x": [0, 1, 2]}).merge(pd.DataFrame({"vjust": ["center", "top", "bottom"], "y": [0, 1, 2]}), how="cross")
just
"label"] = just["hjust"].astype(str).str.cat(just["vjust"].astype(str), sep=", ")
just[
("x", "y")) +
ggplot(just, aes(= "grey", size = 5) +
geom_point(colour = "label", hjust = "hjust", vjust = "vjust"))
geom_text(aes(label + expand_limits(x = [-.5, 2.5], y = [-.5, 2.5])
)
Note that you can use numbers outside the range (0, 1), but it’s not recommended.