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

如何用ggplot实现属性名称置于条形图层级上方的布局?

解决方案:调整属性标签至层级组上方

单组布局实现

通过手动计算每个属性组的中心位置,将属性标签添加到对应层级组的右侧(因coord_flip后布局变化),同时保留层级作为y轴标签:

library(tidyverse)

df <- tribble(
  ~group, ~level, ~value, ~attribute,
  "g1", 0, 1, "attr1",
  "g1", 1, 2, "attr1",
  "g1", 0, 0, "attr2",
  "g1", 14, 3, "attr2",
  "g1", 16, 4, "attr2"
)

# 排序并生成每个条目的y轴位置
df <- df %>%
  arrange(attribute, level) %>%
  mutate(y_pos = row_number())

# 计算每个属性组的中心位置
attr_centers <- df %>%
  group_by(attribute) %>%
  summarise(center_y = mean(y_pos), .groups = "drop")

ggplot(df, aes(x = value, y = y_pos)) +
  geom_bar(stat = "identity", width = 0.8) +
  # 添加属性标签到组右侧
  geom_text(data = attr_centers, aes(x = max(df$value)*1.1, y = center_y, label = attribute),
            hjust = 0, size = 4, fontface = "bold") +
  # 设置y轴显示层级
  scale_y_continuous(breaks = df$y_pos, labels = df$level, expand = expansion(add = c(1,1))) +
  ggtitle("Title") +
  xlab("Marginal utility") +
  ylab("") +
  # 扩展x轴范围,避免标签被截断
  coord_cartesian(xlim = c(0, max(df$value)*1.2), clip = "off") +
  # 右侧留足够空间放标签
  theme(plot.margin = margin(r = 50))

双组布局实现

基于单组逻辑,通过facet_wrap实现双组,并为每个分组单独计算属性标签位置:

library(tidyverse)

df <- tribble(
  ~group, ~level, ~value, ~attribute,
  "g1", 0, 1, "attr1",
  "g1", 1, 2, "attr1",
  "g1", 0, 0, "attr2",
  "g1", 14, 3, "attr2",
  "g1", 16, 4, "attr2",
  "g2", 0, 3, "attr1",
  "g2", 1, 1, "attr1",
  "g2", 0, 0, "attr2",
  "g2", 14, 2, "attr2",
  "g2", 16, 3, "attr2"
)

# 按分组排序并生成y轴位置
df <- df %>%
  group_by(group) %>%
  arrange(attribute, level) %>%
  mutate(y_pos = row_number()) %>%
  ungroup()

# 计算每个分组内属性组的中心位置和最大值
attr_centers <- df %>%
  group_by(group, attribute) %>%
  summarise(center_y = mean(y_pos), max_val = max(value), .groups = "drop")

ggplot(df, aes(x = value, y = y_pos)) +
  geom_bar(stat = "identity", width = 0.8) +
  # 为每个分组添加属性标签
  geom_text(data = attr_centers, aes(x = max_val*1.1, y = center_y, label = attribute),
            hjust = 0, size = 4, fontface = "bold") +
  scale_y_continuous(breaks = df$y_pos, labels = df$level, expand = expansion(add = c(1,1))) +
  facet_wrap(~group, ncol = 2) +
  ggtitle("Title") +
  xlab("Marginal utility") +
  ylab("") +
  coord_cartesian(xlim = c(0, max(df$value)*1.2), clip = "off") +
  theme(plot.margin = margin(r = 50))

备选方案:使用ggh4x嵌套分面

利用ggh4x的facet_nested将属性作为嵌套层级,调整strip位置到层级上方:

library(tidyverse)
library(ggh4x)

df <- tribble(
  ~group, ~level, ~value, ~attribute,
  "g1", 0, 1, "attr1",
  "g1", 1, 2, "attr1",
  "g1", 0, 0, "attr2",
  "g1", 14, 3, "attr2",
  "g1", 16, 4, "attr2",
  "g2", 0, 3, "attr1",
  "g2", 1, 1, "attr1",
  "g2", 0, 0, "attr2",
  "g2", 14, 2, "attr2",
  "g2", 16, 3, "attr2"
)

ggplot(df, aes(x = value, y = level)) +
  geom_bar(stat = "identity") +
  facet_nested(group ~ attribute, scales = "free_y", space = "free_y") +
  coord_flip() +
  ggtitle("Title") +
  xlab("Marginal utility") +
  ylab("") +
  theme(strip.placement = "outside",
        strip.text.y = element_text(angle = 0),
        axis.text.y = element_text(margin = margin(r = 20)))

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 00:58:17