r - 在 for 循环中添加 geom_*
问题描述
我想在一张图中将真实世界的数据与模拟数据进行比较。代码应该接受任意数量的线来绘制。我想出了这个:
simulationRuns <- 5 #Variable to be changed depending on how many simulations were made
plotLoop <- ggplot() +
geom_line(data = relWorldData,
mapping = aes(x = DateTime, y = VALUE, color = "realWorldData"))
for (i in 1:simulationRuns){
plotLoop <- plotLoop +
geom_line(data = listOfSimResults[[i]],
mapping = aes(x = DateTime, y = VALUE, color = paste0("simRun-", i)))
}
figureLoop <- ggplotly(plotLoop)
问题是,所有行都显示为 simRun-5,因此不是独立的 -
我是 R 新手,所以请怜悯;)提前谢谢,帕特里克
后续问题 bc。在评论中阅读代码很糟糕:
我阅读了 Lapply 并将代码重写为:
plotLoop <- ggplot() + geom_line(data = relWorldData, mapping = aes(x = DateTime, y = VALUE, color = "RealWorldData"))
addGeomLine <- function (i, obj){
obj <- obj +
geom_line(data = listOfSimResults[[i]], mapping = aes(x = DateTime, y = VALUE, color = paste0("simRun-", i)))
}
lapply(1:runs, addGeomLine, plotLoop)
figureLoop <- ggplotly(plotLoop)
这一次,只显示 RealWorldData,但没有显示任何 Simulations。你能告诉我我错过了什么吗?
解决方案
欢迎来到 SO!
你遇到了一个微妙的问题,让很多比你有更多经验的人感到困惑。问题是懒惰地ggplot2
评估。简而言之,这意味着当你告诉它你想要什么时,它会“记下”它需要做什么,但实际上直到最后一刻才做任何事情。
在这里,你告诉 ggplot 你想geom
在你的for
循环中添加一个。ggplot 记下geom
' 的定义,但不评估它。“在最后一刻”是你打电话的时候ggplotly
。现在ggplot
意识到它有一些工作要做。对于每一个geom
,它注意到它需要知道 的值i
。所以它查找它并找到 value 5
。因此你的问题。
有几种方法可以解决这个问题。使用您的代码,我首选的选择是for
用lapply
. 与for
循环不同,lapply
强制在执行时评估变量。
我相信您也可以保留for
循环并将每个引用包装i
在 in 中force()
,尽管我没有亲自尝试过。
在我看来,从长远来看,最好的方法是让你的工作流程整洁,避免for
循环或lapply
完全不需要。这还将为您带来更紧凑、更健壮和可读的代码的好处,这些代码几乎肯定会运行得更快。[前几天我做了一些工作,将类似于你的循环转换为一个整洁的解决方案,运行时间从近 40 秒减少到 2 秒以下。]
另外,请阅读这篇文章以获取有关如何创建最小工作示例的建议。提供 MWE 将最大限度地提高您获得有用答案的机会。
更新
为了扩展我对使用整洁数据方法的优势的评论......
首先合成一些数据,因为您没有提供任何数据。我将尝试匹配您的数据结构,但不匹配您的值。您的数据集的唯一区别是我添加了一个ID
变量来识别每个观察来自的模拟运行/真实世界数据集。
library(lubridate)
library(tidyverse)
inVivoBG <- tibble(
ID="Real-world data",
DateTime2=seq(as_date("2006-03-01"), as_date("2015-03-01"), "3 months"),
VALUE=100 + rnorm(37, mean=150, sd=20)
)
listOfSimResults <- lapply(
1:5,
function(x) {
tibble(
ID=paste0("simRun-", x),
DateTime2=seq(as_date("2006-03-01"), as_date("2015-03-01"), "3 months"),
VALUE=100 + rnorm(37, mean=150, sd=20)
)
}
)
现在将各种数据框组合成一个。
data <- bind_rows(inVivoBG, listOfSimResults)
此时,您的情节的构建是单行调用。
data %>%
ggplot() +
geom_line(mapping = aes(x = DateTime2, y = VALUE, color = ID))
给予
这种方法避免了对自定义函数的需要或对lapply
. 它在所需的行数及其标签方面也很健壮。就个人而言,我也认为它更容易理解。
推荐阅读
- visual-studio-code - 文件、文件夹观察者
- javascript - 如何取消订阅方法中的功能?
- ios - 存储完成处理程序并稍后调用成功/错误
- python - 无法使用 python 脚本从 powershell 命令获取输出
- django - 保存数据前的 Django 自定义验证(在数据库级别强制执行)
- maven - 确定从 Maven 项目启动 VS Code 的 projectName
- reactjs - 基于roots/sage在Wordpress项目中嵌入React组件
- apache-spark - Spark SQL - 获取字符串中 Hive 表的列名
- python - 如何计算熊猫数据框中选定列中值的唯一组合,包括值为0的频率?
- javascript - 解码自定义 base64 图像