rggplot2shinyplotlytreemap

Treemaps with images as backgrounds


Hello and thanks in advance, I am looking for a way to implement background images in my treemap and, ideally, automatically adjust the color of the text to the colors of the background image, just like plotly does when there is only background. I have so far tried with Plotly, ECharts, ggplot2, and have not been able to find any way to succeed. I found the "add_trace(x, type="image")" in Plotly, but could not locate any examples online on how to use it with treemap.

Here is an example code:

treemap <- data.frame(names = c("Bob", "Rob", "Knob", "Pam", "Sam"), n = c(13, 44, 1, 22, 9))

Solution

  • Since it looks like you're new to SO--welcome to the community! If you want great answers quickly, it's best to make your question reproducible. This includes sample data like the output from dput() or reprex::reprex() and any libraries you are using. (The data you provided isn't complete; what about the images?) When you've tried but haven't been successful, you need to include the code that did not work (not a list of libraries). We're all about helping you with code, not doing it for you... Check it out: making R reproducible questions.

    After my explanation, I'll provide the same code again altogether (much easier copy + paste).

    Within this answer, I've used the highcharter, tidywikidatar and tidyverse libraries.

    Here's the plan I followed.

    1. collect some data
    2. prepare data for treemap
    3. make a plain treemap to ensure data setup is correct
    4. collect images to use in treemap
    5. recreate treemap with images, check for form, fit and function

    Step 1 get some data

    library(tidyverse)
    library(highcharter)
    library(tidywikidatar)
    
    data("mpg")
    
    funModeling::df_status(mpg) # what data do we have? --simplify for example
    mpg2 <- mpg %>% filter(manufacturer %in% unique(mpg$manufacturer)[3:5]) %>% 
      mutate(model = stringr::str_to_sentence(model)) # change from all small letters
    

    Step 2 prep data

    # prepare data for treemap
    dout <- data_to_hierarchical(mpg2, c(manufacturer, model), cty)
    

    Step 3 inspect what I expect

    hchart(dout, type = "treemap")  # validate the structure before adding images
    

    Step 4 collect images to use

    This step has several substeps.

    Collect image data, using mpg data and Wikipedia

    1. create search terms
    2. collect image URLs from Wikipedia
    3. add to dout (the data used in the original treemap)
    #  1) create search terms 
    mods <- mpg2[, c(1, 2), ] %>% 
      mutate(imgN = paste0(manufacturer, "_", strsplit(model, " ") %>% map_chr(., 1)))
    
    mods2 <- mods[!duplicated(mods), ] # only one image per 'square'
    
    #  2) collect image URLs from Wikipedia 
    mods3 <- lapply(1:nrow(mods2), function(i) {
      ids <- tidywikidatar:::tw_search_single(mods2[i, 3], limit = 1) # find picture IDs
      urls <- tw_get_image(id = ids, format = "embed")[1, 2]          # use Ids to get image
      data.frame(mods2[i, 1], mods2[i, 2], mods2[i, 3], urls)         # add to dataframe
    }) %>% list_rbind() # return data frame (not list)
    
    
    #  3) add to dout
    invisible(lapply(1:length(dout), function(k) {
      if(any(names(dout[[k]]) %in% "parent")) {                       # find children 
        wh <- filter(mods3, manufacturer == dout[[k]]$parent,         # id correct URL
                     model == dout[[k]]$name)
                                                            # add encoded url to dout 
        dout[[k]]$color <<- list(pattern = list(image = URLencode(unlist(wh$image)),
                                                aspectRatio = 1/1))
      }
    }))
    

    Step 5 recreate the treemap with images

    hchart(dout, type = "treemap") %>% 
      hc_add_dependency("modules/pattern-fill.js") # necessary plugin to add images
    

    enter image description here

    It's really hard to read the labels, so I wanted to modify them. I've only used a few of the many parameters available. You can read about all of the possibilities here.

    # Hard to read labels, can be adjusted a variety of ways
    hchart(dout, type = "treemap", dataLabels = list(
      backgroundColor = "black", borderWidth = 2,
      style = list(color = "yellow", fontSize = "15px"))) %>% 
      hc_add_dependency("modules/pattern-fill.js") # necessary plugin to add images
    

    enter image description here

    All that code altogether

    library(tidyverse)
    library(highcharter)
    library(tidywikidatar)
    
    data("mpg")
    
    funModeling::df_status(mpg) # what data do we have? --simplify for example
    mpg2 <- mpg %>% filter(manufacturer %in% unique(mpg$manufacturer)[3:5]) %>% 
      mutate(model = stringr::str_to_sentence(model)) # change from all small letters
    
    # prepare data for treemap
    dout <- data_to_hierarchical(mpg2, c(manufacturer, model), cty)
    
    hchart(dout, type = "treemap")  # validate the structure before adding images
    
    # collect image data, using mpg data dn Wikipedia
    #  1) create search terms 
    #  2) collect image URLs from Wikipedia 
    #  3) add to dout
    
    #  1) create search terms 
    mods <- mpg2[, c(1, 2), ] %>% 
      mutate(imgN = paste0(manufacturer, "_", strsplit(model, " ") %>% map_chr(., 1)))
    
    mods2 <- mods[!duplicated(mods), ] # only one image per 'square'
    
    #  2) collect image URLs from Wikipedia 
    mods3 <- lapply(1:nrow(mods2), function(i) {
      ids <- tidywikidatar:::tw_search_single(mods2[i, 3], limit = 1) # find picture IDs
      urls <- tw_get_image(id = ids, format = "embed")[1, 2]          # use Ids to get image
      data.frame(mods2[i, 1], mods2[i, 2], mods2[i, 3], urls)         # add to dataframe
    }) %>% list_rbind() # return data frame (not list)
    
    
    #  3) add to dout
    invisible(lapply(1:length(dout), function(k) {
      if(any(names(dout[[k]]) %in% "parent")) {                       # find children 
        wh <- filter(mods3, manufacturer == dout[[k]]$parent,         # id correct URL
                     model == dout[[k]]$name)
                                                                      # add url to dout 
        dout[[k]]$color <<- list(pattern = list(image = URLencode(unlist(wh$image)),
                                                aspectRatio = 1/1))
      }
    }))
    
    
    # recreate treemap
    hchart(dout, type = "treemap") %>% 
      hc_add_dependency("modules/pattern-fill.js") # necessary plugin to add images
    
    
    # Hard to read labels, can be adjusted a variety of ways
    hchart(dout, type = "treemap", dataLabels = list(
      backgroundColor = "black", borderWidth = 2,
      style = list(color = "yellow", fontSize = "15px"))) %>% 
      hc_add_dependency("modules/pattern-fill.js") # necessary plugin to add images