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

如何复用ggplot2 facet_wrap仅数据绘图的坐标轴范围?

解决ggplot2 facet_wrap添加GLM拟合曲线后坐标轴范围被扩大的问题

当你用facet_wrap(scales = "free_y")绘制仅数据的图形,再添加GLM拟合曲线时,拟合曲线的预测值可能超出原数据的y范围,导致面板y轴被大幅拉伸。要复用原数据图的坐标轴范围,可以按以下步骤操作:

步骤1:提取原数据图的面板y轴范围

直接访问plot_data_only$scales无法获取每个面板的独立尺度信息,需要用ggplot_build()提取绘图的构建参数:

# 加载必要包(未安装则先安装)
if (!require("purrr")) install.packages("purrr")
library(purrr)

# 提取仅数据图的构建信息
pb <- ggplot_build(plot_data_only)

# 提取每个面板的y轴范围,并关联对应的ID
panel_y_limits <- pb$layout$panel_params %>%
  map_dfr(~data.frame(ymin = .$y$limits[1], ymax = .$y$limits[2]), .id = "panel") %>%
  mutate(ID = levels(data$ID)[as.integer(panel)])

步骤2:复用原坐标轴范围绘制带拟合曲线的图

这里推荐用ggh4x包的facetted_pos_scales函数,它支持给每个facet面板单独设置坐标轴尺度:

先安装并加载ggh4x

if (!require("ggh4x")) install.packages("ggh4x")
library(ggh4x)

构建每个面板的y轴尺度并绘图

# 原代码中的glm_combined未定义,先拟合全局模型(若需要start参数)
glm_combined <- glm(y ~ 1 + x + I(x^2), data = data, family = quasipoisson(link = "log"))

# 为每个ID创建对应的y轴尺度
y_scales <- map2(panel_y_limits$ymin, panel_y_limits$ymax, 
                 ~scale_y_continuous(limits = c(.x, .y)))
names(y_scales) <- panel_y_limits$ID

# 绘制图形,复用原数据图的y轴范围
plot_data_only +
  stat_smooth(method = "glm",
              method.args = list(
                family = quasipoisson(link = "log"),
                start = coefficients(glm_combined),
                maxit = 100),
              se = FALSE,
              formula = y ~ 1 + x + I(x^2), size = 1) +
  labs(title = "Data and model fits (y轴范围与仅数据图一致)") +
  facetted_pos_scales(y = y_scales)

替代方法:限制拟合曲线的预测范围

如果不想额外安装包,可以手动拟合每个面板的模型,然后绘制曲线时限制y值在原数据范围内:

# 按ID分组拟合模型
model_list <- data %>%
  group_by(ID) %>%
  group_map(~glm(y ~ 1 + x + I(x^2), data = ., family = quasipoisson(link = "log")))
names(model_list) <- levels(data$ID)

# 生成每个ID的预测数据,并限制y在原数据范围内
pred_data <- data %>%
  group_by(ID) %>%
  group_map(function(.data, .id) {
    x_seq <- seq(min(.data$x), max(.data$x), length.out = 100)
    pred <- predict(model_list[[.id]], newdata = data.frame(x = x_seq), type = "response")
    # 限制预测值在原数据的y范围内
    pred_clamped <- pmax(min(.data$y), pmin(max(.data$y), pred))
    data.frame(ID = .id, x = x_seq, y_pred = pred_clamped)
  }) %>%
  bind_rows()

# 绘制图形
plot_data_only +
  geom_line(data = pred_data, aes(x = x, y = y_pred), size = 1) +
  labs(title = "Data and model fits (限制拟合曲线y范围)")

内容的提问来源于stack exchange,提问作者mikemtnbikes

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 23:45:41