Search code examples
rggplot2legendlegend-properties

get legend labels (text) from ggplot


I am trying to extract the label text from a ggplot legend object, e.g. for this plot:

library(ggplot2)
(p <- ggplot(mtcars, aes(x=mpg, y=disp, color=as.character(cyl))) + geom_point())

enter image description here

I can extract the legends via

library(ggpubr)
legend <- ggpubr::get_legend(p)

Next, I would like to get the actual string values that are contained in the legend object, i.e. for this case "4", "6", "8". How can these values be retrieved from the legend object?

Note: I do not have the original data available, only the legend object.


Solution

  • First set up the legend:

    library(ggplot2)
    library(ggpubr)
    
    p <- ggplot(mtcars, aes(x=mpg, y=disp, color=as.character(cyl))) + geom_point()
    
    legendp <- ggpubr::get_legend(p)
    

    From legendp$grobs[[1]], we know that the labels are probably stored in grobs 9 to 11:

    legendp$grobs[[1]]
    # TableGrob (7 x 6) "layout": 11 grobs
    #     z     cells       name                                grob
    # 1   1 (1-7,1-6) background rect[legend.background..rect.19172]
    # 2   2 (2-2,2-5)      title             gTree[GRID.gTree.19173]
    # 3   3 (4-4,2-2) key-3-1-bg        rect[legend.key..rect.19163]
    # 4   4 (4-4,2-2)  key-3-1-1           points[GRID.points.19164]
    # 5   5 (5-5,2-2) key-4-1-bg        rect[legend.key..rect.19166]
    # 6   6 (5-5,2-2)  key-4-1-1           points[GRID.points.19167]
    # 7   7 (6-6,2-2) key-5-1-bg        rect[legend.key..rect.19169]
    # 8   8 (6-6,2-2)  key-5-1-1           points[GRID.points.19170]
    # 9   9 (4-4,4-4)  label-3-3             gTree[GRID.gTree.19174]
    # 10 10 (5-5,4-4)  label-4-3             gTree[GRID.gTree.19175]
    # 11 11 (6-6,4-4)  label-5-3             gTree[GRID.gTree.19176]
    

    Then we can unlist grobs 9 to 11 (with which(grepl("label", legendp$grobs[[1]]$layout$name)) to dynamically output the target grobs). The labels are stored under a sublist element with a name that starts with "children.guide.label" and ends with "label", therefore we can grep that pattern to get our target labels

    legendp_grobs9_11 <- unlist(legendp$grobs[[1]]$grobs[which(grepl("label", legendp$grobs[[1]]$layout$name))])
    
    unname(legendp_grobs9_11[grepl("children.guide.label.*text.*label$", names(legendp_grobs9_11))])
    # [1] "4" "6" "8"
    

    Another example to show it works.

    library(tidyverse)
    library(ggpubr)
    
    p2 <- ggplot(diamonds, aes(cut, price, col = cut)) + geom_point()
    p2
    

    legendp2 <- get_legend(p2)
    legendp2_grobs13_17 <- unlist(legendp2$grobs[[1]]$grobs[which(grepl("label", legendp2$grobs[[1]]$layout$name))])
    unname(legendp2_grobs13_17[grepl("children.guide.label.*text.*label$", names(legendp2_grobs13_17))])
    #> [1] "Fair"      "Good"      "Very Good" "Premium"   "Ideal"
    

    Created on 2023-06-09 with reprex v2.0.2