Featured image of post ggplot2 Layer (二) Collective Geoms (上)

ggplot2 Layer (二) Collective Geoms (上)

关于 ggplot2 中的 Collective Geoms

1. 什么是Collective Geoms

在前面一节我们初步了解了单独的几何层(Individual Geoms),这些图形的一个特点是一个观测值(Observation),在表格中通常为一行,对应着一个图形对象。举一个例子,在散点图中,每一个点都是由数据集中的一个观察值绘制而成。在ggplot2中还有另一类Geoms,也就是本节要了解的Collective Geoms。与Individual Geoms不同,Collective Geoms的一个图形对象往往是由多个观察值绘制而成,例如箱线图。然而还有一些Geoms是介于Individual和Collective之间,例如线图或者路径图;这些图形有多条线段组成,而每一条线段由两个端点(观察值)连接而成。 对于Collective Geoms,我们怎么控制观察值与图形的映射关系?这里我们将用到 **group **属性。接下来我们看几个例子。

2. 在同一图层分组别绘制图像

先看下面一个来自于nlme包的数据集Oxboys

1
2
3
4
5
6
7
8
9
data(Oxboys, package = "nlme")
head(Oxboys)
#>   Subject     age height Occasion
#> 1       1 -1.0000    140        1
#> 2       1 -0.7479    143        2
#> 3       1 -0.4630    145        3
#> 4       1 -0.1643    147        4
#> 5       1 -0.0027    148        5
#> 6       1  0.2466    150        6

该数据集有四个变量,衡量了26个男生(Subject)的年龄(age),身高(height)变化。 假如我们想了解每个男生年龄与身高的关系,我们该怎么做?按照以往的经历,我们可能会写出下列代码:

1
ggplot(Oxboys,aes(age,height))+geom_point()+geom_line()

杂乱的图

这张图给人的第一感觉就是杂乱。原因是我们期望的图形应该是从左到右的横向的连线,我们希望看到的是每一个男生个体身高随年龄变化的趋势,但这张图却是竖向的连接了所有观察点,与我们所期盼的相差甚远。 如何解决这个问题?这里我们引入group属性,即group=Subject,对每一个男生单独分类绘制。

1
ggplot(Oxboys,aes(age,height,group=Subject))+geom_point()+geom_line()

group=Subject

我们能看到,加上group之后,我们就能正常绘制出根据个体分类的图像了。 这里还有一个问题:在R语言中我们知道分类变量一般我们会将它设置为因子factor),group属性是否必须要对应因子变量? 原数据集中Subject变量本身已经是因子,为了确认group是否能正确处理除因子以外其他的变量类型,我们将Subject转换为数值变量:

1
Oxboys$Subject=as.numeric(Oxboys$Subject)

接下来我们再来绘制:

1
ggplot(Oxboys,aes(age,height,group=Subject))+geom_point()+geom_line()

group=Subject

可以看到,即使是数值变量,group属性依然能够正确处理。那么在ggplot中因子与其他变量在绘图时有区别吗?别急,我们马上会看到。

3. 在不同图层绘制不同组别

有时候,我们可能会想给图像加上一些总结性质的信息;例如在上面的个体年龄与身高变化线图中增加一条拟合的折线,表示对于所有男生来说年龄与身高的总体变化。我们可能会这么做:

1
ggplot(Oxboys,aes(age,height,group=Subject))+geom_point()+geom_line()+geom_smooth(method="lm",se=FALSE)

杂乱的图

这张图简直就是disaster😢.拟合的线性回归线与每一个男生的折线图重叠在了一起。我们需要的并不是拟合每一个男生的变化,我们只想要一条能够反映整体变化趋势的回归线。 为什么每个类别都被绘制了一条回归线?其实问题还是出在group上。再看下面这段代码:

1
ggplot(Oxboys,aes(age,height))+geom_point()+geom_line(aes(group=Subject))+geom_smooth(method="lm",se=FALSE)

geom_smooth

我们能看到,这才是我们所需要的图形。与之前代码不同的是,我们将group属性从ggplot()中已到了geom_line()这一层中;因为一旦将group放置在ggplot()中,将对后面所有的层都适用,也就是说,回归线也将被分类绘制。 可是为什么之前我们同样有两个图层:geom_point和geom_line,为什么散点没有出现绘制错误?聪明的你一定能想出来为什么😎。(散点分不分类画出来不都一样吗🤣)

4. 覆写默认的分类

看以下这幅图像:

1
2
ggplot(Oxboys, aes(Occasion, height)) + 
  geom_boxplot()

geom_boxplot

如果我们想要将每一个男生的数据点单独连接起来,怎么办?我们可能会尝试:

1
2
3
ggplot(Oxboys, aes(Occasion, height)) + 
  geom_boxplot()+
  geom_line(color="blue")

不添加group属性

我们能看到,在不添加group属性时,默认的分类方式还是单独将属于同一Occasion的所有数据点连接起来。 为了覆写默认的group,我们需要显式的指明group:

1
2
3
ggplot(Oxboys, aes(Occasion, height)) + 
  geom_boxplot()+
  geom_line(color="blue",aes(group=Subject))

指定group

欢迎关注我的公众号和小红书呀~

微信公众号 小红书
Wechat Xiaohongshu