Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom legend with imported images

Tags:

r

legend

ggplot2

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.

like image 931
RH2015 Avatar asked Jan 07 '23 10:01

RH2015


2 Answers

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)
    }
}
like image 196
Sandy Muspratt Avatar answered Jan 19 '23 03:01

Sandy Muspratt


Using html tags with element_markdown, you can specify anything you want in your legend.

Assuming that you have a png image in a file, that this file is located in a certain folder having a filename image, then you can run, for example:

p = ggplot(mtcars, aes(mpg, disp, colour = factor(vs))) + 
    geom_point() +
    theme(legend.key.size = unit(1, "cm"))
labels <- c()
labels[1]=paste0("<img src='", folder, image, ".png' width='16' />")
labels[2]="<strong>Faces</strong>"
p + theme(legend.text = element_markdown(color = "black", size = 11)) + 
scale_color_manual(name = "factor(vs)", labels = labels, , values = c(1,2))

will return this: enter image description here

like image 31
Denis Cousineau Avatar answered Jan 19 '23 05:01

Denis Cousineau