引题
如果你的代码是这样的:
pdf("figure1_PCA3.pdf", width = 3.5, height = 3) biplot(p, x = 'PC1', y = 'PC2', colby = 'Group', shape = 'Group') dev.off()那么你的pdf文件将会显示文件损坏,无法打开。
那么,我们该怎么样让他可以正常打开呢?
很简单:
pdf("figure1_PCA3.pdf", width = 3.5, height = 3) p1 <- biplot(p, x = 'PC1', y = 'PC2', colby = 'Group', shape = 'Group') print(p1) dev.off()这样,你就可以打开你的pdf文件了。
同样的绘图函数,同样的参数,仅仅是加了一行print(p1),损坏的PDF就变正常了。这不是巧合,更不是R的bug。这是你对R的图形系统理解还不够深。
核心原因:ggplot2是“懒”的
biplot()函数来自PCAtools包。这个函数返回的对象不是一张画好的图,而是一个包含所有绘图指令的ggplot对象。
关键在于:当你直接在一个函数调用后面不加print()时,R的行为取决于运行环境。
在R交互式环境(命令行/RStudio控制台)中:
biplot(p, x = 'PC1', y = 'PC2') # 自动打印,图会显示R会自动调用print(),所以你能看到图。
在脚本中或pdf()设备内部:
pdf("output.pdf") biplot(p, x = 'PC1', y = 'PC2') # 不会自动打印 dev.off()R不会自动打印。 图形设备打开了,但没有任何内容被“画”进去。你只是创建了一个ggplot对象,然后丢弃了它。PDF文件虽然被创建,但里面是空的——这就是你看到的“损坏文件”。
print(p1)做了什么?
p1 <- biplot(...) # 创建ggplot对象,存到p1 print(p1) # 主动告诉R:把这个图画到当前设备上print()函数会触发ggplot对象的渲染,把图形真正“绘制”到当前打开的PDF设备中。有了内容,PDF文件自然就是完整的、可打开的。
为什么有时候不加print()也能成功?
这是因为某些绘图函数内部已经包含了print()或类似机制。例如基础R的plot()、hist()等函数,它们直接向设备输出图形,不返回需要打印的对象。
ggplot2体系的设计哲学不同:它分离了“创建图形对象”和“渲染图形”两个步骤。这种设计让你可以在创建对象后继续修改它(比如加+ theme_light()),最后统一渲染。
但这种设计的代价就是:在非交互式环境中,你必须显式调用print()。
一句话记住:在脚本中写ggplot2代码,保存对象,然后用print()或ggsave()输出。不要依赖自动打印。
这不是R的缺陷,而是ggplot2设计上的取舍。理解了这一点,你就再也不会被“PDF损坏”困扰了。
云生信团队简介
“ 云生信” 团队致力于为生命科学领域研究者提供专业的生物信息学服务 ,主营业务包括 定制生信分析、生信云服务器租赁及托管、生信课程、算法开发、数据挖掘、数据库开发 等服务。 团队打造的“ 云生信” 自动化分析平台 ,是国内首个标准化分析+个性化分析的开放型生物信息学在线平台。(http://www.biocloudservice.com/ )
目前“ 云生信” 团队已获得40余项独立软件著作权证书 ,还有3项发明专利。
服务领域
定制分析业务: 根据客户需求 ,订制个性化数据分析。 包含自有测序数据高级分析、公共 数据库挖掘分析 ,整合分析等; 热点涵盖: 机器学习、单细胞测序、孟德尔随机化、 网络 药理学、 GBD等临床数据库挖掘分析、分子对接及分子动力学模拟等......
生信云服务器: 超十年服务器深度操作经验 ,提供卓越服务器租赁与托管服务。 用户享受一对一技术支持:软件安装、环境搭建等;近20P规模服务获众多客户续费与推荐。
生信课程: 专注生信、 专注实操; 内容涵盖单细胞、 空转、 MR等热点方向以及机器学习等 前沿技术重点讲解 ,热点全面 ,持续更新生信前沿热点。
感兴趣的老师可以扫描下方二维码联系我们哦!!