Updating Inputs Based on Previous Input in Shiny R - r

I have a dataset on which I want to apply 3 filters (City, Type and Name of Universities) consecutively. I want to apply a sequential filtering such that when I choose a specific City, other select inputs (Type and Name of universities) be updated accordingly.
I have tried many variations also through stackoverflow solution, however, unable to come up with a solution.
library(shiny)
library(shinythemes)
library(dplyr)
library(tidyr)
library(readxl)
data <- read_excel("foreign_students_by_nationality_2021_2022.xlsx")
colnames(data) <- c("name", "type", "city", "country", "male", "female", "total")
data$male <- as.numeric(data$male)
data$female <- as.numeric(data$female)
data$total <- as.numeric(data$total)
print(str(data))
# Define UI for application that draws a histogram
ui <- fluidPage(
# Application title
titlePanel("Foreign Students in Turkish Universities"),
theme = shinythemes::shinytheme("superhero"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
selectInput("uni_city",
"Select a City",
choices = data$city %>% unique() %>% sort()
),
selectInput("uni_type",
"Select a University Type",
choices = ""
),
selectInput("uni_name",
"Select a University",
choices = ""
)
),
mainPanel(
plotOutput("barplot")
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output, session) {
type_var <- reactive({data %>% filter(city == input$uni_city) %>%
select(type) %>% unique()})
observe({
updateSelectInput(session, "uni_type", choices = type_var())
})
name_var <- reactive({data %>% filter(city == input$uni_city, type == input$uni_type) %>%
select(name) %>% unique() %>% sort()})
observe({
updateSelectInput(session, "uni_name", choices = name_var())
})
output$barplot <- renderPlot({
highest_country <-
data %>%
filter(city == input$uni_city,
type == input$uni_type,
name == input$uni_name) %>%
group_by(country) %>%
summarise(female = sum(female),
male = sum(male),
total = sum(total)) %>%
arrange(desc(total)) %>%
pivot_longer(c(-country, -total), names_to = "gender", values_to = "value") %>%
slice_max(total, n = 20)
ggplot(highest_country,
aes(x = reorder(country, total),
y = value,
fill = gender)
) +
geom_col() +
coord_flip() +
labs(x = "Nationality", y = "Number of Students")
})
}
# Run the application
shinyApp(ui = ui, server = server)

Related

How avoid "invalid (NULL) left side of assignment" error in R Shiny app?

I have a dataset and want to create an R Shiny app with if condition (based on RadioButton).
Additionally, after filtering my initial dataset, I want to replace all 2 values in Quantity column to 200 (Yes, it it possible to do it outside the server(), but in my case, it is necessary to do it inside).
I always get error here sales_by_mfr()$Quantity <- reactive(ifelse(sales_by_mfr()$Quantity == 2,200,sales_by_mfr()$Quantity))
Additionally, I tried to replace all 2 values in my dataset with sales_by_mfr()[sales_by_mfr() == 2] <- reactive({200}) , however got the same error.
Could you help to find a way to avoid "invalid (NULL) left side of assignment" error inside this code?
library(dplyr)
library(shiny)
data <- MASS::Cars93[18:47, ] %>%
mutate(ID = as.character(18:47), Date = seq(as.Date("2019-01-01"), by = "day", length.out = 30)) %>%
select(ID, Date, Manufacturer, Model, Type, Price)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
#sliderInput
radioButtons("dist", "Data:",
c("The most recent" = "most_recent",
"Historical" = "historical"))
),
# plot graphs
mainPanel(tabsetPanel(
tabPanel("Plot",
h3(helpText("Nordpool prices")),
#plotOutput("plot"),
reactableOutput("table")
#h3(helpText("Descr.statistics")),
#verbatimTextOutput("Descr.stat.price")
)
)
))
)
server <- function(input, output, session) {
sales_by_mfr<-reactive({
if (input$dist == "most_recent"){
data %>%
filter(Manufacturer %in% c("Chevrolet","Hyundai","Honda")) %>% group_by( Manufacturer) %>%
summarize(Quantity = n(), Sales = sum(Price))
}else{
data %>%
group_by( Manufacturer) %>%
summarize(Quantity = n(), Sales = sum(Price))
}
})
sales_by_mfr()$Quantity <- reactive(ifelse(sales_by_mfr()$Quantity == 2,200,sales_by_mfr()$Quantity))
#sales_by_mfr()[sales_by_mfr() == 2] <- reactive({200})
#Create columns in two rows (1-dat,2-diffs)
output$table <- renderReactable({
reactable(
sales_by_mfr(),#
# columns = columns(),columnGroups = columnGroups()
#defaultColDef = colDef(minWidth = 222,vAlign = "center"),
#defaultColDef = colDef(vAlign = "center", headerVAlign = "bottom"),
# Set a maximum width on the table:
#style = list(maxWidth = 650),
# Or a fixed width:
#width = 650,
)
})
}
shinyApp(ui = ui, server = server)
Try this
library(MASS)
library(reactable)
data <- MASS::Cars93[18:47, ] %>%
mutate(ID = as.character(18:47), Date = seq(as.Date("2019-01-01"), by = "day", length.out = 30)) %>%
dplyr::select(ID, Date, Manufacturer, Model, Type, Price)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
#sliderInput
radioButtons("dist", "Data:",
c("The most recent" = "most_recent",
"Historical" = "historical"))
),
# plot graphs
mainPanel(tabsetPanel(
tabPanel("Plot",
h3(helpText("Nordpool prices")),
#plotOutput("plot"),
reactableOutput("table")
#h3(helpText("Descr.statistics")),
#verbatimTextOutput("Descr.stat.price")
)
)
))
)
server <- function(input, output, session) {
sales_by_mfr<-reactive({
if (input$dist == "most_recent"){
data %>%
filter(Manufacturer %in% c("Chevrolet","Hyundai","Honda")) %>% group_by( Manufacturer) %>%
summarize(Quantity = n(), Sales = sum(Price))
}else{
data %>%
group_by( Manufacturer) %>%
summarize(Quantity = n(), Sales = sum(Price))
}
ifelse(data$Quantity == 2,200,data$Quantity)
data
})
#sales_by_mfr()$Quantity <- reactive(ifelse(sales_by_mfr()$Quantity == 2,200,sales_by_mfr()$Quantity))
#sales_by_mfr()[sales_by_mfr() == 2] <- reactive({200})
#Create columns in two rows (1-dat,2-diffs)
output$table <- renderReactable({
reactable(
sales_by_mfr(),#
# columns = columns(),columnGroups = columnGroups()
#defaultColDef = colDef(minWidth = 222,vAlign = "center"),
#defaultColDef = colDef(vAlign = "center", headerVAlign = "bottom"),
# Set a maximum width on the table:
#style = list(maxWidth = 650),
# Or a fixed width:
#width = 650,
)
})
}
shinyApp(ui = ui, server = server)

Trying to get a checkboxGroupInput derived from column values to filter a bar graph, but keep getting various errors?

I keep getting errors like Error in : object of type 'closure' is not subsettable or
'..1'. x Input '..1' must be of size 28 or 1, not size 0. I am trying to change the bar graph based on what options are selected or not in the checkbox.
I changed the column names for ease of use from where I got the data.
library(shiny)
library(dplyr)
library(plotly)
#dataset link: https://www.kaggle.com/mahirahmzh/starbucks-customer-retention-malaysia-survey?select=Starbucks+satisfactory+survey.csv
#c("Timestamp","Gender","age","currently","income","visit_freq","Enjoy","Time","Nearby","membership","freq_purchase","avg_spend","Ratevsother","rateprice","salesandpromotion","ambiance","wifi","service","meetup","heardaboutpromotions","continuepatronage")
data <-read.csv("Starbucks satisfactory survey.csv", header=TRUE)
Categorical.Variables <- c("visit_freq", "age", "income")
ui <- fluidPage(
sidebarPanel(
selectInput('category', choices = Categorical.Variables, label = 'Select filter options:'),
conditionalPanel(condition = "input.category != '-'",
uiOutput("select_category"))
)
)
server <- function(input, output) {
output$select_category <- renderUI({
choices <- as.list(unique(data[[input$category]]))
checkboxGroupInput('categorycheck', label = 'Select filter:',
choices = choices,selected = choices)
data2 <- reactive({
data %>%
group_by(gender,data[[input$category]], currently,membership) %>%
summarize(n = n(), .groups="drop") %>%
filter(data[[input$category]] %in% input$categorycheck) %>%
filter(membership == "Yes")})
renderPlotly({
data2 <- data2()
colnames(data2) <- c("gender","filtercategory","currently","membership","n")
plot_ly(data2, x = ~currently, y = ~n, type = "bar", color=~gender, colors="Dark2") %>%
layout(barmode = 'group')
})
})
}
shinyApp(ui, server)
You have several issues. You should close your renderUI prior to using input$categorycheck in the reactive object data2. In addition, columns names in the csv file are long. Once you define the column names of data the way you are analyzing, it will work. Try this
mydata <-read.csv("Starbucks satisfactory survey.csv", header=TRUE)
names(mydata)[1:10] <- c("Timestamp", "gender", "Age", "currently", "Income", "visit_freq","drink_freq","time_spent", "nearby","membership")
Categorical.Variables <- c("Age", "Income", "visit_freq")
ui <- fluidPage(
sidebarPanel(
selectInput('category', choices = Categorical.Variables, label = 'Select filter options:'),
#conditionalPanel(condition = "input.category != '-'",
uiOutput("select_category")
# )
),
mainPanel(plotlyOutput("myplot"),
DTOutput("t1")
)
)
server <- function(input, output) {
output$select_category <- renderUI({
req(input$category)
choices <- as.list(unique(mydata[[input$category]]))
checkboxGroupInput('categorycheck', label = 'Select filter:',
choices = choices,selected = choices)
})
data2 <- reactive({
req(input$category,input$categorycheck)
mydata %>%
group_by(gender,.data[[input$category]], currently,membership) %>%
dplyr::summarize(n = n(), .groups="drop") %>%
filter(.data[[input$category]] %in% input$categorycheck) %>%
filter(membership == "Yes")})
output$t1 <- renderDT(data2())
output$myplot <- renderPlotly({
req(data2())
data2 <- data2()
colnames(data2) <- c("gender","filtercategory","currently","membership","n")
plot_ly(data2, x = ~currently, y = ~n, type = "bar", color=~gender, colors="Dark2") %>%
layout(barmode = 'group')
})
}
shinyApp(ui, server)

Select columname through selectinput in shiny appliaction

I'm trying to build a shiny app, it is good to go but I am trying to put a column from my dataframe in selectinput, but so far didn't found a solution. I have a column with 505 factors, called AAPL, AAL, etc.. I want these factors in my selectinput, so that you can choose from these 505 factors, This is my code right now, and the column name that I'm trying to get in selectinput is bcl-data$Name.
library(shiny)
library(tidyverse)
library(shinythemes)
library(ggplot2)
library(dplyr)
bcl <- read.csv("bcl-data.csv", stringsAsFactors = FALSE)
# Define UI for application that draws a histogram
ui <- fluidPage(theme = shinytheme("darkly"),
# Application title
titlePanel("Overzicht S&P 500 Aandelen"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
sliderInput(inputId = "priceInput", label = "close", min = 0, max = 2050, value = c(0,300), pre = "$"),
selectInput(inputId = "typeInput", label = "Name", choices = (bcl-data$Name)),
dateRangeInput(inputId = "dateInput",
label = "date",
start = "2013/02/08",
end = "2013/03/08",
format = "yy/mm/dd")
),
# Show a plot of the generated distribution
mainPanel(
tabsetPanel(
tabPanel("Plot", plotOutput("Plot")),
tabPanel("Datatable", tableOutput("Datatable"))
)
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output) {
output$Plot <- renderPlot({
filtered <- bcl %>%
filter(close >= input$priceInput[1]) %>%
filter(close <= input$priceInput[2]) %>%
filter(date >= input$dateInput[1] & date <= input$dateInput[2]) %>%
filter(bcl-data$Name == input$typeInput)
filtered
ggplot(filtered, aes(x = date, y = close, color = Name)) +
geom_point()
})
output$Datatable <- renderTable({
filtered <-
bcl %>%
filter(close >= input$priceInput[1]) %>%
filter(close <= input$priceInput[2]) %>%
filter(date >= input$dateInput[1] & date <= input$dateInput[2]) %>%
filter(bcl-data$Name == input$typeInput)
filtered
})
}
# Run the application
shinyApp(ui = ui, server = server)
Comment from above: I think you're error is with bcl-data$Name. While bcl-data.csv is the file you loaded, you saved it as the object bcl - meaning it should simply be bcl$Name. selectInput(inputId = "typeInput", label = "Name", choices = bcl$Name) In your filters, you can also simply have filter(Name == because you're already feeding the bcl data/object through the pipe.
To make sure we remove duplicate values, we can include unique.
Here's what I think should work (cannot test because no data).
library(shiny)
library(tidyverse)
library(shinythemes)
library(ggplot2)
library(dplyr)
bcl <- read.csv("bcl-data.csv", stringsAsFactors = FALSE)
# Define UI for application that draws a histogram
ui <- fluidPage(theme = shinytheme("darkly"),
# Application title
titlePanel("Overzicht S&P 500 Aandelen"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
sliderInput(inputId = "priceInput", label = "close", min = 0, max = 2050, value = c(0,300), pre = "$"),
selectInput(inputId = "typeInput", label = "Name", choices = unique(bcl$Name)),
dateRangeInput(inputId = "dateInput",
label = "date",
start = "2013/02/08",
end = "2013/03/08",
format = "yy/mm/dd")
),
# Show a plot of the generated distribution
mainPanel(
tabsetPanel(
tabPanel("Plot", plotOutput("Plot")),
tabPanel("Datatable", tableOutput("Datatable"))
)
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output) {
output$Plot <- renderPlot({
filtered <- bcl %>%
filter(close >= input$priceInput[1]) %>%
filter(close <= input$priceInput[2]) %>%
filter(date >= input$dateInput[1] & date <= input$dateInput[2]) %>%
filter(Name == input$typeInput)
filtered
ggplot(filtered, aes(x = date, y = close, color = Name)) +
geom_point()
})
output$Datatable <- renderTable({
filtered <-
bcl %>%
filter(close >= input$priceInput[1]) %>%
filter(close <= input$priceInput[2]) %>%
filter(date >= input$dateInput[1] & date <= input$dateInput[2]) %>%
filter(Name == input$typeInput)
filtered
})
}
# Run the application
shinyApp(ui = ui, server = server)

Shiny and ggplot2 with multiple lines

I'm new to Shiny and have run into problems when I try to render a ggplot. I want to render a plot with multiple lines but I get the error: Warning: Error in : Aesthetics must be either length 1 or the same as the data (1)
It work fine when I render a single line, but not multiple. There are earlier questions on Stack Overflow adressing similar issues, but I'm afraid I dont fully understand their soulutions.
Help would be much appreciated. :)
library(tidyverse)
library(shiny)
url <- paste("https://www.ecdc.europa.eu/sites/default/files/documents/COVID-19-geographic-disbtribution-worldwide-",format(Sys.time(), "%Y-%m-18"), ".xlsx", sep = "")
GET(url, authenticate(":", ":", type="ntlm"), write_disk(tf <- tempfile(fileext = ".xlsx")))
df <- read_excel(tf)
df <- df %>%
rename(country = countriesAndTerritories) %>%
arrange(country, dateRep) %>%
group_by(country) %>%
mutate(Cumulative_Death = cumsum(deaths)) %>%
ungroup() %>%
filter(Cumulative_Death > 9) %>%
group_by(country) %>%
mutate(numbers_of_days = row_number(),
First_Death_Date = min(dateRep)) %>%
select(country, numbers_of_days, deaths, Cumulative_Death)
ui <- fluidPage(
titlePanel("Statistik Covid-19"),
sidebarLayout(
sidebarPanel(
selectInput("cou", "Country:", choices = unique(df$country), selected = "SWeden", multiple = TRUE),
selectInput("var", "Variable:", choices = c("deaths", "Cumulative_Death"))),
mainPanel(
plotOutput("covid"))
))
server <- function(input, output, session){
selected <- reactive(filter(df, country %in% input$cou))
output$covid <- renderPlot({
ggplot(selected(), aes(x=numbers_of_days, input$var, colour = input$cou)) +
geom_line(size = 1.5) +
labs(title = "Covid-19: Antal döda per 100 000 invånare",
x = "DAGAR SEDAN ANTAL DÖDSFALL ÖVERSTEG TIO",
y = paste0(input$var),
caption = "Source: European Centre for Disease Prevention and Control") +
guides(colour = guide_legend(title=NULL))
})
}
shinyApp(ui, server)
Try this. As #SusanSwitzer already mentioned. Main issue is that you use input$land. So. Simply replace with input$country. Second. Map colour on country which is the varname in the df. Third I switched to aes_string instead of aes to use the character inputs:
library(shiny)
library(ggplot2)
library(dplyr)
url <- paste("https://www.ecdc.europa.eu/sites/default/files/documents/COVID-19-geographic-disbtribution-worldwide-",format(Sys.time(), "%Y-%m-18"), ".xlsx", sep = "")
httr::GET(url, httr::authenticate(":", ":", type="ntlm"), httr::write_disk(tf <- tempfile(fileext = ".xlsx")))
df <- readxl::read_excel(tf)
df <- df %>%
rename(country = countriesAndTerritories) %>%
arrange(country, dateRep) %>%
group_by(country) %>%
mutate(Cumulative_Death = cumsum(deaths)) %>%
ungroup() %>%
filter(Cumulative_Death > 9) %>%
group_by(country) %>%
mutate(numbers_of_days = row_number(),
First_Death_Date = min(dateRep)) %>%
select(country, numbers_of_days, deaths, Cumulative_Death)
ui <- fluidPage(
titlePanel("Statistik Covid-19"),
sidebarLayout(
sidebarPanel(
selectInput("country", "Country:", choices = unique(df$country), selected = "Sweden", multiple = TRUE),
selectInput("var", "Variable:", choices = c("deaths", "Cumulative_Death"))),
mainPanel(
plotOutput("covid"))
))
server <- function(input, output, session){
# input$country instead input$land
selected <- reactive(filter(df, country %in% input$country))
output$covid <- renderPlot({
# switch to aes_string. map colour on country instead of input$land
ggplot(selected(), aes_string(x = "numbers_of_days", y = input$var, colour = "country")) +
geom_line(size = 1.5) +
labs(title = "Covid-19: Antal döda per 100 000 invånare",
x = "DAGAR SEDAN ANTAL DÖDSFALL ÖVERSTEG TIO",
y = paste0(input$var),
caption = "Source: European Centre for Disease Prevention and Control") +
guides(colour = guide_legend(title=NULL))
})
}
shinyApp(ui, server)

Display multiple summary statistics depending on user selection

I'm creating a shiny app where a user can select a state parent_location and a county name from two drop downs. They can also select a variable of interest layer which will then produce a summary statistics table. I've got my code working up to this point.
What I need to do is select other similar counties (contained in the cluster column) and then display summary statistics for this county as well. I can't seem to figure out how to A) display multiple summary statistics tables and B) dynamically create a list of similar counties.
Code that works
library(shiny)
library(tidyverse)
library(lubridate)
eviction_county_2010 <- read.csv("./eviction_county_2010.csv")
ui <- fluidPage(
sliderInput(inputId = "year",
label = "Select a Year:",
min = 2010,
max = 2016,
value = 2010,
step = 1),
radioButtons(inputId = "layer",
label = "Select a Dataset to View:",
choices = c("Eviction Filing Rate"="eviction_filing_rate", "Percent Rent Burden"="rent_burden",
"Percent Renter Occupied"="pct_renter_occupied", "Poverty Rate"="poverty_rate")),
selectInput(inputId = "state",
label = "Select a State:",
eviction_county_2010$parent_location),
selectInput(inputId = "county",
label = "Select a County:",
choices = NULL),
mainPanel(
h2("Summary of the variable"),
verbatimTextOutput("sum")
)
)
server <- function(input, output, session) {
observe({
x <- filter(eviction_county_2010,parent_location == input$state) %>%
select(name)
updateSelectInput(session,"county","Select a County:",choices = unique(x))}
)
output$sum <- renderPrint({
ec <- eviction_county_2010 %>%
filter(parent_location == input$state) %>%
filter(name == input$county)
summary(ec[,input$layer])
})
}
# Run the application
shinyApp(ui = ui, server = server)
Code I've attempted for displaying for similar counties. It returns Error in .getReactiveEnvironment()$currentContext(): Operation not allowed without an active reactive context. (You tried to do something that can only be done from inside a reactive expression or observer.) I'm not sure which part needs to be placed inside a reactive expression.
ui <- fluidPage(
sliderInput(inputId = "year",
label = "Select a Year:",
min = 2010,
max = 2016,
value = 2010,
step = 1),
radioButtons(inputId = "layer",
label = "Select a Dataset to View:",
choices = c("Eviction Filing Rate"="eviction_filing_rate", "Percent Rent Burden"="rent_burden",
"Percent Renter Occupied"="pct_renter_occupied", "Poverty Rate"="poverty_rate")),
selectInput(inputId = "state",
label = "Select a State:",
eviction_county_2010$parent_location),
selectInput(inputId = "county",
label = "Select a County:",
choices = NULL),
mainPanel(
h2("Summary of the variable"),
verbatimTextOutput("sum")
)
)
server <- function(input, output, session) {
ec <- eviction_county_2010 %>%
filter(parent_location == input$state) %>%
filter(name == input$county)
sel_clust <- unique(ec$cluster)
sim_cty <- eviction_county_2010[ sample(which(eviction_county_2010$cluster == sel_clust), 4),]
sim_cty <- unique(sim_cty$GEOID)
sim_cty <- append(sim_cty, unique(ec$GEOID))
observe({
x <- filter(eviction_county_2010,parent_location == input$state) %>%
select(name)
updateSelectInput(session,"county","Select a County:",choices = unique(x))}
)
output$sum <- renderPrint({
df1 <- eviction_county_2010 %>%
filter(GEOID == sim_cty[1])
df2 <- eviction_county_2010 %>%
filter(GEOID == sim_cty[2])
df3 <- eviction_county_2010 %>%
filter(GEOID == sim_cty[3])
df4 <- eviction_county_2010 %>%
filter(GEOID == sim_cty[4])
df5 <- eviction_county_2010 %>%
filter(GEOID == sim_cty[5])
summary(df1[,input$layer])
summary(df2[,input$layer])
summary(df3[,input$layer])
summary(df4[,input$layer])
summary(df5[,input$layer])
})
}
# Run the application
shinyApp(ui = ui, server = server)
Is this even possible? What am I doing wrong here?
Move this section:
ec <- eviction_county_2010 %>%
filter(parent_location == input$state) %>%
filter(name == input$county)
sel_clust <- unique(ec$cluster)
sim_cty <- eviction_county_2010[ sample(which(eviction_county_2010$cluster == sel_clust), 4),]
sim_cty <- unique(sim_cty$GEOID)
sim_cty <- append(sim_cty, unique(ec$GEOID))
To a reactive({}) statement. I think that's where your error is.
For example:
ec <- reactive({
eviction_county_2010 %>%
filter(parent_location == input$state) %>%
filter(name == input$county)
sel_clust <- unique(ec$cluster)
sim_cty <- eviction_county_2010[ sample(which(eviction_county_2010$cluster == sel_clust), 4),]
sim_cty <- unique(sim_cty$GEOID)
sim_cty <- append(sim_cty, unique(ec$GEOID))
})
Then later in your sever code use:
ec() %>%
...stuff...

Resources