Skip to content
dysonsphere

Global theme overrides

Everything ds.theme() accepts as a keyword can also live in a dysonsphere.toml config file, so a project (or your whole machine) keeps its look without repeating arguments in every notebook. This page is the complete reference for the file: where it lives, how values merge, named styles, custom palettes, and every valid key. To put one together interactively, use the dysonsphere.toml generator.

import dysonsphere as ds
ds.create_config() # writes ./dysonsphere.toml
ds.create_config(persist=True) # writes to your user config dir instead

create_config() writes a commented template with the built-in style presets at their defaults and an empty custom-style placeholder; it never overwrites an existing file. persist=True targets the platform user config directory - ~/.config/dysonsphere/ on macOS and Linux (respecting $XDG_CONFIG_HOME), %APPDATA%/dysonsphere/ on Windows - so it applies across all your projects.

The scaffold looks like this:

dysonsphere.toml
# Theme configuration for dysonsphere.
# Load a style with ds.theme(style="name").
[default]
[notebook]
chartWidth = 900
chartHeight = 900
darkmode = true
fontSize = 18
transparent = true
[my_style] # Rename to your desired style name
[palettes]
# my_palette = ["#DFE9F7", "#C6D9F1", "#ADC8EC", ...]

ds.theme() looks for config files in two places, in ascending priority:

  1. User-wide: $XDG_CONFIG_HOME/dysonsphere/dysonsphere.toml (default ~/.config/dysonsphere/dysonsphere.toml; %APPDATA%\dysonsphere\dysonsphere.toml on Windows) - your personal defaults, applied everywhere.
  2. Project: the first dysonsphere.toml found by walking up from the current working directory to the filesystem root - the same discovery rule as .git. Keep it next to your pyproject.toml and every notebook or script inside the project sees it.

When both exist, the project file’s values win over the user-wide file’s, key by key.

Values are merged in ascending priority - later sources override earlier ones, key by key:

  1. dysonsphere’s built-in defaults
  2. [default] from the config file(s)
  3. the built-in preset named by style= (e.g. notebook)
  4. the [style] section of the same name from the config file(s)
  5. explicit ds.theme(...) keyword arguments

So a call decides last, a named style beats [default], and the config file beats the built-ins. A worked example:

[default]
palette = "greens"
fontSize = 8
[poster]
chartWidth = 300
chartHeight = 220
fontSize = 14
ds.theme() # greens palette, 8 pt type
ds.theme(style="poster") # greens palette, 14 pt type, 300 x 220
ds.theme(style="poster", fontSize=16) # ... but 16 pt - the kwarg wins

Only the keys present in a section are applied; everything else keeps its default. Calling ds.theme() again re-reads the config files and replaces the active theme entirely.

Any table in the file other than [default] and [palettes] is a style, selected with ds.theme(style="name"). Styles are how you keep several looks on tap - a print figure, a poster, a slide deck:

[print]
chartWidth = 100 # publication scale (the default)
chartHeight = 100
[slides]
chartWidth = 260
chartHeight = 180
fontSize = 12
markSize = 25

The built-in "notebook" preset works with no config file at all; a [notebook] section in your config customises it (your keys override the preset’s, per the merge order). Asking for a style that is neither built-in nor in any config file raises a ValueError naming it.

The [palettes] table registers custom palettes alongside the built-in catalogue - each value a non-empty list of hex strings. They become available everywhere a palette name works: ds.palette("brand"), ds.theme(palette="brand"), or any per-type key (heatmapPalette = "brand").

[palettes]
brand = ["#0B3954", "#1B5F7E", "#2E86AB", "#63A8C7", "#A8CFE0", "#E8F1F5"]

Sequential dysonsphere palettes carry 12 stops and diverging ones 13 (a neutral midpoint), but custom palettes may be any length. Two notes:

  • Custom palettes are re-registered on each ds.theme() call and vanish cleanly when the config file does - ds.colors is restored to the built-in catalogue first.
  • Overriding a built-in base hue (say blues) does not ripple into the derived categorical palette, which is fixed at import time. Override categorical itself - or set categoryPalette - to recolor categories.

The file is checked eagerly on every ds.theme() call: an unknown key in any section raises a ValueError immediately, naming the key. Typos never silently do nothing.

Every key below is valid in [default], in any style section, and as a ds.theme() keyword.

KeyDefaultWhat it does
chartWidth100Plot area width in px (publication scale; scale up for screens)
chartHeight100Plot area height in px
darkmodefalseInvert ink (axes, text, medians) to white for dark backgrounds
transparentfalseNo chart background fill (notebook/web embedding)
chartFillautoChart background when not transparent; auto = white, black in darkmode
viewFillunsetPlot-area (data rect) fill; setting it implies a closed frame
KeyDefaultWhat it does
fontHelvetica NeueFont family for all chart text
fontSize7Primary size (axis titles, labels, annotations) in pt
secondaryFontSizederivedAuxiliary tier, fontSize - 1 (floored at smallestFontSize)
smallestFontSize5Floor for the secondary tier; true shrinks the whole plot to the floor
fontStylenormalCSS font style (italic, …)
fontWeight400CSS font weight
KeyDefaultWhat it does
axisOffsettickSize * 1.5Detached-axis gap in px (Prism style); 0 reattaches
axisWidth0.25Stroke width of axis lines, ticks, and grid
closedautoDraw all four spines (a boxed frame); auto = on with inwardTicks/viewFill
inwardTicksfalsePoint ticks into the plot (physics style); implies closed
tickstrueMaster tick visibility
tickSize3Tick length in px
xAxis / yAxistrueHide an axis’s domain line and ticks (labels stay)
xDomain / yDomaintrueDomain line visibility per axis
xTicks / yTickstrueTick visibility per axis
xLabels / yLabelstrueLabel visibility per axis (independent of xAxis/yAxis)
xLabelAngle / yLabelAngle0Label rotation in degrees; alignment derived from the sign
KeyDefaultWhat it does
gridfalseDraw grid lines
gridColorlight greyGrid line color
dashedGridfalseDash the grid (uses dashedWidth)
KeyDefaultWhat it does
markSizederivedMaster mark size; most mark-type sizes derive from it
markFilllight greyDefault fill (boxplot boxes via the bar config, bars, …)
markFillOpacity1Fill opacity
markStrokeblackMark outline color
markStrokeOpacity1Outline opacity
markStrokeWidthaxisWidthOutline width; error bar and boxplot strokes derive from it
markMedianFillblackBoxplot median bar fill
markMedianStrokeblackBoxplot median outline color (when a stroke is enabled)
boxplotOutliersfalseShow boxplot outlier glyphs; true sizes them from markSize
cornerRadiusfalseRound bar tips/rects/arcs; true derives px from chart size
strokeCaproundLine cap for axis/tick/grid/rule strokes
bandPadding0.1Band-scale padding (category spacing)
KeyDefaultWhat it does
dashedRuletrueDash mark_rule (reference lines)
dashedLinefalseDash mark_line
dashedWidth[2, 2]The dash pattern used wherever dashing is on
KeyDefaultWhat it does
legendtrueMaster legend visibility
legendOffsettickSize * 1.5Gap between legend and plot
legendStrokefalseOutline legend symbols at axisWidth
KeyDefaultWhat it does
palettecategoricalMaster palette: name or list; overrides every per-type key
categoryPalettederivedCategorical (nominal) scale range
divergingPalettebuilt-inDiverging scale scheme
heatmapPalettebuilt-inHeatmap scale scheme
ordinalPalettegreysOrdinal scale scheme
rampPalettebuilt-inSequential ramp scheme
KeyDefaultWhat it does
sigFigs3Significant figures for on-plot statistical labels
saveFormat["svg", "json"]Default ds.save() formats
saveBackground"light"Default ds.save() background variant(s) (light, dark, or both)