You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 18:40:42