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

如何为Kaplan-Meier(阶梯函数)曲线的指定区间绘制下方阴影区域

如何为Kaplan-Meier(阶梯函数)曲线的指定区间绘制下方阴影区域

我来帮你搞定这个Kaplan-Meier曲线阴影的问题!你之前遇到的问题,核心是KM曲线是阶梯状的右连续函数,普通的polygon或geom_area会直接连接数据点,没法还原阶梯的水平段,所以绘制出来的面积会出错。下面我分别给你基础R和ggplot2的正确实现方法,完美覆盖0-40和20-60这两个区间的阴影绘制。

基础R实现

首先我们先加载包和数据,拟合KM模型,然后写一个辅助函数来生成符合阶梯形态的坐标,这样就能轻松绘制任意区间的阴影了:

library(survival)
data(leukemia)
# 拟合KM生存曲线
km <- survfit(Surv(time, status) ~ 1, data = leukemia)

# 定义函数:生成指定区间内KM阶梯曲线的填充坐标
get_km_steps <- function(km, start, end) {
  # 合并区间端点与符合条件的KM时间点,排序去重
  all_times <- sort(unique(c(start, km$time[km$time >= start & km$time <= end], end)))
  # 为每个时间点匹配对应的生存概率(右连续特性:取<=当前时间的最大生存概率)
  all_surv <- sapply(all_times, function(t) km$surv[max(which(km$time <= t), 1)])
  # 构造阶梯的x坐标:每个中间时间点重复两次,生成水平段
  x_steps <- c(start, rep(all_times[-c(1, length(all_times))], each = 2), end)
  # 构造对应的y坐标:匹配x段的生存概率,首尾为0(连接x轴)
  y_steps <- c(0, rep(all_surv[-c(1, length(all_surv))], each = 2), 0)
  return(data.frame(x = x_steps, y = y_steps))
}

接下来绘制KM曲线和两个区间的阴影(用半透明颜色避免遮挡曲线):

# 绘制基础KM曲线
plot(km, conf.int = F, xlab = "time until relapse (in weeks)", 
     ylab = "proportion without relapse", mark.time = T, col = 'blue')
abline(h = 0, v = 0)

# 生成0-40区间的阶梯坐标,绘制蓝色半透明阴影
area_0_40 <- get_km_steps(km, start = 0, end = 40)
polygon(area_0_40$x, area_0_40$y, col = adjustcolor("blue", alpha.f = 0.3), border = F)

# 生成20-60区间的阶梯坐标,绘制红色半透明阴影
area_20_60 <- get_km_steps(km, start = 20, end = 60)
polygon(area_20_60$x, area_20_60$y, col = adjustcolor("red", alpha.f = 0.3), border = F)

ggplot2实现

在ggplot2里,我们不用geom_area(它会线性连接点),而是用geom_rect来逐个绘制阶梯段的矩形,这样能精准贴合KM曲线的阶梯形态:

library(ggplot2)

# 定义函数:生成适合ggplot的KM阶梯阴影数据
get_ggplot_km_data <- function(km, start, end) {
  # 收集区间端点与符合条件的KM时间点,排序去重
  time_points <- sort(unique(c(start, km$time[km$time >= start & km$time <= end], end)))
  # 生成每个阶梯段的x起始和结束点
  x_start <- c(start, time_points[-length(time_points)])
  x_end <- time_points
  # 匹配每个阶梯段对应的生存概率
  surv_vals <- sapply(x_start, function(t) km$surv[max(which(km$time <= t), 1)])
  # 返回包含矩形边界的数据框
  return(data.frame(xmin = x_start, xmax = x_end, ymin = 0, ymax = surv_vals))
}

# 准备KM曲线的基础数据(加上t=0时的生存概率1,让曲线从原点上方开始)
km_dat <- data.frame(
  time = c(0, km$time),
  surv = c(1, km$surv)
)

# 生成两个区间的阴影数据
area_0_40_gg <- get_ggplot_km_data(km, 0, 40)
area_20_60_gg <- get_ggplot_km_data(km, 20, 60)

# 绘制最终图形
ggplot() +
  # 先画20-60的阴影(底层,避免被0-40的阴影完全遮挡)
  geom_rect(data = area_20_60_gg, aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax),
            fill = adjustcolor("red", alpha.f = 0.3)) +
  # 再画0-40的阴影
  geom_rect(data = area_0_40_gg, aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax),
            fill = adjustcolor("blue", alpha.f = 0.3)) +
  # 绘制KM阶梯曲线
  geom_step(data = km_dat, aes(x = time, y = surv), color = "black", linewidth = 1) +
  # 设置轴标签和主题
  labs(x = "time until relapse (in weeks)", y = "proportion without relapse") +
  theme_minimal() +
  # 确保x轴范围覆盖所有关键时间点
  xlim(0, max(km$time))

这样你就能得到完全贴合KM阶梯曲线的区间阴影了,两个区间的重叠部分也会因为半透明效果清晰可见。

备注:内容来源于stack exchange,提问作者Miguel Angel Arnau

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.21 08:09:36