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

如何在ggplot中合并两张normal probability plot并添加图例?

合并两张正态分布概率图(共用X轴+添加图例)的ggplot实现方案

问题描述

我有如下两张正态概率图的代码:

library(ggplot2)

# Plot 1
ggplot(data.frame(x = c(-4, 4)), aes(x)) + 
  stat_function(fun = dnorm, args = list(mean = 0, sd = 1), col='red') + 
  stat_function(fill='red', fun = dnorm, xlim = c(-4, -1), geom = "area") + 
  stat_function(fill='red', fun = dnorm, xlim = c(-1, 4), geom = "area", alpha = 0.3) 

# Plot 2
ggplot(data.frame(x = c(-4, 4)), aes(x)) + 
  stat_function(fun = dnorm, args = list(mean = 0, sd = 2), col='blue') + 
  stat_function(fill='blue', fun = dnorm, args = list(mean = 0, sd = 2), xlim = c(-4, -1), geom = "area") + 
  stat_function(fill='blue', fun = dnorm, args = list(mean = 0, sd = 2), xlim = c(-1, 4), geom = "area", alpha = 0.3) 

单独展示这两张图正常,但我希望将它们合并到同一绘图窗口,共用x轴,同时基于填充颜色添加图例来区分两者。请问能否用ggplot实现?盼相关指引。

实现方案

可以用ggplot实现,以下提供两种可靠的实现方式:

方式一:基于stat_function循环扩展

核心思路是通过分组变量映射颜色/填充属性,利用循环批量生成曲线和填充区域,自动关联图例:

library(ggplot2)

# 定义分布参数:均值、标准差、分组名称、对应颜色
dist_params <- data.frame(
  mean = c(0, 0),
  sd = c(1, 2),
  group = c("SD=1", "SD=2"),
  color = c("red", "blue")
)

# 创建平滑的x轴数据
x_range <- data.frame(x = seq(-4, 4, length.out = 1000))

ggplot(x_range, aes(x)) +
  # 绘制两条正态分布曲线
  lapply(1:nrow(dist_params), function(i) {
    stat_function(
      fun = dnorm,
      args = list(mean = dist_params$mean[i], sd = dist_params$sd[i]),
      aes(color = dist_params$group[i]),
      linewidth = 1
    )
  }) +
  # 绘制左侧填充区域(x ≤ -1)
  lapply(1:nrow(dist_params), function(i) {
    stat_function(
      fun = dnorm,
      args = list(mean = dist_params$mean[i], sd = dist_params$sd[i]),
      aes(fill = dist_params$group[i]),
      xlim = c(-4, -1),
      geom = "area",
      alpha = 0.8
    )
  }) +
  # 绘制右侧填充区域(x ≥ -1)
  lapply(1:nrow(dist_params), function(i) {
    stat_function(
      fun = dnorm,
      args = list(mean = dist_params$mean[i], sd = dist_params$sd[i]),
      aes(fill = dist_params$group[i]),
      xlim = c(-1, 4),
      geom = "area",
      alpha = 0.3
    )
  }) +
  # 绑定自定义颜色映射
  scale_color_manual(values = setNames(dist_params$color, dist_params$group)) +
  scale_fill_manual(values = setNames(dist_params$color, dist_params$group)) +
  # 合并颜色和填充的图例,统一标题
  guides(
    color = guide_legend(title = "正态分布"),
    fill = guide_legend(title = "正态分布")
  ) +
  # 设置图表标签
  labs(
    x = "X值",
    y = "密度",
    title = "合并后的正态分布概率图"
  ) +
  theme_minimal()

方式二:预计算数据后用geom_ribbon绘制

先计算所有分布的密度值,再用geom_line和geom_ribbon分别绘制曲线和填充区域,代码结构更直观:

library(ggplot2)
library(dplyr)

# 生成包含所有分布数据的数据集
x_vals <- seq(-4, 4, length.out = 1000)
plot_data <- expand.grid(x = x_vals, group = c("SD=1", "SD=2")) %>%
  mutate(
    mean = 0,
    sd = ifelse(group == "SD=1", 1, 2),
    density = dnorm(x, mean, sd),
    # 区分左右区域的密度值(用于填充)
    density_left = ifelse(x <= -1, density, 0),
    density_right = ifelse(x >= -1, density, 0)
  )

ggplot(plot_data, aes(x)) +
  # 绘制正态分布曲线
  geom_line(aes(y = density, color = group), linewidth = 1) +
  # 绘制左侧填充区域
  geom_ribbon(aes(ymin = 0, ymax = density_left, fill = group), alpha = 0.8) +
  # 绘制右侧填充区域
  geom_ribbon(aes(ymin = 0, ymax = density_right, fill = group), alpha = 0.3) +
  # 自定义颜色映射
  scale_color_manual(values = c("SD=1" = "red", "SD=2" = "blue")) +
  scale_fill_manual(values = c("SD=1" = "red", "SD=2" = "blue")) +
  # 合并图例并设置标题
  guides(color = guide_legend(title = "正态分布"), fill = guide_legend(title = "正态分布")) +
  labs(x = "X值", y = "密度", title = "合并后的正态分布概率图") +
  theme_minimal()

关键说明

  • 两种方式都通过aes映射group变量实现图例自动生成,避免手动添加颜色导致的图例失效问题
  • 自定义颜色映射确保曲线和填充色一致,提升图表可读性
  • 使用高密度的x轴数据(length.out=1000)保证曲线和填充区域的平滑度

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 06:01:00