# plotters-statistical
Statistical chart primitives for [`plotters`](https://crates.io/crates/plotters),
packaged as reusable **series types** that plug into `chart.draw_series(...)`
exactly like `plotters`' own built-in `Histogram` / `LineSeries` / `CandleStick`.
Each chart type is a composite element implementing `plotters`' `Drawable` +
`PointCollection` traits — the same pattern `plotters` uses internally for
`CandleStick` — so these feel native rather than bolted on.
> **plotters version:** pinned to **`=0.3.7`**. This crate mirrors `plotters`'
> element/series extension pattern, so it depends on the exact trait signatures
> of one release. Bumping `plotters` here is a deliberate, verified step, not an
> automatic caret upgrade.
## Chart types
**Series** (plug into `chart.draw_series(...)`):
| `BoxPlot` / `BoxPlotSeries` | `matplotlib.pyplot.boxplot`, `seaborn.boxplot` | Tukey 1.5×IQR whiskers + outliers; vertical or horizontal |
| `ViolinPlot` / `ViolinPlotSeries` | `seaborn.violinplot` | Gaussian KDE outline, optional embedded box |
| `RocCurve` | `sklearn.metrics.RocCurveDisplay` | AUC in legend, opt-in chance diagonal + AUC shading |
| `PrecisionRecallCurve` | `sklearn.metrics.PrecisionRecallDisplay` | AP in legend, prevalence baseline (not a diagonal) |
| `RegularizationPath` | scikit-learn coefficient-path plots | Color-cycled lines, log-x friendly, zero-crossing markers |
| `ResidualPlot` | `seaborn.residplot` | Zero line + binned moving-average trend |
| `Ecdf` | `statsmodels` ECDF, `seaborn.ecdfplot` | Step curve, optional DKW confidence band, complementary mode |
| `QqPlot` | `statsmodels.qqplot`, `scipy.stats.probplot` | Normal quantiles + robust reference line |
| `CalibrationCurve` | `sklearn.calibration.CalibrationDisplay` | Reliability diagram vs `y = x` |
| `GainChart` | cumulative-gain / lift charts | `Gain` or `Lift` mode with chance baseline |
| `Heatmap` | `seaborn.heatmap` (cells) | Any matrix; configurable colormap, normalization, annotations |
**Figures** (own their axes / multi-panel layout; render onto a `DrawingArea`):
| `CorrelationHeatmap` | `seaborn.heatmap` on `df.corr()` | Pearson/Spearman, colorbar, cell annotations, diverging map |
| `MissingnessHeatmap` | `missingno.matrix` | Present/absent map with per-column missing % |
| `PairPlot` | `seaborn.pairplot` | Scatterplot matrix, hist/ECDF diagonal, optional hue |
### Colormaps
`GradientColorMap` (viridis, magma, blues, reds, RdBu, coolwarm, grayscale, or
custom stops) plus a `Normalization` (linear or symmetric/diverging) drive every
value-to-color chart. Sources: matplotlib and ColorBrewer.
## Design: math is separate from rendering
All numeric work lives in the `stats` module and has **no `plotters` dependency**,
so it is unit-tested against hand-computed reference values (NumPy/scikit-learn
equivalents) independently of any rendering:
- `stats::quartiles` — type-7 quartiles, IQR, Tukey fences, outliers
- `stats::kde` — Gaussian KDE with a Silverman-rule default bandwidth
- `stats::roc` / `stats::precision_recall` — threshold sweeps, AUC / average precision
- `stats::correlation` — Pearson & Spearman, correlation matrices
- `stats::ecdf` — ECDF + DKW band; `stats::normal` — inverse-normal quantiles
- `stats::histogram` — Sturges / Freedman–Diaconis / Scott / fixed binning
- `stats::calibration` / `stats::gain` — reliability bins, cumulative gain & lift
The `series` module turns those already-computed values into `plotters` draw
calls.
## Quick start
```rust
use plotters::prelude::*;
use plotters_statistical::BoxPlotSeries;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let root = SVGBackend::new("boxes.svg", (640, 480)).into_drawing_area();
root.fill(&WHITE)?;
let mut chart = ChartBuilder::on(&root)
.set_label_area_size(LabelAreaPosition::Left, 40)
.set_label_area_size(LabelAreaPosition::Bottom, 40)
.build_cartesian_2d(0.5f64..2.5f64, 0f64..10f64)?;
chart.configure_mesh().draw()?;
let groups = vec![
(1.0, vec![1.0, 2.0, 2.5, 3.0, 9.0]),
(2.0, vec![2.0, 3.0, 3.5, 4.0, 4.2]),
];
chart.draw_series(BoxPlotSeries::from_samples(groups)?)?;
root.present()?;
Ok(())
}
```
## Examples
One runnable example per chart type, plus a combined dashboard:
```bash
# series
cargo run --example box_plot
cargo run --example violin_plot
cargo run --example roc_curve
cargo run --example precision_recall_curve
cargo run --example regularization_path
cargo run --example residual_plot
cargo run --example ecdf
cargo run --example qq_plot
cargo run --example calibration_curve
cargo run --example gain_chart
cargo run --example heatmap
# figures
cargo run --example correlation_heatmap
cargo run --example missingness_heatmap
cargo run --example pair_plot
# combined
cargo run --example dashboard # the six original panels — hero image
```
Each writes an `.svg` into the working directory.
## Styling
`style::palette_color(i)` cycles the **Okabe–Ito** color-blind-safe qualitative
palette (Okabe & Ito, 2008, <https://jfly.uni-koeln.de/color/>), shared by every
multi-series chart type. Every chart type's style struct is fully overridable —
see `examples/box_plot.rs` for a style override.
## Origin
Built to replace hand-drawn chart code across the **`rust-ml-guide`** project:
its EDA, model-evaluation, and regularization chapters each re-implemented these
charts by hand. The v0.1 core (`BoxPlot`, `ViolinPlot`, `RocCurve`,
`PrecisionRecallCurve`, `RegularizationPath`, `ResidualPlot`) covered the named
gaps; the v0.2 additions (ECDF, Q–Q, calibration, gain/lift, generic heatmap, and
the correlation / missingness / pair-plot figures) round the package out to a
general statistical-plotting toolkit for `plotters`.
## License
Licensed under the MIT license ([LICENSE](LICENSE)).