【问题标题】:Match legend text color in geom_text to symbol将 geom_text 中的图例文本颜色与符号匹配
【发布时间】:2014-06-28 13:57:36
【问题描述】:

我正在尝试将图例文本与使用geom_text 的因子变量生成的文本颜色进行颜色匹配。这是一个最小的工作示例:

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

我相信这是一个简单的解决方法。任何建议或参考以前的帖子都会有所帮助。我没有找到任何具体的内容。

【问题讨论】:

  • 维杰;我认为现在事情进展顺利,值得给 A.S.K 打勾——然后我可以删除我的答案
  • @user20650 谢谢。完毕。这确实是一个更清洁的解决方案,但您的贡献仍然存在!

标签: r ggplot2 legend


【解决方案1】:

这是一个使用 ggtext 并避免直接编辑 grobs 的解决方案。 (它确实涉及从绘图中提取颜色,但后续步骤更加用户友好。)

# Original code, but with a stripped-down call to `scale_color_hue` (since
# we're going to replace it).
library(ggplot2)
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(breaks=c("one", "two"))

# Load the `ggtext` library, which lets us style (parts of) text labels.
library(ggtext)
# Build the plot so we can extract the colors that were actually used.  (If you
# supply colors manually instead, this step isn't necessary.)
g1 = ggplot_build(p1)
# Add a scale with labels that are colored appropriately, using <span> tags.
# Also specify that legend labels should be processed with `element_markdown`.
p1 +
  scale_color_hue(name = "colors should match",
                  breaks = c("one", "two"),
                  labels = paste("<span style='color:",
                                 unname(unlist(unique(g1$data[[1]]["colour"]))),
                                 "'>",
                                 c("should be pink", "should be blue"),
                                 "</span>",
                                 sep = "")) +
  theme(legend.text = element_markdown())

【讨论】:

    【解决方案2】:

    此答案基于Mike H.question hereuser20650 从这个问题给出的答案。

    获取颜色:

      pGrob <- ggplotGrob(p1)
      g.b   <- pGrob[["grobs"]][[which(pGrob$layout$name=="guide-box")]]
      l     <- g.b[[1]][[1]][["grobs"]]
      # get grobs for legend symbols (extract colour)
      lg    <- l[sapply(l, function(i) grepl("GRID.text", i))]
      clr   <- mapply(FUN=function(x){x$gp$col},x=lg)
    

    然后使用以下方法

       gb  <- which(grepl("guide-box", pGrob$layout$name))
       gb2 <- which(grepl("guides", pGrob$grobs[[gb]]$layout$name))
       label_text <- which(grepl("label",pGrob$grobs[[gb]]$grobs[[gb2]]$layout$name))
    
       pGrob$grobs[[gb]]$grobs[[gb2]]$grobs[label_text] <- 
       mapply(FUN = function(x, y) {x[["children"]][[1]][["children"]][[1]]$gp <- gpar(col =y); return(x)},
              x =   pGrob$grobs[[gb]]$grobs[[gb2]]$grobs[label_text],
              y =  clr, SIMPLIFY = FALSE)
    

    之后,你会得到相同的输出文件

    grid.draw(pGrob)
    

    我提供这个答案是因为在代码的第二块中,在 mapply 函数中分配给 x$gp 的参数应该是 gpar 对象。这是Mike H. 的回答中的一个错误,我正在修复它。

    谢谢。

    【讨论】:

      【解决方案3】:

      有时使用grid 的编辑功能更容易编辑 grob - 如果可以找到相关 grobs 的名称。在这种情况下,可以找到它们,并且编辑很简单 - 将标签的颜色从黑色更改为红色或蓝色。

      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))
      

      查看 grobs 列表。我们要编辑的 grobs 位于列表的底部,在 grobs 的“guide-box”集中 - 名称以“label”开头。有两个 grobs:

      标签-3-3.4-4-4-4
      标签-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)
      

      如果要求键是点而不是字母怎么办?它可能很有用,因为“a”是图中的一个符号,它是图例键中的一个符号。这不是一个简单的编辑,就像上面一样。我需要一个点 grob 来代替文本 grob。我在视口中绘制 grobs,但如果我能找到相关视口的名称,那么进行更改应该很简单。

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

      视口[key-4-1-1.5-2-5-2],视口[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)
      

      更新

      考虑到@user20650 更改图例键的建议(请参阅下面的评论):

      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
      

      然后像以前一样继续更改图例文本的颜色。

      【讨论】:

        【解决方案4】:

        绘图中的颜色与图例中的颜色相同,但即使您将绘图符号字体设置为粗体(或斜体),图例字体仍保持纯色。我不确定这是否是ggplot2 设计或预期行为的疏忽。对于某些颜色,粗体字体看起来比普通字体更饱和,使它看起来像是不同的颜色。

        无论如何,这里有一个比弄乱杂物容易得多的杂物,但这可能会让你得到你想要的。将geom_text 与普通字体一起使用,但连续执行两到三遍(或更多),这样您就会得到过度绘图。这将使符号和图例看起来都类似于粗体字体,因为两者都将被过度绘制,并且图例符号将始终与绘图符号看起来相同。

        这是一个例子:

        library(ggplot2)
        library(gridExtra)
        
        # Original plot (with larger font size)
        p1 <- ggplot(data=df) +
          geom_text(aes(x=b, y=a, label=c, color=d), fontface='bold', size=8)
        p1 <- p1 + scale_color_hue(name="colors should match",breaks=c("one", "two"),
                                      labels=c("should be pink", "should be blue")) +
                   ggtitle("Original Plot with Bold Symbols and Plain Legend")
        
        # New version with overplotting. (You don't need to specify 'plain' fontface. 
        # I've just included that to emphasize what the code is doing.)
        p1.overplot <- ggplot(data=df) +
          geom_text(aes(x=b, y=a, label=c, color=d), fontface='plain', size=8) +
          geom_text(aes(x=b, y=a, label=c, color=d), fontface='plain', size=8) +
          geom_text(aes(x=b, y=a, label=c, color=d), fontface='plain', size=8)
        p1.overplot <- p1.overplot + 
          scale_color_hue(name="colors should match",
                          breaks=c("one", "two"),
                          labels=c("should be pink", "should be blue")) +
          ggtitle("Both symbols and legend are overplotted 3 times")
        

        【讨论】:

        • 感谢这个匹配字体的好技巧,但是 - 我实际上试图将图例文本“应该是粉红色”和“应该是蓝色”与图例和情节符号相匹配.例如,文本“应该是粉红色”应该与字母“a”、“c”、“e”、“g”和“i”具有相同的颜色,而文本“应该是蓝色”的颜色必须与“b”、“d”、“f”、“h”和“j”
        • 好吧,我想我下次需要更仔细地阅读这个问题!
        • @eipi10,这个问题不好理解,OP应该写成"this legend text font should be pink"。看了上面评论的前半部分,我以为他想在剧情上印上“应该是粉红色”的文字。我想可能性是无穷无尽的 :-) 顺便说一句,你的拼凑实际上对我很有用!
        猜你喜欢
        • 1970-01-01
        • 2021-08-09
        • 2022-08-17
        • 1970-01-01
        • 2020-01-21
        • 2021-04-27
        • 2011-12-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多