plotlet v0.6.2

6. Color & themes

Palettes for categories, colormaps for values, the cycle notation, and per-chart themes. Every snippet on this page is executed on every build — the figures are its output.

Palettes for categories

A categorical column mapped through aes(...) pulls colors from the default cycle. palette= overrides it: a named palette (pt.list_palettes() — tab10, Set2, colorblind, …) or an explicit {level: color} dict when specific levels must keep specific colors.

import random
rng = random.Random(1)
data = {"grp": [], "value": [], "arm": []}
for i, g in enumerate(["ctrl", "low", "high"]):
    for arm in ("A", "B"):
        data["grp"] += [g] * 40
        data["arm"] += [arm] * 40
        data["value"] += [rng.gauss(5 + i + (arm == "B"), 1)
                          for _ in range(40)]

c = pt.chart(data, aes(x="grp", y="value", fill="arm"), legend=True,
             data_width=380, data_height=200)
c.xscale("category", order=["ctrl", "low", "high"])
c.add_violin(palette={"A": "#3F97C5", "B": "#F99917"}, inner="box")
c.legend()
["ctrl","low","high"]

The color cycle

Literal colors accept hex strings, named colors, and the cycle notation "C0""C9" — slot n of the default tab10 cycle, the same in every theme, so layered artists can coordinate colors without hardcoding hex. A bare color= string is always a literal like these — only aes(...) maps a column. The default cycle is also available as pt.TAB10.

import math
xs = [i * 0.2 for i in range(40)]
waves = {"x": xs, "sin": [math.sin(x) for x in xs],
         "cos": [math.cos(x) for x in xs]}

c = pt.chart(waves, aes(x="x"), data_width=380, data_height=170,
             legend=True)
c.add_line(aes(y="sin"), color="C0", label="C0")
c.add_line(aes(y="cos"), color="C1", label="C1")
c.add_axhline(0, color="C3", linestyle="--", label="C3")
c.legend()

Colormaps for values

Continuous values map through cmap= — the matplotlib names are all registered (pt.list_colormaps()), each with a reversed _r twin. For diverging data, center= pins the midpoint (e.g. 0) to the colormap’s center. Register custom maps with pt.register_colormap.

import math
data = {"col": [f"c{i}" for i in range(10)]}
for r in range(6):
    data[f"r{r}"] = [math.sin(i * 0.6 + r) for i in range(10)]
values = [f"r{r}" for r in range(6)]

left = pt.chart(title="viridis", data_width=220, data_height=150)
left.add_heatmap(data=data, mapping=aes(x="col"), values=values,
                 cmap="viridis")
right = pt.chart(title="RdBu_r, center=0", data_width=220,
                 data_height=150)
right.add_heatmap(data=data, mapping=aes(x="col"), values=values,
                  cmap="RdBu_r", center=0)
c = left | right
["c0","c1","c2","c3","c4","c5","c6","c7","c8","c9"]["r0","r1","r2","r3","r4","r5"]["c0","c1","c2","c3","c4","c5","c6","c7","c8","c9"]["r0","r1","r2","r3","r4","r5"]

Themes

Four built-ins — classic (the default), dark, minimal, void — set per chart, never globally: the same script always produces the same figures. Themes restyle the chrome — background, frame, gridlines, fonts — while series colors and your data code don’t change. Custom themes are a dict away (pt.register_theme, docs/THEMES.md).

import math
xs = [i * 0.1 for i in range(64)]
waves = {"t": xs, "sin": [math.sin(x) for x in xs],
         "cos": [math.cos(x) for x in xs]}

a = pt.chart(waves, aes(x="t", y="sin"), theme="classic",
             title="classic", data_width=210, data_height=140,
             xlabel="t")
a.add_line()
a.add_line(aes(y="cos"), linestyle="--")
b = pt.chart(waves, aes(x="t", y="sin"), theme="minimal",
             title="minimal", data_width=210, data_height=140,
             xlabel="t")
b.add_line()
b.add_line(aes(y="cos"), linestyle="--")
c = a | b

← Sectors & circular coordinates  ·  Reproducibility & AI tooling →