通过循环将多个曲线/函数添加到一个ggplot

时间:2019-02-21 13:58:44

标签: r ggplot2

我想将多个曲线添加到一个ggplot中。使用普通的plotcurve(add=TRUE),我可以循环使用曲线功能并可以添加多个曲线/功能。

由于我想重写ggplot的代码,因此我试图弄清楚如何使用ggplot实现此目的。

我正在使用stat_functionfor循环,但是ggplot并没有添加curve,只是保存了最后一个。

单行的最小可复制示例:

library(ggplot2)
p1<-ggplot()
for (i in 1:10){
  p1<- p1 + stat_function(aes(x=1:200),fun = function(x) {x+i*3}, col=i)
  print(p1)
}

我认为代码应该做什么:

我循环多个stat_function并将其添加到我的情节p1

我想做什么:

我希望将Alle线添加到一个图中(p1)。照原样的代码仅显示循环的最后一行,就好像它总是覆盖绘图一样,但是据我所知ggplot,这应该只添加一行。另外解释一下为什么不起作用的原因可能很好,也许我只是在这里ggplot不理解

2 个答案:

答案 0 :(得分:3)

问题是您所引用的所有stat_function都与 same i变量有关。因此,您添加的每个功能都会与其他功能完美重叠。

解决方案是在局部范围内重新分配变量,为每次迭代创建局部副本:

p1 = ggplot(data.frame(x = 1 : 200)) + aes(x)

for (i in 1:10){
    p1 = local({
        j = i
        p1 + stat_function(fun = function(x) x + j * 3, col = j)
    })
}

为了使事情更加混乱,您实际上不必给局部变量起一个新的名字;您可以很容易地编写i = i,并继续使用i。原因是此分配将生成新的局部变量i ,该变量将掩盖非局部变量i。我希望我们可以同意编写这样的代码会造成混乱,这是一个坏主意。

我还通过将数据xstat_function中移出并直接移到ggplot对象中,略微简化了代码。

但是,在这里完全不使用循环和重新分配更为干净。相反,您可以使用lapplymap(来自purrr软件包):

p1 = ggplot(data.frame(x = 1 : 200)) +
    aes(x) +
    map(
        1 : 10,
        ~ stat_function(fun = function (x) x + .x * 3, color = .x)
    )

这更短,更易读(它着重于“什么”而不是“如何”,即循环的机制),并且使用单个分配。

答案 1 :(得分:2)

尝试:

library(ggplot2)
add_curve <- function(plot, i) {
  return(plot + stat_function(aes(x=1:200),fun = function(x) {x+i*3}, col=i))
}

p1 <- ggplot()


for (i in 1:10){
  p1<- add_curve(p1, i)
}

p1

输出为:

enter image description here

或者,您也可以在for循环中定义函数:

for (i in 1:10){
  add_curve <- function(plot, i) {
    return(plot + stat_function(aes(x=1:200),fun = function(x) {x+i*3}, col=i))
  }
  p1<- add_curve(p1, i)
}

或作为(有点晦涩)Reduce + lapply单线(与@KonradRudolph相似):

eval(
  Reduce(function(a, b) call('+', a, b), 
         lapply(1:10, function(i) {
           bquote(stat_function(aes(x=1:200),fun = function(x) {x+.(i)*3
             }, col=.(i)))}), init = quote(ggplot())))

该想法是立即构建整个ggplot()调用,然后对其进行评估。