Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Match legend text color in geom_text to symbol

Tags:

r

legend

ggplot2

I am trying to color match the text of the legend to the color of text produced by a factored variable using geom_text. Here is a minimal working example:

df <- data.frame(a=rnorm(10),b=1:10,c=letters[1:10],d=c("one","two"))
p1 <-ggplot(data=df,aes(x=b,y=a))
p1 <- p1 + geom_text(aes(label = c, color=d, fontface="bold"))
p1 <- p1 + scale_color_hue(name="colors should match",breaks=c("one", "two"),
                 labels=c("should be pink", "should be blue"))
p1

enter image description here

I am sure its a simple fix. Any suggestions or reference to prior posts would help. I did not find anything specific to this.

like image 785
Vijay Ivaturi Avatar asked May 11 '14 01:05

Vijay Ivaturi


1 Answers

Sometimes it is easier to edit a grob using grid's editing functions - if the names of the relevant grobs can be found. In this case, they can be found, and the edit is straightforward - change colour of label from black to red or blue.

library(ggplot2)
library(grid)

df <- data.frame(a=rnorm(10),b=1:10,c=letters[1:10],d=c("one","two"))
p1 <-ggplot(data=df,aes(x=b,y=a))
p1 <- p1 + geom_text(aes(label = c, color=d, fontface="bold"))
p1 <- p1 + scale_color_hue(name="colors should match",breaks=c("one", "two"),
                 labels=c("should be salmon", "should be sky blue"))
p1

# Get the ggplot grob
g <- ggplotGrob(p1)

# Check out the grobs
grid.ls(grid.force(g))

Look through the list of grobs. The grobs we want to edit are towards the bottom of the list, in the 'guide-box' set of grobs - with names that begin with "label". There are two grobs:

label-3-3.4-4-4-4
label-4-3.5-4-5-4

# Get names of 'label' grobs.
names.grobs <- grid.ls(grid.force(g))$name 
labels <- names.grobs[which(grepl("label", names.grobs))]

# Get the colours
# The colours are the same as the colours of the plotted points.
# These are available in the ggplot build data.
gt <- ggplot_build(p1)
colours <- unique(gt$data[[1]][, "colour"])

# Edit the 'label' grobs - change their colours
# Use the `editGrob` function
for(i in seq_along(labels)) {
    g <- editGrob(grid.force(g), gPath(labels[i]), grep = TRUE,  
         gp = gpar(col = colours[i]))
}

# Draw it
grid.newpage()
grid.draw(g)

enter image description here

What if it was required that the keys be points rather than letters? It could be useful because the 'a' is a symbol in the plot, and it is a symbol in the legend key. This is not a simple edit, like above. I need a point grob to take the place of the text grob. I draw grobs in viewports, but if I can find the names of the relevant viewports, it should be straightforward to make the change.

# Find the names of the relevant viewports
current.vpTree()  # Scroll out to the right to find he relevant 'key' viewports.

viewport[key-4-1-1.5-2-5-2], viewport[key-3-1-1.4-2-4-2],

# Well, this is convenient. The names of the viewports are the same 
# as the names of the grobs (see above). 
# Easy enough to get the names from the 'names.grobs' list (see above). 
# Get the names of 'key' viewports(/grobs)
keys <- names.grobs[which(grepl("key-[0-9]-1-1", names.grobs))]

# Insert points grobs into the viewports:
#    Push to the viewport;
#    Insert the point grob;
#    Pop the viewport.
for(i in seq_along(keys)) {
   downViewport(keys[i])
   grid.points(x = .5, y = .5, pch = 16, gp = gpar(col = colours[i]))
   popViewport()
}
popViewport(0)

# I'm not going to worry about removing the text grobs. 
# The point grobs are large enough to hide them. 

plot = grid.grab()
grid.newpage()
grid.draw(plot)

enter image description here

Update

Taking account of @user20650 's advice to change the legend key (see the comment below):

p1 <-ggplot(data=df,aes(x=b,y=a))
p1 <- p1 + geom_text(aes(label = c, color=d, fontface="bold"))
p1 <- p1 + scale_color_hue(name="colors should match",breaks=c("one", "two"),
                 labels=c("should be salmon", "should be sky blue"))

GeomText$draw_key <- function (data, params, size) { 
   pointsGrob(0.5, 0.5, pch = 16, 
   gp = gpar(col = alpha(data$colour, data$alpha), 
   fontsize = data$size * .pt)) }

p1

Then proceed as before to change the colour of the legend text.

like image 99
Sandy Muspratt Avatar answered Sep 24 '22 15:09

Sandy Muspratt