Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

std.plot examples beside ggplot2 and plotnine

Status: Not implemented. These examples illustrate the std.plot proposal. The Plenty fences show proposed API and are not compiled. Each example assumes a table with the columns of the R dataset named (mtcars, diamonds, mpg) and these imports:

from std.plot import ggplot, aes, factor, after_stat, labs, theme, theme_minimal
from std.plot import geom_point, geom_smooth, geom_histogram, geom_bar
from std.plot import facet_wrap, facet_grid, position_dodge, scale_colour_brewer
from std.plot import Smooth, Brewer, Legend

Scatter plot with a colour mapping

ggplot(mtcars, aes(wt, mpg, colour = factor(cyl))) +
  geom_point(size = 2)
(ggplot(mtcars, aes("wt", "mpg", color="factor(cyl)"))
 + geom_point(size=2))
p = ggplot(mtcars, aes("wt", "mpg", colour=factor("cyl")), [
    geom_point(size=2),
]?)?
p.save("cars.svg", width=6, height=4)?

factor("cyl") makes the integer column discrete, so the legend shows three levels instead of a gradient. size=2 is accepted because numeric settings take i64 as well as f64.

Points with a fitted line

ggplot(mtcars, aes(wt, mpg)) +
  geom_point() +
  geom_smooth(method = "lm")
(ggplot(mtcars, aes("wt", "mpg"))
 + geom_point()
 + geom_smooth(method="lm"))
p = ggplot(mtcars, aes("wt", "mpg"), [
    geom_point(),
    geom_smooth(method=Smooth.Lm),
]?)?

The line carries a 95% confidence band by default (se=True), as in ggplot2.

Histogram

ggplot(diamonds, aes(price)) +
  geom_histogram(binwidth = 500)
ggplot(diamonds, aes("price")) + geom_histogram(binwidth=500)
p = ggplot(diamonds, aes("price"), [
    geom_histogram(binwidth=500),
]?)?

Without binwidth or bins, the stat uses 30 bins and records a note, the counterpart of ggplot2’s `stat_bin()` using `bins = 30` message. Density instead of counts: aes("price", after_stat("density")).

Bars with fill and dodge

ggplot(diamonds, aes(cut, fill = clarity)) +
  geom_bar(position = "dodge")
(ggplot(diamonds, aes("cut", fill="clarity"))
 + geom_bar(position="dodge"))
p = ggplot(diamonds, aes("cut", fill="clarity"), [
    geom_bar(position=position_dodge()),
]?)?

geom_bar counts rows per cut and clarity, so y is not mapped. position_dodge(width=0.8) takes the same arguments as in ggplot2.

Facets

ggplot(mpg, aes(displ, hwy)) +
  geom_point() +
  facet_wrap(~class, ncol = 3)

ggplot(mpg, aes(displ, hwy)) +
  geom_point() +
  facet_grid(drv ~ cyl)
ggplot(mpg, aes("displ", "hwy")) + geom_point() + facet_wrap("class", ncol=3)

ggplot(mpg, aes("displ", "hwy")) + geom_point() + facet_grid("drv ~ cyl")
base = ggplot(mpg, aes("displ", "hwy"), [geom_point(),]?)?
wrapped = base.plus([facet_wrap("class", ncol=3)]?)?
grid = base.plus([facet_grid(rows="drv", cols="cyl")]?)?

base stays usable after each plus; both plots share its table.

Labels, scales and a theme

ggplot(mtcars, aes(wt, mpg, colour = factor(gear))) +
  geom_point(size = 3) +
  scale_colour_brewer(palette = "Set1") +
  labs(title = "Fuel economy by weight",
       x = "Weight (1000 lb)", y = "Miles per gallon", colour = "Gears") +
  theme_minimal(base_size = 12) +
  theme(legend.position = "bottom")
(ggplot(mtcars, aes("wt", "mpg", color="factor(gear)"))
 + geom_point(size=3)
 + scale_color_brewer(type="qual", palette="Set1")
 + labs(title="Fuel economy by weight",
        x="Weight (1000 lb)", y="Miles per gallon", color="Gears")
 + theme_minimal(base_size=12)
 + theme(legend_position="bottom"))
p = ggplot(mtcars, aes("wt", "mpg", colour=factor("gear")), [
    geom_point(size=3),
    scale_colour_brewer(palette=Brewer.Set1),
    labs(title="Fuel economy by weight",
         x="Weight (1000 lb)", y="Miles per gallon", colour="Gears"),
    theme_minimal(base_size=12),
    theme(legend_position=Legend.Bottom),
]?)?

Brewer.Set1 and Legend.Bottom are enum values, so a misspelt palette or position fails to compile.

A complete program from records

from std.plot import ggplot, aes, factor, geom_point, geom_smooth, labs
from std.plot import rows, num, integer, text, Smooth, PlotError

class Car:
    model: str
    wt: f64
    mpg: f64
    cyl: i64

def main() -> Result[(), PlotError | AllocError | IoError]:
    cars = [
        Car("Mazda RX4", 2.620, 21.0, 6),
        Car("Datsun 710", 2.320, 22.8, 4),
        Car("Hornet Sportabout", 3.440, 18.7, 8),
    ]?

    table = rows(&cars, [
        text("model", def(c: &Car) -> str: c.model)?,
        num("wt", def(c: &Car) -> f64: c.wt)?,
        num("mpg", def(c: &Car) -> f64: c.mpg)?,
        integer("cyl", def(c: &Car) -> i64: c.cyl)?,
    ]?)?

    p = ggplot(table, aes("wt", "mpg", colour=factor("cyl")), [
        geom_point(size=2),
        geom_smooth(method=Smooth.Lm, colour="grey30"),
        labs(x="Weight (1000 lb)", y="Miles per gallon", colour="Cylinders"),
    ]?)?

    notes = p.save("cars.svg", width=6, height=4)?
    print(notes)?
    Ok(())

geom_smooth(colour="grey30") is a setting: one fixed colour, so the line does not split by the plot’s colour mapping. In ggplot2 the same setting also overrides the inherited mapping for that layer.

After derived serialization lands, the rows call can become records(&cars)? for a class marked @serial.

A mistake and its error

p = ggplot(table, aes("wt", "mpg", colour="cly"), [geom_point(),]?)?
error: plot mapping: aesthetic `colour` maps unknown column "cly"
  available columns: model, wt, mpg, cyl
  did you mean "cyl"?

The error comes from ggplot(...), before rendering. ggplot2 reports object 'cly' not found when the plot is printed.