为何含ggplot的R条件编译代码无法生成tikz图形?
问题背景
我用命令R -f figures.R运行脚本(从未使用RStudio),想实现仅重新生成已删除的论文图形,但碰到了怪事:
- 套在
if语句里的ggplot代码,生成的.tex文件只有两行注释;把if去掉后,代码又能正常生成完整图形文件。 - 另一段用基础绘图函数(非ggplot)的相似代码,放在
if里却能正常工作。
出问题的ggplot代码
figure <- '../paper/figures/recall_by_choices.tex' if (!file.exists(figure)) { tikz(file=figure,width=3.5, height=2) mem1percent <- mem |> group_by(choices, success1) |> summarize(count=n()) |> mutate(Percent = count/sum(count) * 100) mem1percent |> ggplot(aes(x=factor(choices), y=Percent, fill=success1)) + geom_bar(stat='identity', position=position_dodge(), color='black') + labs(x="Choices", fill="7-day Recall") + scale_fill_manual(values=c('black','grey')) dev.off() }
能正常运行的基础绘图代码
figure <- '../paper/figures/hmn_density.tex' if (!file.exists(figure)) { tikz(file=figure,width=7, height=4) hmn <- table(ifelse(surveys$how_many == 'own' | surveys$how_many == 'n/a' | surveys$how_many == 'lots' | surveys$how_many == '', NA, ifelse(surveys$how_many == 'inf' | nchar(surveys$how_many) > 5, 100000, as.numeric(surveys$how_many)))) plot(density(hmn), main='', xlab='Number of Choices') dev.off() }
运行时的警告信息
当if条件成立时,两段代码分别输出:
summarise()has grouped output by 'choices'. You can override using the.groupsargument.
null device
1
null device
1
Warning message:
In ifelse(surveys$how_many == "inf" | nchar(surveys$how_many) > :
NAs introduced by coercion
问题原因与解决办法
核心问题:ggplot的惰性渲染逻辑
ggplot和基础绘图函数的渲染机制完全不同:
- 基础绘图函数(比如
plot())是即时渲染,调用后直接把图形输出到当前打开的设备(这里是tikz创建的tex文件)。 - ggplot是惰性求值:你写的ggplot代码只是创建了一个图形对象,并没有立刻把它画出来。在R控制台这种交互式环境里,这个对象会自动被打印渲染,但在
if语句块这种非顶层代码环境中,R不会自动执行打印操作,所以图形根本没被输出到tikz设备里,最后dev.off()关闭设备时,只有空的注释内容被写入文件。
而去掉if语句后,ggplot对象处于顶层代码,R会自动打印它,所以能正常生成图形。
解决办法:显式打印ggplot对象
在if语句块里,手动调用print()来渲染ggplot对象即可,另外可以给summarize()加个参数消除分组警告:
figure <- '../paper/figures/recall_by_choices.tex' if (!file.exists(figure)) { tikz(file=figure,width=3.5, height=2) mem1percent <- mem |> group_by(choices, success1) |> summarize(count=n(), .groups = "drop") # 消除summarise的分组警告 p <- mem1percent |> ggplot(aes(x=factor(choices), y=Percent, fill=success1)) + geom_bar(stat='identity', position=position_dodge(), color='black') + labs(x="Choices", fill="7-day Recall") + scale_fill_manual(values=c('black','grey')) print(p) # 显式打印,让ggplot渲染到tikz设备 dev.off() }
内容的提问来源于stack exchange,提问作者Iiridayn
相关产品推荐
相关产品推荐

