Skip to contents

This gallery is organised by intent, not by function name. Find the chart you need, copy the pipeline, adapt the aesthetics. Function-level parameters live in Reference; grammar depth lives in API.

Comparing groups

Counts by category

Map only x and mark_bar() counts rows per category.

ggplot2::mpg |>
  plotit(encode(x = class)) |>
  mark_bar()

Value bars and stacks

Map y for direct values. A second categorical to fill stacks composition.

ggplot2::mpg |>
  plotit(encode(x = class, fill = drv)) |>
  mark_bar(position = "stack")

Filled (100%) bars

ggplot2::mpg |>
  plotit(encode(x = class, fill = drv)) |>
  mark_bar(position = "fill")

Boxplot and beeswarm

ToothGrowth |>
  plotit(encode(x = supp, y = len, fill = supp)) |>
  mark_boxplot()

iris |>
  plotit(encode(x = Species, y = Sepal.Length)) |>
  mark_beeswarm()

Violin

ToothGrowth |>
  plotit(encode(x = supp, y = len, fill = supp)) |>
  mark_violin()

Lollipop and dumbbell

mtcars |>
  plotit(encode(x = reorder(rownames(mtcars), mpg), y = mpg)) |>
  mark_lollipop() |>
  project_cartesian(flip = TRUE)

mpg_mean <- aggregate(cbind(cty, hwy) ~ class, data = ggplot2::mpg, FUN = mean)
mpg_mean |>
  plotit(encode(x = class, y = cty, yend = hwy)) |>
  mark_dumbbell()

Forest plot

est <- data.frame(
  study = paste0("s", 1:5),
  est = c(0.9, 1.1, 0.8, 1.2, 1.0),
  lo = c(0.4, 0.7, 0.5, 0.9, 0.7),
  hi = c(1.6, 1.8, 1.3, 1.9, 1.4)
)
est |>
  plotit(encode(y = study, x = est, xmin = lo, xmax = hi)) |>
  mark_forest(ref = 1)

Error bars and significance

ToothGrowth |>
  plotit(encode(x = supp, y = len, colour = dose)) |>
  mark_errorbar(stat = "mean_sd", width = 0.4)

set.seed(7)
d <- data.frame(
  g = rep(c("ctrl", "A", "B"), each = 20),
  v = rnorm(60, rep(c(0, 0.8, 1.6), each = 20))
)
d |>
  plotit(encode(x = g, y = v)) |>
  mark_boxplot() |>
  mark_significance(comparisons = data.frame(
    group1 = c("ctrl", "ctrl", "A"),
    group2 = c("A", "B", "B"),
    label = c("*", "***", "ns")
  ))

Distributions

Histogram and density

faithful |>
  plotit(encode(x = eruptions)) |>
  mark_histogram(bins = 30)

iris |>
  plotit(encode(x = Sepal.Length, colour = Species)) |>
  mark_density()

Histogram + density overlay

faithful |>
  plotit(encode(x = eruptions)) |>
  mark_histogram(mapping = encode(y = ggplot2::after_stat(density)), bins = 30, alpha = 0.5) |>
  mark_density(bw = 0.15)

ECDF and QQ

faithful |>
  plotit(encode(x = eruptions)) |>
  mark_ecdf()

faithful |>
  plotit(encode(x = eruptions)) |>
  mark_qq() |>
  mark_qq_line()

Bivariate density and binning

faithful |>
  plotit(encode(x = eruptions, y = waiting)) |>
  mark_density_2d(filled = TRUE, bins = 10)

dmid <- ggplot2::diamonds[ggplot2::diamonds$carat < 2, ]
dmid |>
  plotit(encode(x = carat, y = price)) |>
  mark_hex(bins = 30)

dmid |>
  plotit(encode(x = carat, y = price)) |>
  mark_bin2d(bins = 20)

Rug ticks

faithful |>
  plotit(encode(x = eruptions)) |>
  mark_density() |>
  mark_rug(sides = "b", colour = "grey30")

Relationships

Scatter + smooth

airquality |>
  plotit(encode(x = Temp, y = Ozone)) |>
  mark_point(alpha = 0.6) |>
  mark_smooth()
#> `geom_smooth()` using method = 'loess' and formula = 'y ~ x'
#> Warning: Removed 37 rows containing non-finite outside the scale range
#> (`stat_smooth()`).
#> Warning: Removed 37 rows containing missing values or values outside the scale range
#> (`geom_point()`).

Grouped scatter

ggplot2::mpg |>
  plotit(encode(x = displ, y = hwy, colour = class)) |>
  mark_point(alpha = 0.7)

Correlation matrix

plotit(stats::cor(iris[1:4])) |>
  mark_corr()

Contour of a scalar field

volcano_df <- as.data.frame(as.table(volcano))
names(volcano_df) <- c("r", "c", "z")
volcano_df |>
  plotit(encode(x = as.numeric(r), y = as.numeric(c), z = z)) |>
  mark_contour(bins = 12)

Line and step

ggplot2::economics |>
  plotit(encode(x = date, y = unemploy)) |>
  mark_line()

ggplot2::economics |>
  plotit(encode(x = date, y = psavert)) |>
  mark_step(direction = "hv")

Area, ribbon, stacked area

ggplot2::economics |>
  plotit(encode(x = date, y = psavert)) |>
  mark_area()

set.seed(7)
d <- data.frame(
  x = 1:20,
  y = cumsum(rnorm(20)),
  lo = 1:20 - 1.96,
  hi = 1:20 + 1.96
)
d |>
  plotit(encode(x = x, y = y)) |>
  mark_line() |>
  mark_ribbon(mapping = encode(ymin = lo, ymax = hi))

set.seed(7)
df <- expand.grid(t = 1:12, g = letters[1:4])
df$v <- rpois(nrow(df), 5)
df |>
  plotit(encode(x = t, y = v, fill = g)) |>
  mark_area(position = "stack")

Slope chart (recipe)

sl <- data.frame(
  p = rep(c("before", "after"), each = 3),
  g = rep(letters[1:3], 2),
  v = c(3, 2, 1, 1.5, 2.5, 3)
)
sl |>
  plotit(encode(x = p, y = v, group = g, colour = g)) |>
  mark_line() |>
  mark_point()

Proportions

All proportion charts are recipes: mark_bar + project_polar.

Pie and donut

d <- data.frame(cat = c("A", "B", "C"), n = c(40, 35, 25))
d |>
  plotit(encode(x = 1, y = n, fill = cat)) |>
  mark_bar(position = "stack", width = 1) |>
  project_polar(theta = "y")

d |>
  plotit(encode(x = 1, y = n, fill = cat)) |>
  mark_bar(position = "stack", width = 1) |>
  project_polar(theta = "y", inner_radius = 0.4)

Rose / Nightingale

d |>
  plotit(encode(x = cat, y = n, fill = cat)) |>
  mark_bar(width = 1) |>
  project_polar()

Radar (recipe)

Precompute polar coordinates, then draw polygons in Cartesian space.

set.seed(7)
lv <- 4
rd <- data.frame(
  variable = rep(letters[1:lv], 2),
  person = rep(c("p1", "p2"), each = lv),
  value = runif(lv * 2, 4, 9)
)
rd$theta <- (as.numeric(factor(rd$variable)) - 1) / lv * 2 * pi
rd$px <- rd$value * sin(rd$theta)
rd$py <- rd$value * cos(rd$theta)
rd |>
  plotit(encode(x = px, y = py, group = person, colour = person), dodge = 0) |>
  mark_polygon(alpha = 0.2) |>
  project_cartesian(fixed = 1)

Coordinates

Flip, zoom, fixed aspect

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

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

data.frame(x = rnorm(80), y = rnorm(80)) |>
  plotit(encode(x = x, y = y)) |>
  mark_point() |>
  project_cartesian(fixed = 1)

Parallel coordinates

iris |>
  plotit(encode()) |>
  project_parallel(
    columns = c("Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width"),
    group = "Species"
  )

Facets

ggplot2::mpg |>
  plotit(encode(x = displ, y = hwy)) |>
  mark_point(alpha = 0.4) |>
  split_wrap(drv, ncol = 3)

ggplot2::mpg |>
  plotit(encode(x = displ, y = hwy)) |>
  mark_point(alpha = 0.4) |>
  split_grid(drv ~ cyl)

Matrix heatmaps

From long data

set.seed(7)
d <- expand.grid(r = paste0("r", 1:6), c = paste0("c", 1:6))
d$v <- rnorm(nrow(d))
d |>
  plotit(encode(x = c, y = r, fill = v)) |>
  mark_rect() |>
  scale_fill(mid = 0, range = "rdbu")
#> Scale for fill is already present.
#> Adding another scale for fill, which will replace the existing scale.

From a matrix, clustered

set.seed(7)
mat <- matrix(rnorm(48), nrow = 6, dimnames = list(paste0("g", 1:6), paste0("s", 1:8)))
h <- stats::hclust(stats::dist(mat))
plotit(mat, encode()) |>
  mark_heatmap(cluster = h, show_numbers = TRUE, number_format = "%.1f")

Heatmap + dendrogram (compose_annot)

hm <- plotit(mat, encode()) |> mark_heatmap(cluster = h)
tree <- as_graph(h) |>
  plotit() |>
  layout_dendrogram(direction = "up") |>
  mark_rule(data = ~edges)
hm |> compose_annot(top = tree)

Geography

Requires sf.

if (requireNamespace("sf", quietly = TRUE)) {
  nc <- sf::st_read(system.file("shape/nc.shp", package = "sf"), quiet = TRUE)
  nc |>
    plotit(encode(fill = AREA)) |>
    mark_map() |>
    scale_fill(range = "viridis") |>
    project_map()
}
#> Scale for fill is already present.
#> Adding another scale for fill, which will replace the existing scale.

Networks and flows

Sankey

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.

Treemap

tree_df <- data.frame(
  id = c("root", "a", "b", "a1", "a2", "b1"),
  parent = c(NA, "root", "root", "a", "a", "b"),
  value = c(NA, NA, NA, 30, 20, 50)
)
tree_df |>
  plotit(encode(fill = id)) |>
  mark_treemap()

Network

nodes <- data.frame(id = c("a", "b", "c", "d"), type = c("x", "y", "x", "y"))
edges <- data.frame(source = c("a", "a", "b", "c"), target = c("b", "c", "c", "d"))
nodes |>
  plotit(encode(colour = type, label = id)) |>
  mark_network(edges = edges, seed = 4)

Chord

m <- matrix(c(0, 5, 2, 3, 5, 0, 4, 1, 2, 4, 0, 6, 3, 1, 6, 0), 4,
  dimnames = list(letters[1:4], letters[1:4])
)
as_graph(m) |>
  plotit() |>
  layout_chord() |>
  mark_polygon(data = ~ribbons) |>
  mark_polygon(data = ~arcs)

Tree / dendrogram

as_graph(hclust(dist(iris[, 1:4]))) |>
  plotit() |>
  layout_dendrogram(direction = "down") |>
  mark_rule(data = ~edges) |>
  mark_point(data = ~nodes)

Annotations

Reference lines, labels, encircle

ggplot2::mpg |>
  plotit(encode(x = displ, y = hwy)) |>
  mark_point(alpha = 0.5) |>
  mark_rule(yintercept = 25, colour = "#E15759")

set.seed(7)
pts <- data.frame(
  x = rnorm(60), y = rnorm(60),
  g = rep(letters[1:3], each = 20)
)
pts |>
  plotit(encode(x = x, y = y, colour = g)) |>
  mark_point(alpha = 0.6) |>
  mark_encircle(shape = "hull", expand = 0.02)

lab <- data.frame(x = c(1, 2, 3), y = c(3, 1, 2), label = c("peak", "dip", "mid"))
lab |>
  plotit(encode(x = x, y = y, label = label)) |>
  mark_point() |>
  mark_text(repel = TRUE)

Colour scales

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

iris |>
  plotit(encode(x = Sepal.Width, y = Sepal.Length, colour = Species)) |>
  mark_point() |>
  scale_color(range = "brewer")
#> Scale for colour is already present.
#> Adding another scale for colour, which will replace the existing scale.

Next

  • Advanced — multi-panel composition, relational layouts, escape hatch
  • API — verb families and shared signatures
  • Reference — every function