Skip to content

Polar area (rose) ​

Stacked bars on polar axes with the categories on the angle: the sectors of a rose.

ts
import * as d3 from 'd3'
import {
  D3PAutoDomain, d3pAutoInteractionArea, D3PAxis, D3PAxisDomain, D3PBarRenderer, D3PChart, d3pDomLegend,
  d3pDomTooltip, D3PLegendBundle, D3PRadiusAxis, D3PSeries, D3PStack, D3PTooltip, getGlobalBus,
} from 'd3pict'
// your series data: replace these generators with your own values
import { walk } from './data'

const bus = getGlobalBus()

const container = document.getElementById('app')! // any element with a size: the chart fills it

const MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
const COLORS = d3.schemeTableau10
const month = (v: unknown) => MONTHS[Math.round(Number(v))] ?? ''
/** A series of numbers over 12 months, x being the month index. */
const monthly = (seed: number, base: number, spread: number) => walk(seed, 12, base, spread, 5, 100).map((v, i) => [i, v] as [number, number])

const names = ['Rain', 'Snow', 'Sun']
const inputs = names.map((name, i) => new D3PSeries({ bus, name, data: MONTHS.map((m, k) => [m, Math.round(8 + 14 * Math.abs(Math.sin((k + i * 3) * 0.55)))]) }))
const stack = new D3PStack({ bus, series: inputs })

const dmonth = new D3PAxisDomain({ bus, domain: MONTHS })
const ddays = new D3PAxisDomain({ bus, domain: [0, 1] })
const auto = new D3PAutoDomain({ bus })
for (const layer of stack.series) auto.linkSeries(layer, [dmonth, ddays])

// bars on polar axes are the sectors of a rose
const monthAxis = new D3PAxis({ bus, name: 'month', domain: dmonth, position: 'angle', scaleType: 'band', props: { grid: { enabled: true } } })
const days = new D3PRadiusAxis({ bus, name: 'days', domain: ddays, props: { tickCount: 4, grid: { enabled: true } } })
const layers = stack.series.map((layer, i) => new D3PBarRenderer({ bus, series: layer, props: { style: { color: COLORS[i + 4], barWidth: 0.96 } } }))

const tooltip = new D3PTooltip({ bus })
const legend = new D3PLegendBundle({ bus })
const objects = [monthAxis, days, ...layers, tooltip, legend]

const chart = new D3PChart({ container, bus })
const stopArea = d3pAutoInteractionArea(chart) // before the objects: the cursor, the tooltip and the tools ask for an interaction area
objects.forEach((o) => o.addToChart(chart))
const stopTooltip = d3pDomTooltip(tooltip)
const stopLegend = d3pDomLegend(legend)

All the chart types · how each type is built