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

如何为散点图的X、Y轴添加双层标签(ggplot2实现)

实现ggplot2坐标轴双层标签解决方案

需求背景

现有如下DataFrame df:

products price_index quantity_index   price_rank quantity_rank
1         a    95.00000       95.00000   high price   high volume
2         b    80.69012       94.53585   high price   high volume
3         c    74.41048       90.95081   high price   high volume
4         d    73.24853       89.82692 medium price medium volume
5         e    70.50442       79.71225 medium price medium volume
6         f    67.11609       75.43498    low price    low volume
7         g    64.14685       58.26419    low price    low volume
8         h    56.76375       56.16531    low price    low volume
9         i    55.76472       56.02838    low price    low volume
10        j    55.70475       50.24873    low price    low volume

数据结构定义:

df <- structure(list(products = c("a", "b", "c", "d", "e", "f", "g", 
"h", "i", "j"), price_index = c(95, 80.69011538, 74.41047705, 
73.24853055, 70.5044217, 67.1160916, 64.14685495, 56.76375355, 
55.76472446, 55.70475052), quantity_index = c(95, 94.53585227, 
90.95080999, 89.82692004, 79.71224701, 75.43498354, 58.26419203, 
56.16530529, 56.02838119, 50.24873055), price_rank = c("high price", 
"high price", "high price", "medium price", "medium price", "low price", 
"low price", "low price", "low price", "low price"), quantity_rank = c("high volume", 
"high volume", "high volume", "medium volume", "medium volume", 
"low volume", "low volume", "low volume", "low volume", "low volume"
)), class = "data.frame", row.names = c(NA, -10L))

已有基础ggplot2绘图代码:

ggplot(df, aes(x = price_index, y = quantity_index, label = products)) +
   coord_fixed() +
   geom_point(colour = 'blue', size = 3, alpha=0.9) +
   scale_x_continuous(expand = c(0, 0), limits = c(50, 100),
                      breaks = seq(50, 100, 5)
   ) +
   scale_y_continuous(expand = c(0, 0), limits = c(50, 100),
                      breaks = seq(50, 100, 5)
   ) +
   geom_vline(xintercept = c(68, 74), color='black',
              linetype='dotted', size=1) +
   geom_hline(yintercept = c(77, 90), color='black',
              linetype='dotted', size=1)

需要给X轴(price_index)和Y轴(quantity_index)添加双层标签:底层保留原有的数值刻度,上层添加对应区域的分类标签(高值/中值/低值),对应分割线为X轴的68、74,Y轴的77、90。


解决方案

提供两种实现方式,可根据需求选择:

方式一:通过annotate添加外部区域标签

这种方式直接在坐标轴外侧添加分类标签,简单直观,适合需要灵活调整标签位置的场景。

完整代码

library(ggplot2)

# 定义X/Y轴区域标签的位置和内容
x_region_labels <- data.frame(
  x = c(87, 71, 61),  # 高/中/低价位区域的中心位置
  label = c("高价位", "中价位", "低价位")
)

y_region_labels <- data.frame(
  y = c(95, 83.5, 63),  # 高/中/低销量区域的中心位置
  label = c("高销量", "中销量", "低销量")
)

ggplot(df, aes(x = price_index, y = quantity_index, label = products)) +
  coord_fixed() +
  geom_point(colour = 'blue', size = 3, alpha=0.9) +
  # 绘制区域分割线
  geom_vline(xintercept = c(68, 74), color='black', linetype='dotted', size=1) +
  geom_hline(yintercept = c(77, 90), color='black', linetype='dotted', size=1) +
  # 自定义基础坐标轴
  scale_x_continuous(
    expand = c(0, 0), 
    limits = c(50, 100),
    breaks = seq(50, 100, 5),
    name = "价格指数"
  ) +
  scale_y_continuous(
    expand = c(0, 0), 
    limits = c(50, 100),
    breaks = seq(50, 100, 5),
    name = "销量指数"
  ) +
  # 添加X轴上层区域标签
  annotate("text", x = x_region_labels$x, y = 47, label = x_region_labels$label, size = 4, fontface = "bold") +
  # 添加Y轴上层区域标签(旋转90度)
  annotate("text", y = y_region_labels$y, x = 47, label = y_region_labels$label, size = 4, fontface = "bold", angle = 90) +
  # 调整边距避免标签被截断
  theme(
    plot.margin = margin(10, 10, 25, 25, "pt"),
    axis.title.x = element_text(margin = margin(t = 15)),
    axis.title.y = element_text(margin = margin(r = 15))
  )

关键说明

  • 区域标签位置:根据分割线计算各区域的中心坐标,确保标签居中显示
  • 边距调整:扩大绘图区域的下、左边距,防止外侧标签被截断;同时调整轴标题边距,避免和上层标签重叠
  • 样式区分:用fontface = "bold"让分类标签更醒目,和底层数值刻度形成层级

方式二:通过辅助轴(sec_axis)实现双层标签

这种方式利用ggplot2的辅助轴功能,将分类标签绑定到坐标轴系统,位置更规整。

完整代码

library(ggplot2)

ggplot(df, aes(x = price_index, y = quantity_index, label = products)) +
  coord_fixed() +
  geom_point(colour = 'blue', size = 3, alpha=0.9) +
  # 绘制区域分割线
  geom_vline(xintercept = c(68, 74), color='black', linetype='dotted', size=1) +
  geom_hline(yintercept = c(77, 90), color='black', linetype='dotted', size=1) +
  # 自定义X轴:底层数值刻度,上层分类标签
  scale_x_continuous(
    expand = c(0, 0), 
    limits = c(50, 100),
    breaks = seq(50, 100, 5),
    name = "价格指数",
    sec.axis = sec_axis(
      trans = ~.,  # 保持和原轴一致的转换关系
      breaks = c(61,71,87),  # 对应各区域中心位置
      labels = c("低价位","中价位","高价位"),
      name = ""  # 隐藏辅助轴标题
    )
  ) +
  # 自定义Y轴:底层数值刻度,上层分类标签
  scale_y_continuous(
    expand = c(0, 0), 
    limits = c(50, 100),
    breaks = seq(50, 100, 5),
    name = "销量指数",
    sec.axis = sec_axis(
      trans = ~.,
      breaks = c(63,83.5,95),
      labels = c("低销量","中销量","高销量"),
      name = ""
    )
  ) +
  # 调整辅助轴标签的边距
  theme(
    axis.text.x.top = element_text(margin = margin(b = 10)),
    axis.text.y.right = element_text(margin = margin(l = 10))
  )

关键说明

  • 辅助轴转换:设置trans = ~.让辅助轴和原轴完全对齐,保证标签位置准确
  • 标签映射:将分类标签绑定到对应区域的中心位置,实现和分割线的对应
  • 样式调整:通过theme调整辅助轴标签的边距,避免和原轴刻度重叠

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 12:23:10