Use actionButton with updateSelectInput in a shiny app - r

I Have a shiny app that use UpdateselectInput, I want to add a actionButton because there are some bugs whis the updateselectInput alone.
It doesnt seem to work, I want to show the table only if I action the button
My app is similar to this one :
library(shiny)
library(dplyr)
library(DT)
ui <- fluidPage(
titlePanel("Title"),
sidebarLayout(
sidebarPanel(width=3,
selectInput("filter1", "Filter 1", multiple = TRUE, choices = c("All", LETTERS)),
selectInput("filter2", "Filter 2", multiple = TRUE, choices = c("All", as.character(seq.int(1, length(letters), 1)))),
selectInput("filter3", "Filter 3", multiple = TRUE, choices = c("All", letters)),
actionButton("go_button", "GO !")),
mainPanel(
DT::dataTableOutput("tableprint")
)
)
)
server <- function(input, output, session) {
output$tableprint <- DT::renderDataTable({
input$go_button
# Data
df <- tibble(LETTERS = rep(LETTERS, 2), Numbers = as.character(1:52),
letters = paste(LETTERS, Numbers, sep = ""))
df1 <- df
if("All" %in% input$filter1){
df1
} else if (length(input$filter1)){
df1 <- df1[which(df1$LETTERS %in% input$filter1),]
}
# Update selectInput choices based on the filtered data. Update 'selected' to reflect the user input.
updateSelectInput(session, "filter1", choices = c("All", df$LETTERS), selected = input$filter1)
updateSelectInput(session, "filter2", choices = c("All", df1$Numbers), selected = input$filter2)
if("All" %in% input$filter2){
df1
} else if (length(input$filter2)){
df1 <- df1[which(df1$Numbers %in% input$filter2),]
}
updateSelectInput(session, "filter3", choices = c("All", df1$letters), selected = input$filter3)
if("All" %in% input$filter3){
df1
} else if (length(input$filter3)){
df1 <- df1[which(df1$letters %in% input$filter3),]
}
datatable(df1)
})
}
# Run the application
shinyApp(ui = ui, server = server)
Thanks for help !

Are you looking for something like this?? Only when you click on the Go button, will the table display now. The way the filters work are just the same.
library(shiny)
library(dplyr)
library(DT)
ui <- fluidPage(
titlePanel("Title"),
sidebarLayout(
sidebarPanel(width=3,
selectInput("filter1", "Filter 1", multiple = TRUE, choices = c("All", LETTERS)),
selectInput("filter2", "Filter 2", multiple = TRUE, choices = c("All", as.character(seq.int(1, length(letters), 1)))),
selectInput("filter3", "Filter 3", multiple = TRUE, choices = c("All", letters)),
actionButton("go_button", "GO !")),
mainPanel(
DT::dataTableOutput("tableprint")
)
)
)
server <- function(input, output, session) {
goButton <- eventReactive(input$go_button,{
# Data
df <- tibble(LETTERS = rep(LETTERS, 2), Numbers = as.character(1:52),
letters = paste(LETTERS, Numbers, sep = ""))
df1 <- df
if("All" %in% input$filter1){
df1
} else if (length(input$filter1)){
df1 <- df1[which(df1$LETTERS %in% input$filter1),]
}
# Update selectInput choices based on the filtered data. Update 'selected' to reflect the user input.
updateSelectInput(session, "filter1", choices = c("All", df$LETTERS), selected = input$filter1)
updateSelectInput(session, "filter2", choices = c("All", df1$Numbers), selected = input$filter2)
if("All" %in% input$filter2){
df1
} else if (length(input$filter2)){
df1 <- df1[which(df1$Numbers %in% input$filter2),]
}
updateSelectInput(session, "filter3", choices = c("All", df1$letters), selected = input$filter3)
if("All" %in% input$filter3){
df1
} else if (length(input$filter3)){
df1 <- df1[which(df1$letters %in% input$filter3),]
}
datatable(df1)
})
output$tableprint <- DT::renderDataTable({
goButton()
})
}
# Run the application
shinyApp(ui = ui, server = server)
I have moved the filter code to a eventReactive function. So when you click on the button, it will subset your data based on the filters. And the output$tableprint function calls this reactive function, so you will see the table only when you click on the button.

Related

How to set up actionButton() or actionBttn() to clear all selections in pickerInput()

When I click on the Action Button, I would like to clear everything: both the output and the selections in the picketInput() (input$engine and input$cylinder in the code below). For consistency if I can do it with shinyWidget's actionBttn, that will be great as well.
library(shiny)
library(shinyWidgets)
df <- mtcars
ui <- fluidPage(
sidebarPanel(
pickerInput("engine", "Select engine:", choices = unique(df$vs),
options = list(
`actions-box` = TRUE),
multiple = TRUE
),
pickerInput("cylinder", "Select cylinder:", choices = unique(df$cyl),
options = list(
`actions-box` = TRUE),
multiple = TRUE
),
actionButton("reset", "Clear Selection"),
),
mainPanel(
textOutput("results")
)
)
server <- function(input, output, session) {
data <- reactiveValues()
observeEvent(input$cylinder, {
tmp <- df
tmp1 <- tmp[tmp$vs %in% input$engine, ]
tmp2 <- tmp1[tmp1$cyl %in% input$cylinder, ]
data$tmp2 <- tmp2
})
output$results <- renderText({
if(is.null(data$tmp2)) return()
print(row.names(data$tmp2))
})
observeEvent(input$reset, {
updatePickerInput(session, "engine", NULL)
updatePickerInput(session, "cylinder", NULL)
data$tmp2 <- NULL
})
}
shinyApp(ui = ui, server = server)
You'll have to respect the order of updatePickerInput's parameters or name them. Your above approach would have updated the label.
Please see ?updatePickerInput and check the following:
library(shiny)
library(shinyWidgets)
library(datasets)
DF <- mtcars
ui <- fluidPage(
sidebarPanel(
pickerInput("engine", "Select engine:", choices = unique(DF$vs),
options = list(
`actions-box` = TRUE),
multiple = TRUE
),
pickerInput("cylinder", "Select cylinder:", choices = unique(DF$cyl),
options = list(
`actions-box` = TRUE),
multiple = TRUE
),
actionBttn("reset", "Clear Selection"),
),
mainPanel(
textOutput("results")
)
)
server <- function(input, output, session) {
data <- reactiveValues()
observeEvent(input$cylinder, {
tmp <- DF
tmp1 <- tmp[tmp$vs %in% input$engine, ]
tmp2 <- tmp1[tmp1$cyl %in% input$cylinder, ]
data$tmp2 <- tmp2
})
output$results <- renderText({
req(data$tmp2)
row.names(data$tmp2)
})
observeEvent(input$reset, {
updatePickerInput(session, inputId = "engine", selected = "")
updatePickerInput(session, inputId = "cylinder", selected = "")
data$tmp2 <- NULL
})
}
shinyApp(ui = ui, server = server)

Shiny Interdependent Filters values

Unable to make the similar functionality of filters which should be interdependent. So that means if user select a input from one filter, all other filters should get updated.
I have tried multiple ways in shiny but unable to do so however found some code on stackoverflow with similar functionality. The only challenge is that i don't want to show the table as a output and unfortunately the code does not work if we don't pass the output to #tableprint [id of a table].
Any help would be really appreciated.
library(shiny)
library(dplyr)
library(DT)
ui <- fluidPage(
titlePanel("Title"),
sidebarLayout(
sidebarPanel(width=3,
selectInput("filter1", "Filter 1", multiple = TRUE, choices = c("All", LETTERS)),
selectInput("filter2", "Filter 2", multiple = TRUE, choices = c("All", as.character(seq.int(1, length(letters), 1)))),
selectInput("filter3", "Filter 3", multiple = TRUE, choices = c("All", letters)) ),
mainPanel(
DT::dataTableOutput("tableprint")
)
)
)
server <- function(input, output, session) {
output$tableprint <- DT::renderDataTable({
# Data
df <- tibble(LETTERS = rep(LETTERS, 2), Numbers = as.character(1:52),
letters = paste(LETTERS, Numbers, sep = ""))
df1 <- df
if("All" %in% input$filter1){
df1
} else if (length(input$filter1)){
df1 <- df1[which(df1$LETTERS %in% input$filter1),]
}
# Update selectInput choices based on the filtered data. Update 'selected' to reflect the user input.
updateSelectInput(session, "filter1", choices = c("All", df$LETTERS), selected = input$filter1)
updateSelectInput(session, "filter2", choices = c("All", df1$Numbers), selected = input$filter2)
if("All" %in% input$filter2){
df1
} else if (length(input$filter2)){
df1 <- df1[which(df1$Numbers %in% input$filter2),]
}
updateSelectInput(session, "filter3", choices = c("All", df1$letters), selected = input$filter3)
if("All" %in% input$filter3){
df1
} else if (length(input$filter3)){
df1 <- df1[which(df1$letters %in% input$filter3),]
}
datatable(df1)
})
}
# Run the application
shinyApp(ui = ui, server = server)
You can do something like this: its a lot cleaner and easier to read. Note that I added the shinyWidgets package which has the pre-built Select-All Button. You can use the variable called v$df in your other reactives as you said I dont want to show the table as output
library(shiny)
library(dplyr)
library(DT)
library(shinyWidgets)
# Install shinyWidgets
# From CRAN
#install.packages("shinyWidgets")
# From Github
# install.packages("devtools")
#devtools::install_github("dreamRs/shinyWidgets")
df <- tibble(LETTERS = rep(LETTERS, 2), Numbers = as.character(1:52),letters = paste(LETTERS, Numbers, sep = ""))
ui <- fluidPage(
titlePanel("Title"),
sidebarLayout(
sidebarPanel(width=3,
pickerInput("filter1", "Filter 1", choices = LETTERS, options = list(`actions-box` = T), multiple = T),
pickerInput("filter2", "Filter 2", choices = df$Numbers, options = list(`actions-box` = T), multiple = T),
pickerInput("filter3", "Filter 3", choices = letters, options = list(`actions-box` = T), multiple = T)),
mainPanel(
DT::dataTableOutput("tableprint")
)
)
)
server <- function(input, output, session) {
v <- reactiveValues()
observe({
dt <- df$Numbers[df$LETTERS %in% input$filter1]
updatePickerInput(session, "filter2", choices = dt,selected = dt)
})
observe({
dt <- df$letters[df$Numbers %in% input$filter2]
updatePickerInput(session, "filter3", choices = dt,selected = dt)
})
output$tableprint <- DT::renderDataTable({
df <- df[df$LETTERS %in% input$filter1,]
df <- df[df$Numbers %in% input$filter2,]
df <- df[df$letters %in% input$filter3,]
v$df <- df
datatable(df)
})
}
# Run the application
shinyApp(ui = ui, server = server)

How to add a user defined value to the select list of values from dataset

I am new to Shiny R, and as part of a project I would have to show distinct values for selection in a selectlist, but I also need to provide an option called "All" to query with.
dataset <- read.csv("dataset.csv", header=TRUE)
fluidPage(
title = "ABC XYZ",
hr(),
fluidRow(
titlePanel("ABC XYZ"),
sidebarPanel(
selectInput("region", label = "Region",
choices = unique(dataset$region),
selected = 1)
)
)
Can anyone help me achieve the same.
Thanks in advance.
We could create an additional level or unique element 'All' in choices and update with updateSelectInput
library(shiny)
library(DT)
library(dplyr)
#using a reproducible example
dataset <- iris
allchoice <- c("All", levels(dataset$Species))
-ui
ui <- fluidPage(
title = "ABC XYZ",
hr(),
fluidRow(
titlePanel("ABC XYZ"),
sidebarPanel(
selectInput("species", label = "Species",
choices = allchoice, multiple = TRUE),
verbatimTextOutput("selected")
),
mainPanel(dataTableOutput('out')))
)
-server
server <- function(input, output, session) {
observe({
if("All" %in% input$species) {
selected <- setdiff(allchoice, "All")
updateSelectInput(session, "species", selected = selected)
}
})
output$selected <- renderText({
paste(input$species, collapse = ", ")
})
output$out <- renderDataTable({
dataset %>%
filter(Species %in% input$species)
})
-run app
shinyApp(ui, server)

Reactive unputs with actionbutton in shiny

I want to have an ractive shiny app with an actionbuttion, ie I want to automaticly show the choice dependeing in each last choice.
For example if I choose "A" in the filter 1 I want to show "1", "27" and "All" choice in filter 2 without actionate the "go" button
Here is my code :
library(shiny)
library(dplyr)
library(DT)
ui <- fluidPage(
titlePanel("Title"),
sidebarLayout(
sidebarPanel(width=3,
selectInput("filter1", "Filter 1", multiple = TRUE, choices = c("All", LETTERS)),
selectInput("filter2", "Filter 2", multiple = TRUE, choices = c("All", as.character(seq.int(1, length(letters), 1)))),
selectInput("filter3", "Filter 3", multiple = TRUE, choices = c("All", letters)),
actionButton("go_button", "GO !")),
mainPanel(
DT::dataTableOutput("tableprint")
)
)
)
server <- function(input, output, session) {
goButton <- eventReactive(input$go_button,{
# Data
df <- tibble(LETTERS = rep(LETTERS, 2), Numbers = as.character(1:52),
letters = paste(LETTERS, Numbers, sep = ""))
df1 <- df
if("All" %in% input$filter1){
df1
} else if (length(input$filter1)){
df1 <- df1[which(df1$LETTERS %in% input$filter1),]
}
# Update selectInput choices based on the filtered data. Update 'selected' to reflect the user input.
updateSelectInput(session, "filter1", choices = c("All", df$LETTERS), selected = input$filter1)
updateSelectInput(session, "filter2", choices = c("All", df1$Numbers), selected = input$filter2)
if("All" %in% input$filter2){
df1
} else if (length(input$filter2)){
df1 <- df1[which(df1$Numbers %in% input$filter2),]
}
updateSelectInput(session, "filter3", choices = c("All", df1$letters), selected = input$filter3)
if("All" %in% input$filter3){
df1
} else if (length(input$filter3)){
df1 <- df1[which(df1$letters %in% input$filter3),]
}
datatable(df1)
})
output$tableprint <- DT::renderDataTable({
goButton()
})
}
# Run the application
shinyApp(ui = ui, server = server)
I have modified your code so that the select input and table is reactive and gets updated when you change any select input.
library(shiny)
library(dplyr)
library(DT)
ui <- fluidPage(
titlePanel("Title"),
sidebarLayout(
sidebarPanel(width=3,
selectInput("filter1", "Filter 1", multiple = FALSE, choices = c("All", LETTERS), selected = "All"),
selectInput("filter2", "Filter 2", multiple = FALSE, choices = c("All", as.character(seq.int(1, length(letters), 1))), selected = "All"),
selectInput("filter3", "Filter 3", multiple = FALSE, choices = c("All", letters), selected = "All"),
actionButton("go_button", "GO !")),
mainPanel(
DT::dataTableOutput("tableprint")
)
)
)
df <- tibble(LETTERS = rep(LETTERS, 2), Numbers = as.character(1:52),
letters = paste(LETTERS, Numbers, sep = ""))
server <- function(input, output, session) {
data1 <- reactive({
if("All" %in% input$filter1){
df1 <- df
}else{
df1 <- df[which(df$LETTERS %in% input$filter1),]
}
df1
})
data2 <- reactive({
if("All" %in% input$filter2){
df1 <- data1()
} else if (length(input$filter2)){
df1 <- data1()[which(data1()$Numbers %in% input$filter2),]
}
df1
})
data3<- reactive({
if("All" %in% input$filter3){
df1 <- data2()
} else if (length(input$filter3)){
df1 <- data2()[which(data2()$letters %in% input$filter3),]
}
df1
})
observeEvent(input$filter1,{
updateSelectInput(session, "filter2", choices = c("All", data1()$Numbers), selected = "All")
})
observeEvent(input$filter2,{
updateSelectInput(session, "filter3", choices = c("All", data2()$letters), selected = "All")
})
output$tableprint <- DT::renderDataTable({
data3()
})
}
shinyApp(ui = ui, server = server)
To render the table only button click you can use the following server code instead of the above:
server <- function(input, output, session) {
data1 <- reactive({
if("All" %in% input$filter1){
df1 <- df
}else{
df1 <- df[which(df$LETTERS %in% input$filter1),]
}
df1
})
data2 <- reactive({
if("All" %in% input$filter2){
df1 <- data1()
} else if (length(input$filter2)){
df1 <- data1()[which(data1()$Numbers %in% input$filter2),]
}
df1
})
data3<- reactive({
if("All" %in% input$filter3){
df1 <- data2()
} else if (length(input$filter3)){
df1 <- data2()[which(data2()$letters %in% input$filter3),]
}
df1
})
observeEvent(input$filter1,{
updateSelectInput(session, "filter2", choices = c("All", data1()$Numbers), selected = "All")
})
observeEvent(input$filter2,{
updateSelectInput(session, "filter3", choices = c("All", data2()$letters), selected = "All")
})
observeEvent(input$go_button,{
output$tableprint <- DT::renderDataTable({
data3()
})
})
}
In the above code you will notice that after it renders for the first time it gets updated automatically when we change the value of selectinput. To avoid that and get the new table rendered only in the end the code below can be used:
server <- function(input, output, session) {
data3<-NULL
data1 <- reactive({
if("All" %in% input$filter1){
df1 <- df
}else{
df1 <- df[which(df$LETTERS %in% input$filter1),]
}
df1
})
data2 <- reactive({
if("All" %in% input$filter2){
df1 <- data1()
} else if (length(input$filter2)){
df1 <- data1()[which(data1()$Numbers %in% input$filter2),]
}
df1
})
observeEvent(input$filter1,{
updateSelectInput(session, "filter2", choices = c("All", data1()$Numbers), selected = "All")
})
observeEvent(input$filter2,{
updateSelectInput(session, "filter3", choices = c("All", data2()$letters), selected = "All")
if("All" %in% input$filter3){
data3 <<- data2()
} else if (length(input$filter3)){
data3 <<- data2()[which(data2()$letters %in% input$filter3),]
}
})
observeEvent(input$go_button,{
output$tableprint <- DT::renderDataTable({
data3
})
})
}
Hope it helps!

Shiny filter update doesnt show all modalities of variables

i'm trying yo built a dynamic app with can filter a datatable, whatr I want is when I choose a modality for my first varible my next filters will be updated and purpose me only modalities corresponding to my first filter and the same for the third filter
I began by a reactive app but it not seems to works cause i have to always keep the "all" choice to show the other modalities and remove it after that ...is it possible to do that ?
So I decided to add an action button but not seems to work well with my update inputs
How can i fix it ? Thanks
An example of my app :
library(shiny)
library(dplyr)
library(DT)
ui <- fluidPage(
titlePanel("Title"),
sidebarLayout(
sidebarPanel(width=3,
selectInput("filter1", "Filter 1", multiple = T, choices = c("All", LETTERS)),
selectInput("filter2", "Filter 2", multiple = T, choices = c("All", as.character(seq.int(1, length(letters), 1)))),
selectInput("filter3", "Filter 3", multiple = T, choices = c("All", letters)),
actionButton("goButton", "Go!"),
p(class = 'text-center', downloadButton('dl', 'Download Data'))
),
mainPanel(
DT::dataTableOutput("tableprint")
)
)
)
server <- function(input, output, session) {
output$tableprint <- DT::renderDataTable({
# Data
df <- tibble(LETTERS = rep(LETTERS, 2), Numbers = as.character(1:52),
letters = paste(LETTERS, Numbers, sep = ""))
df1 <- df
if("All" %in% input$filter1){
df1
} else if (length(input$filter1)){
df1 <- df1[which(df1$LETTERS %in% input$filter1),]
}
if("All" %in% input$filter2){
df1
} else if (length(input$filter2)){
df1 <- df1[which(df1$Numbers %in% input$filter2),]
}
if("All" %in% input$filter3){
df1
} else if (length(input$filter3)){
df1 <- df1[which(df1$letters %in% input$filter3),]
}
input$goButton
# Update selectInput choices based on the filtered data. Update 'selected' to reflect the user input.
updateSelectInput(session, "filter1", choices = c("All", df$LETTERS), selected = input$filter1)
updateSelectInput(session, "filter2", choices = c("All", df1$Numbers), selected = input$filter2)
updateSelectInput(session, "filter3", choices = c("All", df1$letters), selected = input$filter3)
datatable(df1)
})
output$dl <- downloadHandler('mydata.csv', content = function(file) {
# Data
df <- tibble(LETTERS = rep(LETTERS, 2), Numbers = as.character(1:52),
letters = paste(LETTERS, Numbers, sep = ""))
df1 <- df
if("All" %in% input$filter1){
df1
} else if (length(input$filter1)){
df1 <- df1[which(df1$LETTERS %in% input$filter1),]
}
if("All" %in% input$filter2){
df1
} else if (length(input$filter2)){
df1 <- df1[which(df1$Numbers %in% input$filter2),]
}
if("All" %in% input$filter3){
df1
} else if (length(input$filter3)){
df1 <- df1[which(df1$letters %in% input$filter3),]
}
# Update selectInput choices based on the filtered data. Update 'selected' to reflect the user input.
updateSelectInput(session, "filter1", choices = c("All", df$LETTERS), selected = input$filter1)
updateSelectInput(session, "filter2", choices = c("All", df1$Numbers), selected = input$filter2)
updateSelectInput(session, "filter3", choices = c("All", df1$letters), selected = input$filter3)
datatable(df1)
write.csv(df1, file)
})
}
# Run the application
shinyApp(ui = ui, server = server)
When I select A and B in Filter1, the dataset is subset for LETTERS with A and B. The options in Filter2 are 1,2,27,28 and Filter3 are A1, B2, A27, B28. When I select 1 in Filter2, the option in Filter3is A1 and when 2 is also selected in Filter2, Filter3 is updated with A1 and A27 as options. You do not have an All option for Filter2 and Filter3. Is this what you are expecting?
library(shiny)
library(dplyr)
library(DT)
ui <- fluidPage(
titlePanel("Title"),
sidebarLayout(
sidebarPanel(width=3,
selectInput("filter1", "Filter 1", multiple = TRUE, choices = c("All", LETTERS)),
selectInput("filter2", "Filter 2", multiple = TRUE, choices = c("All", as.character(seq.int(1, length(letters), 1)))),
selectInput("filter3", "Filter 3", multiple = TRUE, choices = c("All", letters)) ),
mainPanel(
DT::dataTableOutput("tableprint")
)
)
)
server <- function(input, output, session) {
output$tableprint <- DT::renderDataTable({
# Data
df <- tibble(LETTERS = rep(LETTERS, 2), Numbers = as.character(1:52),
letters = paste(LETTERS, Numbers, sep = ""))
df1 <- df
if("All" %in% input$filter1){
df1
} else if (length(input$filter1)){
df1 <- df1[which(df1$LETTERS %in% input$filter1),]
}
# Update selectInput choices based on the filtered data. Update 'selected' to reflect the user input.
updateSelectInput(session, "filter1", choices = c("All", df$LETTERS), selected = input$filter1)
updateSelectInput(session, "filter2", choices = c("All", df1$Numbers), selected = input$filter2)
if("All" %in% input$filter2){
df1
} else if (length(input$filter2)){
df1 <- df1[which(df1$Numbers %in% input$filter2),]
}
updateSelectInput(session, "filter3", choices = c("All", df1$letters), selected = input$filter3)
if("All" %in% input$filter3){
df1
} else if (length(input$filter3)){
df1 <- df1[which(df1$letters %in% input$filter3),]
}
datatable(df1)
})
}
# Run the application
shinyApp(ui = ui, server = server)
This code does not include the action button.

Resources