My problem is as follows:
I have a shiny application that displays a variable number of output elements based on user input (as, for example, is detailed in: dynamically add plots to web page using shiny).
However, I'd also like to add to each output element an input element allowing the user to specify some modifier for the output (for example, let the user choose between viewing each element as a plot or a table, but one can generalize for any kind of modification to the variable number of outputs).
I figured the easiest way to do that would be to add to every element a selectInput element with the choices I want the user to have. My problem is that every time the page is rendered, the selectInput elements seem to revert to their initial values, so that changing them has no effect (actually, for an instant they do have an effect, but then they are reset and the effect is reverted).
The following code reproduces the problem (modified based on the answer by @skasch to the above mentioned question):
server.R
library(shiny)
max_plots <- 5
shinyServer(function(input, output) {
# Insert the right number of plot output objects into the web page
output$plots <- renderUI({
plot_output_list <- lapply(1:input$n, function(i) {
modifier <- paste("select",i,sep="")
plotname <- paste("plot", i, sep="")
plottitle <- paste("plottitle", i, sep="")
tablename <- paste("tablename", i, sep="")
# By default I display a plot
disp <- plotOutput(plotname, height = 280, width = 250)
# modifier may not be in the input if this is the first time the element is displayed
if(modifier %in% names(input) && input[[modifier]] == "table") {
disp = tableOutput(tablename)
}
# Make the output element display properly:
tagList(
textOutput(plottitle, container = h3),
uiOutput(modifier),
disp)
})
# Convert the list to a tagList - this is necessary for the list of items
# to display properly.
do.call(tagList, plot_output_list)
})
# 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
modifier <- paste("select",i,sep="")
plotname <- paste("plot", my_i, sep="")
plottitle <- paste("plottitle", my_i, sep="")
tablename <- paste("tablename", 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 = ""))
})
output[[plottitle]] <- renderText({paste("1:", my_i, ". n is ", input$n, sep = "")
})
output[[tablename]] <- renderTable({table(x = 1:my_i, y = 1:my_i)
})
# I suspect the problem is the re-evaluation of this part that resets the "selected" field
output[[modifier]] <- renderUI({selectInput(
inputId = modifier,
label="select how to display",
choices = c("plot","table"),
selected = 1)})
})
}
})
ui.r
library(shiny)
shinyUI(pageWithSidebar(
headerPanel("Dynamic number of plots"),
sidebarPanel(
sliderInput("n", "Number of plots", value=1, min=1, max=5)
),
mainPanel(
uiOutput("plots") # This is the dynamic UI for the plots
)
))