RH2015 RH2015 -4 years ago 118
R Question

Custom legend with imported images

I'm currently creating plots in ggplot2 by importing custom images and using them as geom_points, similar to this post, except I am looping through different images for unique levels of a factor.

Is there an easy way to add these images to the legend? I've seen multiple posts on custom legends in ggplot2, but nothing that deals with imported images.

Answer Source

I'm not sure how you will go about generating your plot, but this shows one method to replace a legend key with an image. It uses grid functions to locate the viewports containing the legend key grobs, and replaces one with the R logo

library(png)
library(ggplot2)
library(grid)

# Get image
img <- readPNG(system.file("img", "Rlogo.png", package="png"))

# Plot
p = ggplot(mtcars, aes(mpg, disp, colour = factor(vs))) + 
    geom_point() +
    theme(legend.key.size = unit(1, "cm"))

# Get ggplot grob
gt = ggplotGrob(p)
grid.newpage()
grid.draw(gt)

# Find the viewport containing legend keys
current.vpTree() # not well formatted
formatVPTree(current.vpTree())  # Better formatting - see below for the formatVPTree() function

    # Find the legend key viewports
    # The two viewports are: 
      # key-4-1-1.5-2-5-2
      # key-3-1-1.4-2-4-2

# Or search using regular expressions
Tree = as.character(current.vpTree())
pos = gregexpr("\\[key.*?\\]", Tree)
match = unlist(regmatches(Tree, pos))

match = gsub("^\\[(key.*?)\\]$", "\\1", match) # remove square brackets
match = match[!grepl("bg", match)]  # removes matches containing bg

# Change one of the legend keys to the image
downViewport(match[2])
grid.rect(gp=gpar(col = NA, fill = "white"))
grid.raster(img, interpolate=FALSE)
upViewport(0)

enter image description here

# Paul Murrell's function to display the vp tree 
formatVPTree <- function(x, indent=0) {
    end <- regexpr("[)]+,?", x)
    sibling <- regexpr(", ", x)
    child <- regexpr("[(]", x)
    if ((end < child || child < 0) && (end < sibling || sibling < 0)) {
        lastchar <- end + attr(end, "match.length")
        cat(paste0(paste(rep("  ", indent), collapse=""), 
                   substr(x, 1, end - 1), "\n"))
        if (lastchar < nchar(x)) {
            formatVPTree(substring(x, lastchar + 1), 
                         indent - attr(end, "match.length") + 1)
        }
    }
    if (child > 0 && (sibling < 0 || child < sibling)) {
        cat(paste0(paste(rep("  ", indent), collapse=""), 
                   substr(x, 1, child - 3), "\n"))
        formatVPTree(substring(x, child + 1), indent + 1)
    }
    if (sibling > 0 && sibling < end && (child < 0 || sibling < child)) {
        cat(paste0(paste(rep("  ", indent), collapse=""), 
                   substr(x, 1, sibling - 1), "\n"))
        formatVPTree(substring(x, sibling + 2), indent)
    }
}
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download