Reputation: 789
I am trying to make a Shiny tool to create histograms based on the selection of a dateframe and then column in the dataframe. However, I am having a hard time getting the UI to read the columns from a selected dataframe to then present the column options for selection.
For example we have DataFrameA with two columns cl1 and cl2, and then DataFrameB with columns clx, cly, clz. If I select DataFrameA, the next selectInput ui should allow me to select the columns cl! or cl2, and if I had selected DataFrameB it would give me the options of clx, cly, clz.
ui = fluidPage(
selectInput(inputId = "dataFrame",
label = "Select Dataframe",
choices = names(which(unlist(eapply(.GlobalEnv,is.data.frame))))
),
#This is where I get fudged, I want the dataframe name to have been read
#in the server now, and used to select the column names so I can now
#display them as select options.
conditionalPanel(condition = "output.columnChoices",
selectInput(inputId = "dataColumn",
label = "Choose Column:",
choices = "output.columnChoices")
)
)
server <- function(input,output) {
#To my understanding this should reactively read in the dataframe name
#selected and output the list of column names for that dataframe.
output$columnChoices <- reactive({
colnames(input$DataFrame)
})
outputOptions(output, "columnChoices", suspendWhenHidden = FALSE)
}
shinyApp(ui, server)
When I run it, it almost looks like it produces both options and then instantly shifts to only the dataframe input option. Any suggestions? In the end I'd like to produce a histogram based on the column selection but I need to figure this out first.
Upvotes: 1
Views: 668
Reputation: 394
You can use
uiOutput
You place uiOutput("ui_id") in ui section and create whatever you want from server with output$ui_id <- renderUI(). I think code would be like this (i used dirty hack by evaluating name from input to get dataframe, also i delete conditionalPanel because we manage it manually in server):
ui = fluidPage(
selectInput(
inputId = "dataFrame",
label = "Select Dataframe",
choices = names(which(unlist(eapply(.GlobalEnv,is.data.frame))))
),
uiOutput("dataColumnInput")
)
server <- function(input,output) {
output$dataColumnInput <- renderUI({
tagList(
selectInput(
inputId = "dataColumn",
label = "Choose Column:",
choices = colnames(eval(parse(text = input$dataFrame)))
)
)
})
}
shinyApp(ui, server)
Also, you can use
updateSelectInput
for normal input in UI and configure that from server how you need.
UPD: But if you will use pre-known dataframes, better and simpler will be use switch with dataframes (instead evaluating), i think it can look like this:
switch(
input$dataFrame,
"test1" = test1,
"test2" = test2)
Upvotes: 0
Reputation: 25385
You can use updateSelectInput
to update your input with the new column names, and you can use get()
to fetch a dataframe from the environment.
Working example:
A = data.frame(a=letters[1:5],b=letters[6:10],c=letters[11:15])
B = data.frame(x=LETTERS[1:5],y=LETTERS[6:10],z=LETTERS[11:15])
library(shiny)
ui = fluidPage(
selectInput(inputId = "dataFrame",
label = "Select Dataframe",
choices = names(which(unlist(eapply(.GlobalEnv,is.data.frame))))
),
selectInput(inputId = "dataColumn",
label = "Choose Column:",
choices = NULL),
textOutput('test')
)
server <- function(input,output,session) {
observeEvent(input$dataFrame,{
updateSelectInput(session,'dataColumn',choices = colnames(get(input$dataFrame)))
})
output$test = renderText({
df = get(input$dataFrame)
text = paste(df[[input$dataColumn]],sep=', ')
})
}
shinyApp(ui, server)
However, I would advise you to store the data.frames
in a list, and use that list in your app:
A = data.frame(a=letters[1:5],b=letters[6:10],c=letters[11:15])
B = data.frame(x=LETTERS[1:5],y=LETTERS[6:10],z=LETTERS[11:15])
my_dfs = list(A=A,B=B)
library(shiny)
ui = fluidPage(
selectInput(inputId = "dataFrame",
label = "Select Dataframe",
choices = names(my_dfs)
),
selectInput(inputId = "dataColumn",
label = "Choose Column:",
choices = NULL),
textOutput('test')
)
server <- function(input,output,session) {
observeEvent(input$dataFrame,{
updateSelectInput(session,'dataColumn',choices = colnames(my_dfs[[input$dataFrame]]))
})
output$test = renderText({
df = my_dfs[[input$dataFrame]]
text = paste(df[[input$dataColumn]],sep=', ')
})
}
shinyApp(ui, server)
Hope this helps!
Upvotes: 1