4

very simple question: I want several barplots in output,

for example: I have a dataset: data and a list of customer: cname

shinyServer(function(input, output){
     for(name in cname){
        output[[name]] <- renderPlot({
        bp<-barplot(data[data$customer==name,1])
        })
     }
}

But it doesn't work, it seems the loop is not fully executed, need someone's help here.

yabchexu
  • 543
  • 7
  • 21
  • Please provide a a [reproducible example](http://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example) with some sample data so we can test the code to see what might be going on. Also include a simple UI to test with. – MrFlick Mar 02 '16 at 02:19

2 Answers2

7

So the problem you seem to be running into is related to delayed evaluation. The commands in renderPlot() are not executed immediately. They are captured and run when the plot is ready to be drawn. The problem is that the value of name is changing each iteration. By the time the plots are drawn (which is long after the for loop has completed), the name variable only has the last value it had in the loop.

The easiest workaround would probably be to switch from a for loop to using Map. Since Map calls functions, those functions create closures which capture the current value of name for each iteration. Try this

# sample data
set.seed(15)
cname <- letters[1:3]
data <- data.frame(
    vals = rpois(10*length(cname),15),
    customer = rep(cname,each=10)
)

runApp(list(server=
shinyServer(function(input, output){
     Map(function(name) {
           output[[name]] <- renderPlot({
           barplot(data[data$customer==name,1])
        })
        },
        cname)
})
,ui=
shinyUI(fluidPage(
    plotOutput("a"),
    plotOutput("b"),
    plotOutput("c")
))
))
Brandon Bertelsen
  • 43,807
  • 34
  • 160
  • 255
MrFlick
  • 195,160
  • 17
  • 277
  • 295
4

I agree with the explanations in the accepted answer. However we don't need to use a Map function which is a wrapper to mapply i.e. a multivariate version of sapply (see ?Map). In that case, we could simply use the more traditional function lapply :

lapply(cname, function(name) {
    output[[name]] <- renderPlot({
      barplot(data[data$customer==name,1])
    })
  })