0

Ok I have code that you can run below. I am trying to modify this code:

https://gist.github.com/wch/5436415/

so that max_plots is dynamically set using input from the UI. The input from the UI is dynamic as well.

Here is my UI.R:

shinyUI(pageWithSidebar(
  headerPanel("Dynamic number of plots"),
  sidebarPanel(
    selectInput("Desk", "Desk:" ,  c("A","B")),
   uiOutput("choose_Product"),
uiOutput("choose_File1"),
uiOutput("choose_Term1"),
sliderInput("n", "Number of plots", value=1, min=1, max=5)
  ),

  mainPanel(
    # This is the dynamic UI for the plots
    h3("Heading 1"),
    uiOutput("plots"),
   h3("Heading 2")
  )
))

Here is my Server.R:

shinyServer(function(input, output) {

  output$choose_Product <- renderUI({
    selectInput("Product", "Product:", as.list( c("Product1","Product2","Product3")))
  })

  output$choose_File1 <- renderUI({
selectInput("File1", "File1:", as.list(c("File1","File2","File3")))
  })

# Insert the right number of plot output objects into the web page

  output$plots <- renderUI({
      plot_output_list <- lapply(1:input$n, function(i) {
        plotname <- paste("plot", i, sep="")
        plotOutput(plotname, height = 280, width = 250)
      })

      # Convert the list to a tagList - this is necessary for the list of items
      # to display properly.
      do.call(tagList, plot_output_list)
  })##End outputplots

  PrintPlots<- reactive({
## I need max_plots to be set as the length of the Vector returns from getAugmentedTerms()
max_plots<-length(getAugmentedTerms(input$Desk, input$Product, input$File1))

# Call renderPlot for each one. Plots are only actually generated when they
# are visible on the web page.

for (i in 1:max_plots) {
  # Need local so that each item gets its own number. Without it, the value
  # of i in the renderPlot() will be the same across all instances, because
  # of when the expression is evaluated.
  local({
        my_i <- i
        plotname <- paste("plot", my_i, sep="")

        output[[plotname]] <- renderPlot({
           plot(1:my_i, 1:my_i,
           xlim = c(1, max_plots),
               ylim = c(1, max_plots),
               main = paste("1:", my_i, ". n is ", input$n, sep = "") )
        })
      })
    }##### End FoR Loop
  })# END OF PRINT PLOTS
})# END OF ENERYTHING

Here is my global.R:

getAugmentedTerms<-function(desk, product, file)
{
   # this function takes 3 inputs from the UI and returns a vector
   # for simplicity I am just returning a 2 element vector
   d<-c(1,2)
   return d
}

Here is code to run it:

library(shiny)
runApp("C:/Users/user/Desktop/R Projects/TestDynamicPlot")

When you run this you can see space is created like there are being plots output but the output is blank. Any ideas? Thank you!

user3022875
  • 8,598
  • 26
  • 103
  • 167
  • The `input` object is undefined outside the shiny server function. And in the example `max_plots` is hard coded, `input$n` for the loop creating the plot ouputs isn't – Julien Navarre Apr 03 '14 at 14:48
  • 1
    @user3022875 Post your comments as a separate answer or edit your question, do not edit others' answers. – vortexwolf Apr 03 '14 at 15:51

1 Answers1

8

So max_plots is hard coded. When you launch the app, the loop for (i in 1:max_plots ) { (It runs only once) creates 5 (= max_plots) new output elements (output$plot1 output$plot2 ...) which render a plot, but the plots are displayed only when the respectiveplotOutputsexists in the UI. TheplotOutputs are created dynamically in the functionlapply(1:input$n, function(i) {input$n is the value of the slider. 5 plots are created but we only createinput$nplot outputs. That's why this is dynamic even ifmax_plots` is hard coded.

If you want you can replace max_plots by the dynamic parameter but you need to include the loop into and observer. And it will run each time input$n changed.

For example :

observe({
    for (i in 1:input$n) {
        # Need local so that each item gets its own number. Without it, the value
        # of i in the renderPlot() will be the same across all instances, because
        # of when the expression is evaluated.
        local({
          my_i <- i
          plotname <- paste("plot", my_i, sep="")

          output[[plotname]] <- renderPlot({
            plot(1:my_i, 1:my_i,
                 xlim = c(1, max_plots),
                 ylim = c(1, max_plots),
                 main = paste("1:", my_i, ". n is ", input$n, sep = "")
            )
          })
        })
     }
})

I don't know what your function returns but i suppose it can also work if you include it into the server function and inside a reactive function in which you can read input object.

observe({ 
    max_plots<-length(getTerm1UI(input$Desk, input$Product, input$File1))
    for(i in 1:max_plots) {
       ...
Gorpik
  • 10,940
  • 4
  • 36
  • 56
Julien Navarre
  • 7,653
  • 3
  • 42
  • 69
  • Julien - I have a test case above that reproduces what I am experiencing. max_plots is set from input from the dynamic UI. You can run the code and see what is happening. Thank you! – user3022875 Apr 03 '14 at 16:30
  • Julien -- My problem now is that in last bit of code you wrote observe({ max_plots<-length(getTerm1UI(input$Desk, input$Product, input$File1))......... This observe gets called BEFORE input$Product and input$File have any values in them. They are both NULL and that causes an error. Can this be made reactive instead of using Observe so that does not happen? – user3022875 Apr 03 '14 at 18:47
  • I tested your code it doesn't work with `reactive` and works with `observe`. I don't understand what you want to do ? – Julien Navarre Apr 03 '14 at 19:01
  • The problem is that the "observe" occurs BEFORE the input$Product and input$File1 are populated. see here: http://stackoverflow.com/questions/22845874/r-shiny-observe-running-before-loading-of-ui-and-this-causes-null-parameters ......Since observe happens first is there a way to move the for loop into a reactive function instead of using observe? – user3022875 Apr 03 '14 at 19:04