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

如何用ggplot2在同图绘制以age=0为界的左右分布水平条形图

实现双向分组条形图的解决方案

你想要的这种图叫做双向条形图(Diverging Bar Chart),核心思路是调整其中一组数据的数值方向,让两组条形分别出现在0轴的两侧,同时基于指定数据框的排序规则来排列类别。下面是完整的实现步骤:

1. 数据预处理

首先我们需要合并两个数据框,给它们打上分组标签,同时把df2的age值取负数(这样它的条形会出现在0轴的另一侧),最后按照df1的age规则对name进行排序:

library(tidyverse)

# 你的原始数据
df1 <- data.frame(name = rep(LETTERS[1:5], each = 5), age = 1:25)
df2 <- data.frame(name = rep(LETTERS[1:5], each = 5), age = c(rep(1,5), rep(5,5), 1,12,3,2,1,1:5,6:10))

# 合并并处理数据
combined_df <- bind_rows(
  df1 %>% mutate(group = "df1"),
  df2 %>% mutate(group = "df2", age = -age)  # 将df2的age取负,放到0轴另一侧
) %>%
  # 基于df1的age排序name(默认用中位数,你也可以改成总和/均值)
  mutate(name = fct_reorder(name, ifelse(group == "df1", age, -age)))

如果希望基于df1中每个name的age总和排序,可以用下面的替代代码,排序逻辑更清晰:

# 先计算df1每个name的age总和
df1_total <- df1 %>% group_by(name) %>% summarise(total_age = sum(age))

# 合并后按总和排序
combined_df <- bind_rows(
  df1 %>% mutate(group = "df1"),
  df2 %>% mutate(group = "df2", age = -age)
) %>%
  left_join(df1_total, by = "name") %>%
  mutate(name = fct_reorder(name, total_age)) %>%
  select(-total_age)

2. 绘制双向条形图

接下来用ggplot绘制图形,同时调整坐标轴和样式,让结果更直观:

ggplot(combined_df, aes(x = name, y = age, fill = group)) +
  geom_bar(stat = "identity", alpha = .6, width = .6) +
  # 添加0轴参考线,明确分界
  geom_vline(xintercept = 0, linetype = "dashed", color = "gray50") +
  coord_flip() +
  # 设置你需要的颜色:绿色对应df1,紫色对应df2
  scale_fill_manual(values = c("df1" = "#74D055FF", "df2" = "#481568FF")) +
  # 把y轴的负数标签转为绝对值,避免用户困惑
  scale_y_continuous(
    labels = function(x) abs(x),
    name = "Age"
  ) +
  labs(fill = "Data Source") +
  theme_bw()

关键逻辑说明

  • 把df2的age取负是核心操作,这样它的条形会自动出现在0轴的另一侧(coord_flip后对应图的左侧)
  • fct_reorder的参数确保排序完全基于df1的age分布,和你单独绘制df1时的排序一致
  • 调整y轴标签为绝对值,让用户看到的是实际年龄数值,而不是处理后的负数

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 16:50:16