I had three inspirations for this package:

  1. This post from Matthew Kay, “I don’t want your monolithic ggplot function”.

  2. This beautiful “thematic” interactive1 graph made in highchartr by Jushua Kunst:

  1. A near death experience in Kathmandu, Nepal two years ago (don’t ask).

What if, I thought, the mountain itself, is a line plot.

What if, I thought, a histogram could be made out of actual buildings.

This, I thought, would make a great first geom.

You can go to the package and try it yourself or you can keep reading.

Annapurna

To reiterate, I was inspired by the Annapurna mountains to make a simple line plot. Here’s the idea.

Take an image of the Annapurna mountains:

Cut it out according to a simple line plot:

library(ggplot2)

ggplot(mtcars, aes(mpg, disp)) +
  geom_line()

And get a line plot made out of the mountains:

library(ggwithimages)

annapurna <- png::readPNG(system.file("extdata", "annapurna.png", package = "ggwithimages"))

ggplot(mtcars, aes(mpg, disp)) +
  geom_line_with_image(annapurna, lineColor = 0)

And of course make it a geom to exrecise my ggplot2 skills and so that it plays well with everything ggplot2 has to offer. Let’s call it geom_line_with_image. We have the bottomImg, let’s add the topImg and do this on some meaningful data:

sky <- png::readPNG(system.file("extdata", "sky.png", package = "ggwithimages"))
kathmandu_hourly_aqi <- readr::read_csv(system.file("extdata", "kathmandu_hourly_aqi.csv", package = "ggwithimages"))

library(ggplot2)
ggplot(kathmandu_hourly_aqi, aes(hour, aqi)) +
  geom_line_with_image(annapurna, sky) +
  labs(title = "Air Quality Index in the Thamel, Kathmandu, Nepal",
       subtitle = "Measured in PM2.5 by the US Embassy in Kathmandu",
       y = "Hourly Mean AQI [PM2.5]",
       x = "Hour") +
  ylim(c(50, 200)) +
  theme(text = element_text(family="mono"),
        axis.title.x = element_text(size = 12),
        axis.title.y = element_text(size = 12))

Yes, I know, it would have been much better to actually have a dataset telling us something about Annapurna - that would add to the graph a whole new dimension! - but this is what I found quickly, air pollution in Kathmandu, Nepal.

Now, how did I make this happen?

I combined Paul Murrell’s2 idea for painting Spain with the Spanish flag from this article. And this wonderful SO answer, telling me about the very handy point.in.polygon function in the very handy sp package. For the details you’d have to see the code, I’m going to make this a short post.

New York, New York

Can we make a histogram out of NYC buildings? Say to see the distribution of daily no. of accidents around the city. Yes, we also have geom_hist_with_image:

nyc <- png::readPNG(system.file("extdata", "nyc.png", package = "ggwithimages"))
night_sky <- png::readPNG(system.file("extdata", "night_sky.png", package = "ggwithimages"))
nyc_accidents <- readr::read_csv(system.file("extdata", "nyc_accidents.csv", package = "ggwithimages"))

ggplot(nyc_accidents, aes(n_accidents)) +
  geom_hist_with_image(nyc, night_sky) +
  labs(title = "NYC Daily No. of Accidents Distribution",
       subtitle = "Data Obtained on January 3, 2018 from NYC OpenData",
       y = "Frequency",
       x = "Daily No. of Accidents") +
  ylim(c(0, 700)) +
  xlim(c(0, 1300)) +
  theme(text = element_text(family="mono"),
        axis.title.x = element_text(size = 12),
        axis.title.y = element_text(size = 12))

Haha!

Notice how if you’re writing a geom instead of a custom plot function, you get so much more for free.

Trumppence

You can even use the magick package to make the bottomImg and topImg, say the same face colorized in a way which intensifies the graph’s message:

trumpPath <- system.file("extdata", "trump_head.jpg", package = "ggwithimages")
trump1 <- magick::image_modulate(
  magick::image_read(trumpPath), brightness = 80, saturation = 120, hue = 180
)
trump2 <- magick::image_modulate(
  magick::image_read(trumpPath), brightness = 80, saturation = 120, hue = 80
)
trump_approval_gallup <- readr::read_csv(
  system.file("extdata", "trump_approval_gallup.csv", package = "ggwithimages")
)

library(dplyr)

trump_approval_gallup %>%
  mutate(date = lubridate::as_date(date)) %>%
  group_by(month) %>%
  summarise(mean_approval = mean(approval)) %>%
  ggplot(aes(month, mean_approval)) +
  geom_line_with_image(trump1, trump2, lineColor = 2, lineWidth = 5) +
  labs(title = "Donald Trump's Approval Rate",
       subtitle = "Gallup Poll, 2017",
       y = "Monthly Mean Approval [%]",
       x = "Month") +
  theme(text = element_text(family="mono"),
        axis.title.x = element_text(size = 12),
        axis.title.y = element_text(size = 12))

Giora Out

One more thing: if you’re interested in more clevel overlaying of images on graphs, I’d check ggimage by Guangchuang Yu.

Go ahead, get the package on Github, try both geom_line_with_image and geom_hist_with_image, tell me if and where it breaks.


  1. This is just a screenshot.

  2. The author of the grid package which is the base for ggplot2.