We want to use a linear gradient as the background of a plot.
Let's start by making a matrix with numbers between 0 and 1.
# The angle of our linear gradient
deg <- 45
rad <- deg / (180 / pi)
# A 5x5 matrix
n <- 5
mat <- matrix(data = 0, ncol = n, nrow = n)
# Let's fill in the matrix.
for (i in 1:n) {
for (j in 1:n) {
mat[i, j] <- (i / n) * cos(rad) + (j / n) * sin(rad)
}
}
What did we get?
mat
#> [,1] [,2] [,3] [,4] [,5]
#> [1,] 0.2828427 0.4242641 0.5656854 0.7071068 0.8485281
#> [2,] 0.4242641 0.5656854 0.7071068 0.8485281 0.9899495
#> [3,] 0.5656854 0.7071068 0.8485281 0.9899495 1.1313708
#> [4,] 0.7071068 0.8485281 0.9899495 1.1313708 1.2727922
#> [5,] 0.8485281 0.9899495 1.1313708 1.2727922 1.4142136
That looks pretty close to what we wanted.
Now, let's clamp the values between 0 and 1.
mat <- mat - min(mat)
mat <- mat / max(mat)
mat
#> [,1] [,2] [,3] [,4] [,5]
#> [1,] 0.000 0.125 0.250 0.375 0.500
#> [2,] 0.125 0.250 0.375 0.500 0.625
#> [3,] 0.250 0.375 0.500 0.625 0.750
#> [4,] 0.375 0.500 0.625 0.750 0.875
#> [5,] 0.500 0.625 0.750 0.875 1.000
Much better!
Let's use grid::rasterGrob()
to make a graphical object and
draw it.
library(grid)
g <- rasterGrob(
image = mat,
width = unit(1, "npc"),
height = unit(1, "npc"),
interpolate = TRUE
)
grid.newpage()
grid.draw(g)

Since we have a grob, we can add it to a ggplot2 figure with
ggplot2::annotation_custom()
.
library(ggplot2)
ggplot(mtcars, aes(factor(cyl))) +
annotation_custom(
grob = g, xmin = -Inf, xmax = Inf, ymin = -Inf, ymax = Inf
) +
geom_bar()

Hooray! We did it. But we're not done yet.
A few notes:
- It'd be nice to have a function that accepts a few arguments:
- angle
- resolution
- colors to use
- Our code above is easy to read, but slow to execute. We need it
to be faster.
Please feel free to copy the make_gradient()
function below and
improve upon it.
library(ggplot2)
library(grid)
library(RColorBrewer)
make_gradient <- function(deg = 45, n = 100, cols = blues9) {
cols <- colorRampPalette(cols)(n + 1)
rad <- deg / (180 / pi)
mat <- matrix(
data = rep(seq(0, 1, length.out = n) * cos(rad), n),
byrow = TRUE,
ncol = n
) +
matrix(
data = rep(seq(0, 1, length.out = n) * sin(rad), n),
byrow = FALSE,
ncol = n
)
mat <- mat - min(mat)
mat <- mat / max(mat)
mat <- 1 + mat * n
mat <- matrix(data = cols[round(mat)], ncol = n)
grid::rasterGrob(
image = mat,
width = unit(1, "npc"),
height = unit(1, "npc"),
interpolate = TRUE
)
}
Example 1
g <- make_gradient(
deg = 45, n = 500, cols = brewer.pal(9, "Spectral")
)
ggplot(mtcars, aes(factor(cyl))) +
annotation_custom(
grob = g, xmin = -Inf, xmax = Inf, ymin = -Inf, ymax = Inf
) +
geom_bar()

Example 2
g <- make_gradient(
deg = 180, n = 500, cols = brewer.pal(9, "RdBu")
)
ggplot(mtcars, aes(factor(cyl))) +
annotation_custom(
grob = g, xmin = -Inf, xmax = Inf, ymin = -Inf, ymax = Inf
) +
geom_bar()

Created on 2019-02-06 by the reprex package (v0.2.1)