1

How can I add_trace in a loop when using a list of dataframes

I keep getting the following using code below

df1<-c(seq(1:32))
df2<-df*2
df3<-df2*8
dff1<-sqrt(df1)
dff2<-sqrt(df2)
dff3<-sqrt(df3)


a<-cbind.data.frame(df1,dff1)
b<-cbind.data.frame(df2,dff2)
c<-cbind.data.frame(df3,dff3)
colnames(a)<-c("df1","df2")
colnames(b)<-c("df1","df2")
colnames(c)<-c("df1","df2")

df<-list()
df[[1]]<-a
df[[2]]<-b
df[[3]]<-c

pl<-plot_ly()
for(i in 1:3){

  pl<- add_trace(pl,data=df[[i]],x=~df[[i]]$df1,y=~df[[i]]$df2,mode='lines',type='scatter') 


}

pl

enter image description here

and when using lapply instead of for loops i get three seperate graphs instead of one graph with three lines

pl<-plot_ly()

pl<-lapply(1:3, function(i){

  pl<- pl%>%
    add_trace(data=df[[i]],x=~df[[i]]$df1,y=~df[[i]]$df2,mode='lines',type='scatter',inherit = TRUE) 


})
pl
aosmith
  • 34,856
  • 9
  • 84
  • 118
shamary
  • 305
  • 3
  • 12
  • Use `evaluate = TRUE` in `add_trace`. – Ryan Morton Sep 14 '17 at 18:12
  • 2
    I knew about evaluate = TRUE in add_trace from other posts. But that doesn't work – shamary Sep 14 '17 at 18:19
  • 1
    I think your problem is in using dollar sign notation for `x` and `y` instead of referring directly to the variable. Use `data=df[[i]],x=~df1,y=~df2` instead. Since *plotly 4.0* evaluation is forced so `evaluation = TRUE` is [no longer needed](https://stackoverflow.com/a/38830530/2461552) – aosmith Sep 14 '17 at 18:19
  • That worked for for loops. I did the same change using lapply that still produces three separate graphs. Is there a way to get lapply to add_trace in loop like fashion instead of it creating three separate charts – shamary Sep 14 '17 at 18:29
  • 1
    The three separate graphs has to do with how the `apply` family works. See [here](https://stackoverflow.com/a/2657002/2461552) for how to alter things outside the scope of the function via `assign` or `<<-`, although sticking with the loop for this task is an easy alternative. – aosmith Sep 14 '17 at 18:51

1 Answers1

1

While other users have correctly noted that this can simply be done with a for loop, I figured I might as well just answer how to do it with lapply() for any future folks who come upon this question.

This can be done with lapply() by using the get() method, which allows you to specify the environment when retrieving a variable. Wrapping your lapply with invisible() prevents the loop from printing intermediates to you console/viewer as it runs.

Here is the code:

df1<-c(seq(1:32))
df2<-df1*2
df3<-df2*8
dff1<-sqrt(df1)
dff2<-sqrt(df2)
dff3<-sqrt(df3)


a<-cbind.data.frame(df1,dff1)
b<-cbind.data.frame(df2,dff2)
c<-cbind.data.frame(df3,dff3)
colnames(a)<-c("df1","df2")
colnames(b)<-c("df1","df2")
colnames(c)<-c("df1","df2")

df<-list()
df[[1]]<-a
df[[2]]<-b
df[[3]]<-c

pl<-plot_ly()

invisible(lapply(seq_along(df), FUN = function(i) {
  pl <<- get("pl", envir = globalenv()) %>% 
    add_trace(pl,data=df[[i]],x=~df[[i]]$df1,y=~df[[i]]$df2,mode='lines',type='scatter')  
}))

pl
Nashvilli
  • 11
  • 1