vellumplot 0.6.0
-
Sankey styling options.
vsankey()/mark_sankey()gainshow_values
(append each node's value to its label),flow_color("source","target",
or"gradient"— a source-to-target colour fade per ribbon), and
node_width/node_gapto tune the node rectangles. -
Sankey crossing minimisation.
vsankey()now orders the nodes within each
column with the Sugiyama barycenter heuristic to minimise ribbon crossings
(previously first-appearance order, which left many avoidable crossings). The
reordering is deterministic and pure R. A related fix stacks each node's ribbon
slices to meet the node in the same vertical order as the nodes they connect to,
removing the remaining crossings within a fan of ribbons. -
Sunburst rendering fixes.
vsunburst()now colours wedges by their
top-level branch (each branch a distinct hue, lightened with depth) instead of
a single colour per ring — sibling branches were previously indistinguishable.
It also starts the first wedge at twelve o'clock and winds clockwise, matching
the package's pies/roses (coord_polar) rather than starting at three o'clock
counter-clockwise. -
Sunburst / radial hierarchies:
vsunburst(). A new plot type for
part-of-whole hierarchies, from a parent list —id,parent(NAat the
root), andvalue(leaf values; internal nodes sum their children). Depth maps
to a ring and each node's angular span is its share of its parent's, drawn as
one batchedsector_grobin an aspect-locked, axis-free square panel (mirroring
vsankey()/vgraph()).inner_radiusopens a central hole (a donut/ring
sunburst); nodes are coloured by depth.mark_sunburst()is the exported layer.
Seevignette("flows-and-hierarchies"). -
Sankey / flow diagrams:
vsankey(). A new plot type for layered flows,
built from a flow list — one row per flow withfrom,to, andvalue(the
ribbon width). Nodes are the union offrom/to; a node that is both a source
and a target makes the diagram multi-stage.vsankey(data, from, to, value)
returns a ready, axis-free plot (mirroringvgraph());mark_sankey()is the
exported layer it adds. The layout is computed R-side (longest-path layering,
value-proportional node heights and ribbon widths, filled Bézier ribbons) and is
deterministic. Flows must form a DAG; nodes are coloured from the qualitative
palette. Seevignette("flows-and-hierarchies"). -
Uncertainty marks:
mark_halfeye()andmark_interval(). ggdist-style
slab + interval marks for sample/posterior input (manyyrows per categorical
x).mark_halfeye()draws a one-sided density slab with a point-interval at
its base — the median (orpoint = "mean"), a thick inner and thin outer
equal-tailed quantile interval at the.widthprobabilities (default
c(0.66, 0.95));mark_interval()is the point-interval alone. A natural fit
for visualising posterior draws (e.g. from \pkg{brms}). -
coord_radial()andscale_size_area().coord_radial()is a fuller
polar system (ggplot2 3.5's name): besidestheta/start/directionit takes
endto sweep only a partial arc (e.g.start = -pi/2, end = pi/2for a
semicircular gauge) andinner_radiusfor a donut hole; with the defaults
it matchescoord_polar().scale_size_area()maps a value to the marker's
area (value0→ size0), the perceptually honest default for bubble
charts, withmax_sizethe size of the largest value. -
Sankey labels stay on-panel.
vsankey()now reserves horizontal margin for
node labels, so the source column's labels (drawn to their left) and the
terminal column's (drawn to their right) no longer clip at the panel edge. -
Robustness of the new marks.
vsunburst()/mark_sunburst()now reject a
missing or negative leafvaluewith a clear message (instead of a cryptic
downstream error), andmark_sunburst()validatesinner_radiuslike
vsunburst()andcoord_radial()do.mark_halfeye()/mark_interval()skip a
category with fewer than two finite observations (with a warning) rather than
drawing an empty interval, and reject awidth =argument (a likely typo for
.width) that was previously ignored silently. -
Consistent argument names for the hole radius / ridge height. The
central-hole fraction is now spelledinner_radiuseverywhere it appears:
coord_radial(),vsunburst()/mark_sunburst(), andmark_donut()(was
hole).mark_ridgeline()'s overlap control is nowheight(wasscale,
which collided withmark_halfeye(scale=), a different quantity). -
Consistent
sketch/blendpassthrough.mark_ecdf(),mark_contour(),
mark_contour_filled(),mark_dotplot(),mark_qq(), andmark_qq_line()now
accept a per-layersketch =(their emitters already honoured it), and
mark_pie()/mark_donut()acceptblend =, matching the rest of the mark
surface. -
Parameterised position adjustments. New
position_nudge(),
position_jitter(),position_dodge(),position_dodge2(), and
position_jitterdodge()give a mark'spositiontunable parameters (a bare
string like"dodge"still works with the defaults). Adds three adjustments:
nudge(shift every element by a constant in data units),dodge2(dodge by
the groups actually present at each x, filling the band with apaddinggap —
so ragged groupings stay centred), andjitterdodge(jitter points within
their dodged slot).position_jitter(width=, height=, seed=)and
position_dodge(width=)expose the previously-fixed jitter/dodge extents. A
plot using the old string positions is unchanged. -
Label repulsion:
mark_text(repel = TRUE)/mark_label(repel = TRUE).
Overlapping text labels are moved apart with a force-directed layout
(ggrepel-style), each keeping a thin leader line back to its point. Because the
plot size is fixed on the spec, the repulsion is resolved exactly against the
true rendered panel — a two-pass compile that reads the panel's device geometry
fromvellum::scene_model(), relaxes the label boxes in pixel space, and maps
the result back — so it needs no approximation and novellumchange, and is
deterministic underseed. Tunable viabox_padding,point_padding,
min_segment_length, andseed. Limited to a single cartesian panel for now
(facets / composition / polar error clearly). -
mark_line(window = ): rolling / cumulative / offset transforms. A line can
now transform itsyper group (over rows ordered byx) before drawing —
movingmean/sum/median/min/maxover a window ofk, running
cumsum/cummean/cummax/cummin,lag/leadshifts, orrank. Pass an op
name (window = "mean") or a list (window = list(op = "mean", k = 7, align = "right", partial = TRUE));alignis trailing/leading/centred andpartial
fills the edges from the shorter window so the line stays continuous. A plot
withoutwindowis unchanged. -
Diverging colour scales:
scale_color_gradient2()/scale_fill_gradient2().
A three-point ramp (low--mid--high) centred onmidpoint(default0),
rescaled about the midpoint (scales::rescale_mid) so the neutral colour sits
on the chosen value and each side spans as far as the data reaches — the correct
scale for signed / anomaly data. A diverging continuous colorbar also reports
midpoint+divergingin itscolorbardescriptor, so an interactive host can
centre a value-range filter on the neutral value. -
symlogposition transform.scale_x_continuous(trans = "symlog")(and
y) adds a symmetric-log axis: linear through zero, logarithmic in the tails
(sign(x) · log10(1 + |x|)), so signed data spanning several orders of magnitude
— including zero and negatives, whichlog10cannot show — reads on one axis.
Breaks sit at zero and signed powers of ten. The transform name flows into the
panelscalesdescriptor like the other transforms. -
New group-region marks:
mark_ellipse()andmark_hull(). Both enclose a
set of(x, y)points in a single region drawn over a scatter — one region per
group when acolor/fillis mapped.mark_ellipse()draws a covariance
ellipse (type = "t"robust default via \pkg{MASS}, or"norm"/"euclid"),
following ggplot2'sstat_ellipse();mark_hull()draws the convex hull. Both
are unfilled boundaries by default (map/set afillto shade them) and need at
least 3 points per group. The region's boundary trains the position scales, so
an ellipse that bulges past the data is not clipped. -
mark_smooth()gains real smoothing methods. Beyond"lm", the smooth
mark now fits"loess"(local regression,span =),"glm"(with afamily
viamethod.args, e.g. logistic — the fit and its ribbon are back-transformed
from the link scale),"gam"(a penalised smooth, defaulty ~ s(x); needs
\pkg{mgcv}), and"rq"(quantile regression at a singlemethod.args$tau;
needs \pkg{quantreg}, line only, no ribbon). The defaultmethod = "auto"
picksloessfor small groups (< 1000 points) andgamfor large ones, as in
ggplot2. Newformula,span, andmethod.argsarguments;glm/gambands
use a normal interval,lm/loessa t-interval. Previouslymark_smooth()
errored on any method other than"lm". \pkg{mgcv} and \pkg{quantreg} are
Suggests — a gated method errors clearly if its package is absent. -
Data panels are emitted as pannable, gridlines tagged. Cartesian data panels
(includingcoord_flipand a linearcoord_trans) now push apannablevellum
viewport, and gridlines carryrole = "grid". This is inert for static rendering
but lets an interactive host (vellumwidget) pan/zoom a panel's marks while its
clip + axes stay fixed and hide/redraw gridlines — the groundwork for axis-aware
zoom. Polar / nonlinear-coord_transpanels stay non-pannable. Requires the
current developmentvellum. -
Continuous colorbar filter metadata. A continuous
colorscale now attaches
each mark's colour value asfilter_valuein its elementmeta, and acolorbar
descriptor (value domain + orientation) to the gradient-bar grob. Together (via
vellum::scene_model()) these let a host such asvellumwidgetoverlay an
interactive value-range filter on the colorbar. Discrete/binned colour scales are
unaffected. No change to rendered output. -
Panels now carry a
scalesdescriptor for interactive hosts. Each cartesian
data panel's viewport gains ameta$scalesrecord — per axis:type
(continuous / log10 / discrete / binned / date / datetime),transform, the
data and native domains, tick breaks + labels, andtime_unitfor date/datetime
axes. It surfaces viavellum::scene_model()$panels$metaand lets a host (e.g.
vellumwidget) map device pixels back to data values — so a brush or a reported
view can be expressed in data coordinates, not just pixels. Requires
vellum(>= 0.4.0.9000). Internal: trained position scales now also record their
transformname and, for date/time axes, atime_unit(previously the
date/datetime nature was lost after training). No change to rendered output.