Powered by AppSignal & Oban Pro

Colour, fill and alpha: aes_colour_fill_alpha

notebooks/aes_colour_fill_alpha.livemd

Colour, fill and alpha: aes_colour_fill_alpha

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

alias Giggly.Plot

economics = Giggly.Datasets.economics()
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 aes_colour_fill_alpha, 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.

colour and fill give a geom its colours, and alpha its opacity. colour draws lines and outlines: points, lines, and the borders of rectangles and polygons. fill colours the inside of an area: rectangles, polygons, and the point shapes 21 to 25. A colour is one of R's named colours, such as "red", an RGB specification, "#RRGGBB", which may add an alpha as "#RRGGBBAA", or NA, for no colour at all; alpha runs from 0, transparent, to 1, opaque. Giggly has all three, mapped to a column or set to a value, a set colour written as CSS writes one: a name, a hex colour, or :none for NA. Where R and CSS give a name different colours, as "green", it is CSS's, and a name CSS lacks, as R's "grey50", is written as its hex. 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.economics/0, ggplot2's economics, and Giggly.Datasets.mtcars/0, R's mtcars, to economics and mtcars, the names ggplot2 and R give them.

The default bars

# Bar chart example
p <- ggplot(mtcars, aes(factor(cyl)))
# Default plotting
p + geom_bar()

factor(cyl) makes the number of cylinders discrete, so the axis has a place for each of 4, 6 and 8. Giggly writes it {:factor, [:cyl]}, and titles the axis factor(cyl), as ggplot2 does.

p = Plot.new(mtcars, %{x: {:factor, [:cyl]}})

p
|> Plot.geom_bar()
|> render.()

Fill and outline colour

# To change the interior colouring use fill aesthetic
p + geom_bar(fill = "red")
# Compare with the colour aesthetic which changes just the bar outline
p + geom_bar(colour = "red")
# Combining both, you can see the changes more clearly
p + geom_bar(fill = "white", colour = "red")

fill: and colour: set every bar's inside and border; "red" and "white" are the same colours in CSS as in R.

p
|> Plot.geom_bar(fill: "red")
|> render.()
p
|> Plot.geom_bar(colour: "red")
|> render.()
p
|> Plot.geom_bar(fill: "white", colour: "red")
|> render.()

RGB colours, and none

# Both colour and fill can take an rgb specification.
p + geom_bar(fill = "#00abff")
# Use NA for a completely transparent colour.
p + geom_bar(fill = NA, colour = "#00abff")

A hex colour is written as R writes it, and :none is R's NA, no colour at all.

p
|> Plot.geom_bar(fill: "#00abff")
|> render.()
p
|> Plot.geom_bar(fill: :none, colour: "#00abff")
|> render.()

Mapping fill to a discrete column

# Colouring scales differ depending on whether a discrete or
# continuous variable is being mapped. For example, when mapping
# fill to a factor variable, a discrete colour scale is used.
ggplot(mtcars, aes(factor(cyl), fill = factor(vs))) + geom_bar()

factor(vs) reads the engine shape, 0 or 1, as two levels, so the fill takes a discrete scale and each bar a stack of two.

mtcars
|> Plot.new(%{x: {:factor, [:cyl]}, fill: {:factor, [:vs]}})
|> Plot.geom_bar()
|> render.()

Mapping fill to a continuous column

# When mapping fill to continuous variable a continuous colour
# scale is used.
ggplot(faithfuld, aes(waiting, eruptions)) +
  geom_raster(aes(fill = density))

Not in Giggly yet: the faithfuld dataset and geom_raster().

Geoms with colour only

# Some geoms only use the colour aesthetic but not the fill
# aesthetic (e.g. geom_point() or geom_line()).
p <- ggplot(economics, aes(x = date, y = unemploy))
p + geom_line()
p + geom_line(colour = "green")
p + geom_point()
p + geom_point(colour = "red")

A line and points take colour:, and have no fill to set. A colour is named as CSS names it, and "green" is CSS's, #008000, darker than R's, #00FF00, so this line is darker than ggplot2's; "red" is #FF0000 in both.

p = Plot.new(economics, %{x: :date, y: :unemploy})

p
|> Plot.geom_line()
|> render.()
p
|> Plot.geom_line(colour: "green")
|> render.()
p
|> Plot.geom_point()
|> render.()
p
|> Plot.geom_point(colour: "red")
|> render.()

Transparency for overplotting

# For large datasets with overplotting the alpha
# aesthetic will make the points more transparent.
set.seed(1)
df <- data.frame(x = rnorm(5000), y = rnorm(5000))
p  <- ggplot(df, aes(x,y))
p + geom_point()
p + geom_point(alpha = 0.5)
p + geom_point(alpha = 1/10)

R's rnorm() draws the points at random from a normal distribution, the same ones every time after set.seed(1).

Giggly draws all three now, but this notebook leaves them undrawn: it would have to write out the 10,000 numbers rnorm() draws here.

Shading with alpha

# Alpha can also be used to add shading.
p <- ggplot(economics, aes(x = date, y = unemploy)) + geom_line()
p
yrng <- range(economics$unemploy)
p <- p +
  geom_rect(
    aes(NULL, NULL, xmin = start, xmax = end, fill = party),
    ymin = yrng[1], ymax = yrng[2], data = presidential
  )
p
p + scale_fill_manual(values = alpha(c("blue", "red"), .3))

The rectangles span each president's term, from the presidential table, coloured by party and as tall as the range of unemployment. Giggly draws the first plot, the number unemployed each month.

p =
  economics
  |> Plot.new(%{x: :date, y: :unemploy})
  |> Plot.geom_line()

render.(p)

Not in Giggly yet: the presidential dataset, removing the plot's x and y from a layer's mapping, R's aes(NULL, NULL), and colours made transparent by alpha().