Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: vellumplot
Title: A Grammar of Graphics on the 'vellum' Backend
Version: 0.8.0.9000
Version: 0.9.0
Authors@R:
person("David", "Schoch", , "david.schoch@cynkra.com", role = c("aut", "cre"))
Description: A declarative, pipe-first grammar of graphics that compiles an
Expand Down
4 changes: 3 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# vellumplot (development version)
# vellumplot 0.9.0

First tagged release. Everything below is included.

* **Merged choropleth regions.** `mark_sf(merge = TRUE)` dissolves adjacent
features that share a fill into one region, so the internal borders between
Expand Down
76 changes: 61 additions & 15 deletions README.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,50 @@ compiled into a vellum scene and rendered.

The compile is a real pipeline (spec → resolve encodings → train scales → measure
layout → compile guides → compile marks → vellum scene) and it runs without a
graphics device, because vellum measures text itself. Two consequences are the
reason to pick this stack:

* **Every mark keeps its identity through to the output.** A compiled plot *is* a
vellum scene, so each drawn element carries its data key and its resolved
device-pixel box (`vellum::scene_model()`). That is what
[vellumwidget](https://github.com/r-vellum/vellumwidget) reads to add tooltips,
brushing, and linked selection: the same marks you already declared, not
`*_interactive()` twins of them, and no second engine re-drawing your plot.
* **One spec, one solved layout, several destinations.** `render_plot()` writes
PNG, SVG, or PDF from the *same* compiled scene instead of re-solving layout per
device, and `as_widget()` hands that scene to the browser. The static figure and
the interactive one cannot drift, because they are one scene.
graphics device, because vellum measures text itself. If you already know
ggplot2 the grammar will feel familiar; the reason to reach for this stack is
what the retained vector scene underneath makes possible.

### What is a little different here

Most of these exist somewhere in R; having them in one grammar, from one spec, is
what is unusual. None of it is a reason to switch on its own — but together they
cover a few gaps.

* **One spec, one solved layout, several destinations — including a *tagged*
PDF.** `render_plot()` writes PNG, SVG, or PDF from the *same* compiled scene
rather than re-solving the layout per device, and the PDF carries a real
structure tree and alt text, so a screen reader can navigate it. Accessible
(tagged) PDF output is uncommon for R graphics.
* **Accessibility is checkable, not just aspirational.** Render through a
colour-vision-deficiency simulation (`render(cvd = "deutan")`) to see the figure
as a colour-blind reader would, and run `plot_lint()` to be told about tiny
text, low contrast, or a single-level legend *before* you publish it.
* **The interactive widget uses the marks you declared.** A compiled plot *is* a
vellum scene, so each element keeps its data key and its resolved device-pixel
box (`vellum::scene_model()`).
[vellumwidget](https://github.com/r-vellum/vellumwidget)'s `as_widget()` reads
those for tooltips, brushing, and linked selection — no `*_interactive()` twins,
and no second engine (Vega, plotly) re-drawing the plot in the browser, so the
static and interactive figures cannot drift.
* **Effects and regions stay vector where they can.** `glow()` / `shadow()` are
real Gaussian blur (and work on text); Venn/Euler diagrams and merged
choropleth regions are computed as boolean *geometry* rather than
alpha-composited overlaps, so they stay crisp in a PDF instead of being
flattened to pixels.
* **Texture, not only hue.** `pattern_*()` hatch fills stay legible in greyscale
print and under colour-vision deficiency, and render on every backend including
PDF.
* **Animation from the same grammar.** `transition_states()` + `animate()` compile
one keyframe per state (scales frozen, so the animation is non-reactive) and
`anim_save()` encodes a GIF, an APNG, or a resolution-independent **animated
SVG** that honours `prefers-reduced-motion`.
* **A hand-drawn mode that is exact.** `theme_sketch()` (or a `sketch =` argument)
gives a plot a wobbly, hand-drawn look generated *natively* in the engine, so it
is identical across PNG, SVG, and PDF rather than a post-hoc filter.
* **The spec is plain data.** `summary()` shows a plot's structure without drawing
it, and the spec round-trips, so a plot is something you can inspect, store, and
program against.

## Installation

Expand Down Expand Up @@ -173,8 +204,23 @@ render_plot(p, "cars.png")
`theme_classic()`, `theme_void()`, `theme_cyberpunk()`, `theme()` /
`set_theme()`) and multi-plot composition (`hconcat()`, `vconcat()`,
`concat()`, `wrap_plots()`, `inset()`, `repeat_()`).
* Layer effects (`glow()`, `outline()`, `shadow()`) and gradient fills
(`linear_gradient()`, `radial_gradient()`).
* Layer effects (`glow()`, `outline()`, `shadow()`, `motion()`, `echo()`) and
gradient fills (`linear_gradient()`, `radial_gradient()`).
* Pattern (hatch) fills: `pattern_stripe()`, `pattern_crosshatch()`,
`pattern_grid()`, `pattern_dot()`, `pattern_checker()`, mapped via
`scale_pattern()` — greyscale- and colour-vision-safe, on every backend.
* Boolean marks: `vvenn()` draws 2-/3-set Venn/Euler diagrams as solid geometry,
and `mark_sf(merge = TRUE)` dissolves adjacent same-value regions into one.
* SVG icon markers (`shape = ` a `d` path string or a `.svg` file) and repelled
labels (`mark_text_repel()`, over the engine's overlap solver).
* Accessibility: tagged PDF output, `plot_lint()` for legibility/contrast
problems, colour-vision-deficiency simulation at render time, and font pinning
for reproducible text.
* Animation: `transition_states()` / `transition_time()` / `transition_reveal()`,
`ease_aes()`, `animate()`, and `anim_save()` to GIF / APNG / animated SVG.
* Output: `render_plot()` (PNG/SVG/PDF), `pdf_pages()` (multi-page reports or
one page per facet), `render_all()` (parallel batch), and `plot_svg()` for an
inline SVG string (e.g. a sparkline inside a `gt` table).
* Hand-drawn rendering: `sketch()` gives any geometry mark a wobbly, hachure-
filled [Rough.js](https://roughjs.com) look (a `sketch =` argument on marks, an
`element_line()` / `element_rect()` `sketch =` slot, or the plot-wide
Expand Down
Loading
Loading