Skip to contents

Overview

plotit is a declarative plotting package built on ggplot2. It wraps ggplot2 with a verb-prefix API — every function starts with a verb that tells you what it does: mark_*() adds marks, scale_*() controls scales, label_*() sets labels.

All functions return a plotit object, so you can chain them with |>:

library(plotit)

iris |>
  plotit(encode(x = Sepal.Width, y = Sepal.Length, colour = Species)) |>
  mark_point(size = 2, alpha = 0.7) |>
  scale_color(range = "viridis") |>
  label_title("Iris Sepal Dimensions") |>
  label_axis(text = "Sepal Width", aes = "x") |>
  label_axis(text = "Sepal Length", aes = "y")
#> Scale for colour is already present.
#> Adding another scale for colour, which will replace the existing scale.

Pipeline Grammar

Every plotit pipeline follows the same grammar:

data |> plotit(encode(...)) |> mark_*() |> scale_*() |> layout_*() |> split_*() |> project_*() |> label_*() |> style() |> export()
Step Function Job
1. Init plotit() Create plot with data & aesthetics
2. Mark mark_*() Add geometric layers
3. Scale scale_*() Control data-to-visual mapping
4. Layout layout_*() Compute relational layouts (optional)
5. Facet split_*() Split into small multiples
6. Coordinate project_*() Choose a coordinate system
7. Label label_*() Set titles, axis labels, legends
8. Style style() Apply a ggplot2 theme
9. Export export() Render to file

Function Families

mark_*() — Geometric Layers

Thirty-nine mark functions add visual elements to your plot, spanning basic geometry (including step lines, ruggeds, spokes and curved links), distributions (histogram, density, box, violin, beeswarm, ECDF, QQ), statistical layers (smooth, hex, bin2d, density_2d, contour, correlation matrices, overlap-aware counts), composite sugar (error bars, significance brackets, lollipops, dumbbells, forest plots, labels) and the relational family (sankey, treemap, network, chord). Standard marks share a unified signature: mapping, data, position, rasterize, and ... forwarded to the underlying geom.

# Scatter plot
mtcars |>
  plotit(encode(x = wt, y = mpg, colour = factor(cyl))) |>
  mark_point(size = 3, alpha = 0.8)

# Bar chart <U+2014> auto-detects geom_col vs geom_bar
iris |>
  plotit(encode(x = Species, y = Sepal.Length)) |>
  mark_bar()

# Boxplot
iris |>
  plotit(encode(x = Species, y = Sepal.Length, fill = Species)) |>
  mark_boxplot()

# Histogram
iris |>
  plotit(encode(x = Sepal.Length, fill = Species)) |>
  mark_histogram(bins = 20, alpha = 0.5)

scale_*() — Data-to-Visual Mapping

Eight scale functions, all with identical parameters: name, trans, limits, range, breaks, labels, and ....

mtcars |>
  plotit(encode(x = wt, y = mpg, colour = hp, size = hp)) |>
  mark_point(alpha = 0.7) |>
  scale_color(range = "viridis") |>
  scale_x(trans = "log10") |>
  scale_size(range = c(0.5, 8))
#> Scale for colour is already present.
#> Adding another scale for colour, which will replace the existing scale.

The range parameter accepts colour scheme names ("viridis", "brewer", "hue") or custom vectors:

mtcars |>
  plotit(encode(x = wt, y = mpg, colour = factor(cyl))) |>
  mark_point(size = 3) |>
  scale_color(range = c("#E41A1C", "#377EB8", "#4DAF4A"))
#> Scale for colour is already present.
#> Adding another scale for colour, which will replace the existing scale.

label_*() — Text Labels

Five label functions use a three-parameter protocol:

Call Behaviour
label_*(text = "str") Set custom text
label_*(hide = TRUE) Remove element and its space
label_*(reset = TRUE) Restore variable name or remove text
iris |>
  plotit(encode(x = Sepal.Width, y = Sepal.Length, colour = Species)) |>
  mark_point() |>
  scale_color(range = "brewer") |>
  label_title("Iris Measurements") |>
  label_subtitle("Anderson's Iris Data") |>
  label_caption("Source: R.A. Fisher, 1936") |>
  label_axis("Sepal Width (cm)", aes = "x") |>
  label_axis("Sepal Length (cm)", aes = "y") |>
  label_legend("Species", aes = "colour")
#> Scale for colour is already present.
#> Adding another scale for colour, which will replace the existing scale.

project_*() — Coordinate Systems

# Flipped coordinates
iris |>
  plotit(encode(x = Species, y = Sepal.Length, fill = Species)) |>
  mark_boxplot() |>
  project_cartesian(flip = TRUE)

# Zoom via xlim/ylim
mtcars |>
  plotit(encode(x = wt, y = mpg)) |>
  mark_point() |>
  project_cartesian(xlim = c(2, 4), ylim = c(15, 25))

split_*() — Facets

iris |>
  plotit(encode(x = Sepal.Width, y = Sepal.Length)) |>
  mark_point() |>
  split_wrap(Species, ncol = 3)

style() — Themes

iris |>
  plotit(encode(x = Sepal.Width, y = Sepal.Length, colour = Species)) |>
  mark_point() |>
  scale_color(range = "viridis") |>
  style(base_theme = ggplot2::theme_minimal(base_size = 14))
#> Scale for colour is already present.
#> Adding another scale for colour, which will replace the existing scale.

Relational Data

Edge tables can be plotted directly through the graph data family. Layouts are deterministic data transforms — coordinates are baked into the tables, and any sub-table (~nodes, ~edges, ~ribbons) can be rendered by a mark:

flows <- data.frame(
  source = c("A", "A", "B", "B", "C"),
  target = c("B", "C", "C", "D", "D"),
  value  = c(10, 5, 8, 3, 6)
)

flows |>
  plotit(encode(
    source = source, target = target,
    value = value, fill = source
  )) |>
  mark_sankey()
#> Coordinate system already present.
#>  Adding new coordinate system, which will replace the existing one.

For full control, build the graph explicitly with as_graph(), apply a layout_*() transform, then reference its sub-tables from any mark. See ?as_graph and ?layout_force.

Export

p <- mtcars |>
  plotit(encode(x = wt, y = mpg, colour = factor(cyl))) |>
  mark_point(size = 2) |>
  label_title("Fuel Economy")

export(p, "mtcars_plot.png", width = 8, height = 5, dpi = 300)