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

如何在循环中设置stat_function绘制双正态分布交互式直方图?

解决方案

1. 先模拟长格式数据集(适配你的场景)

先造一个和你需求匹配的长格式数据,包含分组变量和数值变量:

library(tidyverse)
library(plotly)

# 模拟长格式数据,两个分组各500条数据
set.seed(123)
df_long <- tibble(
  group = rep(c("分组1", "分组2"), each = 500),
  value = c(rnorm(500, mean = 10, sd = 2), rnorm(500, mean = 12, sd = 2.5))
)

2. 提前计算各组统计量(均值/标准差)

先把每个分组的均值、标准差算好,避免后续重复计算:

group_stats <- df_long %>%
  group_by(group) %>%
  summarize(
    mean_val = mean(value),
    sd_val = sd(value),
    .groups = "drop"
  )

3. 两种实现方式任选

方式一:循环生成子图再拼接(适合个性化调整每个图)

循环遍历每个分组,单独生成带正态曲线和统计竖线的直方图,最后拼成交互式并行图:

# 空列表存每个分组的图
plot_list <- list()

# 循环处理每个分组
for (i in seq_len(nrow(group_stats))) {
  current_group <- group_stats$group[i]
  current_mean <- group_stats$mean_val[i]
  current_sd <- group_stats$sd_val[i]
  
  # 生成单个分组的ggplot
  p <- df_long %>%
    filter(group == current_group) %>%
    ggplot(aes(x = value)) +
    geom_histogram(aes(y = ..density..), bins = 20, fill = "#619CFF", alpha = 0.7) +
    # 传入当前分组的均值/标准差画正态曲线
    stat_function(
      fun = dnorm,
      args = list(mean = current_mean, sd = current_sd),
      color = "#F8766D",
      linewidth = 1.2
    ) +
    # 画均值竖线
    geom_vline(xintercept = current_mean, color = "#00BA38", linetype = "dashed", linewidth = 1) +
    labs(title = current_group, x = "数值", y = "密度") +
    theme_minimal()
  
  # 转成交互式图存入列表
  plot_list[[i]] <- ggplotly(p)
}

# 水平拼接两个图,共享Y轴
subplot(plot_list[[1]], plot_list[[2]], nrows = 1, shareY = TRUE)

方式二:用分面+分组映射(无需循环,更简洁)

如果不需要单独调整每个图,用分面结合stat_function的分组映射更高效:

# 把统计量合并到原数据集,方便映射
df_long_with_stats <- df_long %>%
  left_join(group_stats, by = "group")

# 绘制分面交互式直方图
p_facet <- df_long_with_stats %>%
  ggplot(aes(x = value, group = group)) +
  geom_histogram(aes(y = ..density..), bins = 20, fill = "#619CFF", alpha = 0.7) +
  # 自动提取每个分组的均值/标准差画正态曲线
  stat_function(
    fun = dnorm,
    aes(color = group),
    args = function(data) list(mean = unique(data$mean_val), sd = unique(data$sd_val)),
    linewidth = 1.2
  ) +
  # 分组画均值竖线
  geom_vline(aes(xintercept = mean_val, color = group), linetype = "dashed", linewidth = 1) +
  facet_wrap(~group, nrow = 1) +
  scale_color_manual(values = c("分组1" = "#F8766D", "分组2" = "#00BA38")) +
  labs(x = "数值", y = "密度") +
  theme_minimal() +
  theme(legend.position = "none")

# 转成交互式图
ggplotly(p_facet)

关键注意点

  • stat_function的args参数支持动态传值:循环时直接给当前分组的统计量,分面时通过函数提取每个分面的统计量即可。
  • 循环完全可行:适合需要对每个分组做特殊调整(比如不同配色、不同分箱数)的场景。
  • 交互式部分用ggplotly()直接转换ggplot对象,所有图层都会保留交互效果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 19:56:50