写在前面

后天就要回学校了,有点舍不得,舍不得家里2米的大床,舍不得我安静的书房,舍不得我专属的健身空间,舍不得一下楼就能吃到妈妈做的饭菜,舍不得老爸每周给我送水果熬的鸡汤鸽子汤,当然也舍不得家乡的朋友们。

其实,还有一个舍不得的,就是家中的这一平方米。

5a2cc3820da605a3452b2cf32f6fd069.png 4e5cc195bdb9b85a773bc4e64e275168.png 1477b903d6daae64190c8a4a843cb648.png

在家的7个多月时间里,有1/2的时间都是在这一平米度过,在这里处理了数据,完成了我真正意义上的第一篇英文paper和第一篇中文小论文,也自学了许多有趣的知识,写了几篇阅读量还可以的推送。

所以,想在今天,临出发前,和大家,再分享一个有趣、简单但非常实用的小知识,我相信科研小白以及已经上路的研究生博士生们都会用到的。

毕竟回北京以后,我可能就又恢复到foodie美食博主的身份啦!

关于“绘图拼接”

“绘图拼接”,字面上的意思就是,把画好的一堆图,按照你想要的样式、结构,拼起来,成为一个大的、有更多信息和内容的图。

可能只是两个图简单的横向、纵向拼接。

1740c35e043224b2781d3b425a1904a5.png 5aa8e8d5d7b5b1b3046e638bdca88e25.png

也可能是多个类似主题图的拼接,且共用了一个legend。

cdbc62e942150793e9b2b78147f59cc2.png

也可能是两个复杂的图的拼接,每个复杂的图片里面还含有更多子图,reveal更多不同的信息。

那为何要掌握“绘图拼接”呢?因为大多数的期刊,在投稿的时候,都会在投稿须知里面说到,图片数量不允许超过多少多少,有的说不许超过5个,有的不许超过6个,也有可能是4个!

所以,如果把这些子图都分散开,那可能一个主题的图,就要占用4-6个图片数量了,无法表达论文的全部内容。

当然,也有人说,那就分开自己拼呗,Word里面手动拼!

6c9fc77364e0b9c8edbcb3c9ccde3965.png

是的,我曾经···也是这么干的··· 但是这个做法,实际上非常的不方便,每次调整图的时候都要手动调节位置就算了,关键有时间真的做不到“整整齐齐”!其实你们可以看到我的(b)和(d)图是有点歪的。

所以,如果以后想有进步,写出更好的论文,投更好的期刊,这种“手动拼接”做法是不建议的!

那如何解放双手,更简单的实现拼接呢?

先说说R中的par()和customLayout

其实之前,我也是用R写代码拼图的,但是只会简单的par(),比如par(mfrow(2,2)),创建一个2*2的画布,然后分别画四个子图。但是我发现,这种方法画的图①是不太美观②拼接的也不太智能(也可能我没深入挖掘这个方法),虽然它很实用,可以完美拼接R中的base绘图对象,但是我后来还是慢慢抛弃了他。

当然,customLayout也不错,听名字就知道很“自定义”和“为所欲为”,可以拼接base绘图对象也可以拼接ggplot2绘图对象。比如:

2e542410cc03658572daaa84db1b4201.png

先创建一个叫lay1的画布,里面有四个子图空间(我这里没画具体的子图),宽比例是3:2(左:右),高比例是2:1(上:下)。

3d5d684f3d8eb7d4e3272f62920c9d37.png

然后创建一个叫lay2的画布,同样是四个子空间,但是宽比例是3:5(左:右),高比例是2:4(上:下)。

4f85571d079452baade83eeec2c9e1b7.png

然后就可以通过lay_bind_col()或者lay_bind_row()进行按列或者按行的拼接啦,比如我这里按列拼接两个画布。并且指定了lay1宽度是lay2宽度的三倍。

8fcb50d55970e7cd7dbfa5404a284fb7.png

所以大家可以使用customLayout包尽情的customize!

学会用R中的cowplot和patchwork包

前面叽叽喳喳半天,终于到了本推送的核心内容了,其实我最想介绍的是cowplot和patchwork这两个包。

为何说这两个包呢?因为他的拼接思路更符合我们人脑画画的思路,step by step,且和ggplot2包的结合特别好。而ggplot2是R中最强大的绘图包,也是我最常用的,所以,我决定向大家推荐这二者!

首先要注意一下,cowplot包是可以直接install的,但是patchwork是要在github中加载的。如图所示。

fd5e5e8827c1617b1d3864352e620863.png

把这两个包安装完之后,就可以进行拼接了。由于本推送的重点在“拼接”,而非“画图”,所以不会具体解释画图步骤,并且使用的也都是ggplot2中最常见的画图语法。

下面所有图的例子都来自R中内置数据库iris, mtcars和diamonds。

使用cowplot包进行拼接

大家可以发现,我们可以利用cowplot中的plot_grid()进行拼接,上下两幅图同样是纵向拼接,但是上面的图p5就拼接得整整齐齐,而下面图的Y轴并没有对齐。原因就是下面的图p6没有设置align="v",这里的“v”是vertical的意思。所以如果是水平对齐,就要设置align="h",以保证X轴水平对齐。

dfb273817679c1affc37668dbf682a15.png e71597140a3d207cc6e19be645e0d876.png 2a009e3f817bbcc047808c5b2df65236.png

同样地,如果我想给拼接的两个图,添加标签,以及设置相对宽度,高度呢?

25eb2902d7141c8522a74d3010e80938.png

这里我做了水平拼接,设置了相对宽度是1:2,给两个图加了“A”和“B”标签。

是不是很方便很简单???

4b726ee5a882c03f201dd7f2af561799.png

那如果有三个图呢?或者更多的图呢?

我们可以采取一个plot_grid()嵌套的方式来完成,比如下面这个图,我先plot_grid()对p7和p8完成拼接,并标记为“B”和“C”,然后再用这一个整体和p9进行拼接。

d175098c56f0c878aae6aae2314c5d98.png 19cc02e96e3c0257c29a022a933c5139.png

当然,我们还有一个画图思路,同样可以实现上面这个图的拼接,只不过是通过ggdraw()来完成的,而不是plot_grid()。

通过代码可以发现,这和我们小时候画画的思路是完全一样的!!!

e1bbbcbde2a5933755eb681677764e17.png

先把p10和p11拼接起来,两个图的相对宽度是1:2,拼起来的图叫做p12。

然后开始拼接,先画一个空图ggdraw(),然后画图p9,后面四个数字x,y,z,w分别表示p9原点的相对坐标,和长宽占比,同理开始画p12,然后给p9和p12标签,并说明标签的位置和颜色。拼接出来如图所示。

8a029ee1a0998beed18aa627b83d66f9.png

当然,你也可以三个分别直接画上去,进行拼接。和上面对比一下代码、图,有没有看出啥区别!

e7bb399cbb5f708bc4271169c6a7a8b5.png a1955eedc4d776ce43512a4a89b2b409.png

当然,有人会说,有没有嵌套的拼接呢?

有的呀!

仔细看,这里是先ggdraw(p7),也就是说,先画好p7,然后后面的draw_plot(p8)的一系列操作就都是在p7画图基础上去完成啦!这样就实现了嵌套!

f5df93a325551ecc278db673479fb39d.png fa1f172bd3e295b47066630df43b6238.png

我相信有人会问,如何共用一个legend呢?

这里就有一个get_legend()的操作,也就是说我先保留了p10的图例,去掉了p11的图例,即theme(legend.position="none"),然后我获取p10的图例,然后通过plot_grid()对去掉图例的p10和本身没有图例的p11进行拼接,最后再进行一个复合拼接,将他们与图例拼在一起。

(下图只是一个我随便做的例子,图例对不上,重点看代码)

460cea0b9de2863afb3c2b4042ffefd5.png 042caa5fbb730958dadbbb25ad4ded46.png

简单聊聊patchwork

其实能会使用cowplot()基本就可以完成我们正常的科研绘图和拼接工作了,但是为啥要聊聊patchwork呢?因为他的语法实在是太简单!太直观!太可爱啦!

它的表达方式有很多种,比如:加减乘除,比如交集并集,比如花括号,但是其拼接思路就和我们做加减乘除一样简单!

0729b4208b3680343fb35e286933b06b.png ba9897845d80df482f9df97cf0f96300.png

该图是由第一行代码画出来的

((p10+p11)+p7+p8+plot_layout(ncol=2))

大家可以自已试试其他两行代码,画出来有什么区别呢?自己动手加强理解!

至于最后图片的导出问题,比如如何导出高质量的图片,对dpi进行调整,请参考我之前写的“科研小白可能会遇到的期刊图片导出问题”

写在最后

终于完成了在家的最后一篇推送,个人认为写的过程还是很开心、充实的,因为写推送与我而言,是爱好,也是利用输出方式巩固知识的一种方式。

为了写这篇推送我也把这些代码重复写了很多次,加深了理解,所以说practice makes perfect,希望能够对大家有所帮助吧!!!

欢迎大家阅读、转发、打赏、点赞一条龙呀~

Logo

汇聚原天河团队并行计算工程师、中科院计算所专家以及头部AI名企HPC专家,助力解决“卡脖子”问题

更多推荐