I know that there is a very similar question on StackExchange (pickerInput default select all choices), however, the solution can not be applied to my problem.
I have a updatePickerInput which is based on two Inputs. on the updatePickerInput I have the selectAll and clearAll buttons from shinyWidgets. I want selectAll to be the default, but since it is dynamically, I dont know how to pass my choices into the selected option.
Here is my relevant ui code:
radioButtons(inputId = 'selected_group', label = 'group', choices = '')
This is my observeEvent code:
observeEvent(c(input$selected_tab,input$selected_group),{
req(input$selected_group)
updatePickerInput(
session,
'selected_subgroup',
choices = df %>%
filter(tab == input$selected_tab) %>%
filter(group == input$selected_group) %>%
select(subgroup) %>%
distinct(subgroup) %>%
arrange(subgroup) %>%
.[[1]]
)
})
To have all options selected dynamically you'll need to pass the same information to updatePickerInput's choices and selected arguments:
library(shiny)
library(datasets)
library(shinyWidgets)
statesDF <- data.frame(region = state.region, name = state.name, area = state.area, stringsAsFactors = FALSE)
ui <- fluidPage(
radioButtons(inputId = 'selected_group', label = 'group', choices = unique(statesDF$region)),
pickerInput(inputId = 'selected_subgroup', label = 'subgroup', choices = NULL, selected = NULL, multiple = TRUE)
)
server <- function(input, output, session) {
filteredChoices <- reactive({
statesDF$name[statesDF$region == input$selected_group]
})
observeEvent(filteredChoices(), {
updatePickerInput(session, inputId = 'selected_subgroup', label = 'subgroup', choices = filteredChoices(), selected = filteredChoices())
})
}
shinyApp(ui = ui, server = server)
Related
I am trying to generate a shiny app that will first allow the user to (using the notion of dplyr verbs) select the variables they are interested in and then filter those variables based on subsequent selections. I am trying to do this using conditionalPanel() but I am getting stuck finding a way to access the input$ from each conditional panel.
Here is an example:
library('shiny')
library('tidyverse')
library('shinyWidgets')
#Create the data
data <- select(mtcars, c(gear, carb))
#Create page with sidebarlayout
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
#Create picker input where relevant variables are selected
pickerInput(
inputId = 'vars',
label = 'Variables',
choices = colnames(data),
selected = colnames(data),
multiple = T,
pickerOptions(actionsBox = TRUE)
),
#Create conditional panels which show when the variable above is selected
#These panels will be used to filter the data that is selected based on the above variables
conditionalPanel(condition = "input.vars.includes('gear')",
pickerInput(inputId = 'gear',
label = 'Gear',
choices = unique(data$gear),
selected = unique(data$gear),
multiple = T,
pickerOptions(actionsBox = TRUE)
)
),
conditionalPanel(condition = "input.vars.includes('carb')",
pickerInput(inputId = 'carb',
label = 'Carb',
choices = unique(data$carb),
selected = unique(data$carb),
multiple = T,
pickerOptions(actionsBox = TRUE)
)
)
),
mainPanel(
#Show the selected data
verbatimTextOutput('term_selected'),
#Show the selected and filtered data - this won't show
verbatimTextOutput('term_selected_filtered'),
#Try debug with just getting the
verbatimTextOutput('debug_print')
)
)
)
server <- function(input, output) {
#Create the reactive selected data
selected_data <- reactive ({
data %>%
select(input$vars)
})
#Render the selected data
output$term_selected <- renderPrint(selected_data())
#This is where i am stuck
#I need to find a way to access the inputs related to the conditional functions
# selected_filtered_data <- reactive ({
# for (i in length(input$vars)) {
# selected_data() %>%
# filter(input$[first condiitonal panel select] %in% as.symbol(input$vars[i])
# }
# })
#
output$term_selected_filtered <- renderPrint(selected_filtered_data())
#Try to render input input$[first item of input.vars]
output$debug_print <- renderPrint(input$as.symbol(input$vars[1]))
}
shinyApp(ui = ui, server = server)
The problem lies in the server. I have tried input$as.symbol(input$vars[1]) to access the input$gear (assuming that was selected), but it just throws the error: attempt to apply non-function. I tried adding !! as syntactic sugar in front of as.symbol(), but that makes no difference.
I also tried this, in the hope that i could conditionally filter, and had no luck.
selected_filtered_data <- reactive({
selected_data() %>%
if('gear' %in% input$vars) {
filter(gear %in% input$gear) %>%
}
if('carb' %in% input$vars) {
filter(carb %in% input$carb)
}
})
How should I go about doing this?
We may use across (if we want to filter the rows when both column conditions are TRUE) or replace across with if_any (if either one of them is TRUE when they are both selected)
selected_data() %>%
filter(across(all_of(intersect(input$vars,
c('gear', "carb"))), ~ .x %in% input[[cur_column()]]))
-full code
library('shiny')
library('dplyr')
library(tidyr)
library('shinyWidgets')
#Create the data
data <- select(mtcars, c(gear, carb))
#Create page with sidebarlayout
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
#Create picker input where relevant variables are selected
pickerInput(
inputId = 'vars',
label = 'Variables',
choices = colnames(data),
selected = colnames(data),
multiple = TRUE,
pickerOptions(actionsBox = TRUE)
),
#Create conditional panels which show when the variable above is selected
#These panels will be used to filter the data that is selected based on the above variables
conditionalPanel(condition = "input.vars.includes('gear')",
pickerInput(inputId = 'gear',
label = 'Gear',
choices = unique(data$gear),
selected = unique(data$gear),
multiple = T,
pickerOptions(actionsBox = TRUE)
)
),
conditionalPanel(condition = "input.vars.includes('carb')",
pickerInput(inputId = 'carb',
label = 'Carb',
choices = unique(data$carb),
selected = unique(data$carb),
multiple = TRUE,
pickerOptions(actionsBox = TRUE)
)
)
),
mainPanel(
#Show the selected data
verbatimTextOutput('term_selected'),
#Show the selected and filtered data - this won't show
verbatimTextOutput('term_selected_filtered'),
#Try debug with just getting the
verbatimTextOutput('debug_print')
)
)
)
server <- function(input, output) {
#Create the reactive selected data
selected_data <- reactive ({
req(input$vars)
data %>%
select(input$vars)
})
#Render the selected data
output$term_selected <- renderPrint(selected_data())
#This is where i am stuck
#I need to find a way to access the inputs related to the conditional functions
selected_filtered_data <- reactive ({
selected_data() %>%
filter(across(all_of(intersect(input$vars, c('gear', "carb"))), ~ .x %in% input[[cur_column()]]))
})
#
output$term_selected_filtered <- renderPrint(
selected_filtered_data()
)
output$debug_print <- renderPrint(input[[input$vars[1]]])
}
shinyApp(ui = ui, server = server)
-output
I need to update/reverse two inputs from drop down inputs upon a button press. At the moment when I hit the swap button (reverse_xz), it reacts however the updatePickerInput doesn't switch my x and z inputs.
I wanted to have the functionality where, once the swap button is clicked, switch the already selected pickerInputs. Then, all the drop down choices (including the selected) need to get reversed. The reason we have to remove the selected choices from vector is to prevent duplicate selections in both x and z inputs.
I am not sure if I have to render the pickerInput ui on the server side?!
This is my code below:
#global.R
library(shiny)
library(shinydashboard)
library(shinydashboardPlus)
library(shinyWidgets)
library(shinyjs)
#variable labels
my_vars <- c("None"= "NONE",
"All" = "all_all",
"Pro" = "Pro_",
"Locomania" = "locomania_Type",
"Racer" = "race")
#ui.R
ui <- shinydashboardPlus::dashboardPage(
header = shinydashboardPlus::dashboardHeader( ),
body = shinydashboard::dashboardBody( box(textOutput("inputs") ) ),
sidebar = shinydashboardPlus::dashboardSidebar(
shinyWidgets::pickerInput(
inputId = "xvar",
label = "X Axis: ",
choices = my_vars,
options = list(
size = 5),
multiple = FALSE,
selected = "all_all"
),
# Button to reverse the choices
shiny::fluidRow(
shiny::column(12, offset = 4,
shinyWidgets::actionBttn(
inputId = "reverse_xz",
label = "",
style = "simple",
color = "primary",
icon = icon("retweet")
)
)
),
shinyWidgets::pickerInput(
inputId = "zvar",
label = "Z Axis: ",
choices = my_vars,
options = list(
size = 5),
multiple = FALSE,
selected = "race"
)
)
)
#server.R
server <- function(input, output, session) {
#
observe({
if(!is.null(input$reverse_xz))
shinyWidgets::updatePickerInput(session, "zvar",
choices = my_vars[!(my_vars %in% input$xvar)],
selected = isolate(input$zvar) )
shinyWidgets::updatePickerInput(session, "xvar",
choices = my_vars[!(my_vars %in% input$zvar)],
selected = isolate(input$xvar) )
})
# These observers remove the selected choices so both pickers are unique
observe({
if(!is.null(input$zvar))
shinyWidgets::updatePickerInput(session, "xvar",
choices = my_vars[!(my_vars %in% input$zvar)],
selected = isolate(input$xvar) )
})
observe({
if(!is.null(input$xvar))
shinyWidgets::updatePickerInput(session, "zvar",
choices = my_vars[!(my_vars %in% input$xvar)],
selected = isolate(input$zvar) )
})
# output inputs
output$inputs <- renderText({ paste0("x var: ", input$xvar,
"\n\n\n z var:", input$zvar,
"\n\n\nreverse press: ", input$reverse_xz) })
}
shiny::shinyApp(ui= ui, server= server)
Thank you in advance. I have looked at some relavant posts however they couldn't guide me much:
Updatepickerinput with change in pickerinput in Shiny
updatePickerInput not updating values after changing tabs in R shiny
update pickerInput by using updatePickerInput in shiny
Look at this and check if it would be OK for you:
#global.R
library(shiny)
library(shinydashboard)
library(shinydashboardPlus)
library(shinyWidgets)
library(shinyjs)
#variable labels
my_vars <- c("None"= "NONE",
"All" = "all_all",
"Pro" = "Pro_",
"Locomania" = "locomania_Type",
"Racer" = "race")
#ui.R
ui <- shinydashboardPlus::dashboardPage(
header = shinydashboardPlus::dashboardHeader( ),
body = shinydashboard::dashboardBody( box(textOutput("inputs") ) ),
sidebar = shinydashboardPlus::dashboardSidebar(
shinyWidgets::pickerInput(
inputId = "xvar",
label = "X Axis: ",
choices = my_vars,
options = list(
size = 5),
multiple = FALSE,
selected = "all_all"
),
# Button to reverse the choices
shiny::fluidRow(
shiny::column(12, offset = 4,
shinyWidgets::actionBttn(
inputId = "reverse_xz",
label = "",
style = "simple",
color = "primary",
icon = icon("retweet")
)
)
),
shinyWidgets::pickerInput(
inputId = "zvar",
label = "Z Axis: ",
choices = my_vars,
options = list(
size = 5),
multiple = FALSE,
selected = "race"
)
)
)
#server.R
server <- function(input, output, session) {
#
observeEvent(input$reverse_xz, {
shinyWidgets::updatePickerInput(session, "zvar",
choices = my_vars[!(my_vars %in% input$zvar)],
selected = input$xvar)
shinyWidgets::updatePickerInput(session, "xvar",
choices = my_vars[!(my_vars %in% input$xvar)],
selected = input$zvar)
})
observe({
if (input$xvar == input$zvar && (length(input$zvar) > 0 && length(input$xvar) > 0)) {
shinyWidgets::updatePickerInput(session, "zvar",
selected = "")
shinyWidgets::updatePickerInput(session, "xvar",
selected = "")
}
})
# output inputs
output$inputs <- renderText({ paste0("x var: ", input$xvar,
"\n\n\n z var:", input$zvar,
"\n\n\nreverse press: ", input$reverse_xz) })
}
shiny::shinyApp(ui= ui, server= server)
I think that maybe this needs an explanation:
if (input$xvar == input$zvar && (length(input$zvar) > 0 && length(input$xvar) > 0))
So, when user choose two the same inputs, then we are updating pickerInputs, so both will have "Nothing selected" as a sign for user that something goes wrong (or that she/he did something wrong). However, "Nothing selected" is like NULL and we can't use NULL like this NULL == "something" inside if, so I'm checking if some input is NULL using length(input$) > 0, because length of NULL is 0. Instead of length(input$) > 0 you could use !is.null(input$) and maybe you should as it is probably more readable, but I'm leaving this decision for you.
I have a shiny app where a user filters the article column of my dataset depending on the articles he wants to see. Those articles are then displayed in a table. The articles react as actionbutton with a custom function on a click.
I want that whenever a user clicks on a certain article, this article is selected in selectInput. Nevertheless I have no idea which value to pass to the selected attribute of updateSelectInput.
I have put three question marks in the place where I am stuck. By removing the three questionmarks the code is executable.
Any help appreciated
library(shiny)
library(tidyverse)
library(kableExtra)
library(formattable)
df = tibble(article=c("one", "two", "three", "four", "five", "six"),
group=c("a", "a", "a", "b", "b", "b"),
sales=c(12,13,14,43,50,45))
ui = fluidPage(
sidebarPanel(
radioButtons(inputId = "select_a", label = "Choose a group", choices = unique(df$group), selected = "a"),
htmlOutput(outputId = "table")),
sidebarPanel(
selectInput(inputId = "select_b", label = "Choose an article", choices = df$article, selected = "one")
)
)
server = function(input, output, session){
shinyInput <- function(FUN, len, id, labels, ...) {
inputs <- character(len)
for (i in seq_len(len)) {
inputs[i] <- as.character(FUN(paste0(id, i), label = labels[i], ...))
}
inputs
}
df_reactive = reactive({
df %>% filter(group == input$select_a) %>%
mutate(article = shinyInput(actionButton, n(), 'button_', labels = article, onclick = 'Shiny.onInputChange(\"select_button\", this.id)'))
})
output$table = function(){
df_reactive() %>%
kable("html", escape = F, align = "c") %>%
kable_styling(bootstrap_options = c("striped", "condensed", "responsive"), full_width = F, position = "center") %>%
scroll_box(width = "100%", height = "auto")
}
observeEvent(input$select_button, {
updateSelectInput(session = session, inputId = "select_b", selected = ???)
})
}
shinyApp(ui = ui, server = server)
Perhaps you can use this.innerText to retrieve the article here:
mutate(article = shinyInput(actionButton, n(), 'button_', labels = article,
onclick = 'Shiny.onInputChange(\"select_button\", this.innerText)'))
And then input$select_button will contain the text string to select:
updateSelectInput(session = session, inputId = "select_b", selected = input$select_button)
The user interface of the Shiny app I'm working on is supposed to work in the following manner:
User finds the desired observation(s) after applying a set of filters.
User clicks "Add" action button, so selected observation(s) are added to a running list/vector/etc of observations to be analyzed.
User modifies filters to find other observations which are to be included as well.
Loop back to step 1 as many times as user desires.
I cannot seem to find a way to save this list of observations to be analyzed. In the example I attached, the "observation ID" is the name of the model of the car (mtcars is used). I also did not include any data analysis, since I do not think that's necessary. In essence, the entire dataset (mtcars) should be filtered using dplyr in a reactive environment to only include the running list of selected observations.
Here's the code:
data("mtcars")
mtcars$model <- rownames(mtcars)
ui <- fluidPage(
titlePanel("sample"),
sidebarLayout(
sidebarPanel(
uiOutput("disp"),
uiOutput("qsec"),
uiOutput("model"),
actionButton("add", "Add"),
uiOutput("selectedModel")
),
mainPanel(
plotOutput("data_analysis")
)
)
)
server <- function(input, output) {
output$disp <- renderUI({
selectInput(
"disp_sel",
"Select disp:",
unique(mtcars$disp),
selected = NULL,
multiple = T,
selectize = T
)
})
output$qsec <- renderUI({
temp = mtcars
if (!is.null(input$disp_sel)){temp = temp %>% filter(disp %in% input$disp_sel)}
selectInput(
"qsec_sel",
"Select qsec:",
unique(temp$qsec),
selected = NULL,
multiple = T,
selectize = T
)
})
output$model <- renderUI({
temp = mtcars
if (!is.null(input$disp_sel)){temp = temp %>% filter(disp %in% input$disp_sel)}
if (!is.null(input$qsec_sel)){temp = temp %>% filter(qsec %in% input$qsec_sel)}
selectInput(
"model_sel",
"Select model:",
unique(temp$model),
selected = NULL,
multiple = T,
selectize = T
)
})
output$selectedModel <- renderUI({
req(input$add)
selectInput(
"list_of_selections",
"Selected models:",
unique(mtcars$model),
selected = NULL, # this should change when "Add" is pressed
multiple = T,
selectize = T
)
})
r_data = eventReactive(input$add,{
mtcars %>% filter(model %in% input$list_of_selections)
})
output$data_analysis <- renderPlot({
# do something with r_data (filtered data)
})
}
# Run the application
shinyApp(ui = ui, server = server)
I've looked into modular code, reactive lists, and other stuff I don't even remember... Any help is greatly appreciated.
Try this
data("mtcars")
mtcars$model <- rownames(mtcars)
df1 <- mtcars
ui <- fluidPage(
titlePanel("sample"),
sidebarLayout(
sidebarPanel(
uiOutput("disp"),
uiOutput("qsec"),
uiOutput("model"),
actionButton("add", "Add"),
uiOutput("selectedModel")
),
mainPanel(
DTOutput("selecteddata"),
plotOutput("data_analysis")
)
)
)
server <- function(input, output) {
output$disp <- renderUI({
selectInput(
"disp_sel",
"Select disp:",
unique(mtcars$disp),
selected = NULL,
multiple = T,
selectize = T
)
})
output$qsec <- renderUI({
temp = mtcars
if (!is.null(input$disp_sel)){temp = temp %>% filter(disp %in% input$disp_sel)}
selectInput(
"qsec_sel",
"Select qsec:",
unique(temp$qsec),
selected = NULL,
multiple = T,
selectize = T
)
})
output$model <- renderUI({
temp = mtcars
if (!is.null(input$disp_sel)){temp = temp %>% filter(disp %in% input$disp_sel)}
if (!is.null(input$qsec_sel)){temp = temp %>% filter(qsec %in% input$qsec_sel)}
selectInput(
"model_sel",
"Select model:",
unique(temp$model),
selected = NULL,
multiple = T,
selectize = T
)
})
selected_data <- eventReactive(input$add,{
df1 %>% filter(model %in% input$model_sel)
})
output$selecteddata <- renderDT(
selected_data(), # reactive data
class = "display nowrap compact", # style
filter = "top", # location of column filters
options = list( # options
scrollX = TRUE # allow user to scroll wide tables horizontally
)
)
output$selectedModel <- renderUI({
req(input$add)
selectInput(
"list_of_selections",
"Selected models:",
choices = unique(selected_data()$model),
selected = unique(selected_data()$model), # this should change when "Add" is pressed
multiple = T,
selectize = T
)
})
r_data = eventReactive(input$add,{
mtcars %>% filter(model %in% input$list_of_selections)
})
output$data_analysis <- renderPlot({
ggplot(data=selected_data(), aes(x=disp, y=qsec)) + geom_point()
# do something with r_data (filtered data)
})
}
# Run the application
shinyApp(ui = ui, server = server)
Found the answer. I included
selected <- reactiveValues(s = NULL)
observeEvent(input$add,{selected$s = c(selected$s, input$model})
into the server part. Then the selected models are stored in selected$s.
I am developing one app in shiny dashboard in that I want to dynamically populate dropdown box once csv is uploaded. Dropdown will contain top 10 cities by user registrations which I get from following code.
final_data %>%
group_by(registrant_city) %>%
summarise(Total = n()) %>%
arrange(desc(Total)) %>%
top_n(n = 10)
These cities should go into dropdown box.
tabItem("email",
fluidRow(
box(
width = 4, status = "info",solidHeader = TRUE,
title = "Send Emails",
selectInput("email_select",
"Select Email Content",
choices = c("Price" = "price",
"Services" = "service"
)),
selectInput("cities",
"Select City",
choices = ??
))
))
Please help..
Use updateSelectInput in your server like below and set choices = NULL in your ui :
function(input, output, session) {
# If this isn't reactive you can put it in your global
choices_cities <- final_data %>%
group_by(registrant_city) %>%
summarise(Total = n()) %>%
arrange(desc(Total)) %>%
top_n(n = 10)
updateSelectInput(session = session, inputId = "cities", choices = choices_cities$registrant_city)
}
Or if final_data is reactive something like this :
function(input, output, session) {
choices_cities <- reactive({
final_data %>%
group_by(registrant_city) %>%
summarise(Total = n()) %>%
arrange(desc(Total)) %>%
top_n(n = 10)
})
observeEvent(choices_cities(), {
updateSelectInput(session = session, inputId = "cities", choices = choices_cities()$registrant_city)
})
}
A working example :
library("dplyr")
library("shiny")
data("world.cities", package = "maps")
ui <- fluidPage(
sliderInput(inputId = "n", label = "n", min = 10, max = 30, value = 10),
selectInput(inputId = "cities", label = "Select City", choices = NULL)
)
server <- function(input, output, session) {
choices_cities <- reactive({
choices_cities <- world.cities %>%
arrange(desc(pop)) %>%
top_n(n = input$n, wt = pop)
})
observe({
updateSelectInput(session = session, inputId = "cities", choices = choices_cities()$name)
})
}
shinyApp(ui = ui, server = server)
I got the answer for above. Here is what I did.
ui.R
uiOutput("city_dropdown")
And my server.R looks like following
output$city_dropdown <- renderUI({
city <- reg_city(final_data)
city <- city$registrant_city
city <- as.list(city)
selectInput("email_select",
"Select Email Content",
choices = city
)
})
reg_city() gives me the top 10 cities which I want to populate into drop down box,then converting it to a list gives me desired output.