Powered by AppSignal & Oban Pro

Theme elements: element

notebooks/element.livemd

Theme elements: element

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

alias Giggly.Plot

mpg = Giggly.Datasets.mpg()

render = fn plot ->
  plot
  |> Giggly.to_svg()
  |> IO.iodata_to_binary()
  |> Kino.Image.new(:svg)
end

About this notebook

This notebook follows the examples on ggplot2's reference page for element(), which covers margin(), margin_part(), margin_auto(), element_blank(), element_rect(), element_line(), element_text(), element_polygon(), element_point(), element_geom() and rel() too, 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.

In ggplot2's theme system, the element_ functions say how the parts of a plot that are not data are drawn: element_blank() draws nothing and takes no space, element_rect() draws borders and backgrounds, element_line() lines and element_text() text, and element_geom() sets the defaults that layers draw with. element_polygon() and element_point() are not drawn in standard plots and serve extensions. rel() gives a size relative to the parent element's, and margin(), margin_part() and margin_auto() give the margins around an element. Giggly sets a plot's elements with Giggly.Plot.theme/2: a line, a rectangle or a text is a keyword list of its properties, element_blank() is :none, rel(1.5) is {:rel, 1.5}, and a margin is one length for every side or a keyword list of the sides it sets, so margin() and margin_auto() are written as lengths. It has no margin_part(), element_geom(), element_polygon() or element_point(), and no arrow on a line. A plot is described with Giggly.Plot and drawn with Giggly.to_svg/2, which returns an SVG document. The setup cell aliases Giggly.Plot, so the cells write Plot.new/2, and defines render, which draws a plot and shows it below the cell with Kino.Image. The data is Giggly.Datasets.mpg/0, ggplot2's mpg: fuel economy for 234 cars of 38 popular models from 1999 to 2008, which the setup cell binds to mpg, ggplot2's name for it.

Blank elements

# A standard plot
plot <- ggplot(mpg, aes(displ, hwy)) + geom_point()

# Turning off theme elements by setting them to blank
plot + theme(
  panel.background = element_blank(),
  axis.text = element_blank()
)
plot =
  mpg
  |> Plot.new(%{x: :displ, y: :hwy})
  |> Plot.geom_point()

plot
|> Plot.theme(
  panel_background: :none,
  axis_text: :none
)
|> render.()

Styling text

# Text adjustments
plot + theme(
  axis.text = element_text(colour = "red", size = rel(1.5))
)
plot
|> Plot.theme(axis_text: [colour: "red", size: {:rel, 1.5}])
|> render.()

An axis line with an arrow

# Turning on the axis line with an arrow
plot + theme(
  axis.line = element_line(arrow = arrow())
)

Not in Giggly yet: element_line()'s arrow option, here to end each axis's line in an arrow made by grid's arrow().

Backgrounds and margins

plot + theme(
  panel.background = element_rect(fill = "white"),
  plot.margin = margin_auto(2, unit = "cm"),
  plot.background = element_rect(
    fill = "grey90",
    colour = "black",
    linewidth = 1
  )
)

margin_auto(2, unit = "cm") gives the same 2 cm margin on all four sides, which Giggly writes as one length, {2, :cm}. R's "grey90" is a name CSS lacks, so the cell writes its hex, "#E5E5E5".

plot
|> Plot.theme(
  panel_background: [fill: "white"],
  plot_margin: {2, :cm},
  plot_background: [
    fill: "#E5E5E5",
    colour: "black",
    linewidth: 1
  ]
)
|> render.()

Defaults for layers

ggplot(mpg, aes(displ, hwy)) +
  geom_point() +
  geom_smooth(formula = y ~ x, method = "lm") +
  theme(geom = element_geom(
    ink = "red", accent = "black",
    pointsize = 1, linewidth = 2
  ))

Not in Giggly yet: geom_smooth()'s formula option, here y ~ x, and element_geom(), which here sets the colours, point size and line width the layers draw with.