Powered by AppSignal & Oban Pro

Polygons: geom_polygon

notebooks/geom_polygon.livemd

Polygons: geom_polygon

Mix.install([
  {:giggly, path: Path.join(__DIR__, "..")},
  {:kino, "~> 0.19"}
  ])

About this notebook

This notebook follows the examples on ggplot2's reference page for geom_polygon(), in the order the page gives them. Each example shows ggplot2's code first and then Giggly's. An example Giggly cannot draw yet keeps its ggplot2 code and names what it is waiting for, so the page is also a list of what remains.

A polygon is a path whose ends are joined and whose inside is filled. geom_polygon() draws one polygon for each group, through its rows in order, and from R 3.6 a subgroup can mark rows that cut holes in it. Giggly has none of this yet.

Polygons from two tables

# When using geom_polygon, you will typically need two data frames:
# one contains the coordinates of each polygon (positions),  and the
# other the values associated with each polygon (values).  An id
# variable links the two together

ids <- factor(c("1.1", "2.1", "1.2", "2.2", "1.3", "2.3"))

values <- data.frame(
  id = ids,
  value = c(3, 3.1, 3.1, 3.2, 3.15, 3.5)
)

positions <- data.frame(
  id = rep(ids, each = 4),
  x = c(2, 1, 1.1, 2.2, 1, 0, 0.3, 1.1, 2.2, 1.1, 1.2, 2.5, 1.1, 0.3,
  0.5, 1.2, 2.5, 1.2, 1.3, 2.7, 1.2, 0.5, 0.6, 1.3),
  y = c(-0.5, 0, 1, 0.5, 0, 0.5, 1.5, 1, 0.5, 1, 2.1, 1.7, 1, 1.5,
  2.2, 2.1, 1.7, 2.1, 3.2, 2.8, 2.1, 2.2, 3.3, 3.2)
)

# Currently we need to manually merge the two together
datapoly <- merge(values, positions, by = c("id"))

p <- ggplot(datapoly, aes(x = x, y = y)) +
  geom_polygon(aes(fill = value, group = id))
p

merge() joins each polygon's value to its corners by id, giving one table with a row for each corner.

Not in Giggly yet: geom_polygon().

A line over the polygons

# Which seems like a lot of work, but then it's easy to add on
# other features in this coordinate system, e.g.:

set.seed(1)
stream <- data.frame(
  x = cumsum(runif(50, max = 0.1)),
  y = cumsum(runif(50,max = 0.1))
)

p + geom_line(data = stream, colour = "grey30", linewidth = 5)

The stream is a random walk: R draws its steps with runif(), and set.seed(1) makes them the same on every run.

Not in Giggly yet: geom_polygon().

Map projections

# And if the positions are in longitude and latitude, you can use
# coord_map to produce different map projections.

The comment draws nothing; it points to coord_map(), which projects longitude and latitude onto the plane.

Not in Giggly yet: coord_map().

Polygons with holes

if (packageVersion("grid") >= "3.6") {
  # As of R version 3.6 geom_polygon() supports polygons with holes
  # Use the subgroup aesthetic to differentiate holes from the main polygon

  holes <- do.call(rbind, lapply(split(datapoly, datapoly$id), function(df) {
    df$x <- df$x + 0.5 * (mean(df$x) - df$x)
    df$y <- df$y + 0.5 * (mean(df$y) - df$y)
    df
  }))
  datapoly$subid <- 1L
  holes$subid <- 2L
  datapoly <- rbind(datapoly, holes)

  p <- ggplot(datapoly, aes(x = x, y = y)) +
    geom_polygon(aes(fill = value, group = id, subgroup = subid))
  p
}

Each hole is its polygon shrunk halfway towards its centre; subgroup tells the outline's rows from the hole's.

Not in Giggly yet: geom_polygon() and mapping subgroup.