Add multiple curves / functions to one ggplot through looping

后端 未结 2 1145
耶瑟儿~
耶瑟儿~ 2020-12-12 05:01

I want to add multiple curves to one ggplot. With the normal plot and curve(add=TRUE) i can loop the curve function and can add multip

相关标签:
2条回答
  • 2020-12-12 05:29

    The issue is that all the stat_functions you are refer to the same i variable. And as a consequence, each function you add will overlay perfectly with the others.

    The solution is to reassign the variable in a local scope, to make a local copy for each iteration:

    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)
        })
    }
    

    To make matters more confusing, you don’t actually have to give the local variable a new name; you could just as easily have written i = i, and continued to use i. The reason is that this assignment will generate a new local variable i that masks the non-local variable i. I hope we can agree that writing such code is confusing, and a bad idea.

    I’ve also taken the liberty of simplifying your code slightly by moving the data x out of the stat_function, and into the ggplot object directly.

    However, it is altogether cleaner not to use a loop and reassignment here. Instead you can use lapply or map (from the purrr package):

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

    This is shorter, more readable (it focuses on the “what” rather than the “how”, i.e. the mechanics of the loop), and it uses a single assignment.

    0 讨论(0)
  • 2020-12-12 05:34

    Try:

    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
    

    Output is:

    Or alternatively you can also define your function inside the for-loop:

    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)
    }
    

    Or as a (somewhat obscure) Reduce + lapply one-liner (thx to @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())))
    

    The idea is to build the whole ggplot() call at once and then evaluate it.

    0 讨论(0)
提交回复
热议问题