【问题标题】:How to add multiple geoms to ggplot using a list (or for loop)?如何使用列表(或 for 循环)将多个几何图形添加到 ggplot?
【发布时间】:2022-10-04 18:37:02
【问题描述】:

我的问题是,是否可以动态创建一个 geoms 列表,我可以将其添加到 ggplot 中,使我能够一次绘制多个单独的数据系列?

可重现的例子

以下代码演示了我的问题:

library(ggplot2)

# Function to generate fake data
generate_fake_results = function(){
  results = list()
  
  for(i in c(1:10)){
    
    x = c((1+10*i):(10+10*i))
    
    results = append(results, list(data.frame(
      x = as.Date("2000-01-01") + x,
      y = sin(x),
      ylower1 = sin(x) - 0.25,
      ylower2 = sin(x) - 0.5,
      yupper1 = sin(x) + 0.25,
      yupper2 = sin(x) + 0.50
    )
    )
    )
  }
  
  return(results)
}

fake_data = generate_fake_results()


# Function to plot the mean, upper and lower bounds of a model
# The dataset contains two upper and lower bounds; the 80% and 95% confidence interval
predict_margin_func = function(r, color='blue', alpha=0.1){
  return(
    list(
      geom_ribbon(aes(x=as.Date(r$x,"%Y-%m-%d"),
                      ymin=r$ylower1,
                      ymax=r$yupper1), fill=color, alpha=alpha),
      geom_ribbon(aes(x=as.Date(r$x,"%Y-%m-%d"),
                      ymin=r$ylower2,
                      ymax=r$yupper2), fill=color, alpha=alpha),
      geom_line(aes(x=as.Date(r$x,"%Y-%m-%d"), y=r$y), size=1.25, color=color)
    )
  )
}



# This plots the graph that I want, but... I have to manually add each forecast 
# from my fake_data list "manually"
ggplot() +
  predict_margin_func(fake_data[[1]]) + 
  predict_margin_func(fake_data[[2]]) + 
  predict_margin_func(fake_data[[3]]) +
  predict_margin_func(fake_data[[4]]) +
  predict_margin_func(fake_data[[5]])


# I'd rather use a for loop to do this dynamically, but I can't get it to work.
# If I do this, it doesn't work:
plot_list = list()
for(i in c(1:length(fake_data))){
  plot_list = append(plot_list, predict_margin_func(fake_data[[i]]))
}

ggplot() +
  plot_list

虽然解决方案 1“有效”,但我更愿意使用解决方案 2 之类的东西,我不必手动添加要绘制的每个系列,因为如果结果列表中的预测数量发生变化,这更容易扩展.

plot_list 中的结果似乎是 for 循环中最后一个结果/最高 i 的 10 个副本。我在质疑 R 正在做一些聪明的把戏,在这种特定情况下我不想要它,列表中的结果是事物的实例/引用,我想要“也被引用的事物”。

有谁知道我可以在这里做什么?我也许也可以重塑我的数据,但我想知道是否可以使用列表。

【问题讨论】:

  • 您是否尝试过:plot <- ggplot(),然后在循环内执行plot <- plot + predict_margin_func(...)
  • @GregorThomas,不是真的,可以添加一个 geoms 列表:ggplot(mtcars, aes(mpg, disp)) + lapply(c(4,6,8), function(CYL) geom_point(data = ~ subset(., cyl == CYL), color = CYL)) 作品(尽管显然有更好的方法)。
  • 也许问题是您无法添加几何列表的列表...编辑,不,这也很好用。
  • @ImpactGuide,您是否有理由不能将数据(带有一些明确的 ID)和 facet_*group= 合并到该 ID 上?
  • 无论如何,我可以使用ggplot() + lapply(fake_data, predict_margin_func) 重现您的手动绘图(一旦我将fake_results 重命名为fake_data

标签: r ggplot2


【解决方案1】:

预先:我可以修复您的 for 循环(见下文),但我认为更好的解决方案是:

ggplot() + lapply(fake_data, predict_margin_func)


至于为什么你的 for 循环失败了......

ggplot倾向于操作懒洋洋, 所以[[i]] 是在渲染时实现的,而不是在创建 geom 时。这就是为什么你只看到最后一个。虽然R ggplot2 for loop plots same data 似乎是一个类似的问题,但建议的答案并不真正适用。为什么?因为您将值硬编码到 geom 中,而不是在其中分配 data= 并在 geom 本身中使用非标准评估。

在这里,我将data=r 添加到每个geom 并删除它们对r$ 的引用。

predict_margin_func2 = function(r, color='blue', alpha=0.1){
  return(
    list(
      geom_ribbon(data = r, aes(x=as.Date(x,"%Y-%m-%d"),
                      ymin=ylower1,
                      ymax=yupper1), fill=color, alpha=alpha),
      geom_ribbon(data = r, aes(x=as.Date(x,"%Y-%m-%d"),
                      ymin=ylower2,
                      ymax=yupper2), fill=color, alpha=alpha),
      geom_line(data = r, aes(x=as.Date(x,"%Y-%m-%d"), y=y), size=1.25, color=color)
    )
  )
}
plot_list = list()
for(i in c(1:length(fake_data))){
  plot_list = append(plot_list, predict_margin_func2(fake_data[[i]]))
}
ggplot() + plot_list

(产生与上面相同的图)。

【讨论】:

  • 嗨,r2evans!非常感谢您的回答,尤其是有见地的上下文。我一直在思考 for 循环,我完全忘记了 lapply。但即使我确实记得,我也不明白为什么这突然奏效了。关于惰性评估和我的函数将值硬编码到几何和使用非标准评估的上下文,真的非常有价值。
猜你喜欢
  • 2020-01-24
  • 1970-01-01
  • 2016-06-21
  • 1970-01-01
  • 2020-07-21
  • 2020-07-26
  • 2021-01-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多