Automatic GUI Generating in R Shiny

2019-07-02 00:09发布

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.

2条回答
乱世女痞
2楼-- · 2019-07-02 00:42

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? ;)

查看更多
兄弟一词,经得起流年.
3楼-- · 2019-07-02 00:44

My solution to this problem is as follows:

  1. 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'.
  2. Define a reactive object that applies the function to a vector of integers and returns the result as a list using lapply.
  3. 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())})
})
查看更多
登录 后发表回答