shinyfiles and renderUI don't work properly - r

I'm trying to use the shinyFiles library in my shinyApp, in order to give the user the possibility to select a group of files or a directory.
My idea is to use a uiOutput that changes depending on a checkbox selection.
Here I report the code, that maybe is more explicative than words
UtilityUI <- fluidPage(
titlePanel("page1"),
fluidRow(
column(2,
wellPanel(
tags$p("Check the box below if you want to choose an entire directory"),
checkboxInput(inputId = 'directory_flag', label = 'Directory path?', value = FALSE),
uiOutput("input_selection_ui")
)
),
column(8
#...
)
)
)
UtilityServer <- function(input, output, session) {
output$input_selection_ui <- renderUI({
if(input$directory_flag == TRUE) {
shinyDirButton(id = "infiles", label = "Choose directory", title = "Choose a directory")
} else {
shinyFilesButton(id = "infiles", label = "Choose file(s)", title = "Choose one or more files", multiple = TRUE)
}
})
shinyFileChoose(input, 'infiles', roots=getVolumes(), session=session, restrictions=system.file(package='base'))
shinyDirChoose(input, 'infiles', roots=getVolumes(), session=session, restrictions=system.file(package='base'))
}
shinyApp(UtilityUI, UtilityServer)
The problem borns when the "shinyFiles" button is pressed: the popup window doesn't load the roots, in both cases (shinyDirButton and shinyFilesButton).
If I don't use the uiOutput function everything works well... But in that case I cannot change my UI dinamically...
Thanks a lot for your replies,
Inzirio

It seems I can't get it to work either with renderUI(). Instead I implemented the same behavior using conditionalPanel() to show alternative buttons. This seems to work. Here is the code:
ui <- shinyUI(fluidPage(
checkboxInput(
inputId = 'directory_flag',
label = 'Directory path?',
value = FALSE
),
conditionalPanel(
"input.directory_flag == 0",
shinyFilesButton(
id = "infile",
label = "Choose file(s)",
title = "Choose one or more files",
multiple = TRUE
)
),
conditionalPanel(
"input.directory_flag == 1",
shinyDirButton(id = "indir", label = "Choose directory", title = "Choose a directory")
)
))
server <- shinyServer(function(input, output, session) {
shinyFileChoose(
input,
'infile',
roots = getVolumes(),
session = session,
restrictions = system.file(package = 'base')
)
shinyDirChoose(
input,
'indir',
roots = getVolumes(),
session = session,
restrictions = system.file(package = 'base')
)
})
shinyApp(ui, server)

Related

How do I use input from `selectizeInput` to filter a list of options and then `updateSelectizeInput`?

BACKGROUND:
I have a large list of stock symbols, 27,000 rows, that I would like to be choices in a selectizeInput() on a shinyApp. Since the list is large I am using server = T in updateSelectizeInput().
AIM:
I would like the options list to not load/render until a user starts typing a string into selectizeInput(), so that I can return all symbols that start with that letter, to reduce loading all 27,000 rows in the input. I would like input$ticker to be what is observed and then what triggers the filtering code logic. How can i achieve this without using a specific button?
Shown below is
intended output, but with a button to produce the behavior instead of the user being in the text box. This is along the lines of what I would like, but does not automatically start searchign when I type in the box and has bad code smell to me.
current logic, using input$ticker in an observer to trigger selection of df and populate updateSelectize() with new choices, but is failing and the app is evaluating too soon?\
trying to load choices once, using upload button only doesn't work
REPREX:
1.
library(shiny)
tickers <- rep(rownames(mtcars), 850)
ui <- {
renderUI(
shiny::fluidRow(
bs4Dash::box(
title = shiny::selectizeInput(
inputId = "ticker",
label = "Ticker:",
choices = NULL,
selected = "AAPL",
options = list(
placeholder = "e.g AAPL",
create = TRUE,
maxOptions = 50L
)
),
actionButton(
inputId = "update",
label = "UPDATE NOW"
),
id = "tickerBox",
closable = F,
maximizable = F,
width = 12,
height = "250px",
solidHeader = FALSE,
collapsible = F
)
)
)
}
server <- function(input, output, session){
choice <- reactive(
tickers[startsWith(tickers$symbol, input$ticker), ]
)
observeEvent(input$update, {
updateSelectizeInput(
session = session,
label = "Ticker:",
inputId ="ticker",
choices = choice(),
server = TRUE
)
})
}
shiny::shinyApp(ui = ui, server = server)
# REPREX for selectize, glitches and `input$ticker` observer causes loop gltich?
library(shiny)
tickers <- rep(rownames(mtcars), 850)
ui <- {
renderUI(
shiny::fluidRow(
bs4Dash::box(
title = shiny::selectizeInput(
inputId = "ticker",
label = "Ticker:",
choices = NULL,
selected = "AAPL",
options = list(
placeholder = "e.g AAPL",
create = TRUE,
maxOptions = 50L
)
),
actionButton(
inputId = "update",
label = "UPDATE NOW"
),
id = "tickerBox",
closable = F,
maximizable = F,
width = 12,
height = "250px",
solidHeader = FALSE,
collapsible = F
)
)
)
}
server <- function(input, output, session){
# updateSelectizeInput(
# session = session,
# label = "Ticker:",
# inputId ="ticker",
# choices = tickers,
# server = TRUE
# )
observeEvent(input$ticker, {
choices <- tickers[startsWith(tickers$symbol, input$ticker), ]
updateSelectizeInput(
session = session,
label = "Ticker:",
inputId ="ticker",
choices = choices,
server = TRUE
)
})
}
shiny::shinyApp(ui = ui, server = server)
# REPREX for selectize
library(shiny)
tickers <- rep(rownames(mtcars), 850)
ui <- {
renderUI(
shiny::fluidRow(
bs4Dash::box(
title = shiny::selectizeInput(
inputId = "ticker",
label = "Ticker:",
choices = NULL,
selected = "AAPL",
options = list(
placeholder = "e.g AAPL",
create = TRUE,
maxOptions = 50L
)
),
actionButton(
inputId = "update",
label = "UPDATE NOW"
),
id = "tickerBox",
closable = F,
maximizable = F,
width = 12,
height = "250px",
solidHeader = FALSE,
collapsible = F
)
)
)
}
server <- function(input, output, session){
# One call to try and load ticker df
observeEvent(input$update, {
updateSelectizeInput(
session = session,
label = "Ticker:",
inputId ="ticker",
choices = ticker,
server = TRUE
)
})
}
shiny::shinyApp(ui = ui, server = server)
SEE SIMILAR POSTS:
SO POST 1, SO POST 2, SO POST 3
What do you think about something like this?
library(shiny)
tickers <- rep(rownames(mtcars), 850)
ui <- fluidPage(
tags$head(
tags$script(
HTML(
'document.addEventListener("keydown", function(e) {
Shiny.setInputValue("key_pressed", e.key);
})'
)
)
),
fluidRow(
column(2, selectizeInput("select", "Select", choices = "")),
column(1, actionButton("btn", "Search"))
)
)
server <- function(input, output, session) {
observeEvent(input$btn, {
req(input$key_pressed)
updateSelectizeInput(session, "select", choices = tickers[startsWith(tickers, input$key_pressed)], server = TRUE)
})
}
shinyApp(ui, server)
Basically I think it is not possible to just use the words which are putted to the selectInput and we need separate input. I think that selectInput is truthy (isTruthy()) only after some option was chosen (and it can't be "" of course), so we can't use anything which is putted as a word to the selectInput box before some option is actually chosen. I'm not sure, but if I'm right, it is necessary to have separate input for what you want.
However, if we could assume that:
User will use only one letter to get the options to choose
Then we can use "keydown" event (keydown). Now the user doesn't need to put anything to the selectInput box, she/he can just use a key in the keyboards, like C (letter size does matter here, because we are using startsWith()) and then push "Search" button (but of course this letter can still be put to the selectInput box to mimic what you tried to achieve). We could even imagine solution without the button, but I'm afraid in most use-cases it will be not recommended, I mean if user can interact with the app using keyboard not only to choose the options, but also for other purposes, then we would recompute new options everytime user uses key in the keyboard for - well - nothing.
Turns out that selectizeInput doesn't accept a df and must be an atomic vector. When I used tickers[[1]], the issue seemed to be solved, and the list would no longer flash.

How does input from insertUI get stored?

I've created a SelectizeInput() UI using the insertUI() function. Essentially, I have an action button which adds a SelectizeInput() every time it's clicked. The idea is that the user selects columns from their data to put into groups. The creation of the UI works fine. I can also see in the Shiny trace that the selection works fine. However, I'm unsure how to access these variables to use in later plots. This is the code I have:
UI:
actionButton("cr_exp", "Create new biological group")
Server:
observeEvent(input$cr_exp, {
insertUI(
selector = "#cr_exp",
where = "afterEnd",
ui = selectizeInput(inputId = paste0("grp", input$cr_exp), label = "Select samples", choices = colnames(exp_dff()), options = list(create=TRUE), multiple=TRUE))
tags$div(id = paste0("grp", input$cr_exp))
})
In the shiny trace, it shows that the group is created, but I can't figure out how to access the value:
RECV {"method":"update","data":{"grp1":["MV4negControl01","MV4negControl02"]}}
You access the values just like any other input values: by the input element’s
id from the input reactive values:
library(shiny)
ui <- fluidPage(
actionButton("cr_exp", "Create new biological group"),
verbatimTextOutput("choices")
)
server <- function(input, output, session) {
observeEvent(input$cr_exp, {
insertUI(
selector = "#cr_exp",
where = "afterEnd",
ui = selectizeInput(
inputId = paste0("grp", input$cr_exp),
label = "Select samples",
choices = LETTERS,
options = list(create = TRUE),
multiple = TRUE
)
)
tags$div(id = paste0("grp", input$cr_exp))
})
output$choices <- renderPrint({
lapply(seq_len(input$cr_exp), function(i) input[[paste0("grp", i)]])
})
}
shinyApp(ui, server)

How to have a user input text and create a list with shiny? R

I have the following app which allows for text to be entered and it is then saved as VALUE and printed on a panel.
Although it looks like I can only do this with one text input at a time - even if I click add (so I don't believe this button is working). On top of that I would like for the user to be able to add multiple inputs (like I have below).
And then my VALUE function should be list with multiple inputs.
code below
library(shiny)
ui <- fluidPage(
headerPanel("R Package App"),
sidebarPanel(
# selectInput("options", "options", choices=c('abc','def')),
textInput("textbox", "Enter R Package Name", ""),
actionButton("add","Add")
),
mainPanel(
textOutput("caption")
)
)
server <- function(input, output, session) {
observe({
VALUE <- ''
if(input$add>0) {
isolate({
VALUE <- input$textbox
})
}
updateTextInput(session, inputId = "textbox", value = VALUE)
})
output$caption <- renderText({
input$textbox
})
}
shinyApp(ui = ui, server = server)
Have you considered using selectizeInput with it's create option?
library(shiny)
packagesDF <- as.data.frame(installed.packages())
ui <- fluidPage(
headerPanel("R Package App"),
sidebarPanel(
selectizeInput(
inputId = "selectedPackages",
label = "Enter R Package Name",
choices = packagesDF$Package,
selected = NULL,
multiple = TRUE,
width = "100%",
options = list(
'plugins' = list('remove_button'),
'create' = TRUE,
'persist' = TRUE
)
)
),
mainPanel(textOutput("caption"))
)
server <- function(input, output, session) {
output$caption <- renderText({
paste0(input$selectedPackages, collapse = ", ")
})
}
shinyApp(ui = ui, server = server)

R-Shiny: Select input reactive on file input

I am very new to Shiny and am not sure if I am doing this remotely correct/completely oversimplified. I am trying to pull the column headers from an excel fileInput into a selectInput drop down box.
So essentially I would like the options for the select box be determined by the headers of the file input. Then it would link into my equation in the server, which would perform the calculation based on the dataset in the column (the bit in the server with input$col).
I appreciate any comments/answers,
Thanks
EDIT: at a guess, would I need to use uiOutput and renderUI??
ui
ui <- fluidPage(theme = shinytheme(),
setBackgroundColor("white"),
titlePanel(img(src = "image.png", height = 125, width = 450)),
(h1("review app", style = "color:#337ab7")),
p("Calculate"),
headerPanel(h3("Input data here", style = "color:#337ab7")),
sidebarLayout(
sidebarPanel( position =c("left"), style = "color:#337ab7",
numericInput("SL",
"SL", 1, min=1, max=10),
numericInput("LT", "LT",0, min=0, max = 52),
fileInput("file1", 'choose file',
accept = c(".xlsx") ),
selectInput("col", "Column", choices = unique(colnames(input$file1)
)),
checkboxInput("smooth", "Clean my data", value = FALSE, width = NULL),
actionButton("action_Calc", label = "Refresh & Calculate", icon("redo"),
style="color: #fff; background-color: #337ab7; border-color: #2e6da4"),
),
mainPanel(
tabsetPanel(
tabPanel("SS", h1(textOutput("SS"), style = "color:#337ab7")),
tabPanel("guide", img(src = "guide.png", height = 200, width = 600)),
tabPanel("Mydata", div(tableOutput('contents'), style="font-size:55%"))
))))
server
server <- function(input, output) {
Data <- reactive({
req(input$file1)
inFile <- input$file1
read_excel(inFile$datapath, 1)
})
output$contents <- renderTable(bordered = TRUE, style= "border-color:#337ab7", hover = TRUE, {
Data()
})
values<- reactiveValues()
observe({
input$action_Calc
values$int<- isolate({ if (input$smooth) (round( input$SL*sqrt(input$LT/4)*sd( tsclean(Data()[[input$col]],
replace.missing = TRUE, lambda = NULL)) , digits= 2))
else (round( input$SL*sqrt(input$LT/4)*sd(Data()[[input$col]]), digits = 2)) })})
output$SS <- renderText({paste("Calculated is", values$int)} )
}
shinyApp(ui, server)
updatedSelectInput should do it for you. Below is a minimal example.
To reduce package dependencies I switched to loading .csv rather than .xlsx. Note that the loaded file isn't validated, so if junk goes in you'll get junk out.
library(shiny)
#UI
ui <- fluidPage(
selectInput('mydropdown', label = 'Select', choices = 'No choices here yet'),
fileInput('myfileinput', label = 'Select File', accept = c(".csv"))
)
#Server
server <- function(input, output, session) {
observeEvent(input$myfileinput, {
mytable <- read.csv(input$myfileinput$datapath)
updateSelectInput(session, "mydropdown", label = "Select", choices = colnames(mytable))
})
}
shinyApp(ui = ui, server = server)

dynamic number of selectInput

I am new to shiny so this might be a very basic question.
I want to write a shiny app where the user inputs 'n' and we get n number of selectInput options and am not able to do it. Basically any form of for loop is not working.
The code I attempted is following
library(shiny)
ui = fluidPage(
sidebarLayout(
sidebarPanel(
textInput(inputId = "number", label = "number of selectInput",value = 5)
),
mainPanel(
uiOutput(outputId = "putselect")
)
)
)
server = function(input,output){
output$putselect = renderUI(
if(input$number != 0 ){
for(i in 1:(input$number)){
selectInput(inputId = "i", label = "just write something", choices = c(2,(3)))
}
}
)
}
shinyApp(ui = ui , server = server)
You either need to store the inputs you create in a list and return that list, or you can simply wrap your statement in lapply instead of for. A working example is given below, hope this helps!
library(shiny)
ui = fluidPage(
sidebarLayout(
sidebarPanel(
textInput(inputId = "number", label = "number of selectInput",value = 5)
),
mainPanel(
uiOutput(outputId = "putselect")
)
)
)
server = function(input,output){
output$putselect = renderUI(
if(input$number != 0 ){
lapply(1:(input$number), function(i){
selectInput(inputId = "i", label = paste0("input ",i), choices = c(2,(3)))
})
}
)
}
shinyApp(ui = ui , server = server)

Resources