vellumplot 0.4.0
New features
-
Categorical datashading in one call.
mark_datashade()now accepts a mapped
discretecolor/fillaesthetic and shades categorically (datashader's
count_cat): each category is aggregated separately and every cell is coloured by
the count-weighted average of the category hues it holds, opacity by density — so
you see which category dominates where, and where they mix, with a colour
legend. Category hues come from the usual discrete colour scale
(scale_color_*()apply). This replaces the old idiom of stacking one datashade
layer per category withblend = "screen". Newspan/cliparguments clamp the
density range (absolute limits or percentiles) so a few extreme cells don't
flatten the rest. Requires the accompanyingvellumdev version. -
mark_image()draws images at data points. A new mark places a bitmap
image (e.g. a country flag or company logo) at each(x, y), replacing the
usual point marker.srcis a column of local file paths or one constant
path, andsizesets the height in millimetres (the width follows each
image's native aspect ratio). Requires the suggestedmagickpackage (#33). -
coord_trans()— nonlinear display transforms. Warps the display of one
or both position axes after the scale has trained, so gridlines bunch up and
straight lines curve while the axis keeps its original data-value labels (unlike
scale_*(trans=), which rescales the data and relabels in transformed space).
Each ofx/ytakes a transform name ("log10","sqrt","identity") or a
scales::transform_*()object, e.g.coord_trans(y = "log10"). Supports the
common marks (points, lines, areas/ribbons, bars, tiles, smooths, text, …);
segment/interval, boxplot, edges, and raster/datashade marks are not warped yet
and raise a clear error undercoord_trans(). -
mark_violin()andmark_ridgeline()no longer clip at the edges. The
position scales are now trained to include each mark's drawn footprint -- the
full kernel-density support for a violin, and the ridge height (scale) above
the top category for a ridgeline -- so the tallest ridge and the density tails
are no longer cropped by the panel. Explicit axis limits still take precedence. -
Marginal distributions with
add_marginal(). A new plot modifier draws a
density or histogram of the panel'sxvariable along the top edge and of its
yvariable along the right edge, each sharing the scatter's axis so they line
up (the vellumplot analogue ofggExtra::ggMarginal()). Pick the distribution
withtype = "density"/"histogram", the edges withsides("t","r",
"tr"), and the extent withsize;group = TRUEsplits each marginal by a
discretecolor/fillmapping in the matching palette. It readsx/yfrom
the first plain (identity-stat) layer and reuses the existing density/bin
stats, so no axes or legends are duplicated. This version supports a single
panel only (an error is raised with facets, a non-Cartesian coordinate system,
or a locked aspect ratio). -
Positional constants now render. A bare literal on a coordinate channel
(e.g.mark_segment(x = i, y = 0, xend = i, yend = value)for a lollipop
baseline) is now treated as a constant-valued coordinate rather than a style
param, so it populates the layer's values and trains the position scale.
Previouslyy = 0was dropped from scale training, collapsing each segment's
start onto its end (zero-length, invisible), and a segment-only plot errored
with "Every layer needs an x and y encoding". Segment/edge endpoints (xend/
yend) now also extend the axis domain, so a segment-only plot derives its
range from both ends. Affects the positional channelsx,y,xend,
yend,xmin,xmax,ymin,ymax. -
Faster
mark_sf()on large maps. Non-interactive sf layers now batch all
features that share a resolved fill/colour into a single grob per style group
(polygons into oneevenoddpath_grob, lines into one NA-separated
lines_grob), instead of one grob per feature, and the layer's bounding box is
computed in a single linear pass rather than by growing coordinate vectors. On
a 40k-polygon grid this cut scene compilation from ~24s to ~0.8s. Interactive
layers (those declaringdata_id/tooltip/hover_group) are unchanged —
they still emit one keyed grob per feature so every feature stays addressable.
Note: because a batched polygon group is filled with oneevenoddrule, two
same-fill features that overlap would cancel in the overlap region (the same
property a self-overlappingMULTIPOLYGONalready has); disjoint features —
every real choropleth and coverage map — are unaffected.
Bug fixes
-
linetypenow works on stroked marks.mark_segment(),mark_linerange(),
mark_rule(),mark_errorbar(),mark_rug(),mark_edges(), and
mark_contour()(andannotate("segment", ...)) previously ignored
linetypeand always drew solid lines; they now honour it, consistent with
mark_line()(#30). -
annotate("rect", ...)honours infinite bounds. A bound of-Inf/Inf
(e.g.xmin = -Inf, xmax = Inffor a full-width band) now extends the
rectangle to the panel edge, matching ggplot2, instead of silently rendering
nothing (#29). -
Continuous labels no longer group thousands by default. A default
continuous axis or legend now renders 4-digit-plus values without a grouping
separator, so years and IDs read2010instead of2 010(#27). Pass
explicitlabelsto restore grouping. -
More inputs fail fast. A
designlayout area must be a solid rectangle (and
area()requirest <= b,l <= r); a per-row interactivity value
(tooltip/data_id/…) must be length 1 or the data's row count; and
add_marginal()requires a cleanly numeric column. Each now errors clearly
instead of silently mis-rendering. -
Clearer alt text for grid facets. A
facet_grid()plot's automatic alt text
now distinguishes the row and column variables (e.g. "Faceted by rows cyl,
columns am") instead of running them together. -
Compositions can be themed.
theme()now accepts a composition (from
[concat()] / [hconcat()] / [vconcat()]) and styles its figure-level chrome —
the title/subtitle/caption bands, the collected legend, panel spacing, and
tags. Previously a composition's figure chrome always used the default theme.
Each sub-plot still carries its own theme. -
Gradient fills fail clearly on marks that don't support them. A
fill = linear_gradient(...)is painted bymark_area(),mark_ribbon(), and
mark_bar(); on any other mark it now raises a clear error instead of leaking
an undefined paint into the renderer. -
Inputs are validated up front.
theme()now checkspanel.spacing,
plot.margin,aspect.ratio, andaxis.ticks.length(and rejectsNA/Inf
in any numeric setting);vplot()checkswidth/heightthe way it already
checkeddpi; a discreteshape/linetypescale with more categories than
its palette errors instead of silently reusing a glyph; and a binned colour
scale given fewer than two breaks errors instead of crashing in
colorRampPalette(). Valid input is unaffected. -
Legends read consistently. A horizontal (top/bottom) continuous colour
legend now draws theNAkey that the vertical one always did.
guide_legend(reverse = TRUE)now actually flips a continuous colourbar
(previously a silent no-op) and no longer desyncs a binned colour scale's
boundaries from its swatches. A merged colour+shape legend's swatches are now
tagged for interactive highlight/select. Minor gridlines past the outermost
breaks use the local break spacing at each end, so they sit correctly when
breaks are unevenly spaced. -
Numeric facets order numerically. Faceting on a numeric variable now orders
panels1, 2, 10rather than the lexicographic1, 10, 2; multi-variable
facets order by each variable's own type. -
Log/reversed axes. Bars and areas on a
scale_*(trans = "log10")(or
"sqrt") axis draw from the axis floor instead of a degenerate shape (the zero
baseline that maps to-Infis clamped into the trained range). A descending
limit such asylim(hi, lo)on a bar/area is no longer silently un-reversed by
the zero baseline. -
Grouped histogram density.
after_stat(density)/after_stat(prop)on a
grouped histogram or bar now normalizes per group (each group integrates/sums
to 1), matching ggplot2, rather than dividing by the grand total. -
Clearer errors instead of silent surprises or crashes.
coord_trans()
rejects a"reverse"transform (a no-op there — use
scale_*(trans = "reverse")) and rejects bar/area marks on a nonlinearly
transformed axis (a zero baseline has no place on a log display). Histogram /
2-D bin / hexbin stats abort cleanly on all-NAinput instead of a cryptic
seq()error.mark_raster()and z-surface contours reject a grid with a
duplicated cell (previously a silent transparent/NAhole). Composition
auto-tags continue past 26 sub-plots (Z,AA,AB, …) instead ofNA. -
mark_area()now stacks.mark_area(position = ...)was silently ignored;
it gains apositionargument ("stack"default, plus"fill"and
"identity"), so areas sharing anxwith a mappedfill/colorcombine into
a band instead of overlapping from the zero baseline. An area with no fill
mapping is unchanged. -
Mapped aesthetics that were silently dropped now take effect. A mapped
fillonmark_label()colours the label background (previously it always fell
back to white); a mapped or constantalphais honoured per category/tick by
mark_violin(),mark_ridgeline(),mark_contour(),mark_contour_filled()
andmark_rug()(previously collapsed to one value or ignored), andmark_rug()
also honours a mappedcolor. -
British spelling works everywhere.
hover_colour/selected_colourare now
recognised as interactivity arguments (previously only the American spelling
was), andmark_bin2d()/mark_hex()no longer add a default count fill when a
Britishcolour =is supplied. -
vgraph()warns on a layout-column clash. A vertex/edge attribute named
x/y(orxend/yend) is overwritten by the layout coordinates; that used
to happen silently and now emits a warning naming the attribute.