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
The issue is that all the stat_function
s 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.
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.