Powered by AppSignal & Oban Pro

Reference lines: geom_abline

notebooks/geom_abline.livemd

Reference lines: geom_abline

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

alias Giggly.Plot

mtcars = Giggly.Datasets.mtcars()

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 geom_abline(), which covers geom_hline() and geom_vline() 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.

These geoms add reference lines to a plot: vertical ones at an xintercept, horizontal ones at a yintercept, and diagonal ones given a slope and an intercept. Given as arguments, a line is the same in every panel; mapped from a data frame, the lines can differ from panel to panel. Unlike other geoms, they take nothing from the plot's mapping and do not change the plot's scales. Giggly has none of them yet. 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. It binds Giggly.Datasets.mtcars/0, R's mtcars, to mtcars, R's name for it.

Vertical and horizontal lines

p <- ggplot(mtcars, aes(wt, mpg)) + geom_point()
# Fixed values
p + geom_vline(xintercept = 5)
p + geom_vline(xintercept = 1:5)
p + geom_hline(yintercept = 20)

Not in Giggly yet: geom_vline() and geom_hline().

Diagonal lines

p + geom_abline() # Can't see it - outside the range of the data
p + geom_abline(intercept = 20)

With no arguments, the line is y = x, which runs below the panel, out of sight. Not in Giggly yet: geom_abline().

A line of best fit

# Calculate slope and intercept of line of best fit
coef(lm(mpg ~ wt, data = mtcars))
p + geom_abline(intercept = 37, slope = -5)

R fits mpg to wt with a linear model and prints its intercept and slope, which the line then rounds. Not in Giggly yet: models fitted by lm(), and geom_abline().

Fitting the line with geom_smooth()

# But this is easier to do with geom_smooth:
p + geom_smooth(method = "lm", se = FALSE)

p is the first example's plot, mtcars' weights against their miles per gallon, which Giggly draws here. The smooth fits the same line as lm(mpg ~ wt).

p =
  mtcars
  |> Plot.new(%{x: :wt, y: :mpg})
  |> Plot.geom_point()

p
|> Plot.geom_smooth(method: :lm, se: false)
|> render.()

Lines that differ between facets

# To show different lines in different facets, use aesthetics
p <- ggplot(mtcars, aes(mpg, wt)) +
  geom_point() +
  facet_wrap(~ cyl)
mean_wt <- data.frame(cyl = c(4, 6, 8), wt = c(2.28, 3.11, 4.00))
p + geom_hline(aes(yintercept = wt), mean_wt)

The facets are in Giggly: facet_wrap(~ cyl) is Giggly.Plot.facet_wrap(plot, :cyl). Each line comes from the row of mean_wt with its panel's cyl. Not in Giggly yet: geom_hline() and mapping yintercept.

Other aesthetics

# You can also control other aesthetics
ggplot(mtcars, aes(mpg, wt, colour = wt)) +
  geom_point() +
  geom_hline(aes(yintercept = wt, colour = wt), mean_wt) +
  facet_wrap(~ cyl)

Not in Giggly yet: geom_hline() and mapping yintercept.