R 将geom_文本中的图例文本颜色与符号匹配

R 将geom_文本中的图例文本颜色与符号匹配,r,ggplot2,legend,R,Ggplot2,Legend,我正在尝试使用geom\u 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 + sca

我正在尝试使用
geom\u 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

df绘图中的颜色与图例中的颜色相同,但即使将绘图符号fontface设置为粗体(或斜体),图例fontface仍保持原色。我不确定这是否是设计
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")
库(ggplot2)
图书馆(gridExtra)
#原始绘图(字体较大)

p1有时使用
网格
的编辑功能编辑一个grob更容易-如果可以找到相关grob的名称。在这种情况下,他们可以找到,编辑是简单的-改变颜色的标签从黑色到红色或蓝色

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

这很方便。视口的名称相同 #作为grob的名称(见上文)。 #很容易从“names.grobs”列表中获取名称(见上文)。 #获取“关键”视口的名称(/grobs)
keys此答案基于和的答案

要获得颜色:

  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)
我提供这个答案是因为在代码的第二部分中,在
mapply
函数中分配给
x$gp
的参数应该是
gpar
对象。这是我的答案中的一个错误,我正在纠正它

多谢各位


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

#原始代码,但带有对“缩放颜色”的精简调用(自
#我们将替换它)。
图书馆(GG2)

df感谢这个很好的技巧来匹配字体,但是-我实际上是在尝试将图例文本“应该是粉红色”和“应该是蓝色”与图例和情节符号匹配。e、 g文本“应该是粉红色”应该与字母“a”、“c”、“e”、“g”和“i”具有相同的颜色,而文本“应该是蓝色”必须与字母“b”、“d”、“f”、“h”和“j”具有相同的颜色。嗯,我想我下次需要更仔细地阅读这个问题@eipi10,这个问题不容易理解,OP应该写下
“这个图例文本字体应该是粉红色的”
。在阅读了上面评论的前半部分后,我认为他希望在情节上打印文本“应该是粉红色的”。我想可能性是无穷的:-)顺便说一句,你的胡言乱语实际上对我很有用!维杰;我认为现在事情继续发展,给A.S.K打勾是值得的,这样我就可以删除我的answer@user20650非常感谢。完成。这确实是一个更干净的解决方案,但您的贡献仍然有效!
# Find the names of the relevant viewports
current.vpTree()  # Scroll out to the right to find he relevant 'key' viewports.
# 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)
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
  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)
# 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())