Powered by AppSignal & Oban Pro

Discrete position scales: scale_discrete

notebooks/scale_discrete.livemd

Discrete position scales: scale_discrete

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

alias Giggly.Plot

mpg = Giggly.Datasets.mpg()
diamonds = Giggly.Datasets.diamonds()

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 scale_x_discrete(), which covers scale_y_discrete() 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.

scale_x_discrete() and scale_y_discrete() are the scales for a discrete x and y, which ggplot2 adds by itself for such a column. Setting one by hand changes its title, the labels of its values, or which values it shows and in what order. A discrete scale places its values at 1, 2, 3 and so on, so continuous positions can fall between them, which is how jittering works. Giggly chooses a discrete position scale from the data, as ggplot2 does, and orders its values as ggplot2 does: text alphabetically, and a factor by its levels, a Giggly.Factor's in the table or those a mapping's {:factor, [...], levels: [...]} or {:reorder, [...]} gives. It has Giggly.Plot.scale_x_discrete/2 and Giggly.Plot.scale_y_discrete/2, with their titles, labels, limits, breaks and expansion, and limits: shows values in the order given. 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 cells draw Giggly.Datasets.mpg/0, ggplot2's mpg: fuel economy for 234 cars of 38 popular models from 1999 to 2008, and ggplot2's diamonds, Giggly.Datasets.diamonds/0, which the setup cell binds to mpg and diamonds, ggplot2's names for them.

Bars on a discrete axis

ggplot(diamonds, aes(cut)) + geom_bar()

cut is an ordered factor, so the bars run from Fair to Ideal, the order of its levels.

diamonds
|> Plot.new(%{x: :cut})
|> Plot.geom_bar()
|> render.()

Jittered points on two discrete axes

Parentheses around an assignment print its value, so this draws d as well as naming it.

# The discrete position scale is added automatically whenever you
# have a discrete position.

(d <- ggplot(subset(diamonds, carat > 1), aes(cut, clarity)) +
      geom_jitter())

Not in Giggly yet: geom_jitter().

The axis title and labels

d + scale_x_discrete("Cut")
d +
  scale_x_discrete(
    "Cut",
    labels = c(
      "Fair" = "F",
      "Good" = "G",
      "Very Good" = "VG",
      "Perfect" = "P",
      "Ideal" = "I"
    )
  )

The labels are given by value, so the order they are written in does not matter.

Not in Giggly yet: geom_jitter().

Which values are shown

# Use limits to adjust the which levels (and in what order)
# are displayed
d + scale_x_discrete(limits = c("Fair","Ideal"))

Not in Giggly yet: geom_jitter().

The xlim() and ylim() shortcuts

Given values rather than two numbers, xlim() and ylim() set a discrete scale's limits.

# you can also use the short hand functions xlim and ylim
d + xlim("Fair","Ideal", "Good")
d + ylim("I1", "IF")

Not in Giggly yet: geom_jitter().

Ordering by another column

Giggly orders the manufacturers alphabetically, as ggplot2 does for a column of text.

# See ?reorder to reorder based on the values of another variable
ggplot(mpg, aes(manufacturer, cty)) +
  geom_point()
mpg
|> Plot.new(%{x: :manufacturer, y: :cty})
|> Plot.geom_point()
|> render.()

reorder() orders the manufacturers by the mean of another column, cty and then displ.

ggplot(mpg, aes(reorder(manufacturer, cty), cty)) +
  geom_point()
ggplot(mpg, aes(reorder(manufacturer, displ), cty)) +
  geom_point()

Giggly writes reorder(manufacturer, cty) as {:reorder, [:manufacturer, :cty]}, and titles the axis as R does.

mpg
|> Plot.new(%{x: {:reorder, [:manufacturer, :cty]}, y: :cty})
|> Plot.geom_point()
|> render.()
mpg
|> Plot.new(%{x: {:reorder, [:manufacturer, :displ]}, y: :cty})
|> Plot.geom_point()
|> render.()

Abbreviated labels

# Use abbreviate as a formatter to reduce long names
ggplot(mpg, aes(reorder(manufacturer, displ), cty)) +
  geom_point() +
  scale_x_discrete(labels = abbreviate)

Not in Giggly yet: R's abbreviate(), which shortens each name.