Skip to content

Charts

Every chart class and setting in beacon.plot. Charts explains how to use them, and the Gallery shows each one.

Chart classes, each drawn with matplotlib and made interactive with .interactive():

Class Draws
Line One or more series over dates or numbers, with an optional second axis
Area Parts of a whole stacked, or one series filled from zero
Column Values by category, upright
Bar Values by category, across
Combo Columns on the left axis and a line on the right
Scatter One measure against another
Histogram Counts in equal bins
Heatmap A table of values as colour
Grid Several charts under one heading
Table A DataFrame as a table, as an image or as HTML

Every chart class is a Chart: .save(), .show(), .figure, .ax, .axes, .layout and .interactive(). Results draw through their .plot accessor (PlotAccessor), and compare() puts several results on one chart.

Settings. A Style holds every setting, in groups: SizeSettings, HeadingSettings, TextSettings, LineSettings, AxesSettings, LegendSettings, NotesSettings, ColorSettings and TableSettings. Each group's fields are its settings, and configure(), settings() and style= take them by their short names, which the settings table lists with their defaults. use() sets the theme, palette() returns a theme's named colours and reset() goes back to Beacon's design.

Interactive charts. .interactive() returns a BeaconFigure (beacon.plot.interactive.figure), a plotly figure whose write_html() and to_html() carry the chart's fonts and its popup.

plot

Charting.

Reached through a .plot accessor on the result objects (IndexResult, BacktestResult, AttributionResult, OptimisationResult, RiskModel) rather than through free functions taking a result. That follows the same stance as the asset views: plotting is a result-layer concern, so a result knows how to draw itself and nothing else grows a chart method.

result.plot.level()
backtest.plot.performance()

Importing beacon costs nothing extra. The accessor is a descriptor that resolves on first access, so matplotlib is imported when a chart is drawn and not before. import beacon does not import it, and a test asserts that.

To compare several results on one chart, use beacon.plot.compare(a, b). To restyle any matplotlib chart, use beacon.plot.use().

Every method takes ax= and returns the Axes it drew on, so charts compose into a figure the caller laid out. The signatures carry nothing matplotlib-specific, which is what keeps an interactive backend possible later without changing any call site.

ChartMethods

ChartMethods(result: Any)

Base for the accessor classes, providing the listing repr.

A caller who types result.plot and presses enter should be told what they can do with it. Without this they get the default object repr, which answers a question nobody asked.

methods

methods() -> list[str]

Chart methods this accessor offers, alphabetically.

PlotAccessor

PlotAccessor(accessor_name: str)

Descriptor that resolves to a result's plotting methods on first use.

Attributes:

Name Type Description
accessor_name

Class in beacon.plot.accessors to instantiate, named rather than imported so this module stays free of matplotlib.

Area

Area(
    data: Data,
    stacked: bool = True,
    title: str = "",
    subtitle: str = "",
    notes: str = "",
    source: str | None = None,
    ylabel: str = "",
    xlabel: str = "",
    ylim: Limits = None,
    percent: bool = False,
    colors: Sequence[str] | None = None,
    style: StyleArgument = None,
)

Bases: Chart

Filled series: stacked parts of a whole, or one filled series such as a drawdown. The horizontal axis runs from the first value to the last, so the fill meets the axes with no gap.

Parameters:

Name Type Description Default
data Data

A Series, or a DataFrame of one series per column, indexed by dates or numbers.

required
stacked bool

Whether several series are stacked one on another; one series is filled from zero.

True
title str

The heading.

''
subtitle str

Beneath it.

''
notes str

The notes line, after "Notes:".

''
source str | None

Where the data came from, written first in the notes.

None
ylabel str

The vertical axis's title.

''
xlabel str

The horizontal axis's title.

''
ylim Limits

The vertical axis's (low, high); either may be None.

None
percent bool

Whether values are shares, written as percentages.

False
colors Sequence[str] | None

Each series' colour, by token name or hex, in order.

None
style StyleArgument

Settings for this chart alone: a Style, or settings by name.

None

Bar

Bar(
    data: Data,
    title: str = "",
    subtitle: str = "",
    notes: str = "",
    source: str | None = None,
    xlabel: str = "",
    ylabel: str = "",
    percent: bool = False,
    decimals: int = 1,
    gap: float = GAP,
    inner_gap: float = INNER_GAP,
    value_labels: bool = False,
    cap: float | None = None,
    signed: bool | None = None,
    color: str | None = None,
    up_color: str | None = None,
    down_color: str | None = None,
    colors: Sequence[str] | None = None,
    xlim: Limits = None,
    style: StyleArgument = None,
)

Bases: _Bars

Horizontal bars, one per category from the top down, so long names read across; grouped where there are several series.

Parameters:

Name Type Description Default
data Data

A Series, or a DataFrame of one series per column; its index names the categories, top to bottom.

required
title str

The heading.

''
subtitle str

Beneath it.

''
notes str

The notes line, after "Notes:".

''
source str | None

Where the data came from, written first in the notes.

None
xlabel str

The horizontal axis's title.

''
ylabel str

The categories' title.

''
percent bool

Whether values are shares, written as percentages.

False
decimals int

Decimals in the value labels.

1
gap float

The space between categories, as a share of each category's slot; 0 closes it.

GAP
inner_gap float

The space between the bars in one category, as a share of a bar; 0 closes it.

INNER_GAP
value_labels bool

Whether each bar's value is written at its end.

False
cap float | None

A marked limit, drawn as a dashed line down.

None
signed bool | None

Whether a single series is coloured by sign; by default it is, and several series take their own colours.

None
color str | None

The colour of unsigned bars; grey by default.

None
up_color str | None

Gains' colour, for this chart alone.

None
down_color str | None

Losses' colour, for this chart alone.

None
colors Sequence[str] | None

Each series' colour, in order.

None
xlim Limits

The horizontal axis's (low, high); either may be None.

None
style StyleArgument

Settings for this chart alone: a Style, or settings by name.

None

Chart

Chart(
    title: str = "",
    subtitle: str = "",
    notes: str = "",
    source: str | None = None,
    style: StyleArgument = None,
)

A chart in the Beacon frame: the mark, the heading, the plot and the notes line.

Attributes:

Name Type Description
title

The heading.

subtitle

Beneath it.

notes

The notes line, after "Notes:".

source

Where the data came from, written first in the notes.

style Style

The settings it is drawn in, fixed when it is built.

plan property

plan: Plan

What the chart's renderers draw: its layout's description and its marks.

layout property

layout: Layout

Where everything in the chart's frame goes.

figure property

figure: Any

The matplotlib figure, drawn on first use.

ax property

ax: Any

The matplotlib axes of the chart's top panel, drawn on first use.

axes property

axes: list[Any]

Every panel's matplotlib axes, top to bottom.

show

show() -> None

Show the chart: in a notebook, beneath the cell; otherwise in a window.

interactive

interactive() -> Any

The chart as an interactive plotly figure, laid out as its image is, with a popup and crosshair under the pointer.

Its .write_html() and .to_html() carry the chart's fonts, plotly.js and the popup's script, so the file looks the same offline.

Returns:

Name Type Description
BeaconFigure Any

A plotly figure.

save

save(path: str | Path, dpi: int | None = None) -> Path

Write the chart to a file at its designed size.

Parameters:

Name Type Description Default
path str | Path

Where; its suffix picks the format: .png, .svg or .pdf.

required
dpi int | None

Pixels per inch for a PNG; the style's by default.

None

Returns:

Name Type Description
Path Path

Where it was written.

Column

Column(
    data: Data,
    title: str = "",
    subtitle: str = "",
    notes: str = "",
    source: str | None = None,
    ylabel: str = "",
    xlabel: str = "",
    percent: bool = False,
    decimals: int = 1,
    gap: float = GAP,
    inner_gap: float = INNER_GAP,
    value_labels: bool = False,
    cap: float | None = None,
    signed: bool | None = None,
    color: str | None = None,
    up_color: str | None = None,
    down_color: str | None = None,
    colors: Sequence[str] | None = None,
    ylim: Limits = None,
    style: StyleArgument = None,
)

Bases: _Bars

Vertical bars, one per category, grouped where there are several series.

Parameters:

Name Type Description Default
data Data

A Series, or a DataFrame of one series per column; its index names the categories, left to right.

required
title str

The heading.

''
subtitle str

Beneath it.

''
notes str

The notes line, after "Notes:".

''
source str | None

Where the data came from, written first in the notes.

None
ylabel str

The vertical axis's title.

''
xlabel str

The categories' title.

''
percent bool

Whether values are shares, written as percentages.

False
decimals int

Decimals in the value labels.

1
gap float

The space between categories, as a share of each category's slot; 0 closes it.

GAP
inner_gap float

The space between the columns in one category, as a share of a column; 0 closes it.

INNER_GAP
value_labels bool

Whether each column's value is written at its end.

False
cap float | None

A marked limit, drawn as a dashed line across.

None
signed bool | None

Whether a single series is coloured by sign; by default it is, and several series take their own colours.

None
color str | None

The colour of unsigned columns; grey by default.

None
up_color str | None

Gains' colour, for this chart alone.

None
down_color str | None

Losses' colour, for this chart alone.

None
colors Sequence[str] | None

Each series' colour, in order.

None
ylim Limits

The vertical axis's (low, high); either may be None.

None
style StyleArgument

Settings for this chart alone: a Style, or settings by name.

None

Combo

Combo(
    columns: Series,
    line: Series,
    title: str = "",
    subtitle: str = "",
    notes: str = "",
    source: str | None = None,
    ylabel: str = "",
    ylabel_secondary: str = "",
    xlabel: str = "",
    gap: float = GAP,
    signed: bool = True,
    color: str | None = None,
    up_color: str | None = None,
    down_color: str | None = None,
    line_color: str | None = None,
    ylim: Limits = None,
    ylim_secondary: Limits = None,
    style: StyleArgument = None,
)

Bases: Chart

Columns on the left axis and a line on the right, for a flow and a stock measured on one calendar.

On dates, each column is as wide as the step to the next date less the gap; with gap=0 each runs to the next date, so daily columns meet edge to edge.

Parameters:

Name Type Description Default
columns Series

The columns' series, indexed by dates or categories.

required
line Series

The line's series, on the same index, measured on the right.

required
title str

The heading.

''
subtitle str

Beneath it.

''
notes str

The notes line, after "Notes:".

''
source str | None

Where the data came from, written first in the notes.

None
ylabel str

The left axis's title.

''
ylabel_secondary str

The right axis's title.

''
xlabel str

The horizontal axis's title.

''
gap float

The space between columns, as a share of each one's slot.

GAP
signed bool

Whether the columns are coloured by sign; they are by default.

True
color str | None

The colour of unsigned columns; grey by default.

None
up_color str | None

Gains' colour, for this chart alone.

None
down_color str | None

Losses' colour, for this chart alone.

None
line_color str | None

The line's colour; the accent by default.

None
ylim Limits

The left axis's (low, high); either may be None.

None
ylim_secondary Limits

The right axis's (low, high).

None
style StyleArgument

Settings for this chart alone: a Style, or settings by name.

None

Grid

Grid(
    charts: Sequence[Sequence[Chart | None]],
    title: str = "",
    subtitle: str = "",
    notes: str = "",
    source: str | None = None,
    heights: Sequence[float] | None = None,
    widths: Sequence[float] | None = None,
    sharex: bool = False,
    style: StyleArgument = None,
)

Bases: Chart

Charts laid out in rows and columns under one heading and one notes line, each panel with its chart's title above it.

The same chart named in neighbouring cells takes them all, so a tall chart can run beside two short ones. Each column is given the room its labels take, and the heading and legend line up with the outer panels' edges.

Parameters:

Name Type Description Default
charts Sequence[Sequence[Chart | None]]

Rows of charts, top to bottom, each row left to right; None leaves a cell empty, and one chart in a rectangle of cells spans them. Each chart draws one panel, titled with its own title; its subtitle and notes are not drawn.

required
title str

The heading.

''
subtitle str

Beneath it.

''
notes str

The notes line, after "Notes:".

''
source str | None

Where the data came from, written first in the notes.

None
heights Sequence[float] | None

The rows' shares of the height, such as (3, 1) for a tall row over a short one; equal by default.

None
widths Sequence[float] | None

The columns' shares of the width; equal by default.

None
sharex bool

Whether every panel on dates runs over the same dates, even where one series starts later. A panel on dates with another directly beneath it then leaves its dates to the one beneath.

False
style StyleArgument

Settings for this chart alone: a Style, or settings by name.

None

Raises:

Type Description
ValueError

If there is no chart, one draws more than one panel, or one is named in cells that do not make a rectangle.

Heatmap

Heatmap(
    data: DataFrame,
    title: str = "",
    subtitle: str = "",
    notes: str = "",
    source: str | None = None,
    colormap: str | Sequence[str] | None = None,
    vmin: float | None = None,
    vmax: float | None = None,
    values: bool = True,
    decimals: int = 2,
    percent: bool = False,
    lower: bool = False,
    shading: Literal["squares", "blended"] = "squares",
    gap: float = GAP,
    colorbar: bool = True,
    style: StyleArgument = None,
)

Bases: Chart

A table of values as colour: one cell per row and column.

The frame is cropped to what the chart draws, at the same scale, so a square table does not leave the frame's width empty.

Parameters:

Name Type Description Default
data DataFrame

A DataFrame: its index names the rows, top to bottom, and its columns the columns, left to right.

required
title str

The heading.

''
subtitle str

Beneath it.

''
notes str

The notes line, after "Notes:".

''
source str | None

Where the data came from, written first in the notes.

None
colormap str | Sequence[str] | None

A colour map's name (beacon.plot.colormaps), "_r" on the end to reverse it, or a list of hex colours from low to high. By default "blue-red" around zero for values either side of it, and "blues" otherwise.

None
vmin float | None

The value at the map's low end; by default the data's, or minus the largest size either side of zero.

None
vmax float | None

The value at its high end.

None
values bool

Whether each cell's value is written in it.

True
decimals int

Decimals in the written values and the colour bar's ends.

2
percent bool

Whether values are shares, written as percentages.

False
lower bool

Whether only the lower triangle is drawn, for a symmetric table such as correlations.

False
shading Literal['squares', 'blended']

"squares" draws each cell as its own square; "blended" blends each colour into the next.

'squares'
gap float

The space between cells, as a share of a cell; 0 for none.

GAP
colorbar bool

Whether the colour scale is drawn beside, labelled at its ends.

True
style StyleArgument

Settings for this chart alone: a Style, or settings by name.

None

Histogram

Histogram(
    data: Data,
    bins: int = BINS,
    title: str = "",
    subtitle: str = "",
    notes: str = "",
    source: str | None = None,
    xlabel: str | None = None,
    ylabel: str = "Count",
    normal: bool = False,
    mark: Mapping[str, float] | None = None,
    percent: bool = False,
    color: str | None = None,
    style: StyleArgument = None,
)

Bases: Chart

How a measure is spread: counts in equal bins.

Parameters:

Name Type Description Default
data Data

The values, as a Series.

required
bins int

How many equal bins.

BINS
title str

The heading.

''
subtitle str

Beneath it.

''
notes str

The notes line, after "Notes:".

''
source str | None

Where the data came from, written first in the notes.

None
xlabel str | None

The horizontal axis's title; the series' name by default.

None
ylabel str

The vertical axis's title.

'Count'
normal bool

Whether to draw the normal curve with the values' mean and standard deviation.

False
mark Mapping[str, float] | None

Values marked with a line and named, such as {"95% VaR": -0.02}.

None
percent bool

Whether values are shares, written as percentages.

False
color str | None

The bars' colour.

None
style StyleArgument

Settings for this chart alone: a Style, or settings by name.

None

Line

Line(
    data: Data,
    secondary: Data | None = None,
    title: str = "",
    subtitle: str = "",
    notes: str = "",
    source: str | None = None,
    ylabel: str = "",
    ylabel_secondary: str = "",
    xlabel: str = "",
    reference: float | None = None,
    label_last: bool | str | Sequence[str] = False,
    end_names: bool | Sequence[str] = False,
    legend: bool = True,
    periods: Periods = None,
    period_labels: bool = True,
    period_legend: str | None = None,
    xlim: Limits = None,
    ylim: Limits = None,
    ylim_secondary: Limits = None,
    invert: bool = False,
    percent: bool = False,
    colors: Sequence[str] | None = None,
    style: StyleArgument = None,
)

Bases: Chart

One or more series as lines, the first in the accent colour and drawn heavier.

Parameters:

Name Type Description Default
data Data

A Series, or a DataFrame of one series per column. Its index is the horizontal axis: dates, or numbers.

required
secondary Data | None

Series measured on a second axis, on the right, drawn lighter.

None
title str

The heading.

''
subtitle str

Beneath it.

''
notes str

The notes line, after "Notes:".

''
source str | None

Where the data came from, written first in the notes.

None
ylabel str

The left axis's title.

''
ylabel_secondary str

The right axis's title.

''
xlabel str

The horizontal axis's title.

''
reference float | None

A value the chart is read against, such as 100, drawn as a line across it.

None
label_last bool | str | Sequence[str]

Dot and label the last value: True for the first series, or the names of the series to label.

False
end_names bool | Sequence[str]

Write series' names at their lines' ends: True for every series but the first, or the names of the series to name.

False
legend bool

Whether several series are named in a legend.

True
periods Periods

Marked periods, as boxes from the bottom of the plot to the top behind the series: {label: (start, end)}, or a list of (start, end) or (start, end, label).

None
period_labels bool

Whether each period's label is written at the top of its box.

True
period_legend str | None

Names the periods once in the legend.

None
xlim Limits

The horizontal axis's (low, high); either may be None.

None
ylim Limits

The left axis's (low, high).

None
ylim_secondary Limits

The right axis's (low, high).

None
invert bool

Whether the left axis runs from high at the bottom to low at the top.

False
percent bool

Whether values are shares, written as percentages.

False
colors Sequence[str] | None

Each series' colour, by token name or hex, in order (the secondary series after the others); the palette by default.

None
style StyleArgument

Settings for this chart alone: a Style, or settings by name.

None

Scatter

Scatter(
    data: DataFrame | None = None,
    x: str | Series | None = None,
    y: str | Series | None = None,
    labels: str | Series | None = None,
    name: str = "Points",
    title: str = "",
    subtitle: str = "",
    notes: str = "",
    source: str | None = None,
    xlabel: str | None = None,
    ylabel: str | None = None,
    fit: Literal["linear"] | None = None,
    curve: Series | None = None,
    curve_label: str | None = None,
    axes: Literal["ends", "origin"] = "ends",
    quadrants: Sequence[str] | None = None,
    signed: bool = False,
    percent: Percent = False,
    xlim: Limits = None,
    ylim: Limits = None,
    color: str | None = None,
    style: StyleArgument = None,
)

Bases: Chart

Points, one measure against another.

Parameters:

Name Type Description Default
data DataFrame | None

A DataFrame with a column for each measure, or None when x and y are given as series.

None
x str | Series | None

The horizontal measure: a column's name, or a series.

None
y str | Series | None

The vertical measure: a column's name, or a series.

None
labels str | Series | None

Names written beside the points: a column's name, or a series.

None
name str

What the points are, in the legend when there is one.

'Points'
title str

The heading.

''
subtitle str

Beneath it.

''
notes str

The notes line, after "Notes:".

''
source str | None

Where the data came from, written first in the notes.

None
xlabel str | None

The horizontal axis's title; the x measure's name by default.

None
ylabel str | None

The vertical axis's title; the y measure's name by default.

None
fit Literal['linear'] | None

"linear" draws a fitted line and writes its slope (beta) and fit (R squared) on the chart.

None
curve Series | None

A curve through the same axes, such as a frontier: a series of y indexed by x.

None
curve_label str | None

The curve's name in the legend.

None
axes Literal['ends', 'origin']

"ends" puts the axes at the plot's edges; "origin" draws them through zero, for a chart read as four quadrants.

'ends'
quadrants Sequence[str] | None

Names for the quadrants, from the top right anticlockwise.

None
signed bool

Whether points are coloured by whether x and y share a sign.

False
percent Percent

Whether values are shares, written as percentages: True for both axes, or "x" or "y" for one.

False
xlim Limits

The horizontal axis's (low, high); either may be None.

None
ylim Limits

The vertical axis's (low, high).

None
color str | None

The points' colour.

None
style StyleArgument

Settings for this chart alone: a Style, or settings by name.

None

Table

Table(
    data: DataFrame,
    title: str = "",
    subtitle: str = "",
    notes: str = "",
    source: str | None = None,
    formats: Mapping[str, Format] | None = None,
    negatives: str = "minus",
    signed: Sequence[str] = (),
    groups: Mapping[str, int | Sequence[str]] | None = None,
    row_groups: Mapping[str, Sequence[str]] | None = None,
    row_group_headings: bool = False,
    highlight: Sequence[str] = (),
    heatmap: Mapping[str, Any] | None = None,
    preset: str | None = None,
    style: StyleArgument = None,
)

Bases: Chart

A DataFrame under the Beacon frame: the mark, the heading, the table and the notes line. Its look (rules, boxes, spacing, text and colours) is the style's table group.

Parameters:

Name Type Description Default
data DataFrame

The table: its index names the rows, its columns the columns.

required
title str

The heading.

''
subtitle str

Beneath it.

''
notes str

The notes line, after "Notes:".

''
source str | None

Where the data came from, written first in the notes.

None
formats Mapping[str, Format] | None

Each column's format, or a group's for all its columns: a format string for a value's size such as "{:,.1f}", a mapping of decimals, prefix, suffix, thousands and percent, or a function.

None
negatives str

"minus" writes a negative with a minus sign; "brackets" writes -1.2 as (1.2).

'minus'
signed Sequence[str]

Columns, or groups, whose values are coloured by sign.

()
groups Mapping[str, int | Sequence[str]] | None

Column groups: {heading: [columns]}, or {heading: how many columns} in order. Each heading sits centred over its columns.

None
row_groups Mapping[str, Sequence[str]] | None

Row groups: {heading: [rows]}. Rows in no group follow.

None
row_group_headings bool

Whether each row group's heading is shown: in a column at the table's left, merged and centred beside its rows.

False
highlight Sequence[str]

Rows set in bold.

()
heatmap Mapping[str, Any] | None

Colours a column, or a column group, by value: {"column": name} or {"group": heading}, with "colormap" (a map's name or hex colours; "blue-red" by default), "reverse", "scale" ("column" or "group"), "center" (such as 0), "fade" (near-neutral cells take the table's background), "values" (False hides the numbers), "shading" ("squares" or "blended") and "blend" ("columns", "rows" or "both").

None
preset str | None

The look's rules and boxes: "lines", "plain" or "boxed"; the style's by default.

None
style StyleArgument

Settings for this table alone: a Style, or settings by name.

None

Raises:

Type Description
ValueError

If an option names a column, group or row the table does not have.

layout property

layout: Layout

Where the table's frame goes: its heading, notes, accent bar and mark.

show

show() -> None

Show the table: in a notebook, beneath the cell; otherwise in a window.

interactive

interactive() -> Any

A table has no plotly figure: its HTML (to_html()) is its interactive form, with columns that sort.

Raises:

Type Description
TypeError

Always.

to_html

to_html() -> str

The table as HTML: the heading, the table and the notes, in the table's theme, with columns that sort when their headings are clicked.

Style dataclass

Style(
    theme: str = "beacon-light",
    size: SizeSettings = SizeSettings(),
    heading: HeadingSettings = HeadingSettings(),
    text: TextSettings = TextSettings(),
    lines: LineSettings = LineSettings(),
    axes: AxesSettings = AxesSettings(),
    legend: LegendSettings = LegendSettings(),
    notes: NotesSettings = NotesSettings(),
    colors: ColorSettings = ColorSettings(),
    table: TableSettings = TableSettings(),
)

A chart look: every setting, with Beacon's design as the default.

Build one from a preset and change what differs:

house = Style.beacon().replace(heading={"mark": False},
                               lines={"series_width": 2.0})

Attributes:

Name Type Description
theme str

The theme: "beacon-light" (the default), "beacon-dark", "github-dark", "white", "transparent-dark-axes" or "transparent-light-axes".

size, (heading, text, lines, axes, legend, notes, colors, table)

The settings, grouped. Each group's documentation lists its own.

beacon classmethod

beacon() -> Style

Beacon's design: the default.

plain classmethod

plain() -> Style

Beacon's design for work that is not a Beacon report: no beta mark, on white. The accent bar and Beacon's fonts stay.

preset classmethod

preset(name: str) -> Style

A preset by name: "beacon" or "plain".

Raises:

Type Description
ValueError

If there is no such preset.

replace

replace(
    theme: str | None = None,
    **groups: Mapping[str, Any] | Any,
) -> Style

A copy with some settings changed, by group.

Parameters:

Name Type Description Default
theme str | None

A new theme.

None
**groups Mapping[str, Any] | Any

A group's name and either the settings that change in it, as a mapping, or a whole group object.

{}

Raises:

Type Description
ValueError

If a group or setting does not exist, or a value is not allowed.

updated

updated(**settings: Any) -> Style

A copy with settings changed by their short names, as configure() takes them: style.updated(mark=False, scale=1.2).

Raises:

Type Description
ValueError

If a name is not a setting, or a value is not allowed.

to_dict

to_dict() -> dict[str, Any]

Every setting, by group. Unset (None) settings are left out.

from_dict classmethod

from_dict(data: Mapping[str, Any]) -> Style

A style from to_dict()'s form; settings left out keep their defaults.

Raises:

Type Description
ValueError

If a group or setting does not exist, or a value is not allowed.

save

save(path: str | Path) -> Path

Write this style to a TOML file, to load again with Style.load().

Returns:

Name Type Description
Path Path

Where it was written.

load classmethod

load(path: str | Path) -> Style

A style from a TOML file that Style.save() wrote, or one written by hand in the same form.

Raises:

Type Description
ValueError

If the file is not valid TOML or holds settings that do not exist.

configure

configure(
    style: Style | str | Path | None = None,
    *,
    preset: str | None = None,
    **settings: Any,
) -> Style

Make a look the default for every chart drawn afterwards.

Settings given by name change the current style rather than replacing it, so configure(mark=False) and then configure(scale=1.2) keep both.

Parameters:

Name Type Description Default
style Style | str | Path | None

A Style, or the path of a TOML file Style.save() wrote, to start from instead of the current style.

None
preset str | None

"beacon" or "plain", to start from instead.

None
**settings Any

Settings by their short names, such as mark=False, heading_scale=1.2, legend="bottom" or theme="white".

{}

Returns:

Name Type Description
Style Style

The style now in force.

Raises:

Type Description
TypeError

If both a style and a preset are given.

ValueError

If a setting does not exist or a value is not allowed.

current

current() -> Style

The style charts are drawn in now.

reset

reset() -> Style

Go back to Beacon's design.

Returns:

Name Type Description
Style Style

The default style, now in force.

settings

settings(
    style: Style | str | Path | None = None,
    *,
    preset: str | None = None,
    **changes: Any,
) -> Iterator[Style]

A look for one with block; the previous one comes back after it.

with settings(mark=False, theme="white"):
    result.plot.level()

Takes what configure() takes.

Yields:

Name Type Description
Style Style

The style in force inside the block.

accessors

The chart methods reached through result.plot.

Each method builds one of the chart classes in beacon.plot from a result and returns it, so a result's chart has the same options as any other: .show(), .save(path), its .figure and .ax, and style=. A chart is drawn only when it is used, so these methods need no matplotlib.

Where the numbers come from

Nowhere here. Every method reads a result object and draws it; the arithmetic belongs to the analysis layer and is tested there. The one exception is the reconciliation total in the contributions chart's notes, recomputed from the bars actually drawn, because a total that does not match the bars beside it is worse than none.

IndexPlots

IndexPlots(result: Any)

Bases: ChartMethods

Charts for an IndexResult.

level
level(
    benchmark: Series | None = None,
    label: str = "Index",
    title: str | None = None,
    subtitle: str | None = None,
    notes: str | None = None,
    style: StyleArgument = None,
) -> Chart

The index level over time, rebased to 100.

Parameters:

Name Type Description Default
benchmark Series | None

Optional comparison series, drawn subordinate.

None
label str

The index's name in the legend.

'Index'
title str | None

The heading. Defaults to the chart's own.

None
subtitle str | None

Beneath the heading. Defaults to what the chart shows.

None
notes str | None

The notes line, after "Notes:". Defaults to the data's source and dates and what the chart needs said.

None
style StyleArgument

Settings for this chart alone: a Style, or settings by name such as {"mark": False, "scale": 1.2}. None draws in the current style (beacon.plot.configure).

None

Returns:

Name Type Description
Chart Chart

The chart, drawn when it is used.

constituents
constituents(
    limit: int = MAX_LINES,
    title: str | None = None,
    subtitle: str | None = None,
    notes: str | None = None,
    style: StyleArgument = None,
) -> Chart

The index among its constituents, each rebased to 100.

The constituents are the names held at the latest rebalance, each drawn from its close in the data the index was calculated from and named at the end of its line. The index is drawn over them.

Parameters:

Name Type Description Default
limit int

How many constituents to draw, the largest by weight at the latest rebalance. The notes say how many were left out.

MAX_LINES
title str | None

The heading. Defaults to the chart's own.

None
subtitle str | None

Beneath the heading. Defaults to what the chart shows.

None
notes str | None

The notes line, after "Notes:". Defaults to the data's source and dates and what the chart needs said.

None
style StyleArgument

Settings for this chart alone: a Style, or settings by name such as {"mark": False, "scale": 1.2}. None draws in the current style (beacon.plot.configure).

None

Returns:

Name Type Description
Chart Chart

The chart, drawn when it is used.

Raises:

Type Description
ValueError

If the result is bound to no data to read the constituents' prices from.

weights
weights(
    date: Timestamp | None = None,
    title: str | None = None,
    subtitle: str | None = None,
    notes: str | None = None,
    style: StyleArgument = None,
) -> Chart

Constituent weights at a rebalance, largest first, with the cap.

Parameters:

Name Type Description Default
date Timestamp | None

Which rebalance. Defaults to the latest.

None
title str | None

The heading. Defaults to the chart's own.

None
subtitle str | None

Beneath the heading. Defaults to what the chart shows.

None
notes str | None

The notes line, after "Notes:". Defaults to the data's source and dates and what the chart needs said.

None
style StyleArgument

Settings for this chart alone: a Style, or settings by name such as {"mark": False, "scale": 1.2}. None draws in the current style (beacon.plot.configure).

None

Returns:

Name Type Description
Chart Chart

The chart, drawn when it is used.

BacktestPlots

BacktestPlots(result: Any)

Bases: ChartMethods

Charts for a BacktestResult.

performance
performance(
    title: str | None = None,
    subtitle: str | None = None,
    notes: str | None = None,
    style: StyleArgument = None,
) -> Chart

Growth of 100 with a drawdown panel beneath it.

The two share a horizontal axis, because a drawdown is only meaningful against the path that produced it, and reading them side by side would mean matching dates by eye.

Parameters:

Name Type Description Default
title str | None

The heading. Defaults to the chart's own.

None
subtitle str | None

Beneath the heading. Defaults to what the chart shows.

None
notes str | None

The notes line, after "Notes:". Defaults to the data's source and dates and what the chart needs said.

None
style StyleArgument

Settings for this chart alone: a Style, or settings by name such as {"mark": False, "scale": 1.2}. None draws in the current style (beacon.plot.configure).

None

Returns:

Name Type Description
Chart Chart

The chart, drawn when it is used.

constituents
constituents(
    limit: int = MAX_LINES,
    title: str | None = None,
    subtitle: str | None = None,
    notes: str | None = None,
    style: StyleArgument = None,
) -> Chart

The index the backtest tracked, among its constituents.

The same chart as IndexResult.plot.constituents(), for the index the run aimed at.

Parameters:

Name Type Description Default
limit int

How many constituents to draw, the largest by weight.

MAX_LINES
title str | None

The heading. Defaults to the chart's own.

None
subtitle str | None

Beneath the heading. Defaults to what the chart shows.

None
notes str | None

The notes line, after "Notes:". Defaults to the data's source and dates and what the chart needs said.

None
style StyleArgument

Settings for this chart alone: a Style, or settings by name such as {"mark": False, "scale": 1.2}. None draws in the current style (beacon.plot.configure).

None

Returns:

Name Type Description
Chart Chart

The chart, drawn when it is used.

Raises:

Type Description
ValueError

If the run tracked weights rather than an index.

annual_returns
annual_returns(
    title: str | None = None,
    subtitle: str | None = None,
    notes: str | None = None,
    style: StyleArgument = None,
) -> Chart

Calendar-year returns as signed columns.

Parameters:

Name Type Description Default
title str | None

The heading. Defaults to the chart's own.

None
subtitle str | None

Beneath the heading. Defaults to what the chart shows.

None
notes str | None

The notes line, after "Notes:". Defaults to the data's source and dates and what the chart needs said.

None
style StyleArgument

Settings for this chart alone: a Style, or settings by name such as {"mark": False, "scale": 1.2}. None draws in the current style (beacon.plot.configure).

None

Returns:

Name Type Description
Chart Chart

The chart, drawn when it is used.

AttributionPlots

AttributionPlots(result: Any)

Bases: ChartMethods

Charts for an AttributionResult.

contributions
contributions(
    title: str | None = None,
    subtitle: str | None = None,
    notes: str | None = None,
    style: StyleArgument = None,
) -> Chart

Per-constituent contributions as diverging bars, largest first.

The drags are stated in the chart's notes rather than drawn as bars, because they are comparisons against a counterfactual rather than terms in the decomposition: adding them to the same total would mix two different questions.

The total in the notes is recomputed from the bars actually drawn. A total that does not match what is beside it is worse than none, and adding up the page is the only way to be sure.

Parameters:

Name Type Description Default
title str | None

The heading. Defaults to the chart's own.

None
subtitle str | None

Beneath the heading. Defaults to what the chart shows.

None
notes str | None

The notes line, after "Notes:". Defaults to the data's source and dates and what the chart needs said.

None
style StyleArgument

Settings for this chart alone: a Style, or settings by name such as {"mark": False, "scale": 1.2}. None draws in the current style (beacon.plot.configure).

None

Returns:

Name Type Description
Chart Chart

The chart, drawn when it is used.

OptimisationPlots

OptimisationPlots(result: Any)

Bases: ChartMethods

Charts for an OptimisationResult.

exposures
exposures(
    title: str | None = None,
    subtitle: str | None = None,
    notes: str | None = None,
    style: StyleArgument = None,
) -> Chart

Active weights as sign-coloured tilts against the index, largest first.

Parameters:

Name Type Description Default
title str | None

The heading. Defaults to the chart's own.

None
subtitle str | None

Beneath the heading. Defaults to what the chart shows.

None
notes str | None

The notes line, after "Notes:". Defaults to the data's source and dates and what the chart needs said.

None
style StyleArgument

Settings for this chart alone: a Style, or settings by name such as {"mark": False, "scale": 1.2}. None draws in the current style (beacon.plot.configure).

None

Returns:

Name Type Description
Chart Chart

The chart, drawn when it is used.

frontier
frontier(
    frontier: Any,
    risk_free_rate: float | None = None,
    title: str | None = None,
    subtitle: str | None = None,
    notes: str | None = None,
    style: StyleArgument = None,
) -> Chart

The efficient frontier, with the named portfolios and the capital market line.

Parameters:

Name Type Description Default
frontier Any

An EfficientFrontier over the same universe.

required
risk_free_rate float | None

Where the capital market line starts. None uses the rate the frontier was traced at, which is the one its tangency portfolio is tangent from.

None
title str | None

The heading. Defaults to the chart's own.

None
subtitle str | None

Beneath the heading. Defaults to what the chart shows.

None
notes str | None

The notes line, after "Notes:". Defaults to the data's source and dates and what the chart needs said.

None
style StyleArgument

Settings for this chart alone: a Style, or settings by name such as {"mark": False, "scale": 1.2}. None draws in the current style (beacon.plot.configure).

None

Returns:

Name Type Description
Chart Chart

The chart, drawn when it is used.

RiskPlots

RiskPlots(result: Any)

Bases: ChartMethods

Charts for a RiskModel.

correlation
correlation(
    shading: str = "squares",
    title: str | None = None,
    subtitle: str | None = None,
    notes: str | None = None,
    style: StyleArgument = None,
) -> Chart

The correlation matrix as a heatmap.

Parameters:

Name Type Description Default
shading str

"squares" draws each pair as its own cell; "blended" runs the colours smoothly from cell to cell, which shows the shape of the matrix rather than each value.

'squares'
title str | None

The heading. Defaults to the chart's own.

None
subtitle str | None

Beneath the heading. Defaults to what the chart shows.

None
notes str | None

The notes line, after "Notes:". Defaults to the data's source and dates and what the chart needs said.

None
style StyleArgument

Settings for this chart alone: a Style, or settings by name such as {"mark": False, "scale": 1.2}. None draws in the current style (beacon.plot.configure).

None

Returns:

Name Type Description
Chart Chart

The chart, drawn when it is used.

Raises:

Type Description
ValueError

If shading is not "squares" or "blended".

analysis_charts

The chart methods for an OptimisationResult and a RiskModel, reached through result.plot like the others in accessors.

OptimisationPlots

OptimisationPlots(result: Any)

Bases: ChartMethods

Charts for an OptimisationResult.

exposures
exposures(
    title: str | None = None,
    subtitle: str | None = None,
    notes: str | None = None,
    style: StyleArgument = None,
) -> Chart

Active weights as sign-coloured tilts against the index, largest first.

Parameters:

Name Type Description Default
title str | None

The heading. Defaults to the chart's own.

None
subtitle str | None

Beneath the heading. Defaults to what the chart shows.

None
notes str | None

The notes line, after "Notes:". Defaults to the data's source and dates and what the chart needs said.

None
style StyleArgument

Settings for this chart alone: a Style, or settings by name such as {"mark": False, "scale": 1.2}. None draws in the current style (beacon.plot.configure).

None

Returns:

Name Type Description
Chart Chart

The chart, drawn when it is used.

frontier
frontier(
    frontier: Any,
    risk_free_rate: float | None = None,
    title: str | None = None,
    subtitle: str | None = None,
    notes: str | None = None,
    style: StyleArgument = None,
) -> Chart

The efficient frontier, with the named portfolios and the capital market line.

Parameters:

Name Type Description Default
frontier Any

An EfficientFrontier over the same universe.

required
risk_free_rate float | None

Where the capital market line starts. None uses the rate the frontier was traced at, which is the one its tangency portfolio is tangent from.

None
title str | None

The heading. Defaults to the chart's own.

None
subtitle str | None

Beneath the heading. Defaults to what the chart shows.

None
notes str | None

The notes line, after "Notes:". Defaults to the data's source and dates and what the chart needs said.

None
style StyleArgument

Settings for this chart alone: a Style, or settings by name such as {"mark": False, "scale": 1.2}. None draws in the current style (beacon.plot.configure).

None

Returns:

Name Type Description
Chart Chart

The chart, drawn when it is used.

RiskPlots

RiskPlots(result: Any)

Bases: ChartMethods

Charts for a RiskModel.

correlation
correlation(
    shading: str = "squares",
    title: str | None = None,
    subtitle: str | None = None,
    notes: str | None = None,
    style: StyleArgument = None,
) -> Chart

The correlation matrix as a heatmap.

Parameters:

Name Type Description Default
shading str

"squares" draws each pair as its own cell; "blended" runs the colours smoothly from cell to cell, which shows the shape of the matrix rather than each value.

'squares'
title str | None

The heading. Defaults to the chart's own.

None
subtitle str | None

Beneath the heading. Defaults to what the chart shows.

None
notes str | None

The notes line, after "Notes:". Defaults to the data's source and dates and what the chart needs said.

None
style StyleArgument

Settings for this chart alone: a Style, or settings by name such as {"mark": False, "scale": 1.2}. None draws in the current style (beacon.plot.configure).

None

Returns:

Name Type Description
Chart Chart

The chart, drawn when it is used.

Raises:

Type Description
ValueError

If shading is not "squares" or "blended".

arrange

A chart's frame, laid out from what it draws and a Style.

lay_out() places the heading (the mark, the accent bar, the title and the subtitle), fits the plot between it and the notes, ends each measuring axis on its ticks, widens the sides to keep every label inside the figure, and puts the legend where the style says. Every size, weight, font and colour comes from the style.

The plot's height depends on how many lines the notes take and how tall the legend is, their widths on where the plot's sides end up, and a heatmap narrows as it shortens, so the layout is worked out in passes.

Heading dataclass

Heading(
    title: float,
    subtitle: float,
    title_font: Font,
    subtitle_font: Font,
    bar_width: float,
    bar_gap: float,
    top: float,
    subtitle_top: float,
    bottom: float,
    reach: float,
)

The heading's sizes and where it sits.

wrap

wrap(
    text: str, width: float, size: float, font: Font
) -> list[str]

Text broken into lines no wider than width inches, at spaces; a word longer than that has a line to itself.

lay_out

lay_out(chart: Description, style: Style) -> Layout

Lay a chart's frame out in a style.

A chart that asks to be cropped is narrowed to what it draws, at the same scale, and laid out again until its width settles.

Parameters:

Name Type Description Default
chart Description

What the chart draws.

required
style Style

The settings it is drawn in.

required

Returns:

Name Type Description
Layout Layout

Where everything goes.

framed

framed(
    chart: Description,
    style: Style,
    heading: Heading,
    laid: list[PanelLayout],
    legend: LegendLayout | None,
    left: float,
    notes: Text | None,
) -> Layout

The layout, with the heading placed beside the plot's left edge.

base

The lazy .plot accessor.

Every result object carries one, and none of them cost anything until it is touched. That is the whole point of this module: it imports nothing beyond the standard library, so import beacon does not import matplotlib, and a user who never draws a chart never pays for the ability to.

The mechanism is a descriptor. IndexResult.plot is an attribute lookup that resolves, on first access, to a class in beacon.plot.accessors, which is where matplotlib is required. Accessed on the class rather than an instance, it returns the descriptor itself, so help() and hasattr work without matplotlib.

PlotAccessor

PlotAccessor(accessor_name: str)

Descriptor that resolves to a result's plotting methods on first use.

Attributes:

Name Type Description
accessor_name

Class in beacon.plot.accessors to instantiate, named rather than imported so this module stays free of matplotlib.

ChartMethods

ChartMethods(result: Any)

Base for the accessor classes, providing the listing repr.

A caller who types result.plot and presses enter should be told what they can do with it. Without this they get the default object repr, which answers a question nobody asked.

methods
methods() -> list[str]

Chart methods this accessor offers, alphabetically.

charts

A chart class for each kind of chart, each taking a DataFrame or a Series and drawing it inside the Beacon frame.

Building a chart only describes it; it is drawn when it is shown, saved, or its figure is asked for. So these import without matplotlib.

Bar

Bar(
    data: Data,
    title: str = "",
    subtitle: str = "",
    notes: str = "",
    source: str | None = None,
    xlabel: str = "",
    ylabel: str = "",
    percent: bool = False,
    decimals: int = 1,
    gap: float = GAP,
    inner_gap: float = INNER_GAP,
    value_labels: bool = False,
    cap: float | None = None,
    signed: bool | None = None,
    color: str | None = None,
    up_color: str | None = None,
    down_color: str | None = None,
    colors: Sequence[str] | None = None,
    xlim: Limits = None,
    style: StyleArgument = None,
)

Bases: _Bars

Horizontal bars, one per category from the top down, so long names read across; grouped where there are several series.

Parameters:

Name Type Description Default
data Data

A Series, or a DataFrame of one series per column; its index names the categories, top to bottom.

required
title str

The heading.

''
subtitle str

Beneath it.

''
notes str

The notes line, after "Notes:".

''
source str | None

Where the data came from, written first in the notes.

None
xlabel str

The horizontal axis's title.

''
ylabel str

The categories' title.

''
percent bool

Whether values are shares, written as percentages.

False
decimals int

Decimals in the value labels.

1
gap float

The space between categories, as a share of each category's slot; 0 closes it.

GAP
inner_gap float

The space between the bars in one category, as a share of a bar; 0 closes it.

INNER_GAP
value_labels bool

Whether each bar's value is written at its end.

False
cap float | None

A marked limit, drawn as a dashed line down.

None
signed bool | None

Whether a single series is coloured by sign; by default it is, and several series take their own colours.

None
color str | None

The colour of unsigned bars; grey by default.

None
up_color str | None

Gains' colour, for this chart alone.

None
down_color str | None

Losses' colour, for this chart alone.

None
colors Sequence[str] | None

Each series' colour, in order.

None
xlim Limits

The horizontal axis's (low, high); either may be None.

None
style StyleArgument

Settings for this chart alone: a Style, or settings by name.

None

Column

Column(
    data: Data,
    title: str = "",
    subtitle: str = "",
    notes: str = "",
    source: str | None = None,
    ylabel: str = "",
    xlabel: str = "",
    percent: bool = False,
    decimals: int = 1,
    gap: float = GAP,
    inner_gap: float = INNER_GAP,
    value_labels: bool = False,
    cap: float | None = None,
    signed: bool | None = None,
    color: str | None = None,
    up_color: str | None = None,
    down_color: str | None = None,
    colors: Sequence[str] | None = None,
    ylim: Limits = None,
    style: StyleArgument = None,
)

Bases: _Bars

Vertical bars, one per category, grouped where there are several series.

Parameters:

Name Type Description Default
data Data

A Series, or a DataFrame of one series per column; its index names the categories, left to right.

required
title str

The heading.

''
subtitle str

Beneath it.

''
notes str

The notes line, after "Notes:".

''
source str | None

Where the data came from, written first in the notes.

None
ylabel str

The vertical axis's title.

''
xlabel str

The categories' title.

''
percent bool

Whether values are shares, written as percentages.

False
decimals int

Decimals in the value labels.

1
gap float

The space between categories, as a share of each category's slot; 0 closes it.

GAP
inner_gap float

The space between the columns in one category, as a share of a column; 0 closes it.

INNER_GAP
value_labels bool

Whether each column's value is written at its end.

False
cap float | None

A marked limit, drawn as a dashed line across.

None
signed bool | None

Whether a single series is coloured by sign; by default it is, and several series take their own colours.

None
color str | None

The colour of unsigned columns; grey by default.

None
up_color str | None

Gains' colour, for this chart alone.

None
down_color str | None

Losses' colour, for this chart alone.

None
colors Sequence[str] | None

Each series' colour, in order.

None
ylim Limits

The vertical axis's (low, high); either may be None.

None
style StyleArgument

Settings for this chart alone: a Style, or settings by name.

None

Combo

Combo(
    columns: Series,
    line: Series,
    title: str = "",
    subtitle: str = "",
    notes: str = "",
    source: str | None = None,
    ylabel: str = "",
    ylabel_secondary: str = "",
    xlabel: str = "",
    gap: float = GAP,
    signed: bool = True,
    color: str | None = None,
    up_color: str | None = None,
    down_color: str | None = None,
    line_color: str | None = None,
    ylim: Limits = None,
    ylim_secondary: Limits = None,
    style: StyleArgument = None,
)

Bases: Chart

Columns on the left axis and a line on the right, for a flow and a stock measured on one calendar.

On dates, each column is as wide as the step to the next date less the gap; with gap=0 each runs to the next date, so daily columns meet edge to edge.

Parameters:

Name Type Description Default
columns Series

The columns' series, indexed by dates or categories.

required
line Series

The line's series, on the same index, measured on the right.

required
title str

The heading.

''
subtitle str

Beneath it.

''
notes str

The notes line, after "Notes:".

''
source str | None

Where the data came from, written first in the notes.

None
ylabel str

The left axis's title.

''
ylabel_secondary str

The right axis's title.

''
xlabel str

The horizontal axis's title.

''
gap float

The space between columns, as a share of each one's slot.

GAP
signed bool

Whether the columns are coloured by sign; they are by default.

True
color str | None

The colour of unsigned columns; grey by default.

None
up_color str | None

Gains' colour, for this chart alone.

None
down_color str | None

Losses' colour, for this chart alone.

None
line_color str | None

The line's colour; the accent by default.

None
ylim Limits

The left axis's (low, high); either may be None.

None
ylim_secondary Limits

The right axis's (low, high).

None
style StyleArgument

Settings for this chart alone: a Style, or settings by name.

None

Chart

Chart(
    title: str = "",
    subtitle: str = "",
    notes: str = "",
    source: str | None = None,
    style: StyleArgument = None,
)

A chart in the Beacon frame: the mark, the heading, the plot and the notes line.

Attributes:

Name Type Description
title

The heading.

subtitle

Beneath it.

notes

The notes line, after "Notes:".

source

Where the data came from, written first in the notes.

style Style

The settings it is drawn in, fixed when it is built.

plan property
plan: Plan

What the chart's renderers draw: its layout's description and its marks.

layout property
layout: Layout

Where everything in the chart's frame goes.

figure property
figure: Any

The matplotlib figure, drawn on first use.

ax property
ax: Any

The matplotlib axes of the chart's top panel, drawn on first use.

axes property
axes: list[Any]

Every panel's matplotlib axes, top to bottom.

show
show() -> None

Show the chart: in a notebook, beneath the cell; otherwise in a window.

interactive
interactive() -> Any

The chart as an interactive plotly figure, laid out as its image is, with a popup and crosshair under the pointer.

Its .write_html() and .to_html() carry the chart's fonts, plotly.js and the popup's script, so the file looks the same offline.

Returns:

Name Type Description
BeaconFigure Any

A plotly figure.

save
save(path: str | Path, dpi: int | None = None) -> Path

Write the chart to a file at its designed size.

Parameters:

Name Type Description Default
path str | Path

Where; its suffix picks the format: .png, .svg or .pdf.

required
dpi int | None

Pixels per inch for a PNG; the style's by default.

None

Returns:

Name Type Description
Path Path

Where it was written.

Plan dataclass

Plan(
    description: Description,
    marks: tuple[Mark, ...],
    grid: str = "none",
    front: Side = "left",
)

A chart as its renderers draw it: what the layout needs, and the marks inside the plot.

Attributes:

Name Type Description
description Description

For the layout.

marks tuple[Mark, ...]

Drawn in order, by layer.

grid str

The chart's own gridlines, "x", "y", "both" or "none"; the style's grid replaces them where it sets one.

front Side

Where a panel has a second axis, which side's marks are drawn over the other's.

Grid

Grid(
    charts: Sequence[Sequence[Chart | None]],
    title: str = "",
    subtitle: str = "",
    notes: str = "",
    source: str | None = None,
    heights: Sequence[float] | None = None,
    widths: Sequence[float] | None = None,
    sharex: bool = False,
    style: StyleArgument = None,
)

Bases: Chart

Charts laid out in rows and columns under one heading and one notes line, each panel with its chart's title above it.

The same chart named in neighbouring cells takes them all, so a tall chart can run beside two short ones. Each column is given the room its labels take, and the heading and legend line up with the outer panels' edges.

Parameters:

Name Type Description Default
charts Sequence[Sequence[Chart | None]]

Rows of charts, top to bottom, each row left to right; None leaves a cell empty, and one chart in a rectangle of cells spans them. Each chart draws one panel, titled with its own title; its subtitle and notes are not drawn.

required
title str

The heading.

''
subtitle str

Beneath it.

''
notes str

The notes line, after "Notes:".

''
source str | None

Where the data came from, written first in the notes.

None
heights Sequence[float] | None

The rows' shares of the height, such as (3, 1) for a tall row over a short one; equal by default.

None
widths Sequence[float] | None

The columns' shares of the width; equal by default.

None
sharex bool

Whether every panel on dates runs over the same dates, even where one series starts later. A panel on dates with another directly beneath it then leaves its dates to the one beneath.

False
style StyleArgument

Settings for this chart alone: a Style, or settings by name.

None

Raises:

Type Description
ValueError

If there is no chart, one draws more than one panel, or one is named in cells that do not make a rectangle.

Heatmap

Heatmap(
    data: DataFrame,
    title: str = "",
    subtitle: str = "",
    notes: str = "",
    source: str | None = None,
    colormap: str | Sequence[str] | None = None,
    vmin: float | None = None,
    vmax: float | None = None,
    values: bool = True,
    decimals: int = 2,
    percent: bool = False,
    lower: bool = False,
    shading: Literal["squares", "blended"] = "squares",
    gap: float = GAP,
    colorbar: bool = True,
    style: StyleArgument = None,
)

Bases: Chart

A table of values as colour: one cell per row and column.

The frame is cropped to what the chart draws, at the same scale, so a square table does not leave the frame's width empty.

Parameters:

Name Type Description Default
data DataFrame

A DataFrame: its index names the rows, top to bottom, and its columns the columns, left to right.

required
title str

The heading.

''
subtitle str

Beneath it.

''
notes str

The notes line, after "Notes:".

''
source str | None

Where the data came from, written first in the notes.

None
colormap str | Sequence[str] | None

A colour map's name (beacon.plot.colormaps), "_r" on the end to reverse it, or a list of hex colours from low to high. By default "blue-red" around zero for values either side of it, and "blues" otherwise.

None
vmin float | None

The value at the map's low end; by default the data's, or minus the largest size either side of zero.

None
vmax float | None

The value at its high end.

None
values bool

Whether each cell's value is written in it.

True
decimals int

Decimals in the written values and the colour bar's ends.

2
percent bool

Whether values are shares, written as percentages.

False
lower bool

Whether only the lower triangle is drawn, for a symmetric table such as correlations.

False
shading Literal['squares', 'blended']

"squares" draws each cell as its own square; "blended" blends each colour into the next.

'squares'
gap float

The space between cells, as a share of a cell; 0 for none.

GAP
colorbar bool

Whether the colour scale is drawn beside, labelled at its ends.

True
style StyleArgument

Settings for this chart alone: a Style, or settings by name.

None

Area

Area(
    data: Data,
    stacked: bool = True,
    title: str = "",
    subtitle: str = "",
    notes: str = "",
    source: str | None = None,
    ylabel: str = "",
    xlabel: str = "",
    ylim: Limits = None,
    percent: bool = False,
    colors: Sequence[str] | None = None,
    style: StyleArgument = None,
)

Bases: Chart

Filled series: stacked parts of a whole, or one filled series such as a drawdown. The horizontal axis runs from the first value to the last, so the fill meets the axes with no gap.

Parameters:

Name Type Description Default
data Data

A Series, or a DataFrame of one series per column, indexed by dates or numbers.

required
stacked bool

Whether several series are stacked one on another; one series is filled from zero.

True
title str

The heading.

''
subtitle str

Beneath it.

''
notes str

The notes line, after "Notes:".

''
source str | None

Where the data came from, written first in the notes.

None
ylabel str

The vertical axis's title.

''
xlabel str

The horizontal axis's title.

''
ylim Limits

The vertical axis's (low, high); either may be None.

None
percent bool

Whether values are shares, written as percentages.

False
colors Sequence[str] | None

Each series' colour, by token name or hex, in order.

None
style StyleArgument

Settings for this chart alone: a Style, or settings by name.

None

Line

Line(
    data: Data,
    secondary: Data | None = None,
    title: str = "",
    subtitle: str = "",
    notes: str = "",
    source: str | None = None,
    ylabel: str = "",
    ylabel_secondary: str = "",
    xlabel: str = "",
    reference: float | None = None,
    label_last: bool | str | Sequence[str] = False,
    end_names: bool | Sequence[str] = False,
    legend: bool = True,
    periods: Periods = None,
    period_labels: bool = True,
    period_legend: str | None = None,
    xlim: Limits = None,
    ylim: Limits = None,
    ylim_secondary: Limits = None,
    invert: bool = False,
    percent: bool = False,
    colors: Sequence[str] | None = None,
    style: StyleArgument = None,
)

Bases: Chart

One or more series as lines, the first in the accent colour and drawn heavier.

Parameters:

Name Type Description Default
data Data

A Series, or a DataFrame of one series per column. Its index is the horizontal axis: dates, or numbers.

required
secondary Data | None

Series measured on a second axis, on the right, drawn lighter.

None
title str

The heading.

''
subtitle str

Beneath it.

''
notes str

The notes line, after "Notes:".

''
source str | None

Where the data came from, written first in the notes.

None
ylabel str

The left axis's title.

''
ylabel_secondary str

The right axis's title.

''
xlabel str

The horizontal axis's title.

''
reference float | None

A value the chart is read against, such as 100, drawn as a line across it.

None
label_last bool | str | Sequence[str]

Dot and label the last value: True for the first series, or the names of the series to label.

False
end_names bool | Sequence[str]

Write series' names at their lines' ends: True for every series but the first, or the names of the series to name.

False
legend bool

Whether several series are named in a legend.

True
periods Periods

Marked periods, as boxes from the bottom of the plot to the top behind the series: {label: (start, end)}, or a list of (start, end) or (start, end, label).

None
period_labels bool

Whether each period's label is written at the top of its box.

True
period_legend str | None

Names the periods once in the legend.

None
xlim Limits

The horizontal axis's (low, high); either may be None.

None
ylim Limits

The left axis's (low, high).

None
ylim_secondary Limits

The right axis's (low, high).

None
invert bool

Whether the left axis runs from high at the bottom to low at the top.

False
percent bool

Whether values are shares, written as percentages.

False
colors Sequence[str] | None

Each series' colour, by token name or hex, in order (the secondary series after the others); the palette by default.

None
style StyleArgument

Settings for this chart alone: a Style, or settings by name.

None

Histogram

Histogram(
    data: Data,
    bins: int = BINS,
    title: str = "",
    subtitle: str = "",
    notes: str = "",
    source: str | None = None,
    xlabel: str | None = None,
    ylabel: str = "Count",
    normal: bool = False,
    mark: Mapping[str, float] | None = None,
    percent: bool = False,
    color: str | None = None,
    style: StyleArgument = None,
)

Bases: Chart

How a measure is spread: counts in equal bins.

Parameters:

Name Type Description Default
data Data

The values, as a Series.

required
bins int

How many equal bins.

BINS
title str

The heading.

''
subtitle str

Beneath it.

''
notes str

The notes line, after "Notes:".

''
source str | None

Where the data came from, written first in the notes.

None
xlabel str | None

The horizontal axis's title; the series' name by default.

None
ylabel str

The vertical axis's title.

'Count'
normal bool

Whether to draw the normal curve with the values' mean and standard deviation.

False
mark Mapping[str, float] | None

Values marked with a line and named, such as {"95% VaR": -0.02}.

None
percent bool

Whether values are shares, written as percentages.

False
color str | None

The bars' colour.

None
style StyleArgument

Settings for this chart alone: a Style, or settings by name.

None

Scatter

Scatter(
    data: DataFrame | None = None,
    x: str | Series | None = None,
    y: str | Series | None = None,
    labels: str | Series | None = None,
    name: str = "Points",
    title: str = "",
    subtitle: str = "",
    notes: str = "",
    source: str | None = None,
    xlabel: str | None = None,
    ylabel: str | None = None,
    fit: Literal["linear"] | None = None,
    curve: Series | None = None,
    curve_label: str | None = None,
    axes: Literal["ends", "origin"] = "ends",
    quadrants: Sequence[str] | None = None,
    signed: bool = False,
    percent: Percent = False,
    xlim: Limits = None,
    ylim: Limits = None,
    color: str | None = None,
    style: StyleArgument = None,
)

Bases: Chart

Points, one measure against another.

Parameters:

Name Type Description Default
data DataFrame | None

A DataFrame with a column for each measure, or None when x and y are given as series.

None
x str | Series | None

The horizontal measure: a column's name, or a series.

None
y str | Series | None

The vertical measure: a column's name, or a series.

None
labels str | Series | None

Names written beside the points: a column's name, or a series.

None
name str

What the points are, in the legend when there is one.

'Points'
title str

The heading.

''
subtitle str

Beneath it.

''
notes str

The notes line, after "Notes:".

''
source str | None

Where the data came from, written first in the notes.

None
xlabel str | None

The horizontal axis's title; the x measure's name by default.

None
ylabel str | None

The vertical axis's title; the y measure's name by default.

None
fit Literal['linear'] | None

"linear" draws a fitted line and writes its slope (beta) and fit (R squared) on the chart.

None
curve Series | None

A curve through the same axes, such as a frontier: a series of y indexed by x.

None
curve_label str | None

The curve's name in the legend.

None
axes Literal['ends', 'origin']

"ends" puts the axes at the plot's edges; "origin" draws them through zero, for a chart read as four quadrants.

'ends'
quadrants Sequence[str] | None

Names for the quadrants, from the top right anticlockwise.

None
signed bool

Whether points are coloured by whether x and y share a sign.

False
percent Percent

Whether values are shares, written as percentages: True for both axes, or "x" or "y" for one.

False
xlim Limits

The horizontal axis's (low, high); either may be None.

None
ylim Limits

The vertical axis's (low, high).

None
color str | None

The points' colour.

None
style StyleArgument

Settings for this chart alone: a Style, or settings by name.

None

Table

Table(
    data: DataFrame,
    title: str = "",
    subtitle: str = "",
    notes: str = "",
    source: str | None = None,
    formats: Mapping[str, Format] | None = None,
    negatives: str = "minus",
    signed: Sequence[str] = (),
    groups: Mapping[str, int | Sequence[str]] | None = None,
    row_groups: Mapping[str, Sequence[str]] | None = None,
    row_group_headings: bool = False,
    highlight: Sequence[str] = (),
    heatmap: Mapping[str, Any] | None = None,
    preset: str | None = None,
    style: StyleArgument = None,
)

Bases: Chart

A DataFrame under the Beacon frame: the mark, the heading, the table and the notes line. Its look (rules, boxes, spacing, text and colours) is the style's table group.

Parameters:

Name Type Description Default
data DataFrame

The table: its index names the rows, its columns the columns.

required
title str

The heading.

''
subtitle str

Beneath it.

''
notes str

The notes line, after "Notes:".

''
source str | None

Where the data came from, written first in the notes.

None
formats Mapping[str, Format] | None

Each column's format, or a group's for all its columns: a format string for a value's size such as "{:,.1f}", a mapping of decimals, prefix, suffix, thousands and percent, or a function.

None
negatives str

"minus" writes a negative with a minus sign; "brackets" writes -1.2 as (1.2).

'minus'
signed Sequence[str]

Columns, or groups, whose values are coloured by sign.

()
groups Mapping[str, int | Sequence[str]] | None

Column groups: {heading: [columns]}, or {heading: how many columns} in order. Each heading sits centred over its columns.

None
row_groups Mapping[str, Sequence[str]] | None

Row groups: {heading: [rows]}. Rows in no group follow.

None
row_group_headings bool

Whether each row group's heading is shown: in a column at the table's left, merged and centred beside its rows.

False
highlight Sequence[str]

Rows set in bold.

()
heatmap Mapping[str, Any] | None

Colours a column, or a column group, by value: {"column": name} or {"group": heading}, with "colormap" (a map's name or hex colours; "blue-red" by default), "reverse", "scale" ("column" or "group"), "center" (such as 0), "fade" (near-neutral cells take the table's background), "values" (False hides the numbers), "shading" ("squares" or "blended") and "blend" ("columns", "rows" or "both").

None
preset str | None

The look's rules and boxes: "lines", "plain" or "boxed"; the style's by default.

None
style StyleArgument

Settings for this table alone: a Style, or settings by name.

None

Raises:

Type Description
ValueError

If an option names a column, group or row the table does not have.

layout property
layout: Layout

Where the table's frame goes: its heading, notes, accent bar and mark.

show
show() -> None

Show the table: in a notebook, beneath the cell; otherwise in a window.

interactive
interactive() -> Any

A table has no plotly figure: its HTML (to_html()) is its interactive form, with columns that sort.

Raises:

Type Description
TypeError

Always.

to_html
to_html() -> str

The table as HTML: the heading, the table and the notes, in the table's theme, with columns that sort when their headings are clicked.

bars

Values by category as bars: Column (vertical), Bar (horizontal), and Combo, columns on the left axis with a line on the right.

Several series are grouped by category. A single series takes the signed colours, gains in green and losses in red, unless signed=False, when every bar takes one colour.

Column
Column(
    data: Data,
    title: str = "",
    subtitle: str = "",
    notes: str = "",
    source: str | None = None,
    ylabel: str = "",
    xlabel: str = "",
    percent: bool = False,
    decimals: int = 1,
    gap: float = GAP,
    inner_gap: float = INNER_GAP,
    value_labels: bool = False,
    cap: float | None = None,
    signed: bool | None = None,
    color: str | None = None,
    up_color: str | None = None,
    down_color: str | None = None,
    colors: Sequence[str] | None = None,
    ylim: Limits = None,
    style: StyleArgument = None,
)

Bases: _Bars

Vertical bars, one per category, grouped where there are several series.

Parameters:

Name Type Description Default
data Data

A Series, or a DataFrame of one series per column; its index names the categories, left to right.

required
title str

The heading.

''
subtitle str

Beneath it.

''
notes str

The notes line, after "Notes:".

''
source str | None

Where the data came from, written first in the notes.

None
ylabel str

The vertical axis's title.

''
xlabel str

The categories' title.

''
percent bool

Whether values are shares, written as percentages.

False
decimals int

Decimals in the value labels.

1
gap float

The space between categories, as a share of each category's slot; 0 closes it.

GAP
inner_gap float

The space between the columns in one category, as a share of a column; 0 closes it.

INNER_GAP
value_labels bool

Whether each column's value is written at its end.

False
cap float | None

A marked limit, drawn as a dashed line across.

None
signed bool | None

Whether a single series is coloured by sign; by default it is, and several series take their own colours.

None
color str | None

The colour of unsigned columns; grey by default.

None
up_color str | None

Gains' colour, for this chart alone.

None
down_color str | None

Losses' colour, for this chart alone.

None
colors Sequence[str] | None

Each series' colour, in order.

None
ylim Limits

The vertical axis's (low, high); either may be None.

None
style StyleArgument

Settings for this chart alone: a Style, or settings by name.

None
Bar
Bar(
    data: Data,
    title: str = "",
    subtitle: str = "",
    notes: str = "",
    source: str | None = None,
    xlabel: str = "",
    ylabel: str = "",
    percent: bool = False,
    decimals: int = 1,
    gap: float = GAP,
    inner_gap: float = INNER_GAP,
    value_labels: bool = False,
    cap: float | None = None,
    signed: bool | None = None,
    color: str | None = None,
    up_color: str | None = None,
    down_color: str | None = None,
    colors: Sequence[str] | None = None,
    xlim: Limits = None,
    style: StyleArgument = None,
)

Bases: _Bars

Horizontal bars, one per category from the top down, so long names read across; grouped where there are several series.

Parameters:

Name Type Description Default
data Data

A Series, or a DataFrame of one series per column; its index names the categories, top to bottom.

required
title str

The heading.

''
subtitle str

Beneath it.

''
notes str

The notes line, after "Notes:".

''
source str | None

Where the data came from, written first in the notes.

None
xlabel str

The horizontal axis's title.

''
ylabel str

The categories' title.

''
percent bool

Whether values are shares, written as percentages.

False
decimals int

Decimals in the value labels.

1
gap float

The space between categories, as a share of each category's slot; 0 closes it.

GAP
inner_gap float

The space between the bars in one category, as a share of a bar; 0 closes it.

INNER_GAP
value_labels bool

Whether each bar's value is written at its end.

False
cap float | None

A marked limit, drawn as a dashed line down.

None
signed bool | None

Whether a single series is coloured by sign; by default it is, and several series take their own colours.

None
color str | None

The colour of unsigned bars; grey by default.

None
up_color str | None

Gains' colour, for this chart alone.

None
down_color str | None

Losses' colour, for this chart alone.

None
colors Sequence[str] | None

Each series' colour, in order.

None
xlim Limits

The horizontal axis's (low, high); either may be None.

None
style StyleArgument

Settings for this chart alone: a Style, or settings by name.

None
Combo
Combo(
    columns: Series,
    line: Series,
    title: str = "",
    subtitle: str = "",
    notes: str = "",
    source: str | None = None,
    ylabel: str = "",
    ylabel_secondary: str = "",
    xlabel: str = "",
    gap: float = GAP,
    signed: bool = True,
    color: str | None = None,
    up_color: str | None = None,
    down_color: str | None = None,
    line_color: str | None = None,
    ylim: Limits = None,
    ylim_secondary: Limits = None,
    style: StyleArgument = None,
)

Bases: Chart

Columns on the left axis and a line on the right, for a flow and a stock measured on one calendar.

On dates, each column is as wide as the step to the next date less the gap; with gap=0 each runs to the next date, so daily columns meet edge to edge.

Parameters:

Name Type Description Default
columns Series

The columns' series, indexed by dates or categories.

required
line Series

The line's series, on the same index, measured on the right.

required
title str

The heading.

''
subtitle str

Beneath it.

''
notes str

The notes line, after "Notes:".

''
source str | None

Where the data came from, written first in the notes.

None
ylabel str

The left axis's title.

''
ylabel_secondary str

The right axis's title.

''
xlabel str

The horizontal axis's title.

''
gap float

The space between columns, as a share of each one's slot.

GAP
signed bool

Whether the columns are coloured by sign; they are by default.

True
color str | None

The colour of unsigned columns; grey by default.

None
up_color str | None

Gains' colour, for this chart alone.

None
down_color str | None

Losses' colour, for this chart alone.

None
line_color str | None

The line's colour; the accent by default.

None
ylim Limits

The left axis's (low, high); either may be None.

None
ylim_secondary Limits

The right axis's (low, high).

None
style StyleArgument

Settings for this chart alone: a Style, or settings by name.

None

base

What every chart has: a heading, notes and a style, and a drawing made only when it is first used.

Building a chart describes it and nothing more. It is drawn the first time it is shown, saved, or its figure or axes are asked for, and a notebook shows it when it is a cell's last value. So a chart that is never drawn costs nothing, and the layout and marks it is drawn from need no renderer.

Plan dataclass
Plan(
    description: Description,
    marks: tuple[Mark, ...],
    grid: str = "none",
    front: Side = "left",
)

A chart as its renderers draw it: what the layout needs, and the marks inside the plot.

Attributes:

Name Type Description
description Description

For the layout.

marks tuple[Mark, ...]

Drawn in order, by layer.

grid str

The chart's own gridlines, "x", "y", "both" or "none"; the style's grid replaces them where it sets one.

front Side

Where a panel has a second axis, which side's marks are drawn over the other's.

Chart
Chart(
    title: str = "",
    subtitle: str = "",
    notes: str = "",
    source: str | None = None,
    style: StyleArgument = None,
)

A chart in the Beacon frame: the mark, the heading, the plot and the notes line.

Attributes:

Name Type Description
title

The heading.

subtitle

Beneath it.

notes

The notes line, after "Notes:".

source

Where the data came from, written first in the notes.

style Style

The settings it is drawn in, fixed when it is built.

plan property
plan: Plan

What the chart's renderers draw: its layout's description and its marks.

layout property
layout: Layout

Where everything in the chart's frame goes.

figure property
figure: Any

The matplotlib figure, drawn on first use.

ax property
ax: Any

The matplotlib axes of the chart's top panel, drawn on first use.

axes property
axes: list[Any]

Every panel's matplotlib axes, top to bottom.

show
show() -> None

Show the chart: in a notebook, beneath the cell; otherwise in a window.

interactive
interactive() -> Any

The chart as an interactive plotly figure, laid out as its image is, with a popup and crosshair under the pointer.

Its .write_html() and .to_html() carry the chart's fonts, plotly.js and the popup's script, so the file looks the same offline.

Returns:

Name Type Description
BeaconFigure Any

A plotly figure.

save
save(path: str | Path, dpi: int | None = None) -> Path

Write the chart to a file at its designed size.

Parameters:

Name Type Description Default
path str | Path

Where; its suffix picks the format: .png, .svg or .pdf.

required
dpi int | None

Pixels per inch for a PNG; the style's by default.

None

Returns:

Name Type Description
Path Path

Where it was written.

data

What the chart classes take in: series and frames, their dates, and the limits a caller sets.

Dates become days since 1970-01-01 (beacon.plot.dateticks), the numbers every renderer draws dates as.

frame_of
frame_of(data: Data, name: str = 'Series') -> pd.DataFrame

A series as a one-column frame, or a frame as it is.

Raises:

Type Description
TypeError

If data is neither.

ValueError

If it is empty.

is_dates
is_dates(index: Index) -> bool

Whether an index holds dates.

positions
positions(index: Index) -> tuple[float, ...]

An index as the numbers it is drawn at: days since 1970-01-01 for dates, the values themselves for numbers.

number
number(when: Any) -> float

A date (or anything pandas reads as one) as days since 1970-01-01.

values
values(series: Series) -> tuple[float, ...]

A series' values as floats, missing values as NaN.

extent
extent(*groups: Iterable[float]) -> tuple[float, float]

The lowest and highest of some values, ignoring missing ones.

Raises:

Type Description
ValueError

If there is no value at all.

limited
limited(
    low: float,
    high: float,
    given: Limits,
    dates: bool = False,
) -> tuple[float, float]

An axis's range from its data and the limits a caller set.

Limits given the wrong way round are swapped. A single limit leaves the other end to the data; where the limit is beyond the data, the automatic end keeps the data's span from it.

Parameters:

Name Type Description Default
low float

The data's low end.

required
high float

Its high end.

required
given Limits

The caller's (low, high), either None for automatic.

required
dates bool

Whether the limits are dates.

False
percent
percent(value: float, decimals: int = 1) -> str

A share as a percentage, with a true minus sign.

plain
plain(value: float, decimals: int = 1) -> str

A number with thousands separated, with a true minus sign.

named
named(columns: Sequence[Any]) -> list[str]

A frame's column names as text.

grid

Several charts in one figure, under one heading and one notes line: Grid.

Grid
Grid(
    charts: Sequence[Sequence[Chart | None]],
    title: str = "",
    subtitle: str = "",
    notes: str = "",
    source: str | None = None,
    heights: Sequence[float] | None = None,
    widths: Sequence[float] | None = None,
    sharex: bool = False,
    style: StyleArgument = None,
)

Bases: Chart

Charts laid out in rows and columns under one heading and one notes line, each panel with its chart's title above it.

The same chart named in neighbouring cells takes them all, so a tall chart can run beside two short ones. Each column is given the room its labels take, and the heading and legend line up with the outer panels' edges.

Parameters:

Name Type Description Default
charts Sequence[Sequence[Chart | None]]

Rows of charts, top to bottom, each row left to right; None leaves a cell empty, and one chart in a rectangle of cells spans them. Each chart draws one panel, titled with its own title; its subtitle and notes are not drawn.

required
title str

The heading.

''
subtitle str

Beneath it.

''
notes str

The notes line, after "Notes:".

''
source str | None

Where the data came from, written first in the notes.

None
heights Sequence[float] | None

The rows' shares of the height, such as (3, 1) for a tall row over a short one; equal by default.

None
widths Sequence[float] | None

The columns' shares of the width; equal by default.

None
sharex bool

Whether every panel on dates runs over the same dates, even where one series starts later. A panel on dates with another directly beneath it then leaves its dates to the one beneath.

False
style StyleArgument

Settings for this chart alone: a Style, or settings by name.

None

Raises:

Type Description
ValueError

If there is no chart, one draws more than one panel, or one is named in cells that do not make a rectangle.

heatmap

A table of values drawn as colour: Heatmap.

Heatmap
Heatmap(
    data: DataFrame,
    title: str = "",
    subtitle: str = "",
    notes: str = "",
    source: str | None = None,
    colormap: str | Sequence[str] | None = None,
    vmin: float | None = None,
    vmax: float | None = None,
    values: bool = True,
    decimals: int = 2,
    percent: bool = False,
    lower: bool = False,
    shading: Literal["squares", "blended"] = "squares",
    gap: float = GAP,
    colorbar: bool = True,
    style: StyleArgument = None,
)

Bases: Chart

A table of values as colour: one cell per row and column.

The frame is cropped to what the chart draws, at the same scale, so a square table does not leave the frame's width empty.

Parameters:

Name Type Description Default
data DataFrame

A DataFrame: its index names the rows, top to bottom, and its columns the columns, left to right.

required
title str

The heading.

''
subtitle str

Beneath it.

''
notes str

The notes line, after "Notes:".

''
source str | None

Where the data came from, written first in the notes.

None
colormap str | Sequence[str] | None

A colour map's name (beacon.plot.colormaps), "_r" on the end to reverse it, or a list of hex colours from low to high. By default "blue-red" around zero for values either side of it, and "blues" otherwise.

None
vmin float | None

The value at the map's low end; by default the data's, or minus the largest size either side of zero.

None
vmax float | None

The value at its high end.

None
values bool

Whether each cell's value is written in it.

True
decimals int

Decimals in the written values and the colour bar's ends.

2
percent bool

Whether values are shares, written as percentages.

False
lower bool

Whether only the lower triangle is drawn, for a symmetric table such as correlations.

False
shading Literal['squares', 'blended']

"squares" draws each cell as its own square; "blended" blends each colour into the next.

'squares'
gap float

The space between cells, as a share of a cell; 0 for none.

GAP
colorbar bool

Whether the colour scale is drawn beside, labelled at its ends.

True
style StyleArgument

Settings for this chart alone: a Style, or settings by name.

None

lines

Series over time or over a measure: Line and Area.

Line
Line(
    data: Data,
    secondary: Data | None = None,
    title: str = "",
    subtitle: str = "",
    notes: str = "",
    source: str | None = None,
    ylabel: str = "",
    ylabel_secondary: str = "",
    xlabel: str = "",
    reference: float | None = None,
    label_last: bool | str | Sequence[str] = False,
    end_names: bool | Sequence[str] = False,
    legend: bool = True,
    periods: Periods = None,
    period_labels: bool = True,
    period_legend: str | None = None,
    xlim: Limits = None,
    ylim: Limits = None,
    ylim_secondary: Limits = None,
    invert: bool = False,
    percent: bool = False,
    colors: Sequence[str] | None = None,
    style: StyleArgument = None,
)

Bases: Chart

One or more series as lines, the first in the accent colour and drawn heavier.

Parameters:

Name Type Description Default
data Data

A Series, or a DataFrame of one series per column. Its index is the horizontal axis: dates, or numbers.

required
secondary Data | None

Series measured on a second axis, on the right, drawn lighter.

None
title str

The heading.

''
subtitle str

Beneath it.

''
notes str

The notes line, after "Notes:".

''
source str | None

Where the data came from, written first in the notes.

None
ylabel str

The left axis's title.

''
ylabel_secondary str

The right axis's title.

''
xlabel str

The horizontal axis's title.

''
reference float | None

A value the chart is read against, such as 100, drawn as a line across it.

None
label_last bool | str | Sequence[str]

Dot and label the last value: True for the first series, or the names of the series to label.

False
end_names bool | Sequence[str]

Write series' names at their lines' ends: True for every series but the first, or the names of the series to name.

False
legend bool

Whether several series are named in a legend.

True
periods Periods

Marked periods, as boxes from the bottom of the plot to the top behind the series: {label: (start, end)}, or a list of (start, end) or (start, end, label).

None
period_labels bool

Whether each period's label is written at the top of its box.

True
period_legend str | None

Names the periods once in the legend.

None
xlim Limits

The horizontal axis's (low, high); either may be None.

None
ylim Limits

The left axis's (low, high).

None
ylim_secondary Limits

The right axis's (low, high).

None
invert bool

Whether the left axis runs from high at the bottom to low at the top.

False
percent bool

Whether values are shares, written as percentages.

False
colors Sequence[str] | None

Each series' colour, by token name or hex, in order (the secondary series after the others); the palette by default.

None
style StyleArgument

Settings for this chart alone: a Style, or settings by name.

None
Area
Area(
    data: Data,
    stacked: bool = True,
    title: str = "",
    subtitle: str = "",
    notes: str = "",
    source: str | None = None,
    ylabel: str = "",
    xlabel: str = "",
    ylim: Limits = None,
    percent: bool = False,
    colors: Sequence[str] | None = None,
    style: StyleArgument = None,
)

Bases: Chart

Filled series: stacked parts of a whole, or one filled series such as a drawdown. The horizontal axis runs from the first value to the last, so the fill meets the axes with no gap.

Parameters:

Name Type Description Default
data Data

A Series, or a DataFrame of one series per column, indexed by dates or numbers.

required
stacked bool

Whether several series are stacked one on another; one series is filled from zero.

True
title str

The heading.

''
subtitle str

Beneath it.

''
notes str

The notes line, after "Notes:".

''
source str | None

Where the data came from, written first in the notes.

None
ylabel str

The vertical axis's title.

''
xlabel str

The horizontal axis's title.

''
ylim Limits

The vertical axis's (low, high); either may be None.

None
percent bool

Whether values are shares, written as percentages.

False
colors Sequence[str] | None

Each series' colour, by token name or hex, in order.

None
style StyleArgument

Settings for this chart alone: a Style, or settings by name.

None
labels_of
labels_of(
    marks: Sequence[Mark], font: str, panel: int = 0
) -> tuple[Label, ...]

The text a panel's marks write in its data, for the layout to keep inside the figure.

points

One measure against another, and how a measure is spread: Scatter and Histogram.

Scatter
Scatter(
    data: DataFrame | None = None,
    x: str | Series | None = None,
    y: str | Series | None = None,
    labels: str | Series | None = None,
    name: str = "Points",
    title: str = "",
    subtitle: str = "",
    notes: str = "",
    source: str | None = None,
    xlabel: str | None = None,
    ylabel: str | None = None,
    fit: Literal["linear"] | None = None,
    curve: Series | None = None,
    curve_label: str | None = None,
    axes: Literal["ends", "origin"] = "ends",
    quadrants: Sequence[str] | None = None,
    signed: bool = False,
    percent: Percent = False,
    xlim: Limits = None,
    ylim: Limits = None,
    color: str | None = None,
    style: StyleArgument = None,
)

Bases: Chart

Points, one measure against another.

Parameters:

Name Type Description Default
data DataFrame | None

A DataFrame with a column for each measure, or None when x and y are given as series.

None
x str | Series | None

The horizontal measure: a column's name, or a series.

None
y str | Series | None

The vertical measure: a column's name, or a series.

None
labels str | Series | None

Names written beside the points: a column's name, or a series.

None
name str

What the points are, in the legend when there is one.

'Points'
title str

The heading.

''
subtitle str

Beneath it.

''
notes str

The notes line, after "Notes:".

''
source str | None

Where the data came from, written first in the notes.

None
xlabel str | None

The horizontal axis's title; the x measure's name by default.

None
ylabel str | None

The vertical axis's title; the y measure's name by default.

None
fit Literal['linear'] | None

"linear" draws a fitted line and writes its slope (beta) and fit (R squared) on the chart.

None
curve Series | None

A curve through the same axes, such as a frontier: a series of y indexed by x.

None
curve_label str | None

The curve's name in the legend.

None
axes Literal['ends', 'origin']

"ends" puts the axes at the plot's edges; "origin" draws them through zero, for a chart read as four quadrants.

'ends'
quadrants Sequence[str] | None

Names for the quadrants, from the top right anticlockwise.

None
signed bool

Whether points are coloured by whether x and y share a sign.

False
percent Percent

Whether values are shares, written as percentages: True for both axes, or "x" or "y" for one.

False
xlim Limits

The horizontal axis's (low, high); either may be None.

None
ylim Limits

The vertical axis's (low, high).

None
color str | None

The points' colour.

None
style StyleArgument

Settings for this chart alone: a Style, or settings by name.

None
Histogram
Histogram(
    data: Data,
    bins: int = BINS,
    title: str = "",
    subtitle: str = "",
    notes: str = "",
    source: str | None = None,
    xlabel: str | None = None,
    ylabel: str = "Count",
    normal: bool = False,
    mark: Mapping[str, float] | None = None,
    percent: bool = False,
    color: str | None = None,
    style: StyleArgument = None,
)

Bases: Chart

How a measure is spread: counts in equal bins.

Parameters:

Name Type Description Default
data Data

The values, as a Series.

required
bins int

How many equal bins.

BINS
title str

The heading.

''
subtitle str

Beneath it.

''
notes str

The notes line, after "Notes:".

''
source str | None

Where the data came from, written first in the notes.

None
xlabel str | None

The horizontal axis's title; the series' name by default.

None
ylabel str

The vertical axis's title.

'Count'
normal bool

Whether to draw the normal curve with the values' mean and standard deviation.

False
mark Mapping[str, float] | None

Values marked with a line and named, such as {"95% VaR": -0.02}.

None
percent bool

Whether values are shares, written as percentages.

False
color str | None

The bars' colour.

None
style StyleArgument

Settings for this chart alone: a Style, or settings by name.

None

table

A DataFrame under the Beacon frame: Table, as an image or as HTML.

Table
Table(
    data: DataFrame,
    title: str = "",
    subtitle: str = "",
    notes: str = "",
    source: str | None = None,
    formats: Mapping[str, Format] | None = None,
    negatives: str = "minus",
    signed: Sequence[str] = (),
    groups: Mapping[str, int | Sequence[str]] | None = None,
    row_groups: Mapping[str, Sequence[str]] | None = None,
    row_group_headings: bool = False,
    highlight: Sequence[str] = (),
    heatmap: Mapping[str, Any] | None = None,
    preset: str | None = None,
    style: StyleArgument = None,
)

Bases: Chart

A DataFrame under the Beacon frame: the mark, the heading, the table and the notes line. Its look (rules, boxes, spacing, text and colours) is the style's table group.

Parameters:

Name Type Description Default
data DataFrame

The table: its index names the rows, its columns the columns.

required
title str

The heading.

''
subtitle str

Beneath it.

''
notes str

The notes line, after "Notes:".

''
source str | None

Where the data came from, written first in the notes.

None
formats Mapping[str, Format] | None

Each column's format, or a group's for all its columns: a format string for a value's size such as "{:,.1f}", a mapping of decimals, prefix, suffix, thousands and percent, or a function.

None
negatives str

"minus" writes a negative with a minus sign; "brackets" writes -1.2 as (1.2).

'minus'
signed Sequence[str]

Columns, or groups, whose values are coloured by sign.

()
groups Mapping[str, int | Sequence[str]] | None

Column groups: {heading: [columns]}, or {heading: how many columns} in order. Each heading sits centred over its columns.

None
row_groups Mapping[str, Sequence[str]] | None

Row groups: {heading: [rows]}. Rows in no group follow.

None
row_group_headings bool

Whether each row group's heading is shown: in a column at the table's left, merged and centred beside its rows.

False
highlight Sequence[str]

Rows set in bold.

()
heatmap Mapping[str, Any] | None

Colours a column, or a column group, by value: {"column": name} or {"group": heading}, with "colormap" (a map's name or hex colours; "blue-red" by default), "reverse", "scale" ("column" or "group"), "center" (such as 0), "fade" (near-neutral cells take the table's background), "values" (False hides the numbers), "shading" ("squares" or "blended") and "blend" ("columns", "rows" or "both").

None
preset str | None

The look's rules and boxes: "lines", "plain" or "boxed"; the style's by default.

None
style StyleArgument

Settings for this table alone: a Style, or settings by name.

None

Raises:

Type Description
ValueError

If an option names a column, group or row the table does not have.

layout property
layout: Layout

Where the table's frame goes: its heading, notes, accent bar and mark.

show
show() -> None

Show the table: in a notebook, beneath the cell; otherwise in a window.

interactive
interactive() -> Any

A table has no plotly figure: its HTML (to_html()) is its interactive form, with columns that sort.

Raises:

Type Description
TypeError

Always.

to_html
to_html() -> str

The table as HTML: the heading, the table and the notes, in the table's theme, with columns that sort when their headings are clicked.

colormaps

Colour maps: colours from low to high, which a value between two ends is blended along.

beacon_corr is the correlation map, from the mode-independent raw.heatmap-* tokens, so a correlation looks the same in every theme. The others are built from the series palette, except viridis. A name ending in "_r" runs the map the other way, and a list of hex colours is a map of its own.

names

names() -> list[str]

Every map's name.

stops

stops(choice: str | Sequence[str]) -> tuple[str, ...]

A colour map's colours, from low to high.

Parameters:

Name Type Description Default
choice str | Sequence[str]

A map's name, "_r" on the end to reverse it, or a list of hex colours.

required

Raises:

Type Description
ValueError

If there is no such map.

colour_at

colour_at(colours: Sequence[str], share: float) -> str

The colour a share of the way along a map, from 0 at its low end to 1 at its high end.

ink_on

ink_on(colour: str) -> str

Text that reads on a colour: dark on a light one, light on a dark one.

colours

Colours by name, resolved in a theme and a style.

A chart's layout and marks carry colours as names, so one chart draws in any theme: a design token such as "accent" or "text-primary", "palette-N" for the Nth series colour, "accent-bar" for the bar beside the title, "period-label" for a marked period's label, or a literal "#rrggbb" a caller chose. Each renderer resolves the names here, in the theme it draws and the style's own colours, which replace the theme's where they are set.

palette

palette(index: int) -> str

The name of the series colour at index, counting from 0.

series_colours

series_colours(
    theme: Theme, style: Style
) -> tuple[str, ...]

The series colours in order: the style's, or the theme's palette.

resolve

resolve(name: str, theme: Theme, style: Style) -> str

A colour by name, as a colour a renderer can draw.

Parameters:

Name Type Description Default
name str

A token, "palette-N", "accent-bar", "period-label", a literal "#rrggbb", or "none".

required
theme Theme

The theme drawn in.

required
style Style

The style drawn in.

required

Returns:

Name Type Description
str str

A hex colour, or "none".

comparison

Comparing several results on one axis.

A free function rather than an accessor because it is not about any one result: compare(a, b, c) is a statement about the set, and hanging it off the first argument would make that arbitrary. Import it as from beacon.plot import compare.

Aligned, not concatenated

Every series is clipped to the window they all share and rebased to 100 on the first shared date. Two indices with different histories compared over different periods differ for no reason but their spans, and the one with the shorter history looks better or worse than it is. Rebasing on the shared start means the lines begin together and the comparison is of shape.

compare

compare(
    *results: Any,
    labels: list[str] | None = None,
    title: str | None = None,
    subtitle: str | None = None,
    notes: str | None = None,
    style: StyleArgument = None,
) -> Chart

Plot several results on one rebased axis.

Parameters:

Name Type Description Default
*results Any

Two or more IndexResult or BacktestResult objects.

()
labels list[str] | None

Display names. Defaults to each result's own identifier (its index id or portfolio id), or "Series N" when it has none.

None
title str | None

The heading. Defaults to "Comparison".

None
subtitle str | None

Beneath the heading. Defaults to what the lines are.

None
notes str | None

The notes line, after "Notes:". Defaults to how many shared observations the comparison rests on.

None
style StyleArgument

Settings for this chart alone: a Style, or settings by name such as {"mark": False, "scale": 1.2}. None draws in the current style (beacon.plot.configure).

None

Returns:

Name Type Description
Chart Chart

The chart, drawn when it is used.

Raises:

Type Description
ValueError

If fewer than two results are given, or they share no dates.

dateticks

Where a date axis puts its ticks, and what they say.

Dates are numbers here, as every renderer can take them: days since 1970-01-01, the epoch matplotlib also counts from. The ticks fall on whole years, months or days, at an interval that gives the axis between five and a dozen of them, and each says only what changed since the last: the year at each January and the month between, or the day within a month.

DateLabels dataclass

DateLabels(labels: tuple[str, ...], offset: str = '')

What a date axis's ticks say, and the offset written once at its end (such as "2024-Feb" under ticks that are days).

to_number

to_number(when: datetime) -> float

A date as days since 1970-01-01.

to_date

to_date(number: float) -> datetime.datetime

Days since 1970-01-01 as a date, to the microsecond.

tick_values

tick_values(
    low: float, high: float, room: int | None = None
) -> list[float]

Every tick for a range of dates, including the years just beyond its ends on a yearly axis.

Parameters:

Name Type Description Default
low float

Days since 1970-01-01.

required
high float

Days since 1970-01-01.

required
room int | None

The most ticks the axis has room for; a dozen or so when None, as matplotlib allows whatever the axis's length.

None

ends

ends(
    low: float, high: float, room: int | None = None
) -> tuple[float, float, bool]

The ticks at or beyond each end of a range of dates, checked so the ticks of the ended range still include both ends.

Returns:

Name Type Description
tuple float

The range's new ends, and whether it was ended. A range with no

float

tick beyond one of its ends is not, though an earlier pass may already

bool

have moved it.

labels

labels(
    ticks: Sequence[float], inverted: bool = False
) -> DateLabels

Each tick as only what changed since the last.

design

The chart design as settings: Style, and the functions that choose one.

Every part of a chart's look is a named setting with Beacon's design as its default, grouped as a chart is built: its size, its heading, its text, its lines, its axes, its legend, its notes and its colours.

  • Style is the look itself: one immutable value holding every setting. It changes nothing until it is used, and saves to a TOML file and loads back from one, so a project can keep its look in a file.
  • configure() makes a look the default for every chart drawn afterwards: a Style, a preset, or settings by name, such as configure(mark=False).
  • settings() does the same for one with block, then puts the previous look back.
  • A chart's own style= changes that chart alone.

The most specific wins: a chart's style=, then a with settings(...) block, then configure(), then Beacon's defaults.

from beacon.plot import Style, configure, settings

configure(mark=False, heading_scale=1.2)
with settings(theme="white", legend="bottom"):
    result.plot.level()

house = Style.beacon().replace(lines={"series_width": 2.0})
house.save("house.toml")
configure(Style.load("house.toml"))

Standard library only, so import beacon.plot stays free of matplotlib.

AxesSettings dataclass

AxesSettings(
    x_line: bool = True,
    y_line: bool = True,
    x_ticks: bool = True,
    y_ticks: bool = True,
    tick_direction: str = "in",
    tick_length: float = 3.5,
    tick_label_size: float = 7.8,
    title_size: float = 8.0,
    grid: str | None = None,
    end_on_ticks: bool = True,
    blank_lowest_label: bool = True,
    reference: bool = True,
)

The axes: their lines, ticks, labels and ends.

Attributes:

Name Type Description
x_line bool

The x axis line.

y_line bool

The y axis line.

x_ticks bool

The x axis's tick marks.

y_ticks bool

The y axis's tick marks.

tick_direction str

"in" or "out".

tick_length float

In points as designed.

tick_label_size float

In points.

title_size float

Axis titles, in points.

grid str | None

"none", "x", "y" or "both"; None keeps each chart's own.

end_on_ticks bool

End each measuring axis on its outermost ticks.

blank_lowest_label bool

Leave the lowest y label blank where both axes measure, so it does not sit on the first x label.

reference bool

Draw the lines a chart is read against, such as 100.

ColorSettings dataclass

ColorSettings(
    series: tuple[str, ...] | None = None,
    up: str | None = None,
    down: str | None = None,
    accent_bar: str | None = None,
    period: str | None = None,
    period_label: str | None = None,
    text: str | None = None,
    muted: str | None = None,
    background: str | None = None,
)

Colours, each a hex code; None follows the theme.

Attributes:

Name Type Description
series tuple[str, ...] | None

The series colours in order, replacing the palette.

up str | None

Gains.

down str | None

Losses.

accent_bar str | None

The bar beside the heading.

period str | None

Marked periods' boxes.

period_label str | None

Marked periods' labels.

text str | None

Text, axes and the mark.

muted str | None

The subtitle.

background str | None

The canvas.

HeadingSettings dataclass

HeadingSettings(
    mark: bool = True,
    accent_bar: bool = True,
    scale: float = 1.0,
    title_font: str = "Inter Tight",
    title_size: float = 9.0,
    subtitle_font: str = "Source Serif 4",
    subtitle_size: float = 6.3,
    subtitle_italic: bool = True,
)

The title, subtitle, accent bar and beta mark.

Attributes:

Name Type Description
mark bool

The beta mark left of the accent bar.

accent_bar bool

The bar beside the title and subtitle.

scale float

Scales the mark, accent bar, title and subtitle together.

title_font str

A font name, or the path of a font file (.ttf or .otf).

title_size float

In points.

subtitle_font str

A font name, or the path of a font file.

subtitle_size float

In points.

subtitle_italic bool

Whether the subtitle is set in italics.

LegendSettings dataclass

LegendSettings(position: str = 'heading')

The legend.

Attributes:

Name Type Description
position str

"heading" (right of the title), "bottom", "right" or "none".

LineSettings dataclass

LineSettings(
    series_width: float = 1.5,
    secondary_width: float = 1.1,
    axis_width: float = 0.6,
    reference_width: float = 0.5,
    grid_width: float = 0.6,
)

Line weights, in points as designed.

Attributes:

Name Type Description
series_width float

The first, leading series.

secondary_width float

Every other series, such as a benchmark.

axis_width float

The axis lines and ticks.

reference_width float

Lines a chart is read against, such as 100 or zero.

grid_width float

Gridlines, where a chart draws them.

NotesSettings dataclass

NotesSettings(
    show: bool = True,
    size: float = 4.5,
    italic: bool = True,
)

The notes line under the chart.

Attributes:

Name Type Description
show bool

Whether to draw it.

size float

In points.

italic bool

Whether it is set in italics.

SizeSettings dataclass

SizeSettings(
    scale: float = 1.0,
    width: float | None = None,
    aspect: str | None = None,
    dpi: int = 300,
)

The chart's size.

Attributes:

Name Type Description
scale float

Zooms the chart, its figure, text and lines together; 1.0 is the size charts are drawn at today. The heading keeps its own scale.

width float | None

The designed width in inches, giving more room at the same text size; None keeps the chart's own, 6in.

aspect str | None

Width to height, such as "16:9"; None keeps the chart's own.

dpi int

Dots per inch when a chart is saved as an image.

ratio
ratio() -> float | None

The aspect as width over height, or None.

TableSettings dataclass

TableSettings(
    preset: str = "lines",
    header_rule: bool | None = None,
    row_rules: bool | None = None,
    bottom_rule: bool | None = None,
    group_rules: bool | None = None,
    column_rules: bool | None = None,
    box: bool | None = None,
    group_boxes: bool | None = None,
    row_boxes: bool | None = None,
    group_box_scope: str = "values",
    rule_width: float = 0.48,
    row_rule_width: float = 0.48,
    box_width: float = 0.36,
    row_padding: float = 2.0,
    cell_padding: float = 3.0,
    name_space: float = 3.0,
    body_size: float = 6.3,
    header_size: float = 5.5,
    group_size: float = 5.5,
    header_weight: int = 300,
    name_weight: int = 400,
    number_align: str = "center",
    header_align: str = "center",
    name_align: str = "right",
    stripes: bool = False,
    rule_color: str | None = None,
    row_rule_color: str | None = None,
    stripe_color: str | None = None,
    header_color: str | None = None,
)

A table's look: its rules and boxes, spacing, text and colours.

Attributes:

Name Type Description
preset str

"lines" (rules under the header, between rows and under the table), "plain" (none at all) or "boxed" (a box around the values). It sets each rule and box below that is left as None.

header_rule bool | None

A rule under the column headings.

row_rules bool | None

Rules between rows.

bottom_rule bool | None

A rule under the table.

group_rules bool | None

Rules under the column groups' headings.

column_rules bool | None

Rules between column groups.

box bool | None

A box around the values.

group_boxes bool | None

A box around each column group.

row_boxes bool | None

A box around each row group; with group boxes too, each block of rows and columns gets its own.

group_box_scope str

Whether column group boxes enclose the "values" or the "headings" too.

rule_width float

The header and bottom rules, in points as designed.

row_rule_width float

The rules between rows.

box_width float

Boxes.

row_padding float

Above and below each row's text, in points.

cell_padding float

Either side of each cell's text, in points.

name_space float

Before the longest row name, in points: the row names' column is as wide as they need, and the values share the rest.

body_size float

The values, in points.

header_size float

The column headings.

group_size float

The group headings.

header_weight int

The column headings' weight.

name_weight int

The row names' weight.

number_align str

"left", "center" or "right".

header_align str

"center", or "numbers" to align as the numbers do.

name_align str

The row names: "left" or "right".

stripes bool

Whether every other row is shaded.

rule_color str | None

The rules; the column headings' colour by default.

row_rule_color str | None

The rules between rows; the theme's divider by default.

stripe_color str | None

The stripes; the theme's divider by default.

header_color str | None

The column headings; the theme's muted text by default.

rules
rules() -> dict[str, bool]

Every rule and box: each one's own setting, or its preset's.

TextSettings dataclass

TextSettings(
    font: str = "Inter Tight",
    scale: float = 1.0,
    label_size: float = 5.5,
)

The chart's own text.

Attributes:

Name Type Description
font str

A font name, or the path of a font file (.ttf or .otf).

scale float

The chart's small text alone, at any chart scale.

label_size float

Legend entries and labels on the chart, in points.

Style dataclass

Style(
    theme: str = "beacon-light",
    size: SizeSettings = SizeSettings(),
    heading: HeadingSettings = HeadingSettings(),
    text: TextSettings = TextSettings(),
    lines: LineSettings = LineSettings(),
    axes: AxesSettings = AxesSettings(),
    legend: LegendSettings = LegendSettings(),
    notes: NotesSettings = NotesSettings(),
    colors: ColorSettings = ColorSettings(),
    table: TableSettings = TableSettings(),
)

A chart look: every setting, with Beacon's design as the default.

Build one from a preset and change what differs:

house = Style.beacon().replace(heading={"mark": False},
                               lines={"series_width": 2.0})

Attributes:

Name Type Description
theme str

The theme: "beacon-light" (the default), "beacon-dark", "github-dark", "white", "transparent-dark-axes" or "transparent-light-axes".

size, (heading, text, lines, axes, legend, notes, colors, table)

The settings, grouped. Each group's documentation lists its own.

beacon classmethod
beacon() -> Style

Beacon's design: the default.

plain classmethod
plain() -> Style

Beacon's design for work that is not a Beacon report: no beta mark, on white. The accent bar and Beacon's fonts stay.

preset classmethod
preset(name: str) -> Style

A preset by name: "beacon" or "plain".

Raises:

Type Description
ValueError

If there is no such preset.

replace
replace(
    theme: str | None = None,
    **groups: Mapping[str, Any] | Any,
) -> Style

A copy with some settings changed, by group.

Parameters:

Name Type Description Default
theme str | None

A new theme.

None
**groups Mapping[str, Any] | Any

A group's name and either the settings that change in it, as a mapping, or a whole group object.

{}

Raises:

Type Description
ValueError

If a group or setting does not exist, or a value is not allowed.

updated
updated(**settings: Any) -> Style

A copy with settings changed by their short names, as configure() takes them: style.updated(mark=False, scale=1.2).

Raises:

Type Description
ValueError

If a name is not a setting, or a value is not allowed.

to_dict
to_dict() -> dict[str, Any]

Every setting, by group. Unset (None) settings are left out.

from_dict classmethod
from_dict(data: Mapping[str, Any]) -> Style

A style from to_dict()'s form; settings left out keep their defaults.

Raises:

Type Description
ValueError

If a group or setting does not exist, or a value is not allowed.

save
save(path: str | Path) -> Path

Write this style to a TOML file, to load again with Style.load().

Returns:

Name Type Description
Path Path

Where it was written.

load classmethod
load(path: str | Path) -> Style

A style from a TOML file that Style.save() wrote, or one written by hand in the same form.

Raises:

Type Description
ValueError

If the file is not valid TOML or holds settings that do not exist.

current

current() -> Style

The style charts are drawn in now.

version

version() -> int

A number that changes whenever the current style does.

configure

configure(
    style: Style | str | Path | None = None,
    *,
    preset: str | None = None,
    **settings: Any,
) -> Style

Make a look the default for every chart drawn afterwards.

Settings given by name change the current style rather than replacing it, so configure(mark=False) and then configure(scale=1.2) keep both.

Parameters:

Name Type Description Default
style Style | str | Path | None

A Style, or the path of a TOML file Style.save() wrote, to start from instead of the current style.

None
preset str | None

"beacon" or "plain", to start from instead.

None
**settings Any

Settings by their short names, such as mark=False, heading_scale=1.2, legend="bottom" or theme="white".

{}

Returns:

Name Type Description
Style Style

The style now in force.

Raises:

Type Description
TypeError

If both a style and a preset are given.

ValueError

If a setting does not exist or a value is not allowed.

reset

reset() -> Style

Go back to Beacon's design.

Returns:

Name Type Description
Style Style

The default style, now in force.

settings

settings(
    style: Style | str | Path | None = None,
    *,
    preset: str | None = None,
    **changes: Any,
) -> Iterator[Style]

A look for one with block; the previous one comes back after it.

with settings(mark=False, theme="white"):
    result.plot.level()

Takes what configure() takes.

Yields:

Name Type Description
Style Style

The style in force inside the block.

scoped

scoped(style: Style) -> Iterator[Style]

style in force while one chart is drawn.

Unlike settings(), it leaves the version alone, so drawing the chart does not put the style into matplotlib's rcParams for good: the chart applies it for itself (beacon.plot.paint).

resolve

resolve(style: Style | Mapping[str, Any] | None) -> Style

The style a single chart is drawn in, from its style= argument: a Style, settings by short name over the current style, or None for the current style.

Raises:

Type Description
ValueError

If a setting does not exist or a value is not allowed.

fitting

A chart's panels fitted between its heading and its notes, pass by pass: placed, their measuring axes ended on their ticks at the size each has, and their sides widened until every label they draw is inside the figure.

Used by beacon.plot.arrange, which runs the passes.

PanelState dataclass

PanelState(
    x: AxisState, y: AxisState, y2: AxisState | None = None
)

A panel's axes as the layout moves them.

Drawn dataclass

Drawn(
    x: AxisLayout,
    y: AxisLayout,
    y2: AxisLayout | None,
    bar: AxisLayout | None,
    x_title: Text | None = None,
    y_title: Text | None = None,
    y2_title: Text | None = None,
)

A panel's axes and titles as they would be drawn now.

Passes

Passes(
    chart: Description, style: Style, margin: float = 0.0
)

The panels' geometry as it is fitted, pass by pass.

place
place(bottom: float, top: float) -> None

Put the panels between bottom and top (figure fractions).

end_axes
end_axes() -> None

End each panel's measuring axes on their ticks at the size each panel has now, and blank the labels that would collide.

axes
axes() -> list[Drawn]

Each panel's axes and their titles as they would be drawn now.

reach
reach() -> tuple[float, float]

How far left and right anything the panels draw reaches, in inches.

fit_sides
fit_sides(margin: float) -> None

Widen the sides until nothing the panels draw runs past margin inches from either edge; in a grid, give each row and column the room its panels take.

outer
outer() -> tuple[float, float]

The plots' outer edges, which the heading and the legend line up with: the top panel's, or a grid's outermost.

panel_titles
panel_titles() -> list[Text | None]

Each panel's title above it, in a grid.

frame

The furniture around a chart, as matplotlib draws it: the bundled fonts, the theme a figure is drawn in, and reading a drawn chart's heading and notes back.

A chart's frame is laid out by beacon.plot.arrange and drawn by beacon.plot.paint:

  • the title in Inter Tight and the subtitle beneath it in Source Serif 4 italic, both left aligned, with a thin square accent bar down their left, level with the y axis
  • the beta mark, the glyph the application shows in its menu bar, just left of the bar and centred on it
  • one italic Notes line at the bottom left: where the data came from, the dates it covers, and whatever the chart itself needs said, run together as sentences rather than listed

The fonts ship in the package under the SIL Open Font License, whose texts sit beside them, so a chart looks the same on every machine and the image regression tests can compare it.

register_fonts cached

register_fonts() -> None

Make the bundled fonts known to matplotlib. Runs once; cached.

theme_of

theme_of(ax: Axes) -> Theme

The theme an axes is drawn in.

The one its figure was drawn in when beacon drew it; otherwise read off the figure's background, because a caller may have styled this figure alone, or drawn it on matplotlib's own white.

mode_of

mode_of(ax: Axes) -> str

Which set of Beacon colours an axes' theme draws with: LIGHT or DARK.

ink

ink(ax: Axes, name: str) -> str

One colour by name, in whichever theme this axes is drawn in and the current style.

frame_text

frame_text(chart: Any, part: str) -> str

What a chart's title, subtitle or notes say.

Parameters:

Name Type Description Default
chart Any

A chart, or the axes of a drawn one.

required
part str

"title", "subtitle" or "notes".

required

Returns:

Name Type Description
str str

The text on one line, the notes without their "Notes:" prefix,

str

and empty when the chart has none.

Raises:

Type Description
ValueError

If part is not one of the three.

gridding

Panels laid out in rows and columns, under one heading.

Each column is given the room its panels' labels take on either side, each row the room its panels' titles take above and their tick labels below, and the plots share what is left by each row's and column's share (equal unless set), so the labels between panels never run into the next one. A panel may take several rows or columns. The room each needs is measured from the panels as drawn in the last pass, so the layout settles over its passes.

Needs dataclass

Needs(
    left: list[float] = list(),
    right: list[float] = list(),
    above: list[float] = list(),
    below: list[float] = list(),
)

The room each column takes beside its plots and each row above and below them, in inches.

Grid

Grid(
    chart: Description,
    zoom: float,
    title_size: float,
    title_font: Font,
)

Where a grid's panels go, from the room each row and column needs.

title_room
title_room() -> float

The room a panel's title takes above its plot, in inches.

cells
cells(
    bottom: float, top: float, margin: float
) -> list[tuple[float, float, float, float]]

Each panel's cell as figure fractions (left, bottom, right, top), between bottom and top inches up the figure and margin inches in from its sides. A panel taking several rows or columns runs from the first one's edge to the last one's.

measure
measure(
    placed: list[Box],
    spans: list[tuple[float, float]],
    lows: list[float],
) -> None

Take each column's and row's room from the panels as drawn: a panel's labels at its left need room in its first column, at its right in its last, and below it in its last row.

Parameters:

Name Type Description Default
placed list[Box]

Each panel's plot.

required
spans list[tuple[float, float]]

How far left and right each panel's drawing reaches.

required
lows list[float]

How far down each panel's drawing reaches.

required
outer
outer(placed: list[Box]) -> tuple[float, float]

The left edge of the leftmost plots and the right edge of the rightmost, which the heading and the legend line up with.

title_at
title_at(plot: Box) -> tuple[float, float]

Where a panel's title sits: its left edge and its bottom.

shape

shape(chart: Description) -> tuple[int, int]

A grid's rows and columns.

groups

The groups of chart settings a Style holds (beacon.plot.design): size, heading, text, lines, axes, legend, notes and colours, each with Beacon's design as its default and each checking its own values.

Standard library only, so import beacon.plot stays free of matplotlib.

SizeSettings dataclass

SizeSettings(
    scale: float = 1.0,
    width: float | None = None,
    aspect: str | None = None,
    dpi: int = 300,
)

The chart's size.

Attributes:

Name Type Description
scale float

Zooms the chart, its figure, text and lines together; 1.0 is the size charts are drawn at today. The heading keeps its own scale.

width float | None

The designed width in inches, giving more room at the same text size; None keeps the chart's own, 6in.

aspect str | None

Width to height, such as "16:9"; None keeps the chart's own.

dpi int

Dots per inch when a chart is saved as an image.

ratio
ratio() -> float | None

The aspect as width over height, or None.

HeadingSettings dataclass

HeadingSettings(
    mark: bool = True,
    accent_bar: bool = True,
    scale: float = 1.0,
    title_font: str = "Inter Tight",
    title_size: float = 9.0,
    subtitle_font: str = "Source Serif 4",
    subtitle_size: float = 6.3,
    subtitle_italic: bool = True,
)

The title, subtitle, accent bar and beta mark.

Attributes:

Name Type Description
mark bool

The beta mark left of the accent bar.

accent_bar bool

The bar beside the title and subtitle.

scale float

Scales the mark, accent bar, title and subtitle together.

title_font str

A font name, or the path of a font file (.ttf or .otf).

title_size float

In points.

subtitle_font str

A font name, or the path of a font file.

subtitle_size float

In points.

subtitle_italic bool

Whether the subtitle is set in italics.

TextSettings dataclass

TextSettings(
    font: str = "Inter Tight",
    scale: float = 1.0,
    label_size: float = 5.5,
)

The chart's own text.

Attributes:

Name Type Description
font str

A font name, or the path of a font file (.ttf or .otf).

scale float

The chart's small text alone, at any chart scale.

label_size float

Legend entries and labels on the chart, in points.

LineSettings dataclass

LineSettings(
    series_width: float = 1.5,
    secondary_width: float = 1.1,
    axis_width: float = 0.6,
    reference_width: float = 0.5,
    grid_width: float = 0.6,
)

Line weights, in points as designed.

Attributes:

Name Type Description
series_width float

The first, leading series.

secondary_width float

Every other series, such as a benchmark.

axis_width float

The axis lines and ticks.

reference_width float

Lines a chart is read against, such as 100 or zero.

grid_width float

Gridlines, where a chart draws them.

AxesSettings dataclass

AxesSettings(
    x_line: bool = True,
    y_line: bool = True,
    x_ticks: bool = True,
    y_ticks: bool = True,
    tick_direction: str = "in",
    tick_length: float = 3.5,
    tick_label_size: float = 7.8,
    title_size: float = 8.0,
    grid: str | None = None,
    end_on_ticks: bool = True,
    blank_lowest_label: bool = True,
    reference: bool = True,
)

The axes: their lines, ticks, labels and ends.

Attributes:

Name Type Description
x_line bool

The x axis line.

y_line bool

The y axis line.

x_ticks bool

The x axis's tick marks.

y_ticks bool

The y axis's tick marks.

tick_direction str

"in" or "out".

tick_length float

In points as designed.

tick_label_size float

In points.

title_size float

Axis titles, in points.

grid str | None

"none", "x", "y" or "both"; None keeps each chart's own.

end_on_ticks bool

End each measuring axis on its outermost ticks.

blank_lowest_label bool

Leave the lowest y label blank where both axes measure, so it does not sit on the first x label.

reference bool

Draw the lines a chart is read against, such as 100.

LegendSettings dataclass

LegendSettings(position: str = 'heading')

The legend.

Attributes:

Name Type Description
position str

"heading" (right of the title), "bottom", "right" or "none".

NotesSettings dataclass

NotesSettings(
    show: bool = True,
    size: float = 4.5,
    italic: bool = True,
)

The notes line under the chart.

Attributes:

Name Type Description
show bool

Whether to draw it.

size float

In points.

italic bool

Whether it is set in italics.

ColorSettings dataclass

ColorSettings(
    series: tuple[str, ...] | None = None,
    up: str | None = None,
    down: str | None = None,
    accent_bar: str | None = None,
    period: str | None = None,
    period_label: str | None = None,
    text: str | None = None,
    muted: str | None = None,
    background: str | None = None,
)

Colours, each a hex code; None follows the theme.

Attributes:

Name Type Description
series tuple[str, ...] | None

The series colours in order, replacing the palette.

up str | None

Gains.

down str | None

Losses.

accent_bar str | None

The bar beside the heading.

period str | None

Marked periods' boxes.

period_label str | None

Marked periods' labels.

text str | None

Text, axes and the mark.

muted str | None

The subtitle.

background str | None

The canvas.

TableSettings dataclass

TableSettings(
    preset: str = "lines",
    header_rule: bool | None = None,
    row_rules: bool | None = None,
    bottom_rule: bool | None = None,
    group_rules: bool | None = None,
    column_rules: bool | None = None,
    box: bool | None = None,
    group_boxes: bool | None = None,
    row_boxes: bool | None = None,
    group_box_scope: str = "values",
    rule_width: float = 0.48,
    row_rule_width: float = 0.48,
    box_width: float = 0.36,
    row_padding: float = 2.0,
    cell_padding: float = 3.0,
    name_space: float = 3.0,
    body_size: float = 6.3,
    header_size: float = 5.5,
    group_size: float = 5.5,
    header_weight: int = 300,
    name_weight: int = 400,
    number_align: str = "center",
    header_align: str = "center",
    name_align: str = "right",
    stripes: bool = False,
    rule_color: str | None = None,
    row_rule_color: str | None = None,
    stripe_color: str | None = None,
    header_color: str | None = None,
)

A table's look: its rules and boxes, spacing, text and colours.

Attributes:

Name Type Description
preset str

"lines" (rules under the header, between rows and under the table), "plain" (none at all) or "boxed" (a box around the values). It sets each rule and box below that is left as None.

header_rule bool | None

A rule under the column headings.

row_rules bool | None

Rules between rows.

bottom_rule bool | None

A rule under the table.

group_rules bool | None

Rules under the column groups' headings.

column_rules bool | None

Rules between column groups.

box bool | None

A box around the values.

group_boxes bool | None

A box around each column group.

row_boxes bool | None

A box around each row group; with group boxes too, each block of rows and columns gets its own.

group_box_scope str

Whether column group boxes enclose the "values" or the "headings" too.

rule_width float

The header and bottom rules, in points as designed.

row_rule_width float

The rules between rows.

box_width float

Boxes.

row_padding float

Above and below each row's text, in points.

cell_padding float

Either side of each cell's text, in points.

name_space float

Before the longest row name, in points: the row names' column is as wide as they need, and the values share the rest.

body_size float

The values, in points.

header_size float

The column headings.

group_size float

The group headings.

header_weight int

The column headings' weight.

name_weight int

The row names' weight.

number_align str

"left", "center" or "right".

header_align str

"center", or "numbers" to align as the numbers do.

name_align str

The row names: "left" or "right".

stripes bool

Whether every other row is shaded.

rule_color str | None

The rules; the column headings' colour by default.

row_rule_color str | None

The rules between rows; the theme's divider by default.

stripe_color str | None

The stripes; the theme's divider by default.

header_color str | None

The column headings; the theme's muted text by default.

rules
rules() -> dict[str, bool]

Every rule and box: each one's own setting, or its preset's.

interactive

Interactive charts: a chart as a plotly figure drawn from the same layout as its image, so the two look the same, with a popup and crosshair under the pointer. Chart.interactive() is the way in.

axes

A panel's axes as plotly draws them, every one taken from the layout: its domain is the panel's box, its range and ticks are the laid-out ones, and none of plotly's own choices are left to it.

Names dataclass
Names(x: str, y: str, y2: str | None = None)

A panel's plotly axis names: as a layout key ("xaxis2") and as a trace refers to it ("x2").

key staticmethod
key(ref: str) -> str

The layout key for an axis reference: "x2" is "xaxis2".

domain
domain(
    box: Box, width: float, height: float
) -> tuple[list[float], list[float]]

A box as fractions of the figure, across and up.

axis
axis(
    laid: AxisLayout,
    span: list[float],
    anchor: str,
    paint: Paint,
    across: bool,
    grid: bool,
) -> dict[str, Any]

One axis: its domain, range, ticks, line and gridlines, as laid out.

tick_labels
tick_labels(
    laid: AxisLayout,
    refs: tuple[str, str],
    side: str,
    base: float,
    paint: Paint,
) -> list[dict[str, Any]]

An axis's tick labels, set where the image sets them: the style's pad from the axis line (and past its tick marks where they point out), each label hung from its baseline.

Parameters:

Name Type Description Default
laid AxisLayout

The axis.

required
refs tuple[str, str]

Its own reference and the other axis's, such as ("x", "y").

required
side str

Where the labels are: "bottom", "left" or "right".

required
base float

Where the axis line sits on the other axis, as a share of its domain.

required
paint Paint

The chart's inks and sizes.

required
origin
origin(
    position: float,
    span: list[float],
    low: float,
    high: float,
) -> float

Where an axis through zero sits on the other axis's domain.

baseline

Where text sits up and down, as the image sets it.

The layout anchors text as matplotlib does, by the box its ink fills (at least as tall as "lp"). Plotly anchors the box the font's own ascent and descent fill, which is taller. So each piece of text is placed by its baseline: the layout's anchor gives the baseline, and plotly's box is hung below it by the font's descent.

descent cached
descent(font: Font) -> float

How far a font's box reaches below its baseline, as a share of its size.

shift
shift(
    words: str, size: float, font: Font, va: str
) -> float

How far up from the layout's anchor to put the bottom of plotly's box, in pixels, so the baseline falls where the image's does.

figure

A chart as a plotly figure, drawn from the same layout as its image: the figure is the layout's size, with no margins, each panel's axes in the box the layout puts them, their ranges and ticks the laid-out ones, and the frame drawn where the layout puts it.

BeaconFigure

Bases: Figure

A Beacon chart as a plotly figure. Its HTML carries the fonts the chart is set in and the script that draws the popup over it, so it looks and reads the same offline as on the page.

to_html
to_html(*args: Any, **kwargs: Any) -> str

The figure as HTML, with its fonts and popup; plotly's own options otherwise.

Takes two options of its own: fonts="embed" (the default) carries the fonts in the page, a stylesheet's address links one that has them, and None leaves them out; fit=True makes the figure fill the frame it is shown in rather than keep its own size.

write_html
write_html(file: Any, *args: Any, **kwargs: Any) -> None

Write the figure's HTML, with its fonts and popup, to a file.

Takes to_html's options. With include_plotlyjs="directory", plotly.js is written once beside it, as plotly's own write_html does, for several figures to share.

aligned
aligned(annotation: dict[str, Any]) -> dict[str, Any]

Text set from its anchored edge. plotly otherwise centres text in a box it measured, and a box measured before the chart's fonts arrive puts each line a little off once they do.

interactive
interactive(chart: Any) -> BeaconFigure

A chart as a plotly figure, laid out as its image is.

frame

The frame around an interactive chart, drawn where the layout puts it: the beta mark, the accent bar, the heading, the legend, the axis and panel titles, the notes and a heatmap's colour scale, in the figure's own coordinates (fractions of its width and height).

Frame
Frame(layout: Layout, paint: Paint)

The frame's shapes and annotations.

text
text(text: Text) -> None

Text placed in inches; each line of several placed on its own, at the layout's line height.

mark
mark(box: Box) -> None

The beta mark, its outline fitted to the layout's box.

legend
legend(legend: LegendLayout) -> None

Each entry's key and label where the layout puts them.

anchors
anchors(text: Text) -> tuple[str, str]

Where plotly anchors text: the layout gives its alignment in the text's own frame, and plotly aligns the box it fills once turned, so a title turned a quarter to read upward has its bottom at the right.

html

An interactive chart's HTML: plotly's, with the fonts the chart is set in embedded and the popup's script run once the figure is drawn. plotly.js is included by default, so the file works offline.

figure_html
figure_html(
    figure: Any,
    render: Callable[..., str],
    *args: Any,
    fonts: str | None = "embed",
    fit: bool = False,
    **kwargs: Any,
) -> str

plotly's HTML for a figure, with the chart's fonts before it and the popup's script after it.

Parameters:

Name Type Description Default
figure Any

The figure.

required
render Callable[..., str]

plotly's own to_html for it.

required
fonts str | None

"embed" to carry the fonts in the page, a stylesheet's address to link one that has them (beacon.plot.webfonts.font_faces with a base), or None for neither.

'embed'
fit bool

Whether the figure fills the frame it is shown in rather than keeping its own size, as in an iframe sized by the page.

False
write_figure_html
write_figure_html(
    html: str, file: Any, beside: bool = False
) -> None

Write HTML to a path or a file opened for writing, and plotly.js beside a path when beside.

figure_fonts
figure_fonts(figure: Any) -> set[Font]

The faces the figure's text is set in: its ticks and labels in the chart's font, and each piece of its frame in its own.

popup

The popup an interactive chart shows under the pointer, as Beacon desktop's popover draws it (beacon-ui Popover.css): a glass fill blurring what is behind it, a half-pixel edge, a 2px radius and a soft shadow. Plotly's own labels are SVG, which cannot blur, so the script hides them and draws this in HTML over the chart, fed by plotly's hover events; where the script cannot run, plotly's labels stay.

It also draws the app's crosshair: a dashed line in the muted text colour down through the date under the pointer, with a dot on each line there, or both ways through a scatter's point.

glass
glass(paint: Paint, crosshair: str) -> dict[str, Any]

What the popup is drawn in, kept in the figure's layout so its script finds it: the glass, its edge, the text and muted colours, the font and the kind of crosshair.

readout

What an interactive chart's popup says: values written with their units, as the axis they are read on writes its ticks, and dates as a reader says them.

date_text
date_text(days: float) -> str

A date, from days since 1970-01-01: 13 Oct 2026.

value_text
value_text(
    value: float, labels: LabelStyle, whole: bool = False
) -> str

A value as its axis writes it, with its units: shares and percentages with a % sign, and an axis's own writing (such as £m) where it has one; whole for a series of counts, written without decimals.

number_text
number_text(value: float) -> str

A number with as many decimals as its size reads with.

spines

A panel's axis lines and tick marks, drawn where the image draws them.

Each panel's lines are one path, joined at the corner where they meet and ending at the plot's edges, and each axis's tick marks one path of the same weight, all placed in the figure's own coordinates from the layout, as the styles preview draws them. Plotly's own lines are snapped to the pixel and drawn outside the plot, and its tick marks leave out an axis's two ends, so neither meets the other as the image's do.

Spines
Spines(
    panel: PanelLayout,
    width: float,
    height: float,
    paint: Paint,
    lines: bool = True,
)

One panel's axis lines and tick marks, as path shapes.

shapes
shapes() -> list[dict[str, Any]]

The panel's lines, then its tick marks.

spine
spine(
    box: Box,
    across: float,
    up: float,
    x_line: bool,
    y_line: bool,
) -> list[dict[str, Any]]

The two axis lines: joined at the corner where they meet at the plot's edges, or each on its own where they cross at zero.

ticks
ticks(
    laid: AxisLayout,
    base: float,
    horizontal: bool,
    side: float,
    shown: bool,
) -> list[dict[str, Any]]

An axis's tick marks, every one the layout has, ends included, as one path: up from a horizontal axis, and in from a vertical one on whichever side it is.

at staticmethod
at(
    laid: AxisLayout,
    start: float,
    length: float,
    value: float,
) -> float

Where a value falls along an axis, in inches.

traces

A chart's marks as plotly draws them: lines, areas, bars, points and cells as traces, the lines a chart is read against and its marked periods as shapes, and its text as annotations, each on its panel's axes.

Each mark that is data also gets a readout for the popup: for every point, what it is (a date, a category, a point's name), and a row per value with the colour it is drawn in. Lines, areas, bars and points carry it on an invisible trace of markers at their points, so the popup and its crosshair snap to the data; the drawn traces themselves take no part in hovering.

Drawn dataclass
Drawn(
    traces: list[dict[str, Any]],
    shapes: list[dict[str, Any]],
    annotations: list[dict[str, Any]],
)

What a chart's marks become: traces, shapes and annotations.

Marks
Marks(
    panels: Sequence[Panel],
    names: Sequence[Names],
    paint: Paint,
    layout: Layout,
    legend: Sequence[str] = (),
)

Turns marks into plotly's traces, shapes and annotations.

draw
draw(marks: Sequence[Mark]) -> Drawn

Every mark, by layer as matplotlib stacks them.

refs
refs(panel: int, side: str = 'left') -> tuple[str, str]

A mark's axes. Marks on a second axis are drawn on the main one, their values carried onto its scale (lift), so plotly draws every mark in one subplot in the order the image does; on axes of its own a second axis's marks would all be drawn over the main one's.

lift
lift(
    panel: int, side: str, values: Sequence[float]
) -> list[float]

Values on the second axis's scale carried onto the main axis's.

x_of
x_of(panel: int, values: Sequence[float]) -> list[float]

Positions across, as the panel's axis counts them.

value
value(
    mark: LineMark | AreaMark | BarMark, value: float
) -> str

A value as the axis it is read on writes it; a series of whole numbers, such as counts, without decimals.

readout
readout(
    panel: int,
    side: str,
    across: Sequence[float],
    up: Sequence[float],
    rows: list[list[list[str]]],
    kind: str,
    name: str,
    labels: Sequence[str] = (),
    along: str = "x",
) -> None

An invisible trace of markers at a mark's points, carrying each point's heading and rows for the popup, and plain text for plotly's own labels where the popup cannot run.

rank
rank(name: str) -> int

Where a series' row comes in the popup: in the legend's order, then in the order the marks are drawn.

heading
heading(axis: Axis, place: float) -> str

What a point is, from where it sits across: a date, a category's name, or a number.

units

The figure's units and inks: inches and points as plotly's pixels, dates as its milliseconds, and the colours, fonts and sizes a chart is drawn in.

Paint dataclass
Paint(style: Style)

A chart's inks, font and sizes, in its theme and style.

canvas property
canvas: str | None

The background, or None where the theme draws none.

ink
ink(name: str) -> str

A colour by name, as a CSS colour.

rgba
rgba(colour: str, alpha: float) -> str

A hex colour at an opacity.

layout

A chart's layout as a value: where everything in its frame goes, worked out once, without a renderer, for every renderer to draw from.

A renderer describes what it will draw as a Description: the figure's size, the heading and notes, each panel's axes (their data ranges, how their ticks are spaced and written) and the labels it writes on them, and the legend's entries. beacon.plot.arrange.lay_out() turns that and a Style into a Layout: the figure's size; each panel's box; each axis's range, ticks and tick labels (a blanked corner label included) and its title; the heading, accent bar and mark; the legend's entries with their keys; and the notes' lines.

Positions are in inches from the figure's bottom left. Text is anchored as matplotlib anchors it: ha and va place the text's box on (x, y), and a rotated title turns about that point. Colours are names, never resolved colours, so one layout draws in any theme: a token name such as "accent" or "text-primary", "accent-bar" for the bar beside the title, "palette-N" for the Nth series colour, or a literal "#rrggbb" a caller chose.

Standard library and numpy only: the plotly renderer lays charts out without importing matplotlib.

Box dataclass

Box(
    left: float, bottom: float, width: float, height: float
)

A rectangle, in inches from the figure's bottom left.

right property
right: float

Its right edge.

top property
top: float

Its top edge.

Text dataclass

Text(
    text: str,
    x: float,
    y: float,
    size: float,
    font: Font,
    colour: Colour,
    ha: HorizontalAlignment = "left",
    va: VerticalAlignment = "baseline",
    rotation: float = 0.0,
    line_height: float = 1.2,
    id: str = "",
)

Text placed on the figure.

Attributes:

Name Type Description
text str

What it says; lines are separated by newlines.

x float

Its anchor across, in inches.

y float

Its anchor up, in inches.

size float

In points.

font Font

The face.

colour Colour

By name.

ha HorizontalAlignment

Which side of the text's box sits on x.

va VerticalAlignment

Which side of it sits on y.

rotation float

Degrees anticlockwise, about the anchor.

line_height float

Between lines, as a multiple of the size.

id str

Names the piece, such as "beacon-title".

Axis dataclass

Axis(
    kind: AxisKind,
    low: float,
    high: float,
    ticks: tuple[float, ...] = (),
    names: tuple[str, ...] = (),
    labels: LabelStyle = "number",
    spacing: Spacing = Spacing(),
    title: str = "",
    show_labels: bool = True,
    rotation: float = 0.0,
    align: HorizontalAlignment = "center",
    inverted: bool = False,
    tick_length: float | None = None,
    shared: int | None = None,
    end: bool = True,
)

One axis of a panel, as the chart sees it.

Attributes:

Name Type Description
kind AxisKind

How it measures.

low float

The low end of its data, or of its range for names and fixed ticks.

high float

The high end.

ticks tuple[float, ...]

For names and fixed ticks, where they are.

names tuple[str, ...]

For names and fixed ticks, what they say.

labels LabelStyle

For numbers, how they are written.

spacing Spacing

For numbers, how the ticks are spaced.

title str

The axis's title, or empty.

show_labels bool

Whether its tick labels are drawn (a panel above another shares the lower one's).

rotation float

Its tick labels' angle.

align HorizontalAlignment

Their alignment across.

inverted bool

Whether it runs high to low (a heatmap's rows).

tick_length float | None

Its tick marks' length in points as drawn, or None for the style's.

shared int | None

Another panel whose axis this one is: the same range and ticks.

end bool

Whether a measuring axis ends on its outermost ticks; one that does not runs to its data's ends (an area that meets the axes).

measures property
measures: bool

Whether the axis measures something, and so ends on its ticks.

Label dataclass

Label(
    text: str,
    x: float,
    y: float,
    dx: float,
    dy: float,
    size: float,
    font: Font,
    ha: HorizontalAlignment = "left",
    va: VerticalAlignment = "baseline",
    rotation: float = 0.0,
    fraction: bool = False,
    clip: bool = False,
)

Text a chart writes on a panel, such as the value at a line's end, which the figure's sides are widened to keep inside.

Attributes:

Name Type Description
text str

What it says.

x float

Where, in the panel's data.

y float

Where, in the panel's data.

dx float

Offset across, in points.

dy float

Offset up, in points.

size float

In points.

font Font

The face.

ha HorizontalAlignment

Which side of its box sits on the point.

va VerticalAlignment

Which side of it sits on the point.

rotation float

Degrees anticlockwise.

fraction bool

Whether x and y are fractions of the panel's box rather than data.

clip bool

Whether it is left out when its point falls outside the panel.

ColourBar dataclass

ColourBar(
    low: float,
    high: float,
    fraction: float = 0.046,
    pad: float = 0.04,
    aspect: float = 20.0,
    labels: tuple[Label, ...] = (),
    ends: tuple[str, str] | None = None,
)

A colour scale beside a panel, taking a share of its width.

Attributes:

Name Type Description
low float

The scale's low end.

high float

Its high end.

fraction float

Its share of the panel's width.

pad float

The gap between, as a share of the panel's width.

aspect float

Its height to its width.

labels tuple[Label, ...]

Text written beside it, such as what its ends mean.

ends tuple[str, str] | None

Labels for its two ends, low then high, in place of ticks.

Panel dataclass

Panel(
    x: Axis,
    y: Axis,
    weight: float = 1.0,
    equal: bool = False,
    labels: tuple[Label, ...] = (),
    colour_bar: ColourBar | None = None,
    y2: Axis | None = None,
    origin: bool = False,
    title: str = "",
    cell: tuple[int, int] = (0, 0),
    span: tuple[int, int] = (1, 1),
)

One plot of a chart.

Attributes:

Name Type Description
x Axis

Its horizontal axis.

y Axis

Its vertical axis.

weight float

Its share of the chart's height, against the other panels.

equal bool

Whether a unit is as long across as up (a heatmap's squares).

labels tuple[Label, ...]

Text written on it.

colour_bar ColourBar | None

A colour scale beside it.

y2 Axis | None

A second vertical axis, on the right, with its own scale.

origin bool

Whether the axes cross at zero rather than sit at the plot's edges.

title str

A short title above the panel, in a grid of several.

cell tuple[int, int]

Its row and column in a grid, counting from the top left.

span tuple[int, int]

How many rows and columns of the grid it takes.

LegendItem dataclass

LegendItem(label: str, colour: Colour, key: Key = 'line')

One legend entry: its label, its colour and the kind of key it has.

Description dataclass

Description(
    size: tuple[float, float],
    title: str,
    subtitle: str = "",
    notes: str = "",
    panels: tuple[Panel, ...] = (),
    gap: float = 0.2,
    legend: tuple[LegendItem, ...] = (),
    bottom_room: float | None = None,
    crop: bool = False,
    columns: int = 1,
    grid: bool = False,
    heights: tuple[float, ...] = (),
    widths: tuple[float, ...] = (),
)

What a chart asks the layout for.

Attributes:

Name Type Description
size tuple[float, float]

The figure's width and height, in inches.

title str

The heading.

subtitle str

Beneath it; empty for none.

notes str

The notes line, without its "Notes:" prefix; empty for none.

panels tuple[Panel, ...]

Top to bottom, in one column.

gap float

Between panels, as a share of their average height.

legend tuple[LegendItem, ...]

Its entries; none for no legend.

bottom_room float | None

Inches kept free under the plot for its tick labels; by default one row of them.

crop bool

Whether the figure is narrowed to what the chart draws, at the same scale, rather than kept at its size (a square heatmap).

columns int

How many columns a grid's panels are laid out in.

grid bool

Whether the panels are laid out as a grid, each at its cell, rather than stacked top to bottom by weight.

heights tuple[float, ...]

A grid's rows' shares of its height; equal when empty.

widths tuple[float, ...]

Its columns' shares of its width; equal when empty.

Tick dataclass

Tick(value: float, label: str)

A tick: where it is and what it says (empty where it is blanked).

AxisLayout dataclass

AxisLayout(
    kind: AxisKind,
    low: float,
    high: float,
    ticks: tuple[Tick, ...],
    offset: str = "",
    title: Text | None = None,
    ended: bool = False,
    show_labels: bool = True,
    rotation: float = 0.0,
    align: HorizontalAlignment = "center",
    inverted: bool = False,
)

An axis as drawn.

Attributes:

Name Type Description
kind AxisKind

How it measures.

low float

The low end shown.

high float

The high end shown.

ticks tuple[Tick, ...]

Every tick inside the range, with its label.

offset str

Written once at the axis's end, such as "2024-Feb"; usually empty.

title Text | None

Its title, placed.

ended bool

Whether it ends on its outermost ticks.

show_labels bool

Whether its tick labels are drawn.

rotation float

Its tick labels' angle.

align HorizontalAlignment

Their alignment across.

inverted bool

Whether it runs high to low.

ColourBarLayout dataclass

ColourBarLayout(
    box: Box,
    axis: AxisLayout,
    labels: tuple[Text, ...] = (),
)

A colour scale as drawn: its box, its axis and the text beside it.

PanelLayout dataclass

PanelLayout(
    box: Box,
    x: AxisLayout,
    y: AxisLayout,
    colour_bar: ColourBarLayout | None = None,
    y2: AxisLayout | None = None,
    origin: bool = False,
    title: Text | None = None,
)

A panel as drawn: the box its plot fills, its axes, whether they cross at zero, and its title in a grid.

LegendEntry dataclass

LegendEntry(
    label: str,
    colour: Colour,
    key: Key,
    key_box: Box,
    text: Text,
)

A legend entry as drawn: its key's box and its label.

LegendLayout dataclass

LegendLayout(
    position: str,
    columns: int,
    box: Box,
    entries: tuple[LegendEntry, ...],
    size: float,
    anchor: tuple[float, float],
    corner: str,
)

The legend as drawn.

Attributes:

Name Type Description
position str

"heading", "bottom" or "right".

columns int

How many columns its entries run in.

box Box

The box its entries fill.

entries tuple[LegendEntry, ...]

Each entry, in the order given.

size float

Its labels' size, in points.

anchor tuple[float, float]

The point the legend is pinned to, in inches.

corner str

Which of its corners is pinned there, such as "lower right".

Layout dataclass

Layout(
    width: float,
    height: float,
    panels: tuple[PanelLayout, ...],
    title: Text,
    subtitle: Text | None = None,
    notes: Text | None = None,
    accent_bar: Box | None = None,
    mark: Box | None = None,
    legend: LegendLayout | None = None,
)

A chart's whole frame, laid out.

Attributes:

Name Type Description
width float

The figure's width, in inches.

height float

Its height.

panels tuple[PanelLayout, ...]

Each panel, top to bottom.

title Text

The heading.

subtitle Text | None

Beneath it, or None.

notes Text | None

The notes, wrapped to the plot's width, or None.

accent_bar Box | None

The bar beside the heading, or None.

mark Box | None

The box the beta mark fills, or None.

legend LegendLayout | None

The legend, or None.

legend

A framed chart's legend: in the heading band by default, or, as the style says (legend.position), under the plot or in one column to its right.

The legend sits at the right of the heading band, right-aligned with the end of the x axis and its bottom level with the subtitle's, in a row of as many entries as fit beside the title and subtitle; it wraps onto more rows, upward, when they do not. A legend taller than the heading pushes the plot down rather than running into it, and one that cannot fit beside the heading at all goes under it.

Widths are measured from the fonts themselves (beacon.plot.metrics), so the layout needs no renderer and comes out the same on every backend.

LegendPlan dataclass

LegendPlan(
    labels: tuple[str, ...],
    columns: int,
    height: float,
    beside: bool,
    width: float = 0.0,
)

How a framed chart's legend is laid out.

text_width

text_width(
    text: str,
    size: float,
    family: str,
    italic: bool = False,
    weight: int = 400,
) -> float

How wide text is set, in inches.

plan

plan(
    labels: Sequence[str],
    size: float,
    font: Font,
    heading_width: float,
    room: float,
    under: bool = False,
    columns: int | None = None,
) -> LegendPlan | None

Lay out a legend for the heading band, or under the plot, or in a set number of columns.

Parameters:

Name Type Description Default
labels Sequence[str]

The entries' labels.

required
size float

Their size, in points.

required
font Font

Their face.

required
heading_width float

How far the heading's text reaches from the plot's left edge, in inches.

required
room float

The plot's width, in inches.

required
under bool

Lay it out across the plot's whole width, under it.

False
columns int | None

A set number of columns, such as one for a legend beside the plot.

None

Returns:

Type Description
LegendPlan | None

LegendPlan | None: None when there are no entries.

entries

entries(
    items: Sequence[LegendItem],
    columns: int,
    size: float,
    font: Font,
    anchor: tuple[float, float],
    corner: str,
) -> tuple[Box, tuple[LegendEntry, ...]]

Each entry's key and label, with the legend's corner (such as "lower right") at anchor.

Entries fill the columns in turn, top to bottom, each column as wide as its widest entry, as matplotlib sets a legend.

mark

The beta mark: the glyph Beacon desktop shows at the top left of its menu bar and pybeacon.dev in its header, drawn beside every framed chart's heading.

Kept as the glyph's outline rather than set in a font, so drawing it needs no font at all, and it is the same shape the application and the site draw.

beta_outline cached

beta_outline() -> Outline

The beta mark as a matplotlib path, parsed once from BETA_PATH.

mark_width

mark_width(size: float = MARK_INCHES) -> float

How wide the mark is drawn, in inches, at size inches tall.

draw_mark

draw_mark(
    figure: Figure,
    right: float,
    middle: float,
    colour_value: str,
    size: float = MARK_INCHES,
) -> None

The beta mark beside the heading.

Parameters:

Name Type Description Default
figure Figure

The figure to draw on.

required
right float

Where the mark ends, in inches from the left.

required
middle float

The heading's middle, in inches from the bottom.

required
colour_value str

The mark's colour.

required
size float

Its height, in inches.

MARK_INCHES

marks

What a chart draws inside its plot, as values every renderer can draw.

A chart class turns its data into marks: lines, filled areas, bars, points, the lines a chart is read against, marked periods, text and grids of coloured cells. Positions are in the panel's data, with dates as days since 1970-01-01 (beacon.plot.dateticks). Colours are names (beacon.plot.colours), and line widths and sizes are in points as drawn.

Each mark names the panel it is drawn in and, where a panel has a second vertical axis, the side whose scale it is measured on. A mark that is data names what it shows, for an interactive chart's popup; one with no name, such as a reference line, is left out of it.

Standard library only, like the layout, so the plotly renderer draws the same marks without importing matplotlib.

LineMark dataclass

LineMark(
    x: tuple[float, ...],
    y: tuple[float, ...],
    colour: Colour,
    width: float,
    dashed: bool = False,
    alpha: float = 1.0,
    layer: float = 3.0,
    panel: int = 0,
    side: Side = "left",
    name: str = "",
)

A line through points, in order.

AreaMark dataclass

AreaMark(
    x: tuple[float, ...],
    lower: tuple[float, ...],
    upper: tuple[float, ...],
    colour: Colour,
    alpha: float = 1.0,
    layer: float = 2.0,
    panel: int = 0,
    side: Side = "left",
    name: str = "",
)

The space between two lines, filled.

BarMark dataclass

BarMark(
    positions: tuple[float, ...],
    values: tuple[float, ...],
    thickness: tuple[float, ...],
    colours: tuple[Colour, ...],
    horizontal: bool = False,
    base: tuple[float, ...] = (),
    edge: bool = False,
    seamless: bool = False,
    layer: float = 2.0,
    panel: int = 0,
    side: Side = "left",
    name: str = "",
    labels: tuple[str, ...] = (),
)

Bars from a base to their values.

Attributes:

Name Type Description
positions tuple[float, ...]

Where each bar sits along its category axis: its centre, or its left edge when edge.

values tuple[float, ...]

How far each reaches.

thickness tuple[float, ...]

Each bar's thickness, in the category axis's units.

colours tuple[Colour, ...]

Each bar's colour.

horizontal bool

Whether the bars run across rather than up.

base tuple[float, ...]

Where each bar starts; zero when empty.

edge bool

Whether a position is the bar's left edge rather than its centre.

seamless bool

Whether bars that meet are drawn without a seam between.

name str

The series the bars show.

labels tuple[str, ...]

What each bar is, such as its category or its bin's range.

PointMark dataclass

PointMark(
    x: tuple[float, ...],
    y: tuple[float, ...],
    colour: Colour,
    size: float,
    alpha: float = 1.0,
    clip: bool = True,
    layer: float = 5.0,
    panel: int = 0,
    side: Side = "left",
    name: str = "",
    names: tuple[str, ...] = (),
    measures: tuple[str, str] = ("", ""),
)

Dots: what they are, each one's name where it has one, and the names of the two measures they are placed by.

RuleMark dataclass

RuleMark(
    value: float,
    colour: Colour,
    width: float,
    vertical: bool = False,
    dashed: bool = False,
    layer: float = 1.0,
    id: str = "",
    panel: int = 0,
    side: Side = "left",
)

A line across the whole plot at one value: up it when vertical, otherwise across it.

SpanMark dataclass

SpanMark(
    start: float, end: float, colour: Colour, panel: int = 0
)

A marked period: a box from the bottom of the plot to the top, over a range of the horizontal axis, behind everything else.

TextMark dataclass

TextMark(
    text: str,
    x: float,
    y: float,
    colour: Colour,
    size: float,
    weight: int = 300,
    dx: float = 0.0,
    dy: float = 0.0,
    ha: Literal["left", "center", "right"] = "left",
    va: Literal[
        "top", "center", "bottom", "baseline"
    ] = "center",
    coords: Literal[
        "data", "axes", "xdata", "ydata"
    ] = "data",
    clip: bool = False,
    halo: bool = False,
    panel: int = 0,
    side: Side = "left",
)

Text on the plot.

Attributes:

Name Type Description
text str

What it says.

x float

Across, in data, or a fraction of the plot when coords says so.

y float

Up, likewise.

colour Colour

By name.

size float

In points.

weight int

The font's weight.

dx float

Offset across, in points.

dy float

Offset up, in points.

ha Literal['left', 'center', 'right']

Which side of its box sits on the point.

va Literal['top', 'center', 'bottom', 'baseline']

Which side of it sits on the point.

coords Literal['data', 'axes', 'xdata', 'ydata']

"data" for both in data, "axes" for both as fractions of the plot, "xdata" for x in data and y as a fraction, "ydata" for x as a fraction and y in data.

clip bool

Whether it is left out when its point falls outside the plot.

halo bool

Whether it is outlined in the background's colour, so it reads over the lines it sits on.

CellsMark dataclass

CellsMark(
    values: tuple[tuple[float | None, ...], ...],
    stops: tuple[Colour, ...],
    low: float,
    high: float,
    blended: bool = False,
    gap: float = 0.0,
    panel: int = 0,
    written: tuple[tuple[str, ...], ...] = (),
)

A grid of values drawn as coloured cells, row by row from the top.

Attributes:

Name Type Description
values tuple[tuple[float | None, ...], ...]

One row of values per row of cells; None leaves a cell empty.

stops tuple[Colour, ...]

The colour map's colours from low to high.

low float

The value at the map's low end.

high float

The value at its high end.

blended bool

Whether each colour blends into the next rather than each cell being its own square.

gap float

The space between cells, as a share of a cell.

written tuple[tuple[str, ...], ...]

Each value as the chart writes it, row by row.

metrics

How wide and how tall a chart's text is set, read from the font files.

A chart's layout (beacon.plot.layout) is worked out before anything is drawn, and the same layout serves every renderer, so text cannot be measured by drawing it. It is measured here from the fonts themselves: each glyph's advance and the exact bounds of its outline, the way matplotlib sets a text path. Glyphs are set at their advances with no kerning, as matplotlib sets them for fonts whose kerning lives in GPOS rather than a kern table, which covers the bundled fonts.

The bundled fonts are found by family; any other font is given as the path of its file (.ttf or .otf). A family that is neither is measured as Inter Tight, with a warning, since there is no file to read.

Font dataclass

Font(family: str, weight: int = 400, italic: bool = False)

A face to set text in: a family (or a font file's path), a weight and a slant.

TextBox dataclass

TextBox(width: float, ascent: float, descent: float)

The box a line of text is set in, in inches: its ink width, its height above the baseline and its depth below it.

height property
height: float

From the bottom of the descent to the top of the ascent.

weight_of

weight_of(weight: str | int | float) -> int

A weight as a number, from a name such as "light" or a number.

font_file

font_file(font: Font) -> Path

The file a face is read from.

A path is itself; a bundled family is its nearest face, matching the slant first and then the weight, as matplotlib chooses. Anything else is measured as Inter Tight.

width

width(text: str, size: float, font: Font) -> float

How wide text is set at size points, in inches: the width of its ink, the widest line's when it has several.

box

box(text: str, size: float, font: Font) -> TextBox

The box one line of text is set in, at size points.

Its height is at least the reference text's, so a row of labels lines up whatever letters each one has, as matplotlib sets them.

notes

What a result chart's notes line says: where the data came from, the dates it covers, and whatever the chart itself needs said, run together as sentences rather than listed.

provenance

provenance(result: Any, what: str, dates: Index) -> str

Where a result's data came from and the dates it covers, as a sentence.

Parameters:

Name Type Description Default
result Any

Anything bound to the data it was calculated from.

required
what str

What the dates are of, such as "backtest" or "index".

required
dates Index

The dates drawn.

required

Returns:

Name Type Description
str str

Such as "Source: Synthetic data, backtest dated from 02/01/2024

str

to 31/12/2024.", or "weights as of 01/10/2024" for a single date. The

str

source is left out when the data recorded none, and the whole is

str

empty when there are no dates.

sentences

sentences(*parts: str) -> str

Notes run together as sentences, skipping the empty ones.

paint

The matplotlib renderer for the chart classes: a chart's plan and layout drawn onto a figure.

Each panel's axes are put where the layout says, its marks drawn on them, and its ranges, ticks and titles set from the layout; then the frame is drawn around them: the mark, the accent bar, the heading, the legend and the notes. Colours are resolved from their names in the chart's theme and style.

Painted dataclass

Painted(
    figure: Figure,
    axes: tuple[Axes, ...],
    right: tuple[Axes | None, ...],
    params: dict[str, Any],
)

A chart drawn: its figure, each panel's axes, each panel's second axes on the right where it has one, and the rcParams it is drawn in.

save
save(target: Any, **options: Any) -> None

Save the figure in the rcParams it was drawn in.

paint

paint(
    plan: Plan,
    layout: Layout,
    style: Style,
    make: Callable[..., Figure] | None = None,
) -> Painted

Draw a chart.

Parameters:

Name Type Description Default
plan Plan

Its marks and description.

required
layout Layout

Where everything goes.

required
style Style

The settings it is drawn in.

required
make Callable[..., Figure] | None

Makes the figure, given its size; a figure of its own, outside pyplot, by default.

None

show

show(plan: Plan, layout: Layout, style: Style) -> None

Draw a chart on a pyplot figure and show it.

panels

A chart's panels, laid out: where each sits, where its axes end, what its ticks say and how far its text reaches past its sides.

Used by beacon.plot.arrange, which fits the panels between the heading and the notes. Boxes here are figure fractions, as a grid of panels divides the figure, until arrange turns them into inches.

AxisState dataclass

AxisState(
    spec: Axis, low: float, high: float, ended: bool = False
)

An axis's range as the layout moves it: where it ends, and whether it has been ended on its ticks.

Sizes dataclass

Sizes(
    tick_label: float,
    axis_title: float,
    pad: float,
    title_pad: float,
    tick_length: float,
    direction: str,
    font: Font,
)

The sizes a style sets for the panels, in points as drawn.

of classmethod
of(style: Style) -> Sizes

The sizes in a style.

label_pad
label_pad(axis: Axis, ticks_on: bool) -> float

From the axis line to its tick labels, in points.

cells

cells(
    weights: Sequence[float],
    gap: float,
    left: float,
    right: float,
    bottom: float,
    top: float,
) -> list[tuple[float, float, float, float]]

Panels stacked in one column, as figure fractions: left, bottom, right, top for each, top to bottom.

split_for_bar

split_for_bar(
    cell: tuple[float, float, float, float], bar: ColourBar
) -> tuple[
    tuple[float, float, float, float],
    tuple[float, float, float, float],
]

A panel's cell divided between its plot and its colour bar.

shrink

shrink(
    cell: tuple[float, float, float, float],
    aspect: float,
    figure_aspect: float,
    anchor: tuple[float, float],
) -> tuple[float, float, float, float]

The largest box of aspect (height to width) in a cell, placed at anchor within it.

boxes

boxes(
    panel: Panel,
    cell: tuple[float, float, float, float],
    state: tuple[AxisState, AxisState],
    figure: tuple[float, float],
) -> tuple[Box, Box | None]

A panel's plot box and its colour bar's, in inches.

end

end(
    state: AxisState,
    length: float,
    sizes: Sizes,
    across: bool,
) -> bool

End a measuring axis on its outermost ticks. Returns whether it was one.

axis_ticks

axis_ticks(
    state: AxisState,
    length: float,
    sizes: Sizes,
    across: bool,
    blank: float | None = None,
) -> tuple[tuple[Tick, ...], str]

An axis's ticks inside its range, with their labels, and the offset written at its end.

at

at(
    value: float,
    state: AxisState,
    start: float,
    length: float,
) -> float

Where a value falls along an axis drawn from start for length inches.

label_span

label_span(
    text: str, size: float, font: Font, rotation: float
) -> tuple[float, float]

How wide and how tall a label's box is once turned, in inches.

across_from

across_from(
    x: float, wide: float, ha: str
) -> tuple[float, float]

A box's left and right edges when its ha side sits at x.

shows

shows(
    label: Label,
    box: Box,
    state: tuple[AxisState, AxisState],
) -> bool

Whether a label is drawn: one clipped to its panel is not when its point falls outside it.

label_reach

label_reach(
    label: Label,
    box: Box,
    state: tuple[AxisState, AxisState],
) -> tuple[float, float] | None

How far a label written on a panel reaches, left and right; None when it is not drawn.

tick_label_reach

tick_label_reach(
    axis: AxisLayout,
    state: AxisState,
    box: Box,
    sizes: Sizes,
    ticks_on: bool,
) -> list[tuple[float, float]]

How far a horizontal axis's tick labels reach, left and right.

y_label_left

y_label_left(
    axis: AxisLayout, box: Box, sizes: Sizes, pad: float
) -> float

Where a vertical axis's tick labels start, at the left: the axis line where there are none.

y_label_right

y_label_right(
    axis: AxisLayout, box: Box, sizes: Sizes, pad: float
) -> float

Where a right-hand axis's tick labels end, at the right: the axis line where there are none.

x_label_bottom

x_label_bottom(
    axis: AxisLayout, box: Box, sizes: Sizes, pad: float
) -> float

Where a horizontal axis's tick labels end, at the bottom: the axis line where there are none.

y_title

y_title(
    text: str, right: float, box: Box, sizes: Sizes
) -> Text

A vertical axis's title, its right edge at right, centred up the panel, reading upward.

y2_title

y2_title(
    text: str, left: float, box: Box, sizes: Sizes
) -> Text

A right-hand axis's title, its left edge at left, centred up the panel, reading upward.

x_title

x_title(
    text: str, top: float, box: Box, sizes: Sizes
) -> Text

A horizontal axis's title, its top at top, centred under the panel.

style

The "beacon" matplotlib styles, generated from the design tokens.

Not hand-written: every colour comes from beacon.tokens, which is a vendored copy of the file the desktop client generates its CSS from. That is the point: a chart embedded in the application should be the same colours as the panel around it, and the only way to guarantee that is for both to read one source. A palette retyped here would be right on the day it was written.

Two styles, beacon and beacon-dark, because the client has two modes and a chart has to follow. Both are registered with matplotlib by name, so once :func:register has run (every chart method, :func:use and beacon.plot.compare run it) plt.style.use("beacon") restyles any plot, including one this library never drew.

What the grammar is
  • an accent line at 1.5pt for the primary series, text-secondary for a benchmark: the comparison should read as subordinate without being hidden
  • divider gridlines on the y axis only, and behind the data
  • muted axis labels and tick text, with the top and right spines removed: a chart is mostly data, and the frame is not the data
The correlation colormap

beacon_corr is registered here too, from the raw.heatmap-* tokens. Mode-independent by design: a correlation of 0.8 must look the same whichever theme the surrounding application is wearing, or two screenshots of the same matrix disagree.

scaled

scaled(value: float) -> float

A designed size at the scale charts are drawn at, in the current style.

series_width

series_width() -> float

The leading series' line weight, as drawn.

secondary_width

secondary_width() -> float

Every other series' line weight, as drawn.

reference_width

reference_width() -> float

A reference line's weight, as drawn.

label_size

label_size() -> float

Legend entries and labels on the chart, in points as drawn.

tick_label_size

tick_label_size() -> float

Tick labels, in points as drawn.

axis_title_size

axis_title_size() -> float

Axis titles, in points as drawn.

reference_lines

reference_lines() -> bool

Whether charts draw the lines they are read against.

font_family

font_family(name: str) -> str

A font's family name: name itself, or the family of the font file it names (.ttf or .otf), which is registered with matplotlib first.

figure_size

figure_size(kind: str) -> tuple[float, float]

The size a chart of kind is drawn at, in inches, in the current style: its designed size, or the style's width (at the same proportions) and aspect, zoomed by the style's scale.

sized

sized(width: float, height: float) -> tuple[float, float]

A designed size as drawn, in inches, in the current style: the style's width (at the same proportions) and aspect where it sets them, zoomed by the style's scale.

palette

palette(
    theme: str | None = None, mode: str | None = None
) -> dict[str, str]

The colours a chart draws with, in one theme.

Parameters:

Name Type Description Default
theme str | None

A theme's name, or LIGHT or DARK for the Beacon canvases. Defaults to LIGHT.

None
mode str | None

Deprecated: the parameter's name before themes, which still works and warns. Use theme.

None

Returns:

Name Type Description
dict dict[str, str]

The token names this module uses, so a caller composing a custom

dict[str, str]

chart can reach the same values rather than sampling them off a figure.

dict[str, str]

A transparent theme's canvas is "none".

style_dict

style_dict(
    theme: str | None = None,
    mode: str | None = None,
    style: Style | None = None,
) -> dict[str, Any]

The rcParams for one theme, in one style.

Built as a mapping rather than written to an .mplstyle file so the values stay derived from the tokens. A generated file would be a second copy to keep in step, which is the thing this module exists to avoid.

Parameters:

Name Type Description Default
theme str | None

A theme's name, or LIGHT or DARK for the Beacon canvases. Defaults to the style's theme.

None
mode str | None

Deprecated: the parameter's name before themes, which still works and warns. Use theme.

None
style Style | None

The settings; Beacon's defaults when None.

None

Returns:

Name Type Description
dict dict[str, Any]

matplotlib rcParams names to values.

correlation_colormap

correlation_colormap() -> Any

The beacon_corr colormap, green through amber to red.

Built from the mode-independent raw.heatmap-* tokens: a correlation of 0.8 must look the same whichever theme the application is wearing, or two screenshots of one matrix disagree.

Returns:

Name Type Description
Colormap Any

Registered under CORRELATION_COLORMAP.

register

register() -> None

Register both styles and the colormap with matplotlib.

Idempotent, and called on first use of any accessor, so plt.style.use("beacon") works as soon as anything in this package has been touched. Registering at import of beacon.plot instead would mean importing matplotlib to do it, which is exactly what the lazy accessor exists to avoid.

apply

apply(force: bool = False) -> None

Put the current style into matplotlib's rcParams, when it has changed since it was last applied.

Charts draw in whatever rcParams are active, so nothing is applied until a style is chosen: configure() takes effect at the next chart, and a user who never calls it keeps the rcParams they set themselves.

use

use(
    theme: str | None = None, mode: str | None = None
) -> None

Apply a beacon theme to every chart drawn afterwards: a shortcut for configure(theme=...), which changes nothing else in the style.

Parameters:

Name Type Description Default
theme str | None

"beacon-light" (or LIGHT, the default), "beacon-dark" (or DARK), "github-dark", "white", "transparent-dark-axes" or "transparent-light-axes".

None
mode str | None

Deprecated: the parameter's name before themes, which still works and warns. Use theme.

None

Raises:

Type Description
ValueError

If there is no such theme.

TypeError

If both theme and mode are given.

tables

A table under the Beacon frame (beacon.plot.Table): its content, its geometry as an image, and its drawing as an image and as HTML.

css

A table's look in HTML, as a style block scoped to its id: rules, boxes and stripes are drawn by where a row is rather than written on each cell, so they stay in place when the rows are sorted.

table_css
table_css(writer: Any) -> str

The style block for one table, from the writer that writes it.

edge
edge(side: str, line: tuple[float, str]) -> str

One edge's rule, as the custom property a cell's shadow reads.

draw

A table's pieces placed in inches: its headings and values, its rules and boxes, its stripes and its heatmap's fills.

HeatText dataclass
HeatText(text: Text, fill: Fill)

A heatmap cell's value, in an ink worked out on its fill when drawn.

Span dataclass
Span(kind: str, top: float, bottom: float)

Where a row is, top and bottom, and what it is.

Placer
Placer(
    model: TableModel,
    style: Any,
    sizes: Any,
    columns: list[float],
    rows: list[tuple[str, float]],
    left: float,
    top: float,
    geometry: Any,
)

Puts a table's pieces where they go.

aligned
aligned(
    edges: tuple[float, float], align: str
) -> tuple[float, str]

Where text aligned in a cell sits across, and how it is anchored.

nearest
nearest(line: list[Fill | None]) -> list[Fill | None]

Each place's fill, or its nearest filled neighbour's.

fonts

The faces a table's HTML sets text in, for beacon.plot.webfonts to embed.

css_family
css_family(name: str) -> str

A font as a CSS font family, with the fonts that stand in for it.

family_name
family_name(name: str) -> str

A font's family as HTML names it: a font file by its name.

font_faces
font_faces(table: Any) -> str

The @font-face rules for every face a table's HTML sets text in.

geometry

Where a table's text, rules, boxes and fills go as an image, and the frame around it, worked out from the fonts without a renderer.

Each column is as wide as its widest text and the cell padding either side, and the columns share any room the frame has to spare in proportion; a table wider than the frame widens the figure. Each row is a line and the row padding above and below it. The table starts at the accent bar, so it lines up with the heading as a chart's plot does, and the notes follow it.

measure
measure(table: Any) -> Geometry

A table's geometry as an image, and its frame.

html

A table as HTML: the heading, the table and the notes in the table's theme, with columns that sort when their headings are clicked.

Each table's look is a style block scoped to its own id, so rules, boxes and stripes follow the rows when they are sorted. Rows sort within their row groups. A script sorts the rows and blends a heatmap's colours; without it the table still reads, its heatmap cells each their own colour.

table_html
table_html(table: Any) -> str

A table as HTML, with its frame.

model

A table's content as its renderers draw it: every cell's text, colour and fill, its column groups and row groups, worked out once from a DataFrame and the table's options, without a renderer.

Colours are names or hex codes (beacon.plot.colours), except a heatmap's fills, which carry the colour map's colour and how strongly it shows, so a faded cell can be laid over whatever the table's background is.

Column dataclass
Column(
    name: str,
    group: int | None = None,
    first: bool = False,
    last: bool = False,
)

One column of values: its heading and the group it is in.

Fill dataclass
Fill(colour: str, alpha: float = 1.0)

A heatmap cell's colour: the colour map's colour and how strongly it shows over the table's background, 1 for fully.

Cell dataclass
Cell(
    text: str,
    value: float | None,
    colour: str | None,
    fill: Fill | None = None,
    bold: bool = False,
    hidden: bool = False,
)

One value cell as drawn.

Attributes:

Name Type Description
text str

What it says.

value float | None

The number, for sorting; None for text or a missing value.

colour str | None

Its text's colour, by name or hex; None for a heatmap cell's own ink, worked out on its fill.

fill Fill | None

Its heatmap fill, or None.

bold bool

Whether its row is highlighted.

hidden bool

Whether its text is left out (a heatmap of colour alone).

Row dataclass
Row(name: str, cells: tuple[Cell, ...], bold: bool = False)

One row: its name, its cells, and whether it is highlighted.

RowGroup dataclass
RowGroup(label: str, rows: tuple[Row, ...])

Rows kept together, with a heading when the table shows one.

Heat dataclass
Heat(
    columns: tuple[int, ...] = (),
    blended: bool = False,
    blend: str = "columns",
)

Which cells are a heatmap and how their colours blend.

Attributes:

Name Type Description
columns tuple[int, ...]

The heatmap's columns, by position.

blended bool

Whether each colour blends into its neighbours.

blend str

"columns" (across), "rows" (down) or "both".

TableModel dataclass
TableModel(
    columns: tuple[Column, ...],
    groups: tuple[str, ...],
    row_groups: tuple[RowGroup, ...],
    group_headings: bool = False,
    heat: Heat = Heat(),
)

A table's content.

Attributes:

Name Type Description
columns tuple[Column, ...]

The value columns, left to right.

groups tuple[str, ...]

The column groups' headings, in order; empty for none.

row_groups tuple[RowGroup, ...]

The rows, in their groups (one unnamed group for none).

group_headings bool

Whether the row groups' headings are shown.

heat Heat

The heatmap, if any.

grouped_rows property
grouped_rows: bool

Whether the rows are in named groups.

column_groups
column_groups(
    columns: Sequence[str],
    groups: Mapping[str, int | Sequence[str]] | None,
) -> tuple[tuple[str, ...], dict[str, int]]

The groups' headings and each column's group, from groups= given as {heading: [columns]} or {heading: how many columns, in order}.

Raises:

Type Description
ValueError

If a group names a column the table does not have.

formatter
formatter(
    format_: Format | None, negatives: str, whole: bool
) -> Callable[[Any], str]

A function writing one column's values.

Parameters:

Name Type Description Default
format_ Format | None

The column's format; by default as many decimals as a number of its kind needs, with thousands separated.

required
negatives str

"minus" for a true minus sign, "brackets" for (1.2).

required
whole bool

Whether every value in the column is a whole number.

required
is_number
is_number(value: Any) -> bool

Whether a cell's value is a number (numpy's included), not a flag.

heat_fill
heat_fill(
    value: float,
    low: float,
    high: float,
    stops: Sequence[str],
    fade: bool,
    centred: bool,
) -> Fill

A heatmap cell's colour, a share of the way along its map.

Faded, near-neutral cells take the table's own background: a map lighter in its middle than at either end fades from the middle out to each end's colour, and a one-way map from its light end to its deep end, so no pale cell stands out on a dark table.

over
over(fill: Fill, ground: str) -> str

A fill laid over the table's background, as one colour.

frame_of
frame_of(data: DataFrame) -> pd.DataFrame

A table's data, checked.

Raises:

Type Description
TypeError

If it is not a DataFrame.

ValueError

If it is empty.

paint

The matplotlib renderer for a table: its geometry drawn onto a figure, in the frame every chart has.

paint_table
paint_table(
    table: Any, make: Callable[..., Figure] | None = None
) -> Painted

Draw a table.

show_table
show_table(table: Any) -> None

Draw a table on a pyplot figure and show it.

script

The script a table's HTML carries: it sorts the rows when a column's heading is clicked, keeping each row group together, and blends a heatmap's colours.

sizes

The pieces a table is drawn from, in inches, and its sizes in a style.

Rule dataclass
Rule(
    x0: float,
    y0: float,
    x1: float,
    y1: float,
    width: float,
    colour: str,
)

A straight line: from (x0, y0) to (x1, y1) in inches, its weight in points, its colour by name or hex.

Patch dataclass
Patch(box: Box, colour: str, fill: Fill | None = None)

A filled box: a stripe or a heatmap cell.

Blend dataclass
Blend(
    box: Box,
    fills: tuple[tuple[Fill, ...], ...],
    direction: str,
)

Heatmap cells whose colours blend into each other: a grid of fills, row by row, over a box, blended across, down or both.

Geometry dataclass
Geometry(
    layout: Layout,
    texts: list[Text] = list(),
    rules: list[Rule] = list(),
    patches: list[Patch] = list(),
    blends: list[Blend] = list(),
    heat_texts: list[Any] = list(),
    widths: list[float] = list(),
)

A table drawn as an image: the frame's layout, and the table's text, rules and fills, and every column's width with the spaces between them, in inches.

Sizes dataclass
Sizes(
    body: float,
    head: float,
    group: float,
    row_pad: float,
    cell_pad: float,
    name_space: float,
    rule: float,
    row_rule: float,
    box: float,
    font: str,
)

A table's text sizes, paddings and line weights, scaled.

rule_gap
rule_gap(sizes: Sizes) -> float

The space either side of a row group's heading, in inches.

blocks
blocks(model: TableModel, rules: dict[str, bool]) -> bool

Whether the row groups stand apart, boxed or headed: then stripes, row rules and blended heatmaps start afresh in each.

gap_before
gap_before(
    model: TableModel, index: int, rules: dict[str, bool]
) -> bool

Whether a narrow gap comes before a value column: where column groups are boxed, before each group but the first column.

themes

The chart themes: the background a chart is drawn on, and the inks that read on it.

beacon-light            Beacon's light canvas (also "light")
beacon-dark             Beacon's dark canvas (also "dark")
github-dark             GitHub's dark page, with its greys for the text
white                   white, with Beacon's light-mode inks
transparent-dark-axes   no background, dark inks: for a light page
transparent-light-axes  no background, light inks: for a dark page

Every theme takes its colours from the design tokens of one Beacon mode and changes only what its background needs: GitHub's dark theme its text greys, and the transparent ones the background itself. So a chart in any theme is still drawn in Beacon's accent, signs and series colours.

A chart records its theme when it is made, so its own inks (a marker, a sign, the frame) follow the theme even when the background, being transparent, says nothing about it.

Theme dataclass

Theme(
    name: str,
    style: str,
    mode: str,
    canvas: str | None,
    overrides: Mapping[str, str] = dict(),
)

A chart theme.

Attributes:

Name Type Description
name str

What beacon.plot.use() takes.

style str

The matplotlib style it is registered as.

mode str

LIGHT or DARK: which set of Beacon tokens its inks come from.

canvas str | None

The background colour; None draws no background at all.

overrides Mapping[str, str]

Token colours this theme replaces.

transparent property
transparent: bool

Whether the theme draws no background.

colour
colour(token: str) -> str

One colour in this theme: "none" for a transparent canvas.

"period", marked periods' boxes, is the theme's own where it has one and its divider otherwise.

series
series() -> tuple[str, ...]

The series colours, in the order series take them.

theme_named

theme_named(name: str) -> Theme

The theme called name, or a mode's own name.

Raises:

Type Description
ValueError

If there is no such theme.

set_current

set_current(name: str) -> Theme

Make name the theme new charts are drawn in.

current

current() -> Theme

The theme beacon.plot.use() last applied.

remember

remember(figure: Any, facecolor: Any) -> Theme

Record the theme a new figure is drawn in, read off the background the style gave it, and return it.

of_figure

of_figure(figure: Any) -> Theme | None

The theme a figure was made in, when it was made here.

for_background

for_background(facecolor: Any) -> Theme

The theme a background belongs to.

The current theme when it is the one that background came from, then any theme with exactly that canvas; otherwise light or dark by brightness, so a figure drawn on matplotlib's own white still gets Beacon's light inks.

ticks

Where a measuring axis puts its ticks, and what they say.

Worked out without a renderer so every renderer shows the same ticks, by the rules matplotlib's own defaults follow, so a chart's ticks are the ones it has always had:

  • an axis has as many ticks as its length has room for, about three label widths apart across and two label heights apart up, at most ten
  • the step is 1, 2, 2.5 or 5 times a power of ten, the smallest that covers the range in that many steps
  • a number is written with as few decimals as tell its ticks apart, with a true minus sign, and a percentage with as many as the range needs

Dates are in beacon.plot.dateticks.

Spacing dataclass

Spacing(
    bins: int | None = None,
    steps: tuple[float, ...] = STEPS,
    least: int = 2,
)

How a measuring axis spaces its ticks.

Attributes:

Name Type Description
bins int | None

The most intervals, or None for as many as the axis has room for.

steps tuple[float, ...]

The steps allowed, as multiples of a power of ten.

least int

The fewest ticks shown.

Labels dataclass

Labels(labels: tuple[str, ...], offset: str = '')

What an axis's ticks say: one label per tick, and any offset written once at the axis's end (such as "+1e6").

room_for

room_for(
    length: float, label_size: float, across: bool
) -> int

How many intervals an axis has room for.

Parameters:

Name Type Description Default
length float

The axis's length, in inches.

required
label_size float

Its tick labels' size, in points.

required
across bool

True for a horizontal axis, whose labels need about three times their size; a vertical axis's need two.

required

nonsingular

nonsingular(
    low: float,
    high: float,
    expander: float = 0.001,
    tiny: float = 1e-15,
) -> tuple[float, float]

A range widened where it is too narrow to divide, in order.

tick_values

tick_values(
    low: float, high: float, spacing: Spacing, room: int
) -> list[float]

Every tick the axis's locator gives for a range, including any just beyond its ends, which a formatter still sees.

Parameters:

Name Type Description Default
low float

The range's low end.

required
high float

Its high end.

required
spacing Spacing

How the axis spaces its ticks.

required
room int

From room_for(), used when the spacing sets no bins.

required

ends

ends(
    low: float, high: float, spacing: Spacing, room: int
) -> tuple[float, float]

The ticks at or beyond each end of a range: where an axis that ends on its ticks ends.

The same step the axis shows, so its ends are ticks the reader sees.

within

within(
    ticks: Sequence[float], low: float, high: float
) -> list[float]

The ticks inside a range, allowing for rounding at its ends.

fix_minus

fix_minus(text: str) -> str

A true minus sign in place of a hyphen.

number_labels

number_labels(
    ticks: Sequence[float], low: float, high: float
) -> Labels

Plain numbers: as few decimals as tell the ticks apart.

Parameters:

Name Type Description Default
ticks Sequence[float]

Every tick the locator gave, as tick_values() returns them.

required
low float

The axis's low end.

required
high float

Its high end.

required

percent_labels

percent_labels(
    ticks: Sequence[float],
    low: float,
    high: float,
    whole: float = 1.0,
    decimals: int | None = None,
    symbol: str = "%",
) -> Labels

Percentages of whole, with as many decimals as the axis's range needs, or decimals.

share_labels

share_labels(
    ticks: Sequence[float], low: float, high: float
) -> Labels

Shares written as percentages, with as few decimals as tell the ticks apart: 5%, 10%, 15% rather than 5.0%, 10.0%, 15.0%.

webfonts

The fonts a chart's or table's HTML carries, so it is set as its image is wherever it is opened, offline included.

Each face used is embedded once, as the file the image is drawn from: the bundled faces (under the SIL Open Font License, which allows embedding) or a font given as the path of its file. A family that is neither is left to the browser.

family_name

family_name(name: str) -> str

A font's family as HTML names it: a font file by its name.

css_family

css_family(name: str) -> str

A font as a CSS font family, with the fonts that stand in for it.

font_faces

font_faces(
    fonts: Iterable[Font], base: str | None = None
) -> str

The @font-face rules for the faces text is set in, each file once, serving every weight that is set in it.

Parameters:

Name Type Description Default
fonts Iterable[Font]

The faces.

required
base str | None

Where the font files are, such as "fonts/", to link them by name rather than embed them (font_files writes them there).

None

font_files

font_files(
    fonts: Iterable[Font], directory: Path
) -> list[Path]

Copy the files the faces are set in into a folder, for a stylesheet that links them (font_faces with base) to share.

embeddable

embeddable(family: str) -> bool

Whether a family has a file to embed: bundled, or given as one.