Plot

Custom

Turning quantitative values into geometric shapes.

AI assisted, human approved — novem uses AI to review and keep our documentation up to date.

Novem custom plots run in a sandboxed iframe so that the plot author can use any JavaScript library they like without affecting the surrounding document. The iframe still inherits the parent document's theme however, with every --novem-* value propagated in two ways: as CSS variables on the iframe's root, and as a JavaScript object available to the plot's render function.

Variables are injected into the iframe's :root before your stylesheet runs, so you can use them directly anywhere you'd write a colour or a font.

body {
  font-family: var(--novem-font-body);
  font-size:   var(--novem-font-size);
  color:       var(--novem-text);
  background:  var(--novem-bg);
}

.tooltip {
  background:    var(--novem-tooltip-bg);
  color:         var(--novem-tooltip-text);
  border-radius: var(--novem-tooltip-radius);
}

Every variable is also exposed on render.theme as a camelCase value, which is useful when you build SVG or canvas content from JavaScript. The categorical palette is an array indexed from zero.

const t = render.theme;

const svg = d3.select(node).append("svg")
  .attr("width", width)
  .attr("height", height)
  .style("font-family", t.fontBody)
  .style("background", "transparent");

const color = d3.scaleOrdinal(t.colors);  // 10 categorical entries

svg.append("text")
  .attr("fill", t.text)
  .attr("font-weight", t.fontWeightHeading)
  .text("My chart");

const arc = d3.arc()
  .innerRadius(parseFloat(t.pieInnerRadius) * r)
  .outerRadius(r);

render.theme is dark-mode aware. The value of t.text already reflects whichever mode is active, so you don't need to branch on render.dark to pick a foreground colour. The boolean is still there if you want it for finer distinctions.