Nightingale Rose Chart

A Nightingale rose (coxcomb chart) is a polar bar chart where each sector's area or radius is proportional to its data value. It was famously used by Florence Nightingale to visualise causes of soldier mortality.

Basic usage

#![allow(unused)]
fn main() {
use kuva::plot::rose::RosePlot;
use kuva::render::{plots::Plot, layout::Layout, render::render_rose};
use kuva::backend::svg::SvgBackend;

let plot = RosePlot::new()
    .with_slice("Jan", 30.0)
    .with_slice("Feb", 20.0)
    .with_slice("Mar", 45.0)
    .with_slice("Apr", 38.0);

let svg = SvgBackend.render_scene(&render_rose(plot, Layout::default()));
std::fs::write("rose.svg", svg).unwrap();
}

Or bulk-add slices:

#![allow(unused)]
fn main() {
use kuva::plot::rose::RosePlot;

let plot = RosePlot::new().with_slices([
    ("Jan", 30.0), ("Feb", 20.0), ("Mar", 45.0), ("Apr", 38.0),
]);
}

Auto-binning bearing data

Pass raw compass bearings (0–360°) and a bin count:

#![allow(unused)]
fn main() {
use kuva::plot::rose::RosePlot;

let bearings = vec![10.0, 45.0, 90.0, 135.0, 180.0, 225.0, 270.0, 315.0, 355.0];
let plot = RosePlot::new()
    .with_bearing_data(bearings, 8)  // 8 compass octants
    .with_compass_labels();          // N, NE, E, SE, ...
}

Stacked mode

Multiple series stacked within each sector:

#![allow(unused)]
fn main() {
use kuva::plot::rose::RosePlot;

let plot = RosePlot::new()
    .with_x_labels(["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"])
    .with_stack("Preventable", vec![12.0, 11.0, 14.0, 10.0, 9.0, 7.0, 6.0, 5.0, 8.0, 10.0, 13.0, 15.0])
    .with_stack("Wounds",      vec![ 3.0,  4.0,  2.0,  3.0, 2.0, 2.0, 1.0, 1.0, 2.0,  3.0,  3.0,  4.0])
    .with_legend("Cause of death");
}

Grouped mode

Each series occupies its own sub-wedge within each sector:

#![allow(unused)]
fn main() {
use kuva::plot::rose::{RosePlot, RoseMode};

let plot = RosePlot::new()
    .with_mode(RoseMode::Grouped)
    .with_x_labels(["Q1", "Q2", "Q3", "Q4"])
    .with_group("Product A", vec![20.0, 35.0, 25.0, 40.0])
    .with_group("Product B", vec![15.0, 22.0, 30.0, 28.0])
    .with_legend("Sales");
}

Encoding modes

ModeFormulaUse case
Area (default)r = sqrt(base² + frac*(max²-base²))Perceptually accurate — areas proportional to values
Radiusr = base + frac*(max_r-base)Radius proportional to values (overestimates large sectors)
#![allow(unused)]
fn main() {
use kuva::plot::rose::{RosePlot, RoseEncoding};

let plot = RosePlot::new()
    .with_encoding(RoseEncoding::Radius)
    .with_slices([("A", 10.0), ("B", 30.0), ("C", 60.0)]);
}

Compass labels

Replace numeric labels with cardinal/intercardinal directions:

#![allow(unused)]
fn main() {
use kuva::plot::rose::{RosePlot, compass_labels_for_n};

// Automatic from sector count (works for 4, 8, 16 sectors)
let plot = RosePlot::new()
    .with_bearing_data(some_bearings, 8)
    .with_compass_labels();

// Or set manually
let labels = compass_labels_for_n(4);  // ["N", "E", "S", "W"]
}

Inner radius / donut

#![allow(unused)]
fn main() {
use kuva::plot::rose::RosePlot;

let plot = RosePlot::new()
    .with_inner_radius(0.3)   // 30% of max_r is hollow
    .with_slices([("A", 40.0), ("B", 60.0), ("C", 30.0)]);
}

Builder reference

MethodDefaultDescription
with_slice(label, value)Add one sector to the default series
with_slices(iter)Add multiple (label, value) sectors
with_x_labels(iter)Set all sector labels at once
with_stack(name, values)Add a stacked series; sets mode=Stacked
with_group(name, values)Add a grouped series; sets mode=Grouped
with_bearing_data(iter, n)Bin raw bearings into n sectors
with_compass_labels()Replace labels with compass directions
with_encoding(enc)AreaRoseEncoding::Area or Radius
with_mode(mode)StackedRoseMode::Stacked or Grouped
with_start_angle(deg)0.0Degrees clockwise from north for sector 0
with_clockwise(bool)trueDirection sectors are laid out
with_inner_radius(f)0.0Donut hole fraction (0–0.95)
with_gap(deg)1.0Angular gap between sectors in degrees
with_grid(bool)trueConcentric grid rings
with_grid_lines(n)4Number of grid rings
with_spokes(bool)trueRadial spoke lines
with_show_labels(bool)trueSector labels around the perimeter
with_show_values(bool)falseValue labels at sector tips
with_legend(label)NoneEnable legend

See also: Polar Plot for continuous polar scatter/line data, Bar Chart for the Cartesian equivalent.


CLI

Render a Nightingale rose (coxcomb) chart from a tabular file.

Input format

Tab- or comma-separated file with at least two columns: a label column and a value column.

direction	count
N	25
NE	18
E	12
SE	8
S	10
SW	14
W	20
NW	22

For multi-series mode, add a group column and use --group-by:

direction	speed_class	count
N	low	15
N	high	8
NE	low	22
NE	high	12

Basic examples

# Single-series rose chart
kuva rose data.tsv --label direction --value count -o rose.svg

# Wind rose from provided example data (stacked low/high speed)
kuva rose examples/data/rose.tsv --label direction \
    --group-by direction --mode stacked -o wind_rose.svg

# With compass direction labels
kuva rose bearings.tsv --value bearing --compass -o compass_rose.svg

# Donut (inner hole)
kuva rose data.tsv --inner-radius 0.3 -o donut_rose.svg

All flags

Data selection

FlagDescription
--label <COL>Label column (name or 0-based index; default: 0)
--value <COL>Value column (name or 0-based index; default: 1)
--group-by <COL>Group/series column for multi-series mode

Chart style

FlagDefaultDescription
--mode <MODE>stackedMulti-series layout: stacked or grouped
--encoding <ENC>areaRadius encoding: area (accurate) or radius
--inner-radius <F>0Fraction 0–1; creates a donut hole
--gap <DEG>1Angular gap between sectors (degrees)
--start-angle <DEG>0Start angle clockwise from north
--no-clockwiseLay out sectors counterclockwise
--no-gridHide concentric grid rings
--grid-lines <N>4Number of concentric grid rings
--no-labelsHide sector labels around the perimeter
--show-valuesShow value labels at the tip of each sector
--compassReplace labels with compass directions (N, NE, E, …)
--legend <LABEL>Show legend (for multi-series plots)

Multi-series example

kuva rose examples/data/rose.tsv \
    --label direction \
    --value low_speed \
    --group-by direction \
    --legend "Wind speed" \
    --mode stacked \
    --title "Wind Rose" \
    -o wind_rose.svg

See also: Shared flags — output, appearance, axes.