ggplot2:如何使图例中的符号与图中的符号匹配

4

我正在尝试绘制一个图形,其中大多数数据点都是正常绘制的,但有一组数据点使用不同大小的符号。我希望图例也能显示相同的效果:大多数点正常显示,但异常点用不同大小的符号绘制。以下是一小段代码:

library(ggplot2)
x = c(1,2,1,2,3)
y = c(1,2,3,4,3)
vendor = c("x", "x", "y", "y", "z")
df = data.frame(x,y,vendor)

p <- ggplot(df) +
     aes_string(x="x", y="y", color="vendor") +
     geom_point(size=3, data=subset(df, vendor!="z")) +
     geom_point(size=5, data=subset(df, vendor=="z"))
ggsave("foo.pdf")

问题在于,在生成的图例中,所有点都用较大的(size=5)符号绘制,而不仅仅是那些属于厂商z的点。我希望在图例中使用较大的点绘制厂商z的点,并使用size=3绘制其他点。
(奖励问题:我真正想要的是一个更大的粗轮廓符号:不是圆圈,我想要一个甜甜圈。我知道shape=2可以绘制轮廓圆,但非常细。我宁愿有一个更粗的轮廓圆。我也想用三角形做同样的事情。有什么简单的方法吗?)
也许我应用得不对,但按照这个建议:ggplot2: Making changes to symbols in the legend 的方法加上 "guides" 行也没有帮助:
guides(size = guide_legend(override.aes = list(shape = 1)))

即相同的输出,在图例中所有三个供应商的符号大小为5
编辑后:非常好的答案,我很快就实现了。现在我已经添加了几行:
library(ggplot2)
x = c(1,2,1,2,3)
y = c(1,2,3,4,3)
vendor = c("x", "x", "y", "y", "z")
df = data.frame(x,y,vendor)

df$vendor_z <- df$vendor=="z"     # create a new column 

ggplot(df) +
  aes_string(x = "x", y = "y", color = "vendor", size = "vendor_z") +
  geom_point() +
  geom_line(size=1.5) +   # this is the only difference
  scale_size_manual(values = c(3, 5), guide = FALSE) 
  guides(colour = guide_legend(override.aes = list(size = c(3, 3, 5))))

ggsave("foo.pdf")

现在图例的大小已经恢复到3,包括那些带有供应商z的点。有什么解决方法吗?


顺便说一句,我是一个完全的 R 初学者,所以请随意批评我的代码,并帮助我使其更好! - jowens
1个回答

4

由于sizeaes_string之外,因此大小不适用于图例。此外,如果创建一个额外的列表示vendor == "z",那么使用ggplot的工作将更加容易。

以下是第一部分的解决方案:

df$vendor_z <- df$vendor=="z"     # create a new column 

ggplot(df) +
  aes_string(x = "x", y = "y", color = "vendor", size = "vendor_z") +
  geom_point() +
  scale_size_manual(values = c(3, 5), guide = FALSE) + 
  guides(colour = guide_legend(override.aes = list(size = c(3, 3, 5))))

请注意,vendor_zaes_string的参数。这将告诉ggplotsize特征创建图例。在函数scale_size_manual中,设置了size的值。此外,guide = FALSE可以避免只针对size的第二个图例。最后,size值应用于color图例。

enter image description here

Part2: 一个“甜甜圈”符号

ggplot中无法修改圆圈线条的大小。以下是一种解决方法:

ggplot(df) +
  aes_string(x = "x", y = "y", color = "vendor", size = "vendor_z") +
  geom_point() +
  geom_point(data = df[df$vendor_z, ], aes(x = x, y = y),
             size = 3, shape = 21, fill = "white", show_guide = FALSE) +
  scale_size_manual(values = c(3, 5), guide = FALSE) + 
  guides(colour = guide_legend(override.aes = list(size = c(3, 3, 5))))

在这里,使用geom_point绘制单个点,并使用数据子集(df[df$vendor_z, ])。我选择了size3,因为这是较小圆的值。 shape 21是一个可以指定fill颜色的圆形。最后,show_guide = FALSE避免新的shape覆盖图例特性。 enter image description here 编辑:第三部分:添加线
您可以使用参数show_guide = FALSE来禁止geom_line的图例。
ggplot(df) +
  aes_string(x = "x", y = "y", color = "vendor", size = "vendor_z") +
  geom_point() +
  geom_line(size=1.5, show_guide = FALSE) +   # this is the only difference
  scale_size_manual(values = c(3, 5), guide = FALSE) +
  guides(colour = guide_legend(override.aes = list(size = c(3, 3, 5))))

enter image description here


谢谢Sven!你的回答非常好。我在问题中添加了一点内容,想问如何使它与geom_line一起工作。 - jowens
在甜甜圈上...有没有办法让甜甜圈也出现在图例中?很好的技巧,将白色绘制在蓝色圆形之上。 - jowens
@jowens 我扩展了答案,并提供了包括线条的解决方案。在图例中为三个符号之一绘制白色覆盖蓝色圆圈可能会很困难,可能需要在ggplot之外进行一些hack。如果我找到答案,我会告诉你。 - Sven Hohenstein
一个非常周到和友善的回答,我很高兴接受。如果有人想要加入讨论,我希望看到以下几点:1)我实际上关心图例中的线条;在我的完整图表中,我有实线和虚线;2)如果我不必硬编码size=c(3,3,5),代码似乎更通用,因为如果我添加另一个供应商的数据,我必须手动更改它;3)我真正做的是展示供应商z是供应商y的一个特殊情况,所以我希望z看起来大部分像y但略有不同,并且不连接到y的线条。 - jowens
如果有人想要查看我正在尝试解决的实际问题,我在http://tinyurl.com/dyhcxh7上发布了一个简短的自述文件,其中包含源代码和生成的图形。 - jowens

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接