Skip to main content

[How-To] How to plot a chart on top of a background image in ggplot2

This post is an instructional one on how to plot a chart on top of a background image in ggplot2 and R. The motivation for plotting on a background may just be a design choice or it may serve the purpose of supporting the message of the chart. I will show how i create my previous post's chart showing the location of successful free kicks on a football pitch.

Below code creates a 10x10 matrix with normally distributed doubles, which we will use as dummy data so you can easily replicate the results.
N <- 10
M <- 10

data <- matrix(rnorm(N*M,mean=0,sd=1), N, M)


We can convert this into a data frame and plot the initial data.
library(ggplot2)

df <- as.data.frame(as.table(data))

ggplot(df, aes(Var2, Var1)) + 
  geom_tile(aes(fill = Freq)) + 
  scale_fill_gradient(low = "white", high = "tomato")





Next we need a background image which you can import with the jpeg package. In my case this is a picture of half a football pitch.
library(jpeg)

img <- readJPEG(PATH)


We can now combine these two parts and annotate the background image to the ggplot plot. We are using ggplot's annotation_custom and the rasterGrob function of the grid package. Essentially we are saying not to scale the imported image and to fill the entire background of the chart area.
library(ggplot2)
library(grid)

ggplot(df, aes(Var2, Var1)) + 
  annotation_custom(rasterGrob(img, width=unit(1,"npc"), height=unit(1,"npc")), -Inf, Inf, -Inf, Inf) +
  geom_tile(aes(fill = Freq)) + 
  scale_fill_gradient(low = "white", high = "tomato")


An issue we face now is that the heat mapis not transparent. My idea was to have the white boxes transparent to keep the feel of having this data plotted on an image of a football pitch.



We can resolve this by making use of alpha property in the geom_tile function. This parameter triggers the transparency of the heat map plot. Combined with the cut function we can implement a value dependent transparency level. The idea is to increase transparency to a very high value for low values of heat map plot.

library(ggplot2)
library(grid)

ggplot(df, aes(Var2, Var1)) + 
  annotation_custom(rasterGrob(img, width=unit(1,"npc"), height=unit(1,"npc")), -Inf, Inf, -Inf, Inf) +
  geom_tile(aes(fill = Freq, alpha=cut(Freq,breaks=c(-Inf,-1,Inf)))) + 
  scale_alpha_manual(values=c(0.2,0.9), guide="none") + 
  scale_fill_gradient(low = "white", high = "tomato")


Above code increases transparency for parts of the plot with a value of below -1. We will see the background picture shine through for these values. Setting guide to None prevents the plot from having another legend on the side, showing information we don't need.



We can finally remove the axes and add a title to give the chart a more polished feel.

library(ggplot2)
library(grid)

ggplot(df, aes(Var2, Var1)) + 
  annotation_custom(rasterGrob(img, width=unit(1,"npc"), height=unit(1,"npc")), -Inf, Inf, -Inf, Inf) +
  geom_tile(aes(fill = Freq, alpha=cut(Freq,breaks=c(-Inf,-1,Inf)))) + 
  scale_alpha_manual(values=c(0.2,0.9), guide="none") + 
  scale_fill_gradient(low = "white", high = "tomato")+
  theme(axis.title.y=element_blank(), axis.text.y=element_blank(), axis.ticks.y=element_blank()) +
  theme(axis.title.x=element_blank(), axis.text.x=element_blank(), axis.ticks.x=element_blank()) +
  labs(title="[HOW TO] ", 
       subtitle="How to plot a chart on top of a background image in ggplot2", 
       caption="thesignificantgame.blogspot.com")


Comments