Documentation
¶
Overview ¶
Package theme holds the visual tokens a chart is drawn with: colours, fonts, sizes and spacings.
A theme is plain data. It is resolved once, before lowering, and every decision that is "how should this look" reads from it rather than hardcoding a value — which is what makes a second theme a data change instead of a code change.
Tokens ¶
The full Theme is wide, and most of it follows from a handful of choices. Tokens holds those choices and Build derives the rest, so a new theme is a dozen lines rather than fifty. Theme.With edits a built theme, and Register and ByName make a theme reachable by name — which is what a configuration file or a command-line flag needs.
Index ¶
- Variables
- func Names() []string
- func Register(t Theme)
- type Option
- func AxisLines(x, y bool) Option
- func Background(c ir.Color) Option
- func Density(f float64) Option
- func FontFamily(name string) Option
- func FontSize(size float64) Option
- func Grid(x, y bool) Option
- func Named(name string) Option
- func Palette(p palette.Qualitative) Option
- func PlotFill(c ir.Color) Option
- func Ramps(sequential, diverging palette.Ramp) Option
- func TickCounts(x, y int) Option
- type Theme
- type Tokens
Constants ¶
This section is empty.
Variables ¶
var Dark = Build(DarkTokens)
Dark is the inverted theme: light ink on a near-black surface.
var DarkTokens = Tokens{ Name: "dark", Background: ir.RGB(0x14, 0x16, 0x1A), Panel: ir.Transparent, Strip: ir.RGB(0x22, 0x26, 0x2D), Ink: ir.RGB(0xF2, 0xF3, 0xF5), InkMuted: ir.RGB(0xC8, 0xCB, 0xD0), InkSubtle: ir.RGB(0xA0, 0xA4, 0xAB), Line: ir.RGB(0x9A, 0x9E, 0xA6), LineSubtle: ir.RGB(0x2A, 0x2E, 0x35), FontSize: 12, Space: 4, Palette: palette.OkabeIto, Sequential: palette.Viridis, Diverging: palette.BlueOrange, }
DarkTokens are the choices the dark theme makes: light ink on near-black.
The axis is deliberately not the same grey as the labels. On a dark surface a line at the label's lightness reads heavier than the same line does on white, because it is the brighter of the two against its background rather than the darker.
var Light = Build(LightTokens)
Light is the default theme: dark ink on a white surface.
var LightTokens = Tokens{ Name: "light", Background: ir.RGB(0xFF, 0xFF, 0xFF), Panel: ir.Transparent, Strip: ir.RGB(0xEE, 0xEF, 0xF1), Ink: ir.RGB(0x1A, 0x1A, 0x1A), InkMuted: ir.RGB(0x33, 0x33, 0x33), InkSubtle: ir.RGB(0x55, 0x55, 0x55), Line: ir.RGB(0x33, 0x33, 0x33), LineSubtle: ir.RGB(0xDD, 0xDD, 0xDD), FontSize: 12, Space: 4, Palette: palette.OkabeIto, Sequential: palette.Viridis, Diverging: palette.BlueOrange, }
LightTokens are the choices the light theme makes: dark ink on white.
Functions ¶
Types ¶
type Option ¶ added in v0.3.0
type Option func(*Theme)
Option edits a theme. Options exist so that "the dark theme, in my typeface, without a grid" is a call rather than a copy of the struct with three fields changed and forty copied.
func Background ¶ added in v0.3.0
Background sets the canvas colour behind everything.
func Density ¶ added in v0.3.0
Density scales every spacing by f, tightening or loosening the whole chart at once. Text sizes are left alone: a dense chart with unreadable labels is not denser, it is worse.
func FontFamily ¶ added in v0.3.0
FontFamily sets the logical font family. It is a name, not a file: the backend resolves it, and the SVG backend passes it through to the viewer.
func FontSize ¶ added in v0.3.0
FontSize rescales all three text sizes so that the label size becomes size, keeping the ratios between title, label and tick.
func Palette ¶ added in v0.3.0
func Palette(p palette.Qualitative) Option
Palette sets the qualitative sequence layers take their colours from.
func PlotFill ¶ added in v0.3.0
PlotFill sets the fill of the plot area itself, which is transparent by default so the background shows through.
func Ramps ¶ added in v0.3.0
Ramps sets the sequential and diverging ramps a colour scale falls back to. A nil argument leaves that ramp alone.
func TickCounts ¶ added in v0.3.0
TickCounts sets how many ticks each axis aims for. They are hints: a scale rounds to whatever produces readable labels.
type Theme ¶
type Theme struct {
Name string
// Surfaces.
Background ir.Color // outside the plot area
PlotFill ir.Color // inside the plot area
// Text.
FontFamily string
TitleSize float64
LabelSize float64
TickSize float64
TitleColor ir.Color
LabelColor ir.Color
TickColor ir.Color
// Axes and grid.
AxisColor ir.Color
AxisWidth float32
GridColor ir.Color
GridWidth float32
GridDash []float32
TickLength float32
TickLabelPad float32
AxisTitlePad float32
ShowGridX bool
ShowGridY bool
ShowAxisLineX bool
ShowAxisLineY bool
TickCountHintX int
TickCountHintY int
// Legend.
LegendSwatch float32
LegendPad float32
LegendGap float32
LegendColor ir.Color
LegendBG ir.Color
LegendBorder ir.Color
LegendPadding float32
// Guides. A chart can carry more than one — a legend for the layers that
// have a colour each, a colourbar for a layer whose colour comes from a
// continuous scale — and they stack in one column beside the plot.
GuideGap float32 // vertical gap between stacked guides
// Colourbar.
ColorbarThickness float32 // across the bar
ColorbarFraction float64 // of the plot height, before clamping
ColorbarBorder ir.Color
ColorbarTickCount int
// Annotations: reference lines, bands and labels that are not data.
AnnotationColor ir.Color
AnnotationWidth float32
AnnotationDash []float32
AnnotationOpacity float64 // fill alpha for a shaded band
// Panels: subplots and facets.
PanelGap float32 // between adjacent panels
StripBG ir.Color
StripColor ir.Color
StripSize float64
StripPad float32
StripBorder ir.Color
// Spacing.
Margin float32 // outer margin on all four sides
// Series colours, and the ramps a colour scale falls back to.
Palette palette.Qualitative
Sequential palette.Ramp
Diverging palette.Ramp
// Default geometry weights.
LineWidth float32
MarkerSize float32
}
Theme is the full set of visual tokens for a chart.
func Build ¶ added in v0.3.0
Build derives a full theme from its tokens.
The type scale is a perfect fourth up for the title and one step down for ticks — 12 gives 16 and 11, which is where the hand-written v0.1 themes already were. The ratios are written as exact fractions rather than decimals so that a round base size produces round derived sizes rather than 15.999.
Spacings are multiples of Tokens.Space. With the default unit of 4 that reproduces the v0.1 numbers exactly, which is the point: a derived theme has to be able to express what was there before it, or the derivation is telling you what to want.
func (Theme) DivergingRamp ¶ added in v0.3.0
DivergingRamp returns the theme's diverging ramp, falling back to the package default.
func (Theme) SequentialRamp ¶ added in v0.3.0
SequentialRamp returns the theme's sequential ramp, falling back to the package default so that a zero Theme still produces colours.
func (Theme) Tokens ¶ added in v0.3.0
Tokens returns the tokens a theme was built from, as far as they can be read back off it.
It is not an inverse of Build — a theme that has been edited afterwards may no longer be derivable from any tokens at all. It is what makes "the dark theme, but in my brand's typeface" one call rather than a rebuild from scratch.
type Tokens ¶ added in v0.3.0
type Tokens struct {
// Name identifies the theme, and is the key it registers under.
Name string
// Background is the canvas outside the plot area; Panel is the fill
// inside it, normally transparent so the background shows through; Strip
// is the band a facet's label sits in.
Background ir.Color
Panel ir.Color
Strip ir.Color
// Ink runs from the strongest text to the faintest: a title, a label, a
// tick. Three levels is enough to build a hierarchy and few enough that a
// second theme has to answer only three questions.
Ink ir.Color
InkMuted ir.Color
InkSubtle ir.Color
// Line is the axis; LineSubtle is the grid behind the data.
Line ir.Color
LineSubtle ir.Color
// FontFamily is the logical family; "" means the backend's default sans.
FontFamily string
// FontSize is the label size in device units. The title and tick sizes
// derive from it — see [Build].
FontSize float64
// Space is the spacing unit every padding and gap is a multiple of.
Space float64
// Palette colours the layers of a chart; Sequential and Diverging are the
// ramps a colour scale falls back to when it is given none.
Palette palette.Qualitative
Sequential palette.Ramp
Diverging palette.Ramp
}
Tokens is the small set of decisions a theme actually makes.
A Theme has around fifty fields, and almost all of them are consequences rather than choices: a tick label is the same colour as the other faint ink, the gap under an axis title is the same rhythm as the gap beside a legend. Writing all fifty out by hand is how two themes drift apart in ways nobody intended. Tokens holds the choices — four inks, two line weights, one type size, one spacing unit, the colours — and Build derives the rest.
Anything derived can still be overridden afterwards: Build returns a plain struct, and Theme.With edits it. Tokens is the starting point, not a cage.