• 新鲜事R语言
  • 诚邀广大R语言、数据可视化爱好者和我们一起搬迁升级谢益辉著作《现代统计图形》

Cloud2016《现代统计图形》涉及 ggplot 的地方(包括第五章对 ggplot 的专门介绍),@yihui 常用 qplot 来做演示。我的个人经验是实际用哥哥作图时很少会用qplot;Hadley 在 ggplot 书第二版里放弃了第一版先介绍 qplot 的安排,认为不利于初学者掌握哥哥语法。《现代统计图形》里涉及 ggplot 的内容本来不多,qplotggplot 混合出现或许会给一些初学者造成困扰。

我建议将书里的qplot 统一成 ggplot() + geom_xx() 的形式,不知意下如何?

    Cloud2016 我弄的话就是蜗牛速度了(参考 TNT 擂台赛)。你要是拿出前两天的干劲儿来,重画一遍也就是一两天的事儿啊。

    Cloud2016 qplot 被比喻为拐杖 (crutch) 很贴切:靠它容易起步;拄久了妨碍正常走路;丢掉它才能跑起来。

    qplot() 我觉得只是方便 Base R 用户在 ggplot2 起步。对于连 Base R 都没基础的,qplot() 实在没必要;而习惯了 Base R 的用户,即使学会了 qplot(),仍然会在进入 ggplot2 的过程里很吃力。

    qplot() 是个很尴尬的存在。

      Cloud2016 我把第五章的 qplot 换成了 ggplot + ... 的形式,另外,修改了原文主题部分的一个小问题。我想把改动推到你的库里,但是好像默认会推送我这个分枝上我和大鹏之前的所有改动。我不知道怎么单独推动关于第五章的改动。库在这里:https://github.com/liechi/msgtv

        Liechi 我注意到你 Fork 的是大鹏的库

        你应该直接 Fork 我的库,修改内容后,往分支 first-edition-update 推送 PR。这个分支用来接收第一版的更新,我也是 Git 操作还不太熟,所以另开这么一个分支,免得把 master 主分支搞崩了!

        P.S.
        master 主分支我暂时不想修改,每积累一点量稳定后更新一次,前两天我又猛推了不少更新到主分支,现在我要克制自己,不然太浪费时间了,也搞的我精疲力尽

          dapengde 我刚看了下你的极乐净土版现代统计图形,我注意到你在使用 BT 之前的分栏方式对比展示 Base R 和 ggplot2 绘制的图形,我建议你使用 cowplot 包来安排,我想会方便很多,详情请见 <https://github.com/XiangyunHuang/MSG-Book/issues/29> 此外,毕竟基于 cowplot 的排图方式已经有很成功的实践,见 <https://serialmentor.com/dataviz/histograms-density-plots.html> 支持不同图形系统的组合和强大的注释功能

            Cloud2016 我想直接 fork 你的库,但是收到提示说我已经 fork 过了,然后提示上显示的是 msgtv 这个库。

              Liechi 你建立 PR 的时候,上流 repo 选我的仓库,而不是大鹏的仓库

                Cloud2016 我选择了你的库发 PR,这样以前我跟大鹏作的所有的修改都会被推过来,但我希望推送的只是关于第五章的最近两次修改。我能全推过来,但你只接受最近两次 commits 吗?

                  Cloud2016 这个 issue 我之前看到了。cowplot 我不熟,暂时没顾上尝试,不过我猜那样的话可能每个插图大小都要调整,眼下实在没精力,可能将来统稿时统一修改比较容易吧。况且,这个极乐净土版的练习性和实验性很强,基本属于自娱自乐,我并不确定这个并排显示有没有意义……

                    dapengde 原来你调用了 ggpubr 包,那也无所谓了,它包裹了 cowplot 所以也具有很强的注释能力

                    Liechi 我想了想,你还是把 PR 提给 @dapengde 吧,操作上更方便一些

                      Cloud2016 好的。

                      Liechi 我做了个任务分配表在项目首页。你要是正在画的话,过来注明一下吧,免得同时重复劳动。4.1 到 4.9 章我今天应该能做完。

                        dapengde Liechi

                        我建议在 ggplot2 里复现 Base R 图形能不能不仅仅形似,而且做到神似,神似不是要追求真假难辨,而是在深入了解 Base R 绘图的过程后(这其中很可能涉及统计的内容,如直方图),将其等价地转换为 ggplot2 代码。如果把图库这一章按照这要求复现出来,我想应该能在统计和可视化两个层面上更上一层楼,这对于提高这两方面的水平是非常有意义的。练习的意义就会更深一层,毕竟我发现两位大侠都是 ggplot2 的粉丝,基础的操作都会。

                        为了说清楚,以现代统计图形之图库之直方图为例,

                        # 这是 Base R 版
                        par(mfrow = c(2, 2), mar = c(2, 3, 2, .5), mgp = c(2, .5, 0))
                        data(geyser, package = "MASS")
                        hist(geyser$waiting, main = "(1) freq = TRUE", xlab = "waiting")
                        hist(geyser$waiting, freq = FALSE, xlab = "waiting", main = "(2) freq = FALSE")
                        hist(geyser$waiting, breaks = 5, density = 10, xlab = "waiting", main = "(3) breaks = 5")
                        hist(geyser$waiting, breaks = 40, col = "red", xlab = "waiting", main = "(4) breaks = 40")
                        # 这是 ggplot2 版
                        library(ggplot2)
                        library(cowplot)
                        p <- ggplot(aes(waiting), data = geyser)
                        p1 <- p + geom_histogram(breaks = seq(40, 110, by = 5))
                        p2 <- p + geom_histogram(breaks = seq(40, 110, by = 5), aes(y = stat(density)))
                        p3 <- p + geom_histogram(breaks = seq(40, 110, by = 10))
                        p4 <- p + geom_histogram(breaks = seq(42, 108, by = 2), fill = "red", color = "black")
                        plot_grid(p1, p2, p3, p4, labels = c(
                          "(1) freq = TRUE",
                          "(2) freq = FALSE",
                          "(3) breaks = 5",
                          "(4) breaks = 40"
                        ), ncol = 2)

                        注意 ggplot2 版的 breaks 的设置,它来源于 Base R 版的绘图结果,不是试出来的。以第一个子图为例

                        h <- hist(geyser$waiting, main = "(1) freq = TRUE", xlab = "waiting")
                        h
                        $breaks
                         [1]  40  45  50  55  60  65  70  75  80  85  90  95 100 105 110
                        
                        $counts
                         [1]  2 26 29 25 17 10 34 59 44 35 14  3  0  1
                        
                        $density
                         [1] 0.0013377926 0.0173913043 0.0193979933 0.0167224080 0.0113712375
                         [6] 0.0066889632 0.0227424749 0.0394648829 0.0294314381 0.0234113712
                        [11] 0.0093645485 0.0020066890 0.0000000000 0.0006688963
                        
                        $mids
                         [1]  42.5  47.5  52.5  57.5  62.5  67.5  72.5  77.5  82.5  87.5  92.5  97.5
                        [13] 102.5 107.5
                        
                        $xname
                        [1] "geyser$waiting"
                        
                        $equidist
                        [1] TRUE
                        
                        attr(,"class")
                        [1] "histogram"

                        此节的另一个例子是

                        demo("hist_geyser", package = "MSG")
                        df <- data.frame(x = seq(40, 110, 5), y = 0, 
                                         xend = seq(40, 110, 5), yend = ht)
                        p2 + geom_density(fill = "lightgray", color = "black") +
                          geom_segment(aes(x = x, y = y, xend = xend, yend = yend),
                            data = df, lty = 3
                          )

                          Cloud2016 我明白你的意思。这个提议是好的,只是需要时间。

                          除了因为懒之外,我眼下是想把能画的先画出来,目标不是跟原图在细节上(如 breaks)都一致,而是用 ggplot 图把文字表达的意思体现出来就算过关了。

                          仍然以直方图为例,geom_histogram(breaks = seq(40, 110, by = 5)) 固然可以完全重现图(1),然而原文的意思是想展示 R 直方图使用默认参数值的效果(见该图的 caption),那么我觉得,ggplot2 重绘时也应该展示 geom_histogram() 的默认参数值效果,结果就导致跟原图的 breaks 不一致。

                          此节的另一个例子也一样。原书是想展示往直方图添加密度曲线的便利性。便利嘛,越简短越好,所以只需 + geom_density() 就行了。geom_segment() 固然跟原图一致,然而我觉得可能离文字就远了。

                          说到底,到底是向原图看齐,还是向文字看齐……

                          不论如何,都是可以以后慢慢修改的嘛。

                          Cloud2016 这些提议要不都写在 issues 里吧?将来一个一个攻破。放这儿的话怕时间长就忘了。