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

ggplot绘图仅显示四级因子PAN首个水平的问题求助

问题描述

我用以下代码绘制带密度图的箱线图:

ggplot(data_alk_pan, aes(x = PAN, y = MEAS_RESULT, fill = PAN)) +
  theme(legend.position = "none") +
  theme(text = element_text(size = 10)) +
  scale_x_discrete(labels = paste(levels(data_alk_pan$PAN), "\n(N=",table(data_alk_pan$PAN),")", sep="")) +
  labs(y = "Concentration (mg/l)", x = "Pan") +
  ggdist::stat_halfeye(
    aes(thickness = stat(pdf*n)),
    adjust = 0.5,
    justification = -.5,
    .width = 0,
    point_colour = NA
  ) +
  geom_boxplot(alpha = 0.5, varwidth = TRUE)

该代码对数据中其他因子均能正常工作,但因子PAN仅显示第一个水平。我已通过运行levels(data_alk_pan$PAN)确认R识别PAN的所有水平,返回结果为:

[1] "Pan_01"  "Pan_02"  "Pan_03"  "Pan_all"

所有水平都有数据(n>0),但绘图仅显示Pan_01。补充的部分数据如下:

> dput(data_alk_pan[1:200, c(8,13)])
structure(list(MEAS_RESULT = c(170, 180, 150, 140, 160, 140, 
330, 130, 130, 210, 130, 130, 310, 400, 200, 160, 160, 160, 170, 
170, 220, 170, 200, 240, 200, 190, 200, 180, 190, 240, 250, 260, 
280, 270, 250, 290, 260, 260, 250, 230, 270, 260, 220, 260, 250, 
310, 270, 86, 270, 150, 290, 290, 300, 290, 270, 210, 280, 300, 
390, 270, 190, 240, 240, 260, 210, 250, 210, 220, 190, 260, 210, 
190, 240, 280, 240, 210, 220, 220, 200, 250, 310, 260, 290, 280, 
180, 280, 310, 310, 300, 300, 280, 190, 180, 180, 200, 210, 180, 
280, 390, 290, 320, 310, 320, 260, 330, 330, 390, 300, 350, 270, 
190, 180, 310, 270, 300, 270, 330, 310, 320, 310, 340, 330, 340, 
270, 340, 57, 360, 28, 320, 170, 21, 370, 320, 330, 430, 340, 
300, 350, 300, 300, 340, 260, 270, 230, 180, 210, 210, 240, 230, 
260, 250, 230, 250, 270, 280, 170, 190, 190, 190, 180, 190, 250, 
250, 260, 270, 180, 260, 260, 260, 260, 250, 260, 280, 290, 130, 
150, 190, 180, 190, 240, 270, 260, 230, 220, 170, 190, 270, 270, 
260, 280, 260, 260, 270, 280, 290, 270, 190, 230, 240, 170), 
    PAN = structure(c(4L, 4L, 4L, 4L, 4L, 4L, 1L, 4L, 4L, 1L, 
    4L, 4L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
    1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
    1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
    1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
    1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
    1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 1L, 2L, 
    2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
    2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
    2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
    2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
    2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 3L, 
    3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 
    3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L), .Label = c("Pan_01", 
    "Pan_02", "Pan_03", "Pan_all"), class = "factor")), row.names = c(NA, 
200L), class = "data.frame")

如何让PAN的四个水平都显示在图中?


问题原因与解决方法

根源分析

问题出在scale_x_discrete的标签设置上:

scale_x_discrete(labels = paste(levels(data_alk_pan$PAN), "\n(N=",table(data_alk_pan$PAN),")", sep=""))

直接用paste拼接会把所有水平的标签合并成单个字符串,而非对应每个水平的标签向量。ggplot将这个单一字符串作为所有x轴水平的标签,导致仅第一个水平被渲染。

修复方案

需确保labels参数是与因子水平长度匹配的向量,以下三种方法均可解决:

方法1:使用mapply逐个拼接标签

ggplot(data_alk_pan, aes(x = PAN, y = MEAS_RESULT, fill = PAN)) +
  theme(legend.position = "none") +
  theme(text = element_text(size = 10)) +
  scale_x_discrete(labels = mapply(function(lvl, n) paste0(lvl, "\n(N=", n, ")"),
                                   levels(data_alk_pan$PAN), table(data_alk_pan$PAN))) +
  labs(y = "Concentration (mg/l)", x = "Pan") +
  ggdist::stat_halfeye(
    aes(thickness = stat(pdf*n)),
    adjust = 0.5,
    justification = -.5,
    .width = 0,
    point_colour = NA
  ) +
  geom_boxplot(alpha = 0.5, varwidth = TRUE)

方法2:使用purrr::map2_chr(需加载purrr包)

library(purrr)

ggplot(data_alk_pan, aes(x = PAN, y = MEAS_RESULT, fill = PAN)) +
  theme(legend.position = "none") +
  theme(text = element_text(size = 10)) +
  scale_x_discrete(labels = map2_chr(levels(data_alk_pan$PAN), table(data_alk_pan$PAN),
                                     ~paste0(.x, "\n(N=", .y, ")"))) +
  labs(y = "Concentration (mg/l)", x = "Pan") +
  ggdist::stat_halfeye(
    aes(thickness = stat(pdf*n)),
    adjust = 0.5,
    justification = -.5,
    .width = 0,
    point_colour = NA
  ) +
  geom_boxplot(alpha = 0.5, varwidth = TRUE)

方法3:提前在数据框中创建标签列

library(dplyr)

data_alk_pan <- data_alk_pan %>%
  mutate(PAN_label = paste0(PAN, "\n(N=", table(PAN)[as.character(PAN)], ")"))

ggplot(data_alk_pan, aes(x = PAN_label, y = MEAS_RESULT, fill = PAN)) +
  theme(legend.position = "none") +
  theme(text = element_text(size = 10)) +
  labs(y = "Concentration (mg/l)", x = "Pan") +
  ggdist::stat_halfeye(
    aes(thickness = stat(pdf*n)),
    adjust = 0.5,
    justification = -.5,
    .width = 0,
    point_colour = NA
  ) +
  geom_boxplot(alpha = 0.5, varwidth = TRUE)

效果验证

运行修复后的代码,x轴会完整显示Pan_01、Pan_02、Pan_03、Pan_all四个水平,每个水平下方附带对应的样本量。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 19:33:33