rimageggplot2iconstreemap

How to (automatically) add custom icon to a treemap using ggplot2 and treemapify?


I'm trying to illustrate land cover data by the means of a treemap. I managed to create a simple treemap and to "grab" some icons. Unfortunately, I struggle to include these icons into the treemap which would help to illustrate the type of land cover.

This is an example code:

# create dataframe
df <- data.frame(category = c("forest", "greenland", "crops"),
                 area = c(20, 10, 70)
)
df$label = paste0(df$area,"%")

# load icons
library(magick)
icon_crops2 <- image_read("https://upload.wikimedia.org/wikipedia/commons/thumb/7/79/Agriculture_-_The_Noun_Project.svg/512px-Agriculture_-_The_Noun_Project.svg.png")
icon_forest2 <- image_read("https://upload.wikimedia.org/wikipedia/commons/thumb/d/da/BSicon_FOREST.svg/500px-BSicon_FOREST.svg.png")
icon_greenland2 <- image_read("https://upload.wikimedia.org/wikipedia/commons/thumb/2/2b/Wikidata_Morse_code_logo_grassroots.svg/600px-Wikidata_Morse_code_logo_grassroots.svg.png")

# add icons to dataframe
df$icons = c(icon_crops2, icon_forest2, icon_greenland2)
print(df$icons)

# plot treemap without icons
library(ggplot2)
library(treemapify)

ggplot(df, aes(area = area, 
                     fill = category, 
                     label = paste(category,label,sep="\n"),
                     subgroup = category)) +
  geom_treemap() +
  geom_treemap_text(colour = "black", place = "center") +
  theme(legend.position = "none")

This results in the following image: treemap land cover without icons

Yet, I would like to have something like this (created with GIMP): desired result (here created with GIMP)

Although I could insert the icons manually, e.g. by using GIMP, I'm looking for an automatic way.

Anyone has an idea how to do this?


Solution

  • One option would be to use ggimage::geom_image. To place the images we could use treemapify::treemapify() to create a dataset with the coordinates of the rectangles which could then be passed to geom_image to place the images in the right rectangles:

    # create dataframe
    df <- data.frame(
      category = c("forest", "greenland", "crops"),
      area = c(20, 10, 70)
    )
    df$label <- paste0(df$area, "%")
    
    # plot treemap without icons
    library(ggplot2)
    library(treemapify)
    library(ggimage)
    
    dat_image <- treemapify(df,
      area = "area",
      layout = "squarified",
      start = "bottomleft"
    ) |>
      transform(x = .5 * (xmin + xmax), y = .5 * (ymin + ymax))
    
    dat_image$icons <- c(
      "https://upload.wikimedia.org/wikipedia/commons/thumb/7/79/Agriculture_-_The_Noun_Project.svg/512px-Agriculture_-_The_Noun_Project.svg.png",
      "https://upload.wikimedia.org/wikipedia/commons/thumb/d/da/BSicon_FOREST.svg/500px-BSicon_FOREST.svg.png",
      "https://upload.wikimedia.org/wikipedia/commons/thumb/2/2b/Wikidata_Morse_code_logo_grassroots.svg/600px-Wikidata_Morse_code_logo_grassroots.svg.png"
    )
    
    ggplot(df, aes(
      area = area,
      fill = category,
      label = label,
      subgroup = category
    )) +
      geom_treemap() +
      geom_treemap_text(colour = "black", place = "center") +
      scale_x_continuous(limits = c(0, 1), expand = c(0, 0)) +
      scale_y_continuous(limits = c(0, 1), expand = c(0, 0)) +
      geom_image(data = dat_image, aes(x = x, y = y, image = icons), inherit.aes = FALSE, nudge_y = .1, size = .1) +
      theme(
        legend.position = "none",
        axis.line = element_blank(),
        axis.text = element_blank(),
        axis.title = element_blank(),
        axis.ticks = element_blank()
      )