50套R语言SCI绘图脚本:从环境配置到发表级出图实战
简介这是一套包含五十套R语言科研绘图代码的资源包面向有一定R基础的研究人员覆盖柱状图、箱线图、小提琴图、热图、火山图、韦恩图、雷达图、桑基图、生存曲线、ROC曲线、PCA分析、GSEA/KEGG富集可视化等常用SCI图表类型。把input文件夹中的数据替换为自己的数据在Rstudio中运行脚本即可出图适合论文配图、课题探索与文章复现。包体共六百九十个文件约九十点二兆字节。核心为五十个R脚本另有二百九十三张PNG示例图、一百一十一个XLS数据表、一百零二个HTML富集分析页、五十五个PDF说明文档和若干txt/gmt辅助文件便于对照结果理解参数。已有一千一百一十人学习下载这套即取即用的绘图模板覆盖多组差异比较、生存分析和富集分析等场景能显著节省科研绘图时间。1. 50套R语言SCI绘图脚本为什么我建议你直接从这套代码改起如果你跟我一样被SCI审稿人打回过“图太简陋”或者在Rstudio里从零写一张火山图写到半夜那你应该能理解科研绘图真正贵的不是画图那一下而是从数据清洗到出图参数的整个过程。这套资源我拿到手第一反应是它把我过去两年积累的ggplot2、pheatmap、ComplexHeatmap、ggpubr等用法直接做成了50套可跑的R语言脚本每套自带示例数据和出图逻辑适用场景覆盖转录组、生信富集、临床预后这类最常被要求“重画”的图形。它不是一个教学PPT也不是把一堆代码扔给你自己琢磨。它更像一个可复现的起点你要做的不是看懂每一行而是找到跟你课题最接近的那一套替换数据、改改颜色和坐标轴就能在半小时内得到一张符合投稿规范的矢量图。适合正在写毕业论文、补实验数据、赶返修材料的人也适合刚接触R语言但不想从函数手册啃起的新手甚至是只想把origin那套图换成R出图风格的熟手。2. 环境先行Rstudio中把这套绘图脚本跑起来的配置顺序2.1 版本与包管理先用一棵“依赖树”看这套脚本很多人在R语言绘图资源上翻车的第一个点不是代码本身而是R版本和包版本对不上。拿到这50套脚本后别急着立刻source先去看它依赖哪些包。我过了一遍核心依赖集中在 ggplot2、dplyr、tidyr、ggpubr、pheatmap、ComplexHeatmap、RColorBrewer、scales、gridExtra 和 survival 这几个上其中ggplot2的版本建议在3.4以上但不是越新越好。判断方法很简单脚本头注释里如果写了library(ggplot2)那么ggplot2版本至少得支持theme()和element_text()的最新参数。我一般会打开Rstudio的Session Info看一眼或者直接在控制台跑一句packageVersion(ggplot2)把结果和脚本注释里要求的版本对照。版本追得太新有些老脚本用的aes_string()在新版里被废弃反而要改代码版本太老after_stat()这类新写法的图又出不来。所以这套资源的思路是尽量避开版本敏感的函数遇到确实用了新语法的脚本脚本里基本会有注释说明需要哪个版本以上。依赖树还有一个容易忽略的分支系统级依赖。pheatmap本身是纯R包但ComplexHeatmap会依赖circlize而circlize在Linux服务器上安装时需要系统有libcurl、libxml2的开发头文件。你在自己Windows电脑上装好了换到服务器上Rscript跑就报configuration failed这不是脚本问题是系统环境缺东西。我一般先在本地把图跑通再决定要不要上服务器。2.2 三步导入从下载到第一次出图拿到下载包后我习惯的步骤是这样的。先把压缩包解压到一个没有中文和空格的路径比如D:/Rplot_50然后打开Rstudio用setwd()设置工作目录再跑一遍依赖安装。这里我给一个可以直接抄的检查流程cd /d/Rplot_50 Rscript -e options(reposhttps://cloud.r-project.org); install.packages(c(ggplot2,dplyr,tidyr,ggpubr,pheatmap,RColorBrewer,scales,gridExtra))这条命令用Rscript从命令行触发包安装options(repos...)指定了清华或云镜像源避免默认源下载超时。如果你在Rstudio里操作也可以直接点右下角Packages面板的Install但命令行方式的好处是会输出每个包的安装日志哪个包失败一眼就能看到。安装完成后先别急着看50个脚本去找名字类似01_quick_start.R或00_check_environment.R的那个文件这类脚本通常是作者用来做环境自检的。自检脚本一般会做三件事检查所有依赖包是否可加载、检查工作目录是否正确、跑一张最简单的散点图验证绘图链通不通。跑通了说明你的Rstudio环境已经能承接后面的复杂脚本。如果自检脚本报there is no package called xxx那说明这个包没装上回到上一步单独装。装的时候注意看有没有ERROR: dependencies yyy are not available这种提示有的话要先装yyy这是R包依赖的传递硬装会一直报错。这三步走完理论上你已经能打开任意一个编号脚本选中全部代码点Run。第一次跑我建议用Rstudio的Source按钮而不是Run因为Source会完整执行脚本变量名、函数定义和最后保存文件的语句都不会漏。之后每次修改参数再按需选中局部代码段执行。2.3 目录结构先知道去哪改颜色和尺寸这类绘图资源通常会把数据、脚本和输出分成三个目录。我看到的这套里面结构大致是下面的样子目录/文件作用你需要动它的时机data/存放每个脚本配套的示例数据多为CSV或TXT换成你自己的表达矩阵或临床表时scripts/50个R脚本按图形类型编号改配色、改坐标轴、改输出格式时output/跑完脚本后自动生成的图片文件基本不用动脚本会自动写入theme_scipub.R统一的主题函数控制字体、网格线、图例想让所有图风格一致时优先改这里README.md每个脚本的用途说明和依赖清单不确定某个脚本是画什么图时先看这里我特别建议你花半小时把theme_scipub.R或类似的公共函数文件读一遍。因为这50个脚本里可能有20个都在ggplot2后面加了 theme_scipub()这个公共函数决定了所有图的字体大小、坐标轴粗细、图例位置和背景网格。你后期想让所有图的标题从14号改成16号不需要去50个脚本里逐个找改这一个函数就行。很多人拿到资源后直接挑一个最像的脚本往里面塞自己的数据结果图出来的样式和自己想象的不一样然后又去逐行改。我遇到过类似的翻车改完数据跑出来坐标轴标签间距挤在一起以为是数据问题折腾半天才发现是主题函数里legend.position写死导致图例占了主图位置。所以我的习惯是正式改数据之前先跑一遍原始脚本把原图保存好之后再改这个对比步骤能省很多排查时间。3. 从数据到成图的完整链路火山图与富集气泡图的改法3.1 火山图看懂 log2FoldChange 与 padj 的双重过滤火山图是转录组差异表达分析的标准出图也是这套资源里最常被单独拎出来改的脚本。原理上它把每个基因的差异表达倍数取log2作为横轴把校正后的p值取负log10作为纵轴于是显著上调的基因在右上角显著下调的在左上角不显著的全部沉到底部。脚本里最关键的一段是阈值过滤常见写法是|log2FoldChange| 1且padj 0.05。library(ggplot2) library(dplyr) # 读取差异表达结果通常来自DESeq2或edgeR输出 deg - read.csv(data/deg_results.csv, row.names 1) # 双重过滤倍数变化绝对值大于2校正p值小于0.05 deg - deg %% mutate(threshold ifelse( abs(log2FoldChange) 1 padj 0.05, ifelse(log2FoldChange 0, up, down), ns )) p - ggplot(deg, aes(x log2FoldChange, y -log10(padj), color threshold)) geom_point(size 1.2, alpha 0.7) scale_color_manual(values c(up #C0392B, down #2874A6, ns #B0B0B0)) theme_classic(base_size 14) labs(x log2 Fold Change, y -log10(adj P value)) ggsave(output/volcano_plot.pdf, p, width 6, height 5, dpi 300)这里有个容易被新手忽略的细节mutate()里嵌套了两个ifelse()。外层的ifelse(abs(log2FoldChange) 1 padj 0.05, ...)先做综合判断是候选差异基因才进入下一步内层再用log2FoldChange的正负区分上下调。如果只写一层判断会出现“padj显著但倍数变化极小”的基因被错标成显著这就是火山图上那些不该出现在两侧的散点的来源。scale_color_manual(values ...)里的三个颜色值我建议固定住上调用红色下调用蓝色不显著用灰色。这是期刊最常接受的三色方案不要换成渐变色。ggsave()里我写了width6, height5, dpi300这是单栏图的典型尺寸如果是双栏图宽度改成7.5到8英寸更合适。这个尺寸后面每套脚本都会用到先记住这个参数。3.2 富集气泡图GeneRatio、Count 与 p.adjust 三列怎么喂进去富集气泡图是GO或KEGG富集分析结果的标配图形它用横轴GeneRatio表示注释到该通路的基因占全部基因的比例纵轴是通路名称气泡大小代表基因Count颜色深浅代表p.adjust。这套资源里画气泡图的脚本核心是把clusterProfiler的输出整理成ggplot2能直接识别的长格式。library(ggplot2) # 假设enrich结果已存在包含GeneRatio、Count、p.adjust、Description四列 go - read.csv(data/GO_enrich_results.csv) # 把Description转成因子并按GeneRatio排序避免y轴乱序 go$Description - factor(go$Description, levels go$Description[order(go$GeneRatio)]) p - ggplot(go, aes(x GeneRatio, y Description)) geom_point(aes(size Count, color p.adjust), alpha 0.8) scale_color_gradient(low #B03A2E, high #F5B7B1) scale_size_continuous(range c(3, 10)) theme_bw(base_size 13) labs(x GeneRatio, y NULL, color adj P value, size Count) ggsave(output/go_bubble.pdf, p, width 7, height 6, dpi 300)很多人在这一步会遇到图出来之后y轴通路顺序乱七八糟的问题。原因不是数据错了而是没把Description转成因子并按数值排序。ggplot2的y轴字符变量默认按字母表排序你必须手动指定因子水平。上面代码里order(go$GeneRatio)这一步就是把通路按GeneRatio从小到大排好再把这个顺序固化成因子水平。scale_color_gradient()的参数我一般会按“富集的通路p.adjust越小越红”来调low端是显著high端是不显著。注意这里和火山图相反火山图颜色区分上下调富集图颜色连续渐变二者不要套同一个配色习惯。气泡大小方面scale_size_continuous(range c(3, 10))里的范围要根据你自己数据里Count的分布微调Count最大值只有5的时候range上限设20就会让你的气泡全部变成大饼。3.3 配色与出图尺寸把 300 DPI 写进函数而不是记在脑子里这套50个脚本里几乎所有ggsave()的参数风格都是统一的width、height用英寸为单位dpi300。但真正到投稿的时候你会发现不同期刊对图片尺寸的要求不一样。有的要单栏86mm有的要双栏170mm还有的只要像素宽度。所以我拿到这套资源后做的第一件事就是把出图参数从所有脚本里抽出来写成一个统一的保存函数。save_fig - function(p, filename, width 6, height 5, device pdf) { ggsave(filename, plot p, width width, height height, dpi 300, device device) }这个函数的好处是你只需要记住save_fig(p, fig1.pdf)这一句所有脚本里的ggsave()都可以替换成它。要转成PNG或TIFF时改device参数就行。我一般PDF用于投稿PNG用于组会PPTTIFF用于部分期刊系统要求的分辨率检查三者用的都是同一个函数入口不会出现同一个图在两种格式下尺寸不一致的情况。字体方面也有一个统一约定所有文本元素建议用theme()统一设置familysans不要在一张图里混用Arial和Helvetica。R在Linux服务器上渲染PDF时波恩字体匹配不像Windows那么智能混用字体可能在最后印刷时被字体替换出现图注字体和其他图不一致的尴尬。统一用sans会省很多事。4. 这批脚本里最容易被忽略的三个硬点4.1 因子顺序图例和坐标轴不听你话的根源做过几个图之后你就会发现ggplot2里图例顺序、坐标轴顺序和你的预期对不上十有八九是因子顺序问题。比如你有一个分组变量Group值是c(Control, Treat, Model)读入R后默认是字符型ggplot2按字母排序于是图例顺序变成Control, Model, Treat完全打乱了你论文里分组的逻辑顺序。解决方式是把分组变量先转成factor并显式指定levelsdata$Group - factor(data$Group, levels c(Control, Model, Treat))这套资源里的脚本普遍已经写了这一行所以直接跑没问题。但换成你自己的数据时要注意你的分组名和原脚本的分组名是否一致。不一致时factor()的levels里写的是原脚本的组名你的数据会变成NA跑出来的图直接缺一个分组而且不报错。这是静默错误里最坑的一种。我一般的检查顺序是换数据后先跑一个unique(data$Group)看返回的分组列表再回过去对照脚本里的levels二者完全一致才继续。这一步能省掉后面至少十分钟的排查。4.2 分组颜色固定换数据后颜色不要跳另一个我见过很多人踩的地方是同一张散点图数据换了一个批次跑出来两组的颜色对调了。原因在于你没显式固定颜色映射。ggplot2的默认配色是从当前数据的分组水平推导的数据顺序变了因子水平顺序变了颜色分配自然就变了。在脚本里用scale_color_manual(values c(...))或scale_fill_manual()固定颜色时values的顺序一定要和你数据的因子水平顺序对应。推荐写法是levels_of_group - c(Control, Model, Treat) colors_for_group - c(#1F618D, #B03A2E, #117A65) data$Group - factor(data$Group, levels levels_of_group) p - ggplot(data, aes(x time, y value, color Group)) geom_point() scale_color_manual(values colors_for_group)这里遵循一个原则levels定义和colors定义分开写不要直接在scale_color_manual()里写颜色字符串。这样当你的数据分组顺序变化时只需调整levels颜色自动跟着对应。资源里有一小部分脚本直接把颜色写在scale_color_manual里我建议你拿到手后统一改成这种分开写的形式不然下次复用一定会踩颜色跳变的坑。4.3 字体与中文PDF 导出发虚的常见原因很多R语言绘图脚本在屏幕上预览时一切正常一导出PDF再打开中文标签变成方框或者文字边缘发虚。这不是因为你眼睛花而是R的默认PDF设备对字体处理不完整。Windows环境下Rstudio里直接ggsave(fig.pdf)用的cairo后端对中文支持时好时坏尤其是ggplot2里element_text(familySimSun)这类中文字体设置导出后几乎必出问题。我在这套资源的实际使用中把出图设备统一改成device cairo_pdf中文字体才稳定下来。具体到代码里是这样ggsave(output/fig_chinese.pdf, plot p, width 6, height 5, device cairo_pdf())注意这里device cairo_pdf()是带括号的调用不是字符串传参。如果你传device pdf走的是系统默认的pdf后端中文字体还是可能丢失。另外如果你的图里本身不需要中文我强烈建议图内所有标签都用英文投稿时也能避免字体匹配问题。把中文留给Excel里的原始数据列名画图时再改成英文标签是代价最小、最稳妥的做法。5. 避坑手册R语言科研绘图常见的五个翻车现场5.1 散点标签全部挤成一坨黑疙瘩现象画富集图或韦恩图时geom_text()或geom_label()加的标签在图上挤成一团交叠在一起完全看不清。原因ggplot2的geom_text()默认不会自动避让。标签位置是由你指定的x和y决定的当多个点的坐标接近时文本自然叠在一起。很多人以为是字体太小改小字号后发现更糊了。解决改用ggrepel包的geom_text_repel()。它会自动计算标签间的重叠并做偏移代价是运行速度变慢。我一般在标注基因名、通路名时用geom_text_repel(size3, max.overlaps20)。如果你不想要自动偏移带来的随机性也有一个笨办法手动给坐标列乘一个1.02的偏移系数把相邻标签稍微分开。ggrepel是这套资源环境里最好用的后悔药。5.2 Rstudio里跑中文文本图出来全是乱码现象脚本注释里有中文或者数据文件里的分组名称是中文跑出来的图例、坐标轴标签全部变成一个个方块或问号。原因Windows下R的默认locale可能不是UTF-8读取CSV时用了系统默认编码把UTF-8的中文读成了乱码后面画图时乱码跟着进了图。解决读CSV时明确指定编码read.csv(data/xxx.csv, fileEncoding UTF-8)。如果还乱就把fileEncoding改成GBK试试因为部分Windows数据源导出的CSV是GBK编码。另外Rstudio里File Reopen with Encoding可以直接看到当前文件的真实编码。我的一般习惯是先把所有数据文件统一转成UTF-8无BOM格式再在脚本里固定写fileEncodingUTF-8一劳永逸。5.3 拼多图时图例重复出现占了一整行空间现象用gridExtra::grid.arrange()或cowplot::plot_grid()把四个小图拼成大图时每个小图都带着自己的图例拼完之后图例重复还占掉了大量绘图区域。原因拼图前小图各自生成了独立的图例拼图函数默认不做去重。解决在拼图前从每个子图里提取图例只保留一个其余全部删掉。这里给一个常用写法library(ggplot2) library(gridExtra) # p1、p2、p3、p4 是四个小图 # 先删掉p1以外的图例 p2_no_legend - p2 theme(legend.position none) p3_no_legend - p3 theme(legend.position none) p4_no_legend - p4 theme(legend.position none) # 保留p1的图例通过legend.position调整位置 grid.arrange(p1, p2_no_legend, p3_no_legend, p4_no_legend, ncol 2)实际投稿时期刊编辑对小图图例重复这件事非常敏感经常直接打回要求重拼。我更推荐的做法是四张小图都用theme(legend.positionnone)去掉图例然后用cowplot::get_legend()单独提取一个图例放到拼图的下方或右侧这样拼出来干净也专业。5.4 坐标轴截断后截断处毫无标记现象为了让图更好看想截断坐标轴直接在scale_y_continuous(limitsc(0, 50))里写死范围结果超范围的数据点全部消失而且截断处没有提示标记。原因limits的作用是裁掉数据而不是截断坐标轴。ggplot2本身不提供简单的坐标轴截断标记功能直接写limits会把超出范围的数据静默删掉审稿人一眼就能看出异常。解决不要用limits做数据截断改用coord_cartesian(ylim c(0, 50))。两者区别是coord_cartesian只放大可视区域不删除数据点超出的数据点仍然参与统计和位置计算只是不显示。如果你的图形要求体现代谢或表达量差异很大最好的处理是保留完整坐标轴而不是截断或者使用分面图把高表达组单独放在一个子图里。5.5 PDF导出后在阅读器里文字发虚、线条毛糙现象同一个代码输出的PNG很清晰PDF放大到200%后线条发虚文字边缘不锐利。原因R的默认PDF设备在部分环境下没有开启cairo抗锯齿或者你导出的PDF实际是矢量没有真正嵌入字体。另外ggplot2默认的line宽度是以mm为单位过细的线在印刷时会被削平。解决导出时用cairo_pdf()设备并且把线条粗细整体调大一号。在主图脚本里可以把geom_line(linewidth0.8)这类参数统一改成1.0以上特别是方框、坐标轴线用theme(axis.line element_line(linewidth0.8))。如果你要投稿的期刊接受TIFF直接导300 DPI的TIFF比PDF更省心字体问题完全绕开。6. 改脚本不变形把50套固化成一个科研绘图流水线6.1 用 config.R 把 DPI、字体、配色收拢到一处这50套脚本最大的复用价值不是每张图的代码本身而是里面沉淀的绘图习惯。我建议你新建一个config.R把散落在各脚本里的公共参数集中起来。比如字体统一用sans分辨率固定300 DPI常用的上调配色、下调配色、不显著配色都定义成变量。这样后续你改任何一个图时只需要改config.R所有脚本的风格自动跟着更新。# config.R BASE_SIZE - 14 FIG_DPI - 300 COL_UP - #C0392B COL_DOWN - #2874A6 COL_NS - #B0B0B0 FONT_FAMILY - sans之后的脚本里所有硬编码的theme_classic(base_size14)、dpi300都可以替换成引用这些常量。好处是当你准备投稿BMC系列需要把全图字体调到16号时只需改BASE_SIZE一处。6.2 用我自己的 theme_scipub() 兜底我拿到这套资源后的习惯做法是把它的公共主题函数复制一份改成自己的theme_scipub()里面默认开启legend.position right、panel.grid element_blank()、axis.line element_line(linewidth0.8)。然后对自己所有新图强制走这个主题。这样做最大的好处是你课题组里所有图风格强制统一不会出现一篇文章里三张图三种背景网格的情况。6.3 输出自检清单最后贴上我每次出图前必过一遍的清单检查项检查方法图例顺序是否和论文分组顺序一致levels(data$Group)所有坐标轴标签是否包含单位目测字体统一导出的PDF在300%下是否有锯齿样本点是否被坐标轴截断检查coord_cartesian而非limits颜色是否色盲友好转成灰度图看对比度DPI是否300用R读回PDF检查页面尺寸与实际像素从那以后我每次拿到新的绘图脚本都会强制走一遍这套流程——先看依赖再跑原图改配置最后过自检清单。照着这套做50套图跑下来基本不会再在投稿前夜被审稿人打回来重画。希望帮到你。本文还有配套的精品资源点击获取