Skip to main content

umber

umber is a plotting library for Python with a rendering core written in Rust. It draws line, scatter, area, bar and histogram charts with careful typography, three built-in themes, and PNG or SVG output.

简体中文

A line chart of daily temperature at two stations, in the Graphite theme

  • Fast on large data. Rendering runs in Rust: a 1,000,000-point line renders to PNG in about 55 ms, and a 100,000-point scatter in about 50 ms (see Performance).
  • Explicit. Every option is a typed value (Color, Size, Dash, TickFormat, …). There are no format strings, no positional style arguments and no silent conversions.
  • Fails fast, pointing at the problem. Invalid input raises at the call that caused it, with a message, a hint and the offending argument highlighted in the traceback.
  • Statically typed. Category and numeric axes are distinct types: calling bar on a numeric axes is reported by pyright and mypy before the code runs.
  • Bundled fonts. Text in the bundled fonts' coverage looks the same on every machine; other characters fall back to system fonts.

Installation

pip install umber

umber requires Python 3.12 or newer and NumPy 2. Prebuilt wheels are published for Linux (x86_64 and aarch64), macOS (Apple silicon and Intel) and Windows (x64). On other platforms pip builds from source, which needs Rust 1.88 or newer.

Quick start

import numpy as np
import umber as ub

t = np.linspace(0, 10, 1_000)
ub.line(t, np.sin(t), label="sin").title("A first chart").figure.save_png("chart.png")

The quick functions ub.line, ub.scatter, ub.bar and ub.hist create a figure with one axes and return the axes, so the rest of the chart is built by chaining.

Building a figure

import numpy as np
import umber as ub

rng = np.random.default_rng(7)
days = np.arange(60)
north = 20 + np.cumsum(rng.normal(0, 1, 60))
south = 18 + np.cumsum(rng.normal(0, 1, 60))

fig = ub.Figure(6, 4, theme=ub.Theme.GRAPHITE)  # width and height in inches
ax = fig.add_axes()
ax.title("Daily temperature").subtitle("Two stations, last 60 days")
ax.xlabel("Day").ylabel("°C")
ax.line(days, north, label="North")
ax.line(days, south, label="South", dash=ub.Dash.DASHED)

fig.save_png("temperature.png", dpi=200)
fig.save_svg("temperature.svg")

This is the chart at the top of this page. Data can be a list, a tuple, a NumPy array, or a pandas or polars Series. Missing values (NaN, or nulls in nullable pandas and polars columns) leave a gap.

Chart Method
Line ax.line(x, y)
Scatter ax.scatter(x, y, marker=ub.Marker.TRIANGLE, size=ub.Size.times(1.5))
Area ax.area(x, y)
Bar, grouped, stacked ax.bar(categories, heights), ax.grouped_bar(categories, series), ax.stacked_bar(categories, series)
Histogram ax.hist(values, bins=30)

Bar charts need a category x axis: fig.add_axes(x=ub.Scale.category()). Log axes use ub.Scale.log(). Limits, ticks and tick label formats are set with xlim, ylim, xticks, xticks_labeled, ytick_format(ub.TickFormat.percent()) and their counterparts on the other axis.

A grouped bar chart in the Pigment theme A histogram with a gradient fill in the Pigment theme

Themes

Three themes are built in: Theme.PIGMENT (warm paper, serif titles), Theme.GRAPHITE (neutral, sans-serif) and Theme.MIDNIGHT (dark, monospaced figures). A theme is an immutable value; derive a variant with its with_* methods:

import umber as ub

theme = ub.Theme.MIDNIGHT.with_fill_style(ub.FillStyle.SOLID).with_legend_style(
    ub.LegendStyle.HEADER
)
fig = ub.Figure(theme=theme)

Two sine waves in the Midnight theme

Errors

An error is raised by the call that caused it: umber.DataError for invalid data, umber.StyleError for an invalid option value, umber.UsageError for a call that is not allowed in the current state, and TypeError for a value of the wrong type. The three umber errors derive from umber.UmberError. The traceback points at the argument:

Traceback (most recent call last):
  File "example.py", line 7, in <module>
    ax.line(t, y, label="signal")
    ~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
umber.DataError: Axes.line(): y[2] is inf; values must be finite.
  ax.line(t, y, label="signal")
             ^
hint: use NaN to leave a gap in the line.
TypeError: Axes.line(): color is str; color must be of type Color.
  ax.line([0, 1, 2], [1, 3, 2], color="red")
                                ^^^^^^^^^^^
hint: use Color.hex("#3366B8"), Color.rgb() or a named color such as Color.BLUE.

In a terminal that supports it, the hint and the highlight are shown in color; set NO_COLOR to turn color off or FORCE_COLOR to force it. The same notes appear in Jupyter.

Static typing

The package ships type information (py.typed) and is checked with pyright and mypy in strict mode. Figure().add_axes() is Axes[float, float]; add_axes(x=Scale.category()) is Axes[str, float]. Methods that only make sense on one kind of axis are typed accordingly:

import umber as ub

ax = ub.Figure().add_axes()
ax.bar(["a", "b"], [1, 2])  # pyright and mypy: bar() needs Axes[str, float]

Performance

Medians from the criterion suite in crates/umber-core/benches, 6 × 4 in at 200 dpi, on an Intel Core Ultra 9 290HX running Linux:

Case Time
1,000,000-point line → PNG 53 ms
1,000,000-point line → SVG 21 ms
100,000-point scatter → PNG 47 ms
Histogram of 1,000,000 values → PNG 20 ms

Lines with sorted numeric x values are downsampled when they have more than four points per pixel column of the plot (counted at a nominal 300 dpi), keeping the first, last, minimum and maximum point in each column, which is visually lossless. Large scatter plots are composited on up to 8 threads; the output is the same for any number of threads.

Rust

The rendering core is published as the umber-core crate and can be used directly from Rust:

use umber_core::{AxisData, Figure, LineOptions, ScaleKind, Theme};

let mut figure = Figure::new(6.0, 4.0, Theme::pigment())?;
figure
    .add_axes(ScaleKind::Linear, ScaleKind::Linear)?
    .title("Signal")
    .line(AxisData::Numbers(vec![0.0, 1.0, 2.0, 3.0]), &[1.0, 3.0, 2.0, 4.0], LineOptions::default())?;
std::fs::write("signal.png", figure.to_png(144)?)?;

Status

umber is at version 0.x. The API is not yet stable and may change or be removed without a deprecation period. More examples are in examples/.

License

Licensed under either of MIT or Apache-2.0, at your option (MIT OR Apache-2.0). Bundled fonts are under the SIL Open Font License 1.1; see crates/umber-core/fonts/LICENSES and crates/umber-core/fonts/MANIFEST.md. Wheels include statically linked Rust dependencies; their licenses are listed in THIRD-PARTY-LICENSES.txt.

Metadata

Release files for umber 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for umber 0.1.0
File Size Uploaded
umber-0.1.0.tar.gz 951.6 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for umber 0.1.0
File
umber-0.1.0-cp312-abi3-win_amd64.whl CPython 3.12 abi3 Windows x86-64 Details
umber-0.1.0-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.12 abi3 Linux glibc 2.17+ x86-64 Details
umber-0.1.0-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.12 abi3 Linux glibc 2.17+ ARM64 Details
umber-0.1.0-cp312-abi3-macosx_11_0_arm64.whl CPython 3.12 abi3 macOS 11.0+ ARM64 Details
umber-0.1.0-cp312-abi3-macosx_10_12_x86_64.whl CPython 3.12 abi3 macOS 10.12+ x86-64 Details

Total release size: 14.7 MB

Release files / umber-0.1.0.tar.gz

Download URL umber-0.1.0.tar.gz
Size 951.6 kB
Tags Source
SHA-256 checksum
How to use checksums
2c7ed1a53d8c031e51aa6cea3c95432b8fe4636ac98d073c30aefc7c19121cb7
BLAKE2b-256 checksum
How to use checksums
e0400df4cac11cc67a32cc483cc5e0e8ffdc6a968c32a0381a22b90211c5835e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.

Transparency log

Release files / umber-0.1.0-cp312-abi3-win_amd64.whl

Download URL umber-0.1.0-cp312-abi3-win_amd64.whl
Size 2.5 MB
Tags CPython 3.12 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
43579118f79d0de9d37f4bca6f4368becddb57c80a431f5601190798d06e8b47
BLAKE2b-256 checksum
How to use checksums
a019b5d1e8d3bf48105da553af98338a2e32e2e17b5b84153f5f5a7b65c1ed9d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.

Transparency log

Release files / umber-0.1.0-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL umber-0.1.0-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 2.9 MB
Tags CPython 3.12 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
2940c6772d0226637283ccfb0b96cd325f1dcbcc145a380bb19ce3fbfe40e986
BLAKE2b-256 checksum
How to use checksums
3bed3fa026427fe3e438f14015b180b0a1310f2e053c108da507a3738927ff7f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.

Transparency log

Release files / umber-0.1.0-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL umber-0.1.0-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 2.9 MB
Tags CPython 3.12 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
68c1d393ece3bd8ccc11ab03145dc47157899243086014d5e5123c77e82b7b0d
BLAKE2b-256 checksum
How to use checksums
730878396b09c3138a0796720f45b3f73b45c5122d5415c824b2b4a04f767b25
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.

Transparency log

Release files / umber-0.1.0-cp312-abi3-macosx_11_0_arm64.whl

Download URL umber-0.1.0-cp312-abi3-macosx_11_0_arm64.whl
Size 2.7 MB
Tags CPython 3.12 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
e3e275ec2f2c416100d3cf1efb3c3de709194dbd63273c361fb0b7ec3348c9f2
BLAKE2b-256 checksum
How to use checksums
d3152b9ab242f9fa884ffc1c2de38168bd5c4b7861cf57a7465c6d549f783136
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.

Transparency log

Release files / umber-0.1.0-cp312-abi3-macosx_10_12_x86_64.whl

Download URL umber-0.1.0-cp312-abi3-macosx_10_12_x86_64.whl
Size 2.7 MB
Tags CPython 3.12 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
5570f56f1258d4d47d46c2bba81d01a766a45522cb419ee7d0eda733fec37463
BLAKE2b-256 checksum
How to use checksums
79a9a1083eede327f74185f15031f6e0b097095e8aa96856553ea7df586c569e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

6 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page