ggplot2可以在一个图例中分别控制点大小和线条大小(线宽)吗?

Sco*_*ott 10 r graph legend ggplot2

ggplot2用于绘制数据点组和连接每个组的均值的线组的示例,使用相同的aesfor shape和for 映射linetype:

p <- ggplot(mtcars, aes(gear, mpg, shape = factor(cyl), linetype = factor(cyl))) + 
  geom_point(size = 2) +
  stat_summary(fun.y = mean, geom = "line", size = 1) +
  scale_shape_manual(values = c(1, 4, 19))
Run Code Online (Sandbox Code Playgroud)

问题是,相对于线符号,图例中的点符号看起来有点太小而无法看到:

p

尝试在图例中放大点大小也会扩大线宽,因此在这里没有用.

p1 <- p + guides(shape = guide_legend(override.aes = list(size = 4)))
Run Code Online (Sandbox Code Playgroud)

P1

如果线宽是一种独特的美学,那将是很好的size.我尝试添加

+ guides(linetype = guide_legend(override.aes = list(size = 1)))
Run Code Online (Sandbox Code Playgroud)

这只是一个警告.

> Warning message:
In guide_merge.legend(init, x[[i]]) : Duplicated override.aes is ignored.
Run Code Online (Sandbox Code Playgroud)

这似乎没有什么区别或者,如果我移动linetype aes的出ggplot()和入stat_summary().如果我只想要点符号,我可以通过这种方式消除图例中的线条.

p2 <- p + guides(shape = guide_legend(override.aes = list(size = 4, linetype = 0)))
Run Code Online (Sandbox Code Playgroud)

P2

相反,(保持小点状符号的图形本身)我想要一个单一的与传说大一点的符号,这最后的图像细线符号作为第一个形象.有没有办法做到这一点?

MrF*_*ick 10

确实似乎很难独立设置这些属性.我只能想出一个黑客.如果您的实际数据差别很大,则可能需要进行调整.但我所做的是用来override.aes设定点的大小.然后我进入并构建了绘图,然后手动更改了实际的低级网格对象中的线宽设置.这是代码

pp<-ggplot(mtcars, aes(gear, mpg, shape = factor(cyl), linetype = factor(cyl))) + 
  geom_point(size = 3) +
  stat_summary(fun.y = mean, geom = "line", size = 1) +
  scale_shape_manual(values = c(1, 4, 19)) +
  guides(shape=guide_legend(override.aes=list(size=5)))

build <- ggplot_build(pp)
gt <- ggplot_gtable(build)

segs <- grepl("geom_path.segments", sapply(gt$grobs[[8]][[1]][[1]]$grobs, '[[', "name"))
gt$grobs[[8]][[1]][[1]]$grobs[segs]<-lapply(gt$grobs[[8]][[1]][[1]]$grobs[segs], 
    function(x) {x$gp$lwd<-2; x})
grid.draw(gt)
Run Code Online (Sandbox Code Playgroud)

神奇的数字"8"是gt$grobs[[8]]$name=="guide-box"我知道我正在传说的地方.我不是最好的网格图形和gtables,所以也许有人可能会建议一个更优雅的方式.

  • 注意:为了使事情变得更加复杂,“geom_path.segments”有时可能隐藏在“gTree”中(因此在本答案中的“sapply()”命令中找不到)。我花了很长时间才弄清楚如何访问“gTree”中嵌套的“grob”;他们是它的“孩子”。因此语法看起来像 `gt$grobs[[mn]][[1]][[1]]$grobs[[i]]$children`,其中 `i` 索引每个名为 `"GRID.gTree 的 `grob` “`在`gt`中。然后可以迭代答案中使用的类似过程来调整嵌套的“段”。 (2认同)

San*_*att 5

使用该grid功能grid.force(),ggplot中的所有grob对grid's编辑功能都是可见的,包括图例键。因此,grid.gedit可以使用,并且可以使用一行代码来完成对图的所需编辑。另外,我增加了图例键的宽度,以便清楚线段的不同线型。

library(ggplot2)
library(grid)
p <- ggplot(mtcars, aes(gear, mpg, shape = factor(cyl), linetype = factor(cyl))) + 
  geom_point(size = 2) +
  stat_summary(fun.y = mean, geom = "line", size = 1) +
  scale_shape_manual(values = c(1, 4, 19)) +
  theme(legend.key.width = unit(1, "cm"))

p

grid.ls(grid.force())    # To get the names of all the grobs in the ggplot

# The edit - to set the size of the point in the legend to 4 mm
grid.gedit("key-[-0-9]-1-1", size = unit(4, "mm"))    
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

保存修改后的图

  g <- grid.grab()
  ggsave(plot=g, file="test.pdf")
Run Code Online (Sandbox Code Playgroud)

  • @Valentine那是因为您正在保存原始的 ggplot 对象,而不是修改后的屏幕网格对象。一种方便的方法是 grid.grab() 屏幕上的对象,然后保存。也就是说,在保存命令之前插入 g &lt;- grid.grab(),但一定要保存 g。请参阅编辑。 (2认同)