今天讲一个小技巧,首先数据还是得有,很简单地生成一些随机数:

set.seed(2019-10-23)
d <- data.frame(val=abs(rnorm(20)), 
                type=rep(c('A', 'B'), 10))

20个数长这样子:

          val type
1  0.04625141    A
2  0.28000082    B
3  0.25317063    A
4  0.96411077    B
5  0.49222664    A
6  0.69874551    B
7  0.82134409    A
8  0.70966741    B
9  1.56752284    A
10 1.12881681    B
11 0.82488089    A
12 0.19897743    B
13 0.76739568    A
14 0.70597703    B
15 0.24332380    A
16 0.55423292    B
17 2.49008811    A
18 1.35153628    B
19 2.13711738    A
20 0.92299795    B

开始进入主题,我们首先用ggplot2来画个图。

library(ggplot2)
ggplot(d, aes(type, val, colour=type)) + geom_point()

毫无惊喜,毫无意外地画出了散点图,因为这个两个组的数据,正如我们有实验组和对照组一般,我们画个箱式图吧。

ggplot(d, aes(type, val, colour=type)) + geom_point() +
  geom_boxplot(aes(fill=type), colour = 'black', width=.2, 
               position=position_nudge(x=-.2))

依然没有惊喜,你可能只学到用position_nudge去调整一个位移而已,这里为什么要用箱式图呢,因为箱式图不同于我们散点,它用的不是原始数据来画图,而是原始数据的统计量(四分位数)来画图,而这些统计量,你并没有提供给ggplot2,它能够画出来,是因为geom_boxplot已经帮你算了。

接下来,就要讲今天的重点,我们经常也需要计算一些统计量,然后拿来画图,这时候你怎么搞,当然是先计算,算好了,再拿来画图。so easy….

但这里我想要介绍的技巧是你不需要跳出ggplot2去计算,算好才回到ggplot2,而是直接就在ggplot2里算,这怎么搞?你需要做的,就是在图层的data这个参数中定义一个函数,然后这个函数会去应用于ggplot2中传入的data,而计算出来的统计量,就会被用于这个图层去画图。语言是苍白的,让我们来点code:

library(ggplot2)
library(dplyr)
ggplot(d, aes(type, val, colour=type)) + geom_point() +
  geom_boxplot(aes(fill=type), colour = 'black', width=.2, 
               position=position_nudge(x=-.2)) +
  geom_pointrange(data = function(d) {
    group_by(d, type) %>%
      summarize(mean=mean(val), sd=sd(val))
    }, aes(y=mean, ymin=mean-sd, ymax=mean+sd), 
    position=position_nudge(x=.2), size=2)

这里geom_pointrange里的data就是一个函数,这个函数计算了均值和方差,然后被用来画图:

这个属于黑魔法,一般人我不告诉他。