← 返回 Tessera
分布4 张图plant_growth(Tessera Toy,30 行 × 3 组)2026-08-11

box

几组连续数据的中位数、离散程度和潜在异常值有什么不同?

需要的输入
1 个分类变量 + 1 个连续数值变量
示例数据
plant_growth(Tessera Toy,30 行 × 3 组)
依赖
ggplot2 · ggpubr · biopalette
配色
walter_white2
成图预览另有 3 张在配方里
box

什么时候用它

箱线图用五个视觉部件压缩一组连续数据:中位数、上下四分位数、两条须,以及落在须外的点。它适合并排比较多个组的位置与离散程度,比均值柱保留的信息更多,也比小提琴图更少依赖分布估计。

每组只有十来个观测时,箱体仍能提供紧凑摘要,但几个分位数会被单个点明显影响。因此小样本箱线图最好叠加全部原始点;读者既能快速比较箱体,也能看见究竟有多少数据支撑它。

如果关心双峰、偏态尾部或完整密度形状,使用小提琴图或密度图;如果只展示一个估计值与不确定性,使用点估计加误差棒。箱线图不是所有“组间比较”的默认答案。

箱体和须分别是什么

  1. 箱体下边缘是 Q1,上边缘是 Q3。 中间 50% 的数据落在箱体内。
  2. 箱体高度是 IQR = Q3 − Q1。 箱体越高,中间一半数据越分散。
  3. 箱内横线是中位数。 它不是均值;偏态数据里两者可以相差很远。
  4. 须不是固定的最小值和最大值。 下须延伸到不低于 Q1 − 1.5 × IQR 的最小观测,上须延伸到不高于 Q3 + 1.5 × IQR 的最大观测。
  5. 须外的点是规则标出的潜在异常值。 它们不一定错误,也不能因为被标出就删除。

围栏 Q1 ± 1.5 × IQR 只是判定界限,须端落在真实观测值上,并不一定正好等于围栏位置。

常见陷阱

  • 样本太少却只画箱体。 n = 5 也能算四分位,但一个整齐箱子会制造过度稳定的印象;叠加原始点。
  • 把须读成最小最大值。 ggplot2 默认使用 1.5 × IQR 规则,须外仍可能有真实观测。
  • 叠点后异常值画两遍。 geom_boxplot() 默认单独画须外点,再叠全部原始点会重复;应设 outlier.shape = NA
  • 纵向抖动。 原始点只能沿分类轴轻微移动;纵向抖动会篡改真实数值。
  • 颜色和形状同时分组。 常规分组箱线图只用颜色;再给每组一种点形会增加没有新信息的图例负担。
  • 隐藏样本量。 同样大小的箱体可能来自 10 个点或 1000 个点;在轴标签或图注中标明 n
  • 用箱线图证明正态。 对称箱体不等于正态分布,箱线图也不足以判断分布假设。
  • 轴范围裁掉须外点。 scale_y_continuous(limits = ...) 会在统计前删除范围外数据;只想放大视图时使用 coord_cartesian()

配色

处理组是无序类别,使用定性色板 walter_white2。箱体用半透明填色和统一深色边框,原始点沿用同一组颜色与同一种圆形;颜色只解释组别一次。

箱线图中的颜色面积比散点大,因此浅色很容易显得发白,深色又可能压住中位数线。保留深色轮廓与适度透明度,比单纯加深所有颜色更稳。色板不足组数时,不循环颜色,也不删除数据;未编码组使用明确的中性色。

配方

方法绘图系统什么时候选它
Ageom_boxplot()ggplot2快速比较各组中位数、四分位范围和须,不强调组别颜色
Baes(fill = group)ggplot2组数不多,颜色需要与报告中的同一分类保持一致
Cgeom_boxplot() + geom_point()ggplot2样本量较小或需要诚实展示全部观测;箱体给摘要,点给真实数据
Dwidth + point sizeggplot2根据最终版面调节箱体占位与原始点强调程度,不改变统计量

数据与公共样式

plant_growth 有一个对照组和两个处理组,每组恰好十株植物。显式固定组别顺序,并把样本量写进横轴标签。

library(ggplot2)
library(ggpubr)
library(biopalette)

d <- read.csv("content/tessera/data/csv/plant_growth.csv")
group_levels <- c("ctrl", "trt1", "trt2")
d$group <- factor(d$group, levels = group_levels)

group_n <- table(d$group)
group_labels <- setNames(
  paste0(group_levels, "\n(n=", as.integer(group_n[group_levels]), ")"),
  group_levels
)

group_colors <- setNames(
  get_palette("walter_white2", type = "qualitative")[1:3],
  group_levels
)

box_scale <- scale_y_continuous(
  breaks = seq(3.5, 6.5, 1),
  expand = expansion(mult = c(0.04, 0.06))
)

box_theme <- theme_pubr(base_size = 13, legend = "none") +
  theme(
    panel.grid.major.y = element_line(color = "#E5E3DC", linewidth = 0.35),
    panel.grid.major.x = element_blank(),
    axis.line = element_line(color = "#333330", linewidth = 0.45),
    axis.ticks = element_line(color = "#333330", linewidth = 0.4),
    plot.title = element_text(face = "bold", size = 15, hjust = 0),
    plot.subtitle = element_text(color = "grey35", hjust = 0),
    plot.margin = margin(14, 16, 12, 12)
  )

A · 基础分组箱线图

先只看统计结构。fill = NA 让箱体完全不填色,只保留轮廓、中位数和须;三个组已经由横轴位置区分,不需要图例。

#| fig: basic
#| fig-width: 7.5
#| fig-height: 5.2
ggplot(d, aes(group, weight)) +
  geom_boxplot(
    width = 0.56,
    fill = NA,
    color = "#333330",
    linewidth = 0.7
  ) +
  scale_x_discrete(labels = group_labels) +
  box_scale +
  labs(
    title = "Plant weight by treatment",
    subtitle = "Outline only · no box fill",
    x = NULL,
    y = "Dried weight"
  ) +
  box_theme
box — basic
box-basic

B · 箱体按组着色

当处理组颜色需要与同一份报告的其他图保持一致时,把 fill 映射到组别。边框、中位数和须仍统一使用深色,避免三套视觉规则同时变化。

#| fig: color
#| fig-width: 7.5
#| fig-height: 5.2
ggplot(d, aes(group, weight, fill = group)) +
  geom_boxplot(
    width = 0.56,
    alpha = 0.72,
    color = "#333330",
    linewidth = 0.7
  ) +
  scale_x_discrete(labels = group_labels) +
  scale_fill_manual(values = group_colors) +
  box_scale +
  labs(
    title = "Plant weight by treatment",
    subtitle = "One categorical color per treatment group",
    x = NULL,
    y = "Dried weight"
  ) +
  box_theme
box — color
box-color

C · 箱线图叠加全部原始点

这是小样本时优先使用的版本。箱线图关闭默认异常值点,全部观测统一交给下一层绘制;抖动只发生在横向,并绑定固定种子,重复导出时点的位置不会变化。

#| fig: points
#| fig-width: 7.5
#| fig-height: 5.2
ggplot(d, aes(group, weight, fill = group)) +
  geom_boxplot(
    width = 0.54,
    alpha = 0.58,
    color = "#333330",
    linewidth = 0.7,
    outlier.shape = NA
  ) +
  geom_point(
    shape = 21,
    size = 2.8,
    stroke = 0.65,
    color = "#333330",
    position = position_jitter(width = 0.1, height = 0, seed = 2026)
  ) +
  scale_x_discrete(labels = group_labels) +
  scale_fill_manual(values = group_colors) +
  box_scale +
  labs(
    title = "Plant weight by treatment",
    subtitle = "All 30 observations retained",
    x = NULL,
    y = "Dried weight"
  ) +
  box_theme
box — points
box-points

D · 箱体宽度与点大小

width 只改变箱体在分类轴上占多少空间,不改变 Q1、Q3、中位数或须;size 只改变原始点的视觉重量,不改变数据。两者都应按最终输出尺寸判断,而不是在 RStudio 的大预览窗里凭感觉设定。

下面把其他设置固定,只分别改变一个参数。宽度对比采用真正的空心彩色箱体:箱体内部不填色,轮廓和原始点使用组别颜色。窄箱体适合类别多、版面紧的图;宽箱体更有块面感,但容易挤满分类间距。小点让箱体摘要占主导,大点则更强调每个真实观测。

#| fig: sizing
#| fig-width: 10
#| fig-height: 7.6
comparison_theme <- theme_pubr(base_size = 11, legend = "none") +
  theme(
    panel.grid.major.y = element_line(color = "#E5E3DC", linewidth = 0.3),
    panel.grid.major.x = element_blank(),
    axis.line = element_line(color = "#333330", linewidth = 0.4),
    plot.title = element_text(face = "bold", size = 12, hjust = 0),
    plot.margin = margin(8, 8, 8, 8)
  )

box_only <- function(box_width, title) {
  ggplot(d, aes(group, weight, color = group)) +
    geom_boxplot(
      width = box_width,
      fill = NA,
      linewidth = 0.8,
      outlier.shape = NA
    ) +
    geom_point(
      size = 2.4,
      alpha = 0.82,
      position = position_jitter(width = 0.1, height = 0, seed = 2026)
    ) +
    scale_x_discrete(labels = group_levels) +
    scale_color_manual(values = group_colors) +
    box_scale +
    labs(title = title, x = NULL, y = "Dried weight") +
    comparison_theme
}

box_with_points <- function(point_size, title) {
  ggplot(d, aes(group, weight, fill = group)) +
    geom_boxplot(
      width = 0.54,
      alpha = 0.58,
      color = "#333330",
      linewidth = 0.7,
      outlier.shape = NA
    ) +
    geom_point(
      shape = 21,
      size = point_size,
      stroke = 0.65,
      color = "#333330",
      position = position_jitter(width = 0.1, height = 0, seed = 2026)
    ) +
    scale_x_discrete(labels = group_levels) +
    scale_fill_manual(values = group_colors) +
    box_scale +
    labs(title = title, x = NULL, y = "Dried weight") +
    comparison_theme
}

ggarrange(
  box_only(0.34, "Narrow boxes · width = 0.34"),
  box_only(0.76, "Wide boxes · width = 0.76"),
  box_with_points(1.7, "Small points · size = 1.7"),
  box_with_points(3.8, "Large points · size = 3.8"),
  ncol = 2,
  nrow = 2,
  align = "hv"
)
box — sizing
box-sizing

四种画法怎么选

  1. 只需要紧凑统计摘要 → A。
  2. 组别颜色需要跨图保持一致 → B。
  3. 样本量小、读者需要看到真实数据 → C;这是本例最诚实、也最适合正式使用的版本。
  4. 需要适配不同版面尺寸 → D;先定最终宽度,再调箱体 width 和散点 size
运行环境3 个包 · 2026-08-11T17:37:58.343+0800

R version 4.5.1 (2025-06-13 ucrt) · x86_64-w64-mingw32

  • biopalette 0.1.0
  • ggplot2 4.0.3
  • ggpubr 0.6.2