HAHS.
Back to Catalog

Nightingale Rose Chart

chart

Also known as: coxcomb chart, polar area chart, rose diagram, Nightingale chart

CompareShow composition CategoricalNumerical Arc/Radial

Description

The Nightingale rose chart — also called a coxcomb chart or polar area chart — arranges categories as equal-angle wedges radiating from a center, with the radius (and thus area) of each wedge proportional to the data value. Unlike a pie chart, where the angle varies and the radius is fixed, the rose chart holds the angle constant and varies the radius. The result is a circular display that combines the categorical structure of a bar chart with the visual impact of a radial layout.

The chart is named after Florence Nightingale, who used this form in her 1858 publication “Notes on Matters Affecting the Health, Efficiency, and Hospital Administration of the British Army” to demonstrate that preventable diseases, not battle wounds, were the primary cause of death during the Crimean War. Her “Diagram of the Causes of Mortality in the Army in the East” is one of the most celebrated statistical graphics in history, and its persuasive power contributed to major public health reforms.

While the rose chart is visually striking and historically important, it has a known perceptual limitation: area grows quadratically with radius, so a value twice as large produces a wedge four times the area. This exaggerates differences between large and small values. Careful scaling (using the square root of the value for the radius) can make areas proportional to values, but designers must be explicit about this choice.

Nightingale Rose — interactive example

When to Use

  • Presenting cyclical data (months, hours, compass directions) where the circular layout reinforces the cyclical nature
  • Creating visually distinctive displays for editorial, dashboard, or presentation contexts
  • Comparing magnitudes across categories when the circular form adds thematic resonance (e.g., wind direction, seasonal data)
  • When the audience will appreciate the historical reference and aesthetic appeal

When NOT to Use

  • When precise value comparison is the goal — a bar chart is more perceptually accurate
  • When categories are not cyclical and the circular layout adds no meaning — the radial distortion is a net cost
  • When there are many categories (>12) and wedges become thin and hard to distinguish
  • When the audience may confuse the chart with a pie chart and misinterpret it as part-to-whole

Anatomy

  • Wedges (petals): Sectors of equal angle, one per category, extending outward from the center. The radius encodes the value.
  • Center point: The common origin from which all wedges radiate.
  • Radial axis: Concentric circles or gridlines showing the scale of the radius dimension.
  • Angle assignment: Categories are evenly spaced around the circle, typically in a meaningful order (e.g., January-December clockwise from the top).
  • Color encoding: Each wedge colored by category to distinguish them; alternatively, a sequential fill encodes the value redundantly with radius.
  • Labels: Category names placed at the outer edge of each wedge or along the circumference.

Variations

  • Stacked rose chart: Multiple layers per wedge, showing sub-category composition within each angular segment (as in Nightingale’s original, which stacked three causes of death).
  • Normalized rose chart: All wedges extend to the same maximum radius; color intensity or layering encodes the value instead.
  • Wind rose: A meteorological variant showing wind speed and direction distributions, with concentric rings for frequency and angular segments for compass directions.
  • Polar bar chart: Bars arranged radially from a center, similar to the rose chart but using bar length rather than wedge area.
  • Small-multiple rose charts: Multiple rose charts compared side by side (e.g., one per year) to show change over time.

Code Reference

// D3 - Nightingale rose chart
import * as d3 from "d3";

const angle = d3.scaleBand()
  .domain(data.map(d => d.category))
  .range([0, 2 * Math.PI]);

const radius = d3.scaleSqrt()
  .domain([0, d3.max(data, d => d.value)])
  .range([0, innerRadius]);

const arc = d3.arc()
  .innerRadius(0)
  .outerRadius(d => radius(d.value))
  .startAngle(d => angle(d.category))
  .endAngle(d => angle(d.category) + angle.bandwidth())
  .padAngle(0.02);

const svg = d3.select("#chart").append("svg")
  .attr("viewBox", [-width / 2, -height / 2, width, height]);

svg.selectAll("path").data(data).join("path")
  .attr("d", arc)
  .attr("fill", d => d3.schemeTableau10[d.index % 10])
  .attr("stroke", "white");