Skip to content

vellumplot 0.4.0

Choose a tag to compare

@schochastics schochastics released this 15 Jul 06:55
· 208 commits to main since this release

New features

  • Categorical datashading in one call. mark_datashade() now accepts a mapped
    discrete color/fill aesthetic 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 with blend = "screen". New span/clip arguments clamp the
    density range (absolute limits or percentiles) so a few extreme cells don't
    flatten the rest. Requires the accompanying vellum dev 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. src is a column of local file paths or one constant
    path, and size sets the height in millimetres (the width follows each
    image's native aspect ratio). Requires the suggested magick package (#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 of x/y takes 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 under coord_trans().

  • mark_violin() and mark_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's x variable along the top edge and of its
    y variable along the right edge, each sharing the scatter's axis so they line
    up (the vellumplot analogue of ggExtra::ggMarginal()). Pick the distribution
    with type = "density" / "histogram", the edges with sides ("t", "r",
    "tr"), and the extent with size; group = TRUE splits each marginal by a
    discrete color/fill mapping in the matching palette. It reads x/y from
    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.
    Previously y = 0 was 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 channels x, 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 one evenodd path_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 declaring data_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 one evenodd rule, two
    same-fill features that overlap would cancel in the overlap region (the same
    property a self-overlapping MULTIPOLYGON already has); disjoint features —
    every real choropleth and coverage map — are unaffected.

Bug fixes

  • linetype now works on stroked marks. mark_segment(), mark_linerange(),
    mark_rule(), mark_errorbar(), mark_rug(), mark_edges(), and
    mark_contour() (and annotate("segment", ...)) previously ignored
    linetype and 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 = Inf for 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 read 2010 instead of 2 010 (#27). Pass
    explicit labels to restore grouping.

  • More inputs fail fast. A design layout area must be a solid rectangle (and
    area() requires t <= 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 by mark_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 checks panel.spacing,
    plot.margin, aspect.ratio, and axis.ticks.length (and rejects NA/Inf
    in any numeric setting); vplot() checks width/height the way it already
    checked dpi; a discrete shape/linetype scale 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 the NA key 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
    panels 1, 2, 10 rather than the lexicographic 1, 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 -Inf is clamped into the trained range). A descending
    limit such as ylim(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-NA input instead of a cryptic
    seq() error. mark_raster() and z-surface contours reject a grid with a
    duplicated cell (previously a silent transparent/NA hole). Composition
    auto-tags continue past 26 sub-plots (Z, AA, AB, …) instead of NA.

  • mark_area() now stacks. mark_area(position = ...) was silently ignored;
    it gains a position argument ("stack" default, plus "fill" and
    "identity"), so areas sharing an x with a mapped fill/color combine 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
    fill on mark_label() colours the label background (previously it always fell
    back to white); a mapped or constant alpha is honoured per category/tick by
    mark_violin(), mark_ridgeline(), mark_contour(), mark_contour_filled()
    and mark_rug() (previously collapsed to one value or ignored), and mark_rug()
    also honours a mapped color.

  • British spelling works everywhere. hover_colour/selected_colour are now
    recognised as interactivity arguments (previously only the American spelling
    was), and mark_bin2d()/mark_hex() no longer add a default count fill when a
    British colour = is supplied.

  • vgraph() warns on a layout-column clash. A vertex/edge attribute named
    x/y (or xend/yend) is overwritten by the layout coordinates; that used
    to happen silently and now emits a warning naming the attribute.