I have a shinyApp, where I would like to capture the change in a specific directory.
i.e : the user click on the shinyDirButton, creates a sub-directory in a specific directory. I would like to capture any change in this directory (creation, deletion). I tried to use reactiveValues but I didn't succeed
library(shiny)
ui = fluidPage(sidebarLayout(
sidebarPanel(
class = "sidebar_upload",
id = "form",
tags$h1("1- Choose a folder"),
shinyFiles::shinyDirButton(
id = 'choose_directory',
label = 'Choose a folder',
title = 'Choose a folder',
multiple = F
),
br(),
br(),
br(),
actionButton("button", "Update")
),
mainPanel(uiOutput(outputId = "test"))
))
server <- function(input, output, session) {
r_global <- reactiveValues()
observe({
r_global$volumes = c(home = 'C:/')
r_global$dossier = list.dirs(r_global$volumes,
recursive = F,
full.names = F)
shinyFiles::shinyDirChoose(
input = input,
id = 'choose_directory',
roots = r_global$volumes,
session = session
)
})
observeEvent(input$button, {
print(r_global$dossier)
})
}
shinyApp(ui, server)
You have to replace your first observe by an observeEvent:
library(shiny)
ui = fluidPage(sidebarLayout(
sidebarPanel(
class = "sidebar_upload",
id = "form",
tags$h1("1- Choose a folder"),
shinyFiles::shinyDirButton(
id = 'choose_directory',
label = 'Choose a folder',
title = 'Choose a folder',
multiple = F
),
br(),
br(),
br(),
actionButton("button", "Update")
),
mainPanel(uiOutput(outputId = "test"))
))
server <- function(input, output, session) {
r_global <- reactiveValues()
#############################
### here add observeEvent ###
#############################
observeEvent(input$button, {
r_global$volumes = c(home = '~/project/SHINY/wedding/PROJET/')
r_global$dossier = list.dirs(r_global$volumes,
recursive = F,
full.names = F)
shinyFiles::shinyDirChoose(
input = input,
id = 'choose_directory',
roots = r_global$volumes,
session = session
)
})
observeEvent(input$button, {
print(r_global$dossier)
})
}
shinyApp(ui, server)
Related
I am not able to delete the generated map after I press the reset button on shiny, could you help me to insert the code to delete the map made after pressing the button? For both selectInput works normally, only the map that is not deleted from the screen.
library(shiny)
library(shinythemes)
library(lubridate)
library(googleway)
set_key("API KEY")
df1<- structure(
list(
Marketname = c("Market1","Market1", "Market2","Market2", "Market3", "Market3", "Market4", "Market4"),
Latitude = c(-22.900200453490385, -22.900200453490385,-22.89279876292728,-22.89279876292728,-22.89107669207457,-22.89107669207457,-22.91668421655409,-22.91668421655409),
Longitude = c(-48.448779371935494,-48.448779371935494, -48.45043377250408,-48.45043377250408,-48.44108027972275,-48.44108027972275,-48.43786997555729,-48.43786997555729)),
row.names = c(NA, 8L), class = "data.frame")
ui <- fluidPage(
shiny::navbarPage(theme = shinytheme("flatly"), collapsible = TRUE,
br(),
tabPanel("Rota",
sidebarLayout(
sidebarPanel(
selectizeInput("market1", label = h5("Choose starting point:"), choices = NULL,
multiple = TRUE,
options = list(maxItems = 1)),
selectizeInput("market2", label = h5("Choose destination point:"), choices = NULL,
multiple = TRUE,
options = list(maxItems = 1)),
actionButton(inputId = "getRoute", label = "Get route"),
actionButton(inputId = "reset", label = "Reset")),
mainPanel(
tabsetPanel(
tabPanel("Route",google_mapOutput(outputId = "mapWarsaw"),
)
))
))))
server <- function(input, output,session) {
observe({
updateSelectizeInput(session, "market1",
choices = unique(df1$Marketname)
)
})
observe({
excludeOption <- NULL
if (!is.null(input$market1)) {
excludeOption <- input$market1
}
updateSelectizeInput(session, "market2",
choices = unique(df1$Marketname[df1$Marketname != excludeOption])
)
})
observeEvent(input$getRoute, {
origin <- df1[df1$Marketname == input$market1, c("Latitude", "Longitude")][1, ]
destination <- df1[df1$Marketname == input$market2, c("Latitude", "Longitude")][1, ]
route <- google_directions(origin = origin,
destination = destination,
mode = "driving")
df_routes <- data.frame(polyline = direction_polyline(route))
df_way <- cbind(
route$routes$legs[[1]]$end_location,
data.frame(address = route$routes$legs[[1]]$end_address)
)
m3<-google_map() %>%
add_polylines(data = df_routes, polyline = "polyline", stroke_weight = 4)
output$mapWarsaw <- renderGoogle_map({
m3
})
})
observeEvent(input$reset, {
updateSelectInput(session, "market1", selected = "")
updateSelectInput(session, "market2", selected = "")
})
}
shinyApp(ui = ui, server = server)
Here I pressed reset, the selectInput was cleared, but the map was not, so I would like to insert some code that cleared the screen. Of course, after inserting the selectInput options again, the map was generated normally on the screen.
I recommend using a reactiveVal to store whether you want to plot or not, then req(.) that value in your plot.
A simple example:
library(shiny)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
numericInput("n", "N", value = 2),
actionButton("toggle", "Toggle")
),
mainPanel(
plotOutput("plot")
)
)
)
server <- function(input, output, session) {
doplot <- reactiveVal(TRUE)
observeEvent(input$toggle, {
doplot(!isTRUE(doplot()))
})
output$plot <- renderPlot({
req(doplot())
plot(runif(input$n))
})
}
shinyApp(ui, server)
doplot defaults to TRUE, so it starts plotting immediately (assuming input$n has a value), and every time input$n is changed, a new plot is rendered;
when you click on toggle, the doplot is inverted, and the dependent output$plot will "fail" the req(doplot()) requirement and clear the plot;
this could be improved to give a clearer indication that the empty plot is because the user toggled the button ... in this case, I should likely change the style of the button to clearly indicate the state, but that's aesthetics and may or may not apply to your app
Another similar method would be to store the data in a reactiveVal, and require it, perhaps like this:
library(shiny)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
numericInput("n", "N", value = 2),
actionButton("toggle", "Toggle")
),
mainPanel(
plotOutput("plot")
)
)
)
server <- function(input, output, session) {
mydat <- reactiveVal(NULL)
observeEvent(input$toggle, {
req(input$n)
if (is.null(mydat())) {
mydat(runif(input$n))
} else mydat(NULL)
})
output$plot <- renderPlot({
plot(req(mydat()))
})
}
shinyApp(ui, server)
This second method won't work as well if you need to preserve the data.
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)
Consider the following example application:
library(shiny)
library(shinyWidgets)
module_UI <- function(id){
tagList(
div(
uiOutput(
outputId = NS(id, "selection")
),
shinyWidgets::dropdown(
uiOutput(outputId = NS(id, "new_option")),
style = "unite",
label = "New",
color = "primary",
animate = animateOptions(
enter = animations$fading_entrances$fadeInLeftBig,
exit = animations$fading_exits$fadeOutRightBig
),
up = F,
width = "600px",
inline = T
)
)
)
}
module_server <- function(id){
moduleServer(id, function(input, output, session){
ns <- session$ns
return_values <- reactiveValues(selection=NULL)
output$selection <- renderUI({
selectInput(inputId = ns("selection"), label = "Select:", choices = 1:5)
})
output$new_option <- renderUI({
div(
numericInput(ns("new_option_input"), label = "Add a new option:"),
shinyWidgets::actionBttn(
inputId = ns("submit_new_option"),
label = "Submit",
icon = icon("paper-plane"))
)
})
observeEvent(input$submit_new_option, {
#does not work as intended
updateSelectInput(session = session, inputId = "selection", selected = input$new_option_input)
})
observe({
return_values$selection <- input$selection
})
return(return_values)
})
}
# Define UI for application that draws a histogram
ui <- fluidPage(
title = "Test App",
module_UI("test"),
verbatimTextOutput(outputId = "selection_chosen")
)
# Define server logic required to draw a histogram
server <- function(input, output) {
picker <- module_server("test")
output$selection_chosen <- renderText({
picker$selection
})
}
# Run the application
shinyApp(ui = ui, server = server)
Basically, the module should do two things:
Allow user to select a pre-existing option --> return that value from module
Allow user to create their own, new option --> return that value from module
I have #1 working, but am struggling on #2. Specifically, where I have the "does not work" comment. How can I achieve this functionality? What are/is the best practice(s) for returning server-side created values from a Shiny module? This is an example app; the real one involves reading the selectInput options from a database, as well as saving the newly created options in the database. Appreciate any help on this! A lot of SO answers regarding Shiny modules have the older callModule(...) syntax, which makes researching this topic a bit more confusing.
You just need to provide the default value in numericInput. Perhaps you are looking for this.
library(shiny)
library(shinyWidgets)
module_UI <- function(id){
ns <- NS(id)
tagList(
div(
uiOutput(
outputId = NS(id, "selection")
),
shinyWidgets::dropdown(
uiOutput(outputId = NS(id, "new_option")),
style = "unite",
label = "New",
color = "primary",
animate = animateOptions(
enter = animations$fading_entrances$fadeInLeftBig,
exit = animations$fading_exits$fadeOutRightBig
),
up = F,
width = "600px",
inline = T
),
DTOutput(ns("t1"))
)
)
}
module_server <- function(id){
moduleServer(id, function(input, output, session){
ns <- session$ns
return_values <- reactiveValues(selection=NULL,myiris = iris)
output$selection <- renderUI({
selectInput(inputId = ns("selection"), label = "Select:", choices = 1:5)
})
output$new_option <- renderUI({
tagList(
numericInput(ns("new_option_input"), label = "Add a new option:",10, min = 1, max = 100),
shinyWidgets::actionBttn(
inputId = ns("submit_new_option"),
label = "Submit",
icon = icon("paper-plane"))
)
})
observeEvent(input$submit_new_option, {
return_values$myiris <- iris[1:input$new_option_input,]
#does work as intended
updateSelectInput(session = session, inputId = "selection", choices= c(1:input$new_option_input), selected = input$new_option_input)
})
output$t1 <- renderDT({return_values$myiris})
observe({
return_values$selection <- input$selection
})
return(return_values)
})
}
# Define UI for application that draws a histogram
ui <- fluidPage(
title = "Test App",
module_UI("test"),
verbatimTextOutput(outputId = "selection_chosen"),
DTOutput("t2")
)
# Define server logic required to draw a histogram
server <- function(input, output) {
picker <- module_server("test")
output$selection_chosen <- renderText({
picker$selection
})
output$t2 <- renderDT({picker$myiris[,c(3:5)]})
}
# Run the application
shinyApp(ui = ui, server = server)
When I use options = list(create = TRUE) in selectizeInput, I can manually add a value - see also https://selectize.dev/docs.html and example 3 in https://shiny.rstudio.com/gallery/selectize-examples.html.
How do I add a new value from server code? The example below use a hypothetical updateSelectizeInput and expectedly does not work.
library(shiny)
ui = fluidPage(
selectizeInput("select", 'Select',
choices = c("anton", "bertha"),
options = list(create = TRUE)
),
actionButton("settext", "Set Text from server")
)
server = function(input, output, session) {
# This code does not work, shows the idea
updateSelectizeInput(session, "select", options = list(value = "Caesar"))
}
shinyApp(ui, function(input, output, session) {})
Is this what you want to achieve?
library(shiny)
choices <- c("anton", "bertha")
ui = fluidPage(
selectizeInput("select", 'Select',
choices = choices,
options = list(create = TRUE)
),
actionButton("settext", "Set Text from server")
)
server = function(input, output, session) {
# Your update is appending Caesar to the choices
updateSelectizeInput(session, "select", choices = c(choices, "Caesar"))
}
shinyApp(ui,server)
library(shiny)
ui = fluidPage(
selectizeInput("select", 'Select or edit manually',
choices = c("anton", "bertha"),
options = list(create = TRUE)
),
verbatimTextOutput("showtext", placeholder = TRUE),
actionButton("goButton", "Get Text from server")
)
server = function(input, output, session) {
output$showtext = renderPrint({
input$goButton
isolate(input$select)
})
}
shinyApp(ui, server)
Does anyone know why this simple code is not working?
What I am trying to do: make the structure tab active whenever users click on the run button (input$runButton). When I click the run button, the value of input$runButton gets updated, but the tab is not changed to structure.
Here is a simple reproducible example:
server.R
function(input, output, session) {
#RUN button
observeEvent(input$runButton, {
updateTabsetPanel(session, "allResults", 'structure')
})
#VAR SELECTION
output$inputVars <- renderText({
if (input$runButton == 0)
return()
print("Vars Selected")
})
#STRUCTURE RESULT
output$structure <- renderText({
if (input$runButton == 0)
return()
print("Structure Results")
})
}
ui.R
fluidPage(
titlePanel("Periscope Structure"),
br(),
sidebarPanel(
fileInput(inputId="inFile", "Choose CSV File",
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv")
),
checkboxInput("header", "Header", TRUE),
numericInput("level", "Structure Level", 3, min = 2, max = 10),
br(),
actionButton("runButton", strong("Run!"))
),
mainPanel(
tabsetPanel(id = "allResults",
tabPanel('Variable Selection', textOutput('inputVars')),
tabPanel('Structure Result', textOutput('structure')))
)
)
Thank you!
Note that you need to assign a value to TabPanel so you can make them active using the updateTabsetPanel call, so try this:
require(shiny)
ui <- fluidPage(
titlePanel("Periscope Structure"),
br(),
sidebarPanel(
fileInput(inputId="inFile", "Choose CSV File",
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv")
),
checkboxInput("header", "Header", TRUE),
numericInput("level", "Structure Level", 3, min = 2, max = 10),
br(),
actionButton("runButton", strong("Run!"))
),
mainPanel(
tabsetPanel(id = "allResults",
tabPanel(value = "inputVars",'Variable Selection', textOutput('inputVars')),
tabPanel(value = "structure",'Structure Result', textOutput('structure')))
)
)
server <- function(input, output, session) {
#RUN button
observeEvent(input$runButton, {
updateTabsetPanel(session, "allResults", 'structure')
})
#VAR SELECTION
output$inputVars <- renderText({
if (input$runButton == 0)
return()
print("Vars Selected")
})
#STRUCTURE RESULT
output$structure <- renderText({
if (input$runButton == 0)
return()
print("Structure Results")
})
}
runApp(shinyApp(ui, server), launch.browser = TRUE)
Note that if you are using shiny modules, that you have to refer to the correct session. For example, if a single tab is a module, the session of that tab won't be able to switch to another tab
To fix this, you can actually pass the session of the "parent" (container) of all your tabs into the constructor of the tab module, and then use that
Rough sketch of an example
shinyUI(function(request) {
source('page/search.R', local = T)
source('page/app.R', local = T)
fluidPage(
tabsetPanel(id = 'inTabset',
tabPanel(id = 'search', 'Search', searchUI('search'), value = 'search'),
tabPanel(id = 'app', 'App', appUI('app'), value = 'app')
)
)
})
shinyServer(function(input, output, session) {
source('page/search.R', local = T)
source('page/app.R', local = T)
searchSession = callModule(searchServer, 'search')
callModule(appServer, 'app', session, searchSession)
})
The shiny module
appUI = function(id) {
ns = NS(id)
tagList(
actionButton(ns('sendToHeatmap'), 'Send ortholog groups to heatmap')
)
}
appServer = function(input, output, session, parentSession, searchSession) {
# listen to a button press and switch to tab
observeEvent(input$sendToSearch, {
updateTextInput(searchSession, 'searchBox', 'funsearchterm')
updateTabsetPanel(parentSession, 'inTabset', selected = 'search')
})
}