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

Draw a chart

std.plot turns data into SVG without an external plotting program. Its names follow ggplot2: a plot combines a table, mappings from column names to visual properties, and a list of layers and styling choices.

This example renders into a memory stream so the lesson creates no files:

import std.plot as gg
import std.io
import std.bytes
from std.plot import Column, PlotError
from std.bytes import BytesError

def main() -> Result[(), AllocError | IoError | PlotError | BytesError]:
    data = gg.table([
        ("hour", Column.Num([9.0, 12.0, 15.0]?)),
        ("temperature", Column.Num([16.0, 22.0, 20.0]?)),
    ]?)?
    chart = gg.ggplot(data, gg.aes("hour", "temperature"), [
        gg.geom_line(colour="navy"),
        gg.geom_point(colour="navy", size=2),
        gg.labs(title="Afternoon temperatures", x="Hour", y="Degrees C"),
        gg.theme_minimal(),
    ]?)?
    mut output = std.io.cursor(std.bytes.empty()?)
    notes = chart.write_svg(&mut output)?
    print(notes)?
    print(output.data.to_text()?.startswith("<svg"))?
    Ok(())
[]
True

For a file, replace the cursor and write_svg with notes = chart.save("temperatures.svg")?. Open the file in a browser or include it in a document. Saving borrows the chart, so you can save it again at another size. The default is 6 by 4 inches; named width, height, and units control dimensions. Only SVG is supported currently.

The distinction between mapping and setting matters. aes(colour="kind") looks up a column and creates a colour scale and legend. geom_point(colour="navy") uses one constant colour. Unknown column names fail when the plot is constructed.

Plot your own records

Typed accessors turn lists of ordinary classes into columns. Compute derived values in these accessors, where Plenty can type-check them; aes does not evaluate strings as expressions.

import std.plot as gg
import std.io
import std.bytes
from std.plot import PlotError
from std.bytes import BytesError

class Sale:
    region: str
    amount: f64

def main() -> Result[(), AllocError | IoError | PlotError | BytesError]:
    sales = [Sale("North", 12.0), Sale("South", 18.0), Sale("North", 5.0)]?
    data = gg.rows(&sales, [
        gg.text("region", def(s: &Sale) -> str: s.region)?,
        gg.num("amount", def(s: &Sale) -> f64: s.amount)?,
    ]?)?
    base = gg.ggplot(data, gg.aes("region", "amount", fill="region"), [
        gg.geom_col(),
        gg.scale_fill_manual({"North": "navy", "South": "#D55E00"}?),
        gg.theme_minimal(),
    ]?)?
    labelled = base.plus([gg.labs(title="Sales by region", y="Sales")]?)?
    mut output = std.io.cursor(std.bytes.empty()?)
    drop(labelled.write_svg(&mut output)?)
    print(len(sales), output.data.to_text()?.startswith("<svg"))?
    Ok(())
3 True

geom_col uses supplied heights and stacks rows at the same x by default. Use geom_bar with no y mapping to count rows instead, or geom_histogram(bins=20) with a continuous x mapping to count numeric intervals. For grouped bars, position=gg.position_dodge() places groups side by side.

The named palette keeps each region’s colour stable even if the input order changes. Include every observed region; extra names are allowed. For a numeric colour mapping, use gg.scale_colour_gradient(low="#132B43", high="#56B1F7") to choose endpoints instead. The legend follows the chosen colours. See manual palettes and gradients for interpolation and validation rules.

plus leaves the original plot unchanged and shares its immutable data. rows copies selected values, so the original records also remain usable. For columns you already own, table moves the lists without copying them.

Missing and non-finite mapped values are omitted, with a note returned by the renderer. Check these notes when interpreting a chart. The final example discards them deliberately because its small, fixed dataset contains no missing values. File/stream errors and allocation failures still propagate through ?. See the reference for supported layers, layout limits, and differences from the larger plotting proposal.