PAYATHON 2026

如何在 ggplot2 facet_grid 右侧显示限值名称和值?

数据阿明

可以。facet_grid() 没有参数可将每个分面的 almin、almax 值显示为额外的列条带。可以在最右侧分面内添加文字标签,并扩展 x 轴范围,为标签留出空间。扩展绘图区域后,geom_hline() 也会延伸到标签区,因此示例改用 geom_segment(),将限值线限制在数据区域内。

示例沿用问题中的 df 和 select_bmk,并假设最右侧的 site 是因子水平中的最后一个值(示例中为 C):

library(ggplot2)
library(dplyr)

select_bmk <- "bmk3"
sel <- df |> filter(bmk == select_bmk)

# 标签放在最右侧的 site 分面
last_site <- tail(levels(droplevels(sel$site)), 1)
x_range <- range(sel$x, na.rm = TRUE)
x_span <- diff(x_range)

# 为标签位置和标签文字预留右侧空间
x_label <- x_range[2] + 0.05 * x_span
x_right <- x_range[2] + 0.8 * x_span

# 每个 qc、site 组合保留一组限值,用于绘制线段
limit_lines <- sel |>
  distinct(qc, site, almin, almax)

# 仅在最右侧 site 分面生成限值文字
limit_labels <- limit_lines |>
  filter(site == last_site) |>
  transmute(
    qc, site,
    x = x_label,
    y = almin,
    label = sprintf("almin (%.2f)", almin)
  ) |>
  bind_rows(
    limit_lines |>
      filter(site == last_site) |>
      transmute(
        qc, site,
        x = x_label,
        y = almax,
        label = sprintf("almax (%.2f)", almax)
      )
  )

sel |>
  ggplot(aes(x = x, y = y)) +
  geom_point() +
  geom_segment(
    data = limit_lines,
    aes(x = x_range[1], xend = x_range[2], y = almin, yend = almin),
    inherit.aes = FALSE,
    linetype = "longdash",
    colour = "red3"
  ) +
  geom_segment(
    data = limit_lines,
    aes(x = x_range[1], xend = x_range[2], y = almax, yend = almax),
    inherit.aes = FALSE,
    linetype = "longdash",
    colour = "red3"
  ) +
  geom_text(
    data = limit_labels,
    aes(x = x, y = y, label = label),
    inherit.aes = FALSE,
    hjust = 0,
    size = 3
  ) +
  facet_grid(qc ~ site, scales = "free_y") +
  coord_cartesian(xlim = c(x_range[1], x_right))

limit_labels 中包含 qc 和 site,facet_grid() 会据此将文字放到对应的行和列。筛选 last_site 后,标签只会显示在最右侧列。coord_cartesian() 扩大显示范围时会保留范围外的数据;线段仍以原数据的 x 范围为终点,因此不会穿过标签区。

如果实际数据中的限值名称分布在多列,可以先将这些列整理成长格式,再用同样的方法生成标签数据。这里的代码使用问题中提供的 almin、almax 两列。标签间距和 x_right 可根据图形和标签长度调整。如果多个限值的 y 值接近,文字可能重叠,此时需要进一步调整标签位置或字号。

备注:内容仅供参考。