Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
487 views
in Technique[技术] by (71.8m points)

r - Set standard legend key size with long label names ggplot

I am building a ggplot visualization in which some fill aesthetics have very long variable names, while other variable names are short. Adding long names changes the size of the legend key corresponding to the long text - lengthening it to match the text. I am wondering if there is a way to standardize the legend key height across all varibles, and change the spaces between the legend items.

I tried modifying theme(legend.key.height()) and theme(legend.key.width()) but that didn't solve the problem.

Here is example code:

#load neccesary package
library('ggplot2')

#create the dataframe
df <- data.frame(year = as.integer(c(1, 1, 1, 1, 1, 2, 2, 2, 2, 2)),
                 class = c('A', 'B', 'C', 'D', 'E'), 
                 value = c(50, 50))

#Create plot
g <- ggplot(df, aes(x = year, y = value, fill = class)) + 
  geom_col(position = 'stack') + 
  scale_fill_discrete(labels = c('This is an
extremely
long label
name', 'short label1', 'Another
long
label
name', 'short label3', 'short label4'))

Plots:

enter image description here

What I want is to have the same key size for all variables, with the white space between keys changing to accommodate the long text. So something that looks like this:

enter image description here

Trying g + theme(legend.key.height = unit(3, 'mm'), legend.key.width = unit(3, 'mm'))

Does not resolve the problem.

Any thoughts?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You can do this by defining your own class of legends. This is of course more verbose than a simple option in the theme and it can be handy to know some gtable/grid, but it gets the job done.

library(ggplot2)
library(grid)

#create the dataframe
df <- data.frame(year = as.integer(c(1, 1, 1, 1, 1, 2, 2, 2, 2, 2)),
                 class = c('A', 'B', 'C', 'D', 'E'), 
                 value = c(50, 50))

labs <-  c('This is an
extremely
long label
name', 'short label1', 
           'Another
long
label
name', 'short label3', 'short label4')

guide_squarekey <- function(...) {
  # Constructor just prepends a different class
  x <- guide_legend(...)
  class(x) <- c("squarekey", class(x))
  x
}

guide_gengrob.squarekey <- function(guide, theme) {
  # Make default legend
  legend <- NextMethod()

  # Find the key grobs
  is_key <- startsWith(legend$layout$name, "key-")
  is_key <- is_key & !endsWith(legend$layout$name, "-bg")

  # Extract the width of the key column
  key_col <- unique(legend$layout$l[is_key])
  keywidth <- convertUnit(legend$widths[2], "mm", valueOnly = TRUE)

  # Set the height of every key to the key width
  legend$grobs[is_key] <- lapply(legend$grobs[is_key], function(key) {
    key$height <- unit(keywidth - 0.5, "mm") # I think 0.5mm is default offset
    key
  })
  legend
}

ggplot(df, aes(x = year, y = value, fill = class)) + 
  geom_col(position = 'stack') + 
  scale_fill_discrete(labels = labs,
                      guide = "squarekey")

Created on 2021-01-20 by the reprex package (v0.3.0)

EDIT: If you want to edit the key background too:

guide_gengrob.squarekey <- function(guide, theme) {
  legend <- NextMethod()
  is_key <- startsWith(legend$layout$name, "key-")
  is_key_bg <- is_key & endsWith(legend$layout$name, "-bg")
  is_key <- is_key & !endsWith(legend$layout$name, "-bg")
  
  key_col <- unique(legend$layout$l[is_key])
  keywidth <- convertUnit(legend$widths[2], "mm", valueOnly = TRUE)
  
  legend$grobs[is_key] <- lapply(legend$grobs[is_key], function(key) {
    key$height <- unit(keywidth - 0.5, "mm")
    key
  })
  legend$grobs[is_key_bg] <- lapply(legend$grobs[is_key_bg], function(bg) {
    bg$height <- unit(keywidth, "mm")
    bg
  })
  legend
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...