每个组的线条前面绘制数据点/ggplot2中type="o"的等效方法

5
假设我想绘制一个图,其中点和线都出现在每个组中的其对应线条的前面。特别地,我希望用红色填充点绘制组1,其中点由一条线连接,但我希望仅用蓝线绘制组2,并将其绘制在组1之上。例如,在基本图形中:
set.seed(101)
dd <- data.frame(x=rep(1:10,2),
         y=rep(1:10,2),
                 f=factor(rep(1:2,each=10)))
dd$y[11:20] <-     dd$y[11:20] + rnorm(10)
d1 <- subset(dd,f=="1")
d2 <- subset(dd,f=="2")

par(cex=1.5)
plot(y~x,data=d1,bg="red",pch=21,type="o")
lines(y~x,data=d2,col="blue",lwd=2)
legend("bottomright",c("group 1","group 2"),
       col=c("black","blue"),
       pch=c(21,NA),
       pt.bg=c("red",NA),
       lty=1,
       lwd=c(1,2))

enter image description here

(我的实际数据稍微复杂一些。)我试图在ggplot2中干净地完成这个任务,但感觉有点疯狂。

如果我先绘制点再绘制线,组1的点会被同一组中的线覆盖:

 library(ggplot2); theme_set(theme_bw())
 g0 <- ggplot(dd,aes(x,y,fill=f,colour=f,shape=f))+
     scale_fill_manual(values=c("red",NA))+
     scale_colour_manual(values=c("black","blue")) +
     scale_shape_manual(values=c(21,NA))
 g0 + geom_point()+  geom_line()
 ggsave("order2.png",width=3,height=3)

enter image description here

如果我在画点之前画线,第二组的线会被第一组的点覆盖:
 g0 + geom_line()+  geom_point()
 ggsave("order3.png",width=3,height=3)

enter image description here

所需顺序为(组1行),(组1点),(组2行)。我可以通过再次手动叠加几何图形来实现这一点,一次处理一个组,但这样做太丑了。
 g0 +  geom_line() + geom_point()+ 
     geom_point(data=d1)+
     geom_line(data=d2,show.legend=FALSE)
 ggsave("order4.png",width=3,height=3)

我认为这个问题的“最佳”解决方案是编写一个低级别的geom_linepoint,以达到所需效果;我已经研究了一些相关内容,但它并非完全简单...有人可以建议更干净、更简单的解决方案吗?

enter image description here


1
自定义几何图形似乎并不太困难,因为您可以重复使用现有组件,并将它们简单地包装在一个新的容器中。然而,与任何ggplot2的修改一样,存在未来可能会出现不可预知错误的风险。 - baptiste
我认为它比你想象的要(1)更难一些,(2)有点不那么脆弱,因为现在有一个官方描述的机制来创建新的几何对象(在我的问题中链接)。我开始着手开发geom_linepoint()(这是我想要已久的东西,但意识到geom_path(用于扩展/修改的适当基础几何对象)比我能够快速处理的要复杂一些(例如,期望在<1小时内完成)... - Ben Bolker
1
你可能是对的,我在这个问题上有不同的看法。2009年我写了一些自定义几何图形,其中一个是为了模仿 type = 'b',当时还有一个名为 ggExtra 的附加包,编写了一个维基页面来描述这个过程等等。所以我觉得很奇怪,为什么每个人突然都认为扩展 ggplot2 是一件事,并且在内部更加稳健。多年来,我见过许多我贡献的东西被打破,这使我对引入自定义解决方案更加谨慎和警惕。 - baptiste
好的,看起来现在扩展更受到“祝福”(并由ggplot2开发人员宣传),但这当然不是保证。 - Ben Bolker
你现在已删除的解决方案有什么问题吗? - Ben Bolker
1个回答

1
这是一个“低技术”1的解决方案。下面是一个函数,它为给定分组变量的每个级别依次添加一条线层和一个点层。
linepoint = function(data, group.var, lsize=1.2, psize=4) {
  lapply(split(data, data[,group.var]), function(dg) {
    list(geom_line(data=dg, size=lsize),
         geom_point(data=dg, size=psize)) 
  })
}

ggplot(dd, aes(x,y, fill=f, colour=f,shape=f))+
  scale_fill_manual(values=c("red",NA))+
  scale_colour_manual(values=c("black","blue")) +
  scale_shape_manual(values=c(21,NA)) +
  linepoint(dd, "f")

enter image description here


1 相对于编写新的几何形状而言,这种方法比较"低技术水平"。@baptiste(现已删除)的答案确实创建了一个新的几何形状,并且似乎完成了任务,所以我不确定他为什么要将其删除。


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