使用ggplot+grid修改图表后PNG保存异常:轴标题被拉长截断
问题描述
使用tidyverse、ggh4x、showtext等包绘制嵌套分面柱状图,初始图表可正常显示并保存为PNG。但用grid包添加分面条带间的垂直线后,修改后的图表在RStudio查看器显示正常,用png()或ggsave()保存为PNG时,Y轴标题被拉长且截断,需要解决保存图像与查看器显示一致的问题。
解决方案
问题核心是ggplot对象转为gtable后,直接用plot()渲染再保存时,showtext字体渲染与设备尺寸适配出现冲突,加上axis.title.y使用ggtext::element_markdown(),进一步加剧了布局计算偏差。以下是两种有效解决方法:
方法1:用grid.draw()替代plot()渲染gtable
grid::grid.draw()能更好适配showtext的字体渲染逻辑,避免轴标题布局异常。修改保存代码如下:
png( filename = "image.png", width = 15.5, height = 8, units = "cm", res = 300 ) grid::grid.draw(g) # 替换原代码中的g %>% plot() dev.off()
方法2:用ggsave()保存并指定兼容设备
若偏好ggsave(),需明确指定cairo设备提升渲染兼容性:
ggsave( filename = "image.png", plot = g, width = 15.5, height = 8, units = "cm", dpi = 300, device = function(...) png(..., type = "cairo") )
额外优化建议
- 尽量避免直接修改gtable内部结构(如替换strip的children),可改用
ggh4x自带的分面样式设置,或annotation_custom()添加垂直线,减少布局计算异常风险。 - 若必须修改gtable,修改后可调用
gtable::gtable_squash_rows()/gtable::gtable_squash_cols()重新校准布局,确保元素尺寸正确。
完整修正后代码
library(tidyverse) library(ggh4x) library(showtext) library(grid) library(ggtext) font_add("Bookman Old Style", "BOOKOS.TTF") showtext_auto() df <- tibble::tibble( estacion = c( "HU22_2", "HU33_3", "HU11_1", "SV33_3", "SV11_1", "SV22_2", "QE11_1", "QE22_2", "QE33_3", "SJ11_1", "SJ22_2", "TI11_1", "TI22_2" ), quebrada = rep(c("yauH", "teiS", "reuQ", "\U{E9}soJ", "aniT"), rep(3:2, 3:2)), n = c(14L, 13L, 11L, 17L, 16L, 16L, 14L, 9L, 9L, 10L, 9L, 9L, 6L), etiqueta = c("14", "13", "11", "17", "16", "16", "14", "9", "9", "10", "9", "9", "6"), ) # 绘制初始图表 grafico <- df %>% ggplot(aes(x = estacion, y = n)) + geom_col(width = 1, position = position_dodge(0.5)) + ggh4x::facet_nested(cols = vars(quebrada), switch = "x", scales = "free_x", space = "free_x") + theme(axis.line = element_blank(), axis.ticks = element_blank(), axis.text.y = element_text(angle = 0, size = 29), axis.title = element_text(face = "bold", size = 38), panel.background = element_blank(), plot.margin = margin(t = 0.8, r = 0.8, unit = "cm"), panel.grid.major.x = element_blank(), panel.grid.minor.y = element_blank(), panel.grid.major.y = element_line(colour = "gray"), legend.text = element_text(size = 30), text = element_text(family = "Bookman Old Style"), axis.text.x = element_text(angle = 0, size = 29, lineheight = unit(.8, "lines")), strip.background = element_rect(fill = "white"), strip.text = element_text(family = "Bookman Old Style", size = 25, lineheight = 0.6, hjust = 0.5), strip.placement = "outside", panel.spacing.x = unit(0, "cm"), axis.title.y = ggtext::element_markdown()) + labs(y = "Riqueza de especies") # 修改分面条带添加垂直线 g <- ggplotGrob(grafico) lr2 <- polylineGrob(x=c(0,0,1,1), y=c(0,1,0,1), id=c(1,1,2,2), gp=gpar(col="gray", lwd=1)) for (k in grep("strip-b", g$layout$name)) { g$grobs[[k]]$grobs[[1]]$children[[1]] <- lr2 } # 保存图像(方法1:grid.draw) png( filename = "image.png", width = 15.5, height = 8, units = "cm", res = 300 ) grid.draw(g) dev.off() # 或者用方法2:ggsave # ggsave( # filename = "image.png", # plot = g, # width = 15.5, # height = 8, # units = "cm", # dpi = 300, # device = function(...) png(..., type = "cairo") # )
内容的提问来源于Stack Exchange,提问作者Alvaro Morales
相关产品推荐
相关产品推荐

