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

如何在双数据框的分组柱状图中实现散点的QQ图式排序

要实现你需要的“QQ图样式排序散点”效果,核心是先对df2每个分组内的散点按数值排序,再调整它们的位置让其垂直排列,同时简化数据处理逻辑避免重复代码。以下是完整的优化方案:

步骤1:优化数据预处理

我们先把df1的阈值合并到df2中,简化颜色判断逻辑,同时给每个分组内的散点按数值排序生成序号(作为QQ图样式的排列依据):

library(dplyr)
library(ggplot2)

# 模拟原数据(保留你的初始代码)
set.seed(4)
df1 <- data.frame(var=c("a", "b", "c", "d"), value=c(15, 19, 18, 17))
df2 <- data.frame(var1=rep(c("a", "b", "c", "d"), each=20), value=rnorm(80, 15, 2), color=NA, fill=NA)

# 合并阈值+排序+颜色赋值
df2 <- df2 %>%
  # 将df1的阈值匹配到df2对应的分组
  left_join(df1, by = c("var1" = "var")) %>%
  rename(threshold = value.y, value = value.x) %>% # 重命名避免列名冲突
  # 按分组对散点数值排序,生成排序序号
  group_by(var1) %>%
  arrange(value) %>%
  mutate(
    point_rank = row_number(), # 每个分组内的排序位置(1到20)
    above_threshold = value > threshold # 标记是否超过阈值
  ) %>%
  ungroup() %>%
  # 简化颜色/填充赋值,不用重复写每个分组的判断
  mutate(
    fill = if_else(above_threshold, "#e18b8b", "#8cbee2"),
    color = if_else(above_threshold, "#ca0d0d", "#0c78ca")
  )

# 额外计算每个分组超过阈值的散点数量(用于绘图参考线)
df1 <- df1 %>%
  left_join(df2 %>% group_by(var1) %>% summarise(above_count = sum(above_threshold)),
            by = c("var" = "var1"))

步骤2:绘制带有序散点的图表

我们把柱状图和排序后的散点分开摆放(散点在柱状图右侧),同时添加双y轴和参考线,让阈值对比更直观:

ggplot() +
  # 绘制df1的阈值柱状图
  geom_bar(data = df1, aes(x = var, y = value),
           stat = "identity", fill = "#8cbee2", width = 0.4) +
  # 绘制排序后的散点:每个分组内按数值从小到大垂直排列
  geom_point(data = df2, aes(x = var1, y = point_rank, fill = fill, color = color),
             shape = 21, size = 2, position = position_nudge(x = 0.2)) +
  # 添加红色虚线:标记每个分组超过阈值的散点数量(对应右侧y轴)
  geom_segment(data = df1, aes(x = as.numeric(factor(var)) + 0.2, xend = as.numeric(factor(var)) + 0.2,
                               y = 0, yend = above_count), linetype = "dashed", color = "#ca0d0d") +
  # 双y轴配置:左侧显示阈值数值,右侧显示散点数量/排序序号
  scale_y_continuous(
    name = "df1 分组阈值数值",
    sec.axis = sec_axis(~ ., name = "df2 散点排序序号(数量)")
  ) +
  # 图表标签调整
  labs(x = "分组", 
       title = "分组阈值与散点分布对比",
       subtitle = "红色散点表示超过对应分组阈值") +
  # 应用自定义颜色(因为用了identity scale)
  scale_fill_identity() +
  scale_color_identity() +
  # 主题优化
  theme_minimal() +
  theme(
    axis.title.y.right = element_text(color = "#ca0d0d"),
    plot.title = element_text(hjust = 0.5),
    plot.subtitle = element_text(hjust = 0.5)
  )

效果说明

  1. 散点排序:每个分组内的散点按value从小到大垂直排列,完全符合你要的QQ图样式,不会像jitter那样混乱;
  2. 阈值对比:红色散点清晰标记超出阈值的点,红色虚线直接显示每个分组超阈值的点数量;
  3. 数据逻辑简化:通过left_join合并阈值,避免了重复的subset判断,代码更易维护。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 21:53:13