Repository navigation
v0.17.0 — statistical graphics for regression diagnostics
Breaking changes
-
Aestheticgained the variantsXintercept,Yintercept,Slopeand
Intercept(exhaustive matches onAestheticneed new arms). -
geom_hline/geom_vline(constant and mapped) now train the y / x
position scale on their intercepts, as in ggplot2: a reference line outside
the data range widens the axis instead of being drawn off-panel. -
geom_ablineis now drawn in data space (y = intercept + slope · xin the
scales' — possibly transformed — units) and clipped to the panel; it used to
interpret slope/intercept in normalized panel units. -
StepDirectiongained the variantMid. -
PositionDodgeis now a struct withwidth: Option<f64>andreverse: bool(a same-namedconstkeeps.position(PositionDodge)compiling);
PositionDodge2gained the public fieldswidthandreverse(construct
it withnew/defaultand thewith_*builders). Both now dodge the
groups present at each x (ggplot2's defaultpreserve = "total") instead
of reserving a slot for every group, and key groups on group + fill +
colour together. -
Reference-line geoms no longer inherit the plot-level mapping (ggplot2's
inherit.aes = FALSE): a plot-levelcolorno longer leaks into
geom_hline. NewGeom::inherit_aes()(defaulttrue) controls this. -
StatQQ/StatQQLineuse the exact normal quantile in every build (they
used the Abramowitz–Stegun approximation, |error| ≈ 4.5e-4, without
regression), andStatQQLineneeds 2 sample values instead of 4.
Fixed
geom_errorbar,geom_linerangeandgeom_pointrangecollapsed to a
point undercoord_flip(only the x pixel of one end was used); every end
is now transformed.geom_errorbar/geom_linerangehonour a mapped
color; an error bar is one polyline (cap–bar–cap) per row.
Fixed — dodged bars
geom_col/geom_barwithposition_dodgeon a discrete x now shift
and narrow each bar by the stored dodge offset and the number of groups at
that x (newposition::DODGE_N_COL), so grouped bars sit side by side
instead of on top of each other.
Added — statistical geoms (reference lines, QQ, Cook's contours, KM/ECDF, dodge)
- Data-mapped reference lines (U1).
Aes::{xintercept, yintercept, slope, intercept}plusGGPlot::{geom_hline_aes, geom_vline_aes, geom_abline_aes}
(and*_aes_with(geom, aes)for custom default styling) draw one line per
row of the layer data, per facet panel, coloured / linetyped by any mapped
color/linetype/alpha. Constant lines are now one-row layers, so
they appear in every facet panel. Lines carrydata-series/data-value
(the intercept) and a tooltip on the native SVG path. Non-finite intercepts
are dropped with a warning; a numericxintercepton a discrete axis sits
between categories (1-based, as in ggplot2) without becoming a level, and a
reference line added before a discrete layer no longer forces a continuous
scale.GeomHline::mapped(),GeomVline::mapped(),GeomAbline::mapped(). - QQ plots against several distributions, with confidence bands (U2).
QQDistribution::{Normal { mean, sd }, StudentT { df }, Exponential { rate }, HalfNormal { sd }}(ggplot2'sdistribution+dparams; constructors
normal(),t(df),exponential(),half_normal()),StatQQDist,
StatQQLineDist(line through theline_pquartiles over the range of the
theoretical quantiles; also emitsslope/intercept) andStatQQBand
(qqplotr'sstat_qq_band:QQBandType::Pointwisenormal-theory envelope or
QQBandType::KsDKW band,level), drawn by the newGeomQQBand. Builder
methodsGGPlot::{stat_qq(dist), stat_qq_line(dist), stat_qq_band(band), geom_qq_band(), geom_qq_band_with(geom, band)}. Validated against
ggplot2 4.0 and qqplotr 0.0.7 to 1e-9 (tests/qq_dist_r.rs,
validation/generate_diagnostics.R). QQ points now carrydata-x/
data-value/ tooltips;geom_qq_linedraws one line per group. - Cook's-distance contours (U4).
GGPlot::stat_cooks_contour(p, levels)
/geom_cooks_contour_with(GeomCooksContour)draw R'splot.lm(which = 5)
contours±√(level · p · (1 − h) / h)on a residuals-vs-leverage panel:
dashed, clipped to the panel (geometrically — the native SVG has no clip
paths), labelled with the level, in every facet panel, optionally limited
towith_h_range(lo, hi); they train no scale. Helpers
geom::cooks::{cooks_contour_y, cooks_distance}. Checked against R
(tests/cooks_contour_r.rs). - Kaplan–Meier / ECDF / horizontal-CI building blocks (U7).
GeomStepribbon(geom_stepribbon(),geom_stepribbon_with(geom); step
edges withStepDirection::{Hv, Vh, Mid}, ±Inf x to the panel edge) for KM
confidence bands; censor marksgeom_censor_marks(censor_col)/
GeomCensorMarks+StatCensored(+glyphs at rows whose column is
> 0/true);stat_ecdf()andstat_ecdf_band(level)/StatEcdfBand
(simultaneous DKW bandF̂ ± √(ln(2/(1−level))/(2n)), validated against R);
geom_errorbarh()/GeomErrorbarh(xmin/xmax/y, one hoverable
polyline per interval withdata-value="xmin xmax"). geom_stepdraws one step line per group (colour / group / linetype) with
mapped linetype anddata-series, and gainsStepDirection::Mid
(ggplot2's"mid").stat_ecdfignores non-finite input values.- Multi-model coefficient forests (U8).
position_dodge(width)/
PositionDodge::new(width).with_reverse(bool)and
PositionDodge2::new(padding).with_width(w).with_reverse(bool)now work on
a discrete x axis (terms): the per-row offset is stored in
.x_dodge_offset(position::DODGE_OFFSET_COL) and applied by
geom_point,geom_pointrange,geom_errorbar,geom_linerange,
geom_ribbonand censor marks, so several models' intervals per term sit
side by side — also undercoord_flip. Interval geoms mapcolorper row
and carrydata-x(term) /data-series(model) /data-value(estimate,
else"ymin ymax") plus a tooltip. examples/diagnostics.rs(runs with--no-default-features): a
regression-diagnostic gallery on the native SVG path — QQ with pointwise +
KS bands, QQ against t(5), residuals vs leverage with Cook's contours,
Kaplan–Meier (survival::lung) with CI step ribbon and censor marks, ECDF
with DKW band, dodged three-model coefficient forest, per-facet mapped ACF
bounds — written toassets/gallery/diagnostics/*.svg.ggplot_rs::stat::distribution: dependency-freeqnorm(AS 241),dnorm,
pt/qt/dt(anyp, anydf) andln_gamma, available in every
feature configuration (the existingstat::dist::qtstill returns the
normal 0.975 quantile withoutregression).geom_ribbondraws one band per group (group / colour / fill) with a
mappedfill, instead of a single polygon through every row.- The native SVG backend draws every
PointShape(square, triangle, diamond,
+,×) instead of falling back to circles;+/×are one stroked
<path>per point, so they keep theirdata-*hover attributes.
Added — composition, label repel, GLM smooths, table brackets
geom_smooth(method = "glm")families:SmoothFamily::Binomial(link)
(SmoothBinomialLink::{Logit, Probit, Cloglog}, shorthand
SmoothFamily::binomial()),SmoothFamily::Gamma(link)
(SmoothGammaLink::{Inverse, Log}, shorthandSmoothFamily::gamma()) and
SmoothFamily::NegativeBinomial(log link, θ by ML asMASS::glm.nb), plus
theGeomSmooth::glm(family)builder. Bands follow ggplot2's
predictdf.glm:linkinv(η ± qnorm(0.975)·se(η)), so they stay inside the
response range. Validated against Rglm()/predict()in
tests/glm_smooth_r.rs.GGPlot::geom_bracket_table(table, BracketTable)— significance brackets
from a precomputed test table (ggpubrstat_pvalue_manual), no test is
recomputed. Reads the anofoxtestcontract (group1,group2,p_adj
falling back top_valueper row,test_id) plus optionaly_position/
labelcolumns; label templates ("p = {p_adj}",{p},{p.signif}/
{stars}with configurable cutpoints, any{column}),hide_ns, automatic
stacking above the data for rows withouty_position. Rows with missing or
unknown groups are dropped with a build warning. Pure grammar: available
without theggpubrfeature.- Brackets (
geom_bracket*) now carry host hover metadata: a<title>
tooltip,data-x="g1 vs g2",data-series(test_idfor table brackets)
anddata-value(the p-value). geom_text_repel/geom_label_repel(GeomTextRepel,GeomLabelRepel,
RepelParams,RepelDirection; ggrepel): deterministic, seeded label
layout that avoids other labels and the labelled points and stays inside the
panel;nudge,box_padding,point_padding,force/force_pull,
direction,max_iter+max_timebounds,max_overlaps(dropped labels
are reported as a warning), connecting segments beyond
min_segment_length. Sweep-pruned collision checks; abovemax_labels
(default 500) the force layout is skipped with a warning.DrawBackend::warn(default no-op): geoms can report draw-time warnings;
the native SVG backend collects them (SvgBackend::take_warnings) and
render_svg_native_with_warningsreturns them after the build warnings.PlotGrid(ggplot_rs::compose, in the prelude): patchwork-style
composition on the native SVG path —PlotGrid::new().add(p).ncol(2), or
a | b(side by side) anda / b(stacked; chains flatten, mixed operators
nest),add_spacer,nrow/byrow, relativewidths/heights,spacing,
sharedtitle/subtitle/caption, panel tags (TagLevels::{Lower, Upper, Numeric, LowerRoman, UpperRoman, Custom}+tag_affixes), and
collect_legends(true)(each distinct legend drawn once to the right or
bottom, identical legends de-duplicated). Renders one SVG
(render_svg_native[_with_size|_with_warnings|_at]); every sub-plot is a
nested<svg>that keeps its host attributes and adds
data-panel="<tag or index>"; the root carriesdata-grid="<rows> <cols>".
Sub-plot warnings are returned prefixedpanel <tag>:.examples/regression_diagnostics.rs: a plotters-free 2×2 diagnostics grid
with repelled labels, table-driven brackets and a logistic GLM smooth.
Changed
SmoothFamily::Poissonbands are now formed on the link scale and mapped
throughexp(as R/ggplot2), instead of a response-scale interval.ggpubr::ggarrangenow delegates toPlotGrid: cells are nested SVG
fragments without a per-cellxmlns, positioned asx="300.00", and carry
data-panel="<index>".- The
regressionfeature now requiresanofox-regression^0.5.17 — the
version the anofox-statistics DuckDB extension uses — and GLM smooths use
that extension's IRLS settings (tolerance 1e-8, ≤ 100 iterations), so SQL
fits and plotted smooths agree.