The problem I have is that I am not able to automatically generate a GUI in Shiny. The idea is to see how many files there are and generate a set of Image + button for each file. I believe the solution to this problem is the solution to ANY GUI generation in R.
I am able to do this statically, writing the code for each button and image, but it doesn't work to put it in a for loop, or to render the image in the server.R and pass it as HTML to the ui.R. I will explain below.
The code I want to generate is:
actionButton("sug1",icon=imageOutput("sug1",width="100px",height="100px"),label="First")
Which gives me a 100x100 clickable image.
I have tried the following:
1) Surrounding it with a for loop inside of ui.R and making the ID("sug1") and the label a variable where the last number increments each loop.
2) Accumulating the result and using the HTML() function in server.R to later output it in ui.R
output$generateImages <- renderUI({
(...)
for(...){
(...)
w <- paste(w, actionButton(paste("oc",which(dir==folders)),label=dir))
}
HTML(w)
})
and then in ui.R in the place I want it to appear:
htmlOutput("generateImages")
3) I guessed that using HTMLoutput or UIOutput should help, but given that the HTML output my code generates(as seen in righ tlick/view page source) is:
<button id="sug1" type="button" class="btn action-button">
<div id="sug1" class="shiny-image-output" style="width: 100px ; height: 100px"></div>
First
</button>
I was not able to figure out how to generate this as I knew not how and where to insert a reference to an image.
Would appreciate help.
Thanks to the help of Jeff in the comment section, I was able to get something that loops and generates elements of UI.
The whole trick is to have a renderUI function, that has a for loop inside, which accumulates the elements in a list, which in my case is:
LL[[i]] <- list(actionButton(txt,icon=imageOutput(pp,width="100px",height="100px"),label=dir))
This list has to be returned by the function. All this is in server.R. In ui.R one should write:
uiOutput(nameOfTheFunctionThatReturnedTheList)
My problem still is however that I cannot make it to display images using the same loop...Help anyone? ;)
My solution to this problem is as follows:
- Define a function that creates the desired type of widget. Give it one parameter, an integer, and append that integer to the name of the widget using `paste0'.
- Define a reactive object that applies the function to a vector of integers and returns the result as a list using
lapply
.
- Define an output object using
renderUI
that returns the reactive object inside tagList
.
Below is the code for a working version.
ui.R
library(shiny)
shinyUI(fluidPage(
titlePanel("WidgetVector"),
sidebarLayout(
sidebarPanel(uiOutput("OnButton"),uiOutput("NumberOfWidgets")),
mainPanel(uiOutput("WidgetVectorDisplay")
)
)
))
server.R
library(shiny)
shinyServer(function(input, output) {
output$OnButton=renderUI({radioButtons("TurnOn",label="On/Off",choices=c("On"=1,"Off"=2),selected=2)})
output$NumberOfWidgets=renderUI({numericInput("WidgetCount",label="How many widgets?",value=1)})
makeRadioButton=function(n=1){radioButtons(paste0("Radio",n),label="Pick",choices=c("a"=1,"b"=2,"c"= 3),selected=1)}
WidgetVector=reactive({lapply(X = 1:input$WidgetCount, FUN = makeRadioButton)})
output$WidgetVectorDisplay <- renderUI({
if(is.null(input$TurnOn)){return()
} else if(input$TurnOn == 2){return()
} else tagList(WidgetVector())})
})