You need to enable JavaScript to run this app. R语言使用cowplot对齐直方图与箱线图实现共享x轴的轴偏移解决
优惠活动
大模型
产品
解决方案
定价
更多

R语言使用cowplot对齐直方图与箱线图实现共享x轴的轴偏移解决

数据
# A tibble: 1,472 x 3
    wage educ  exper
   <dbl> <fct> <dbl>
 1  7.78 1        23
 2  4.82 1        15
 3 10.6  1        31
 4  7.04 1        32
 5  7.89 1         9
 6  8.20 1        15
 7  8.21 1        26
 8 10.4  1        23
 9 11.0  1        13
10  7.21 1        22
# ... 剩余1,462行数据
直方图与箱线图的x轴对齐问题

我用cowplot包把wage列的直方图和箱线图上下排列,想让两个图共享x轴,但现在生成的图里两个图的x轴数值明显对不上,下面是可复现的完整代码:

library(tidyverse)
library(cowplot)

wages <- read_csv("http://vincentarelbundock.github.io/Rdatasets/csv/Ecdat/Bwages.csv") %>% 
  select(-X1, -sex) %>% 
  mutate(educ = factor(educ)) 
#> Warning: Missing column names filled in: 'X1' [1]
#> 
#> -- Column specification --------------------------------------------------------
#> cols(
#>   X1 = col_double(),
#>   wage = col_double(),
#>   educ = col_double(),
#>   exper = col_double(),
#>   sex = col_logical()
#> )


p1 <- ggplot(wages) +
  geom_histogram(aes(x = wage)) +
  geom_vline(xintercept = median(wages$wage), color = "red")

p2 <- ggplot(wages) + 
  geom_boxplot(aes(x = wage)) 

plot_grid(p1, p2, ncol = 1, axis = "l", align = 'v')
#> `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

未调整时的错位生成结果
代码示例由reprex包(v1.0.0版本)于2021-02-27生成

问题:怎么调整代码,才能让两个图的x轴完美对齐?

解决方案

出现错位的核心原因是两个图的x轴范围是ggplot分别自动计算的,没有强制统一,就算用plot_grid的对齐参数也没法修正数值范围本身的偏移。调整方法分三步:

  • 给两个图手动指定完全一致的x轴范围,消除自动计算带来的差异
  • 隐藏上方直方图的x轴所有视觉元素,避免重复展示
  • 去掉两个图相邻边距,让上下图的绘图区域严丝合缝

调整后的完整可运行代码:

library(tidyverse)
library(cowplot)

wages <- read_csv("http://vincentarelbundock.github.io/Rdatasets/csv/Ecdat/Bwages.csv") %>% 
  select(-X1, -sex) %>% 
  mutate(educ = factor(educ)) 

# 统一计算x轴范围,提前设置统一的轴刻度
x_lim <- range(wages$wage) * c(0.95, 1.05) # 左右留少量边距,和直方图默认视觉一致
x_breaks <- pretty(x_lim, n = 8)

# 上方的直方图
p1 <- ggplot(wages) +
  geom_histogram(aes(x = wage), bins = 30) +
  geom_vline(xintercept = median(wages$wage), color = "red") +
  # 强制统一x轴范围和刻度
  scale_x_continuous(limits = x_lim, breaks = x_breaks) +
  # 隐藏x轴所有冗余元素
  theme(
    axis.title.x = element_blank(),
    axis.text.x = element_blank(),
    axis.ticks.x = element_blank(),
    plot.margin = margin(t = 5.5, r = 5.5, b = 0, l = 5.5, unit = "pt") # 去掉下边距
  )

# 下方的横向箱线图
p2 <- ggplot(wages) + 
  geom_boxplot(aes(x = wage, y = 1)) + # 明确y轴固定位置,消除自动计算的影响
  # 用和p1完全一样的x轴设置
  scale_x_continuous(limits = x_lim, breaks = x_breaks) +
  # 隐藏完全没用的y轴元素
  theme(
    axis.title.y = element_blank(),
    axis.text.y = element_blank(),
    axis.ticks.y = element_blank(),
    plot.margin = margin(t = 0, r = 5.5, b = 5.5, l = 5.5, unit = "pt") # 去掉上边距
  )

# 排列两个图
plot_grid(p1, p2, ncol = 1, align = "v", axis = "l")

调整逻辑:之前的代码中,直方图会根据柱子的分布自动扩展x轴范围留边距,而一维横向箱线图会根据箱体、须线的实际位置自动计算x轴范围,两个范围哪怕有微小差异,视觉上就能看到x轴数值错位。强制把两个图的x轴limits、刻度设为完全相同的值,再移除两个图相邻的多余边距,对齐后两个图的x轴会完全对应,不会再有偏移。另外给直方图手动指定bins = 30,可以消掉运行时弹出的默认分箱提示。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.01 14:24:03