I am very struggling with getting my head around the concept of reactivity in R Shiny. I replicated the app with a synthetic data as below.
As you can see, I sort of endedup with working 3 selectInputs with "All" option... Not sure if this is the right way to do it though.
My problem is that every time a input is changed (on any one menu), a whole new output is generated. But I need to utilise the concept of reactivity here...
I only want to generate a new output (new map) whenever the variable 'type' is changed and wants to only filter data using other two drop down menus while the output map remains the same.
I have no idea how to go about re-arranging the code while keeping the "All" option workable. Please help me.
library(shiny)
library(dplyr)
library(leaflet)
library(ggplot2)
library(htmltools)
# Load the Data
schools <- read.csv("https://raw.githubusercontent.com/yunique1020/synthetic_data/main/syntheticdata.csv")
# Data Pre-processing
sapply(schools, function(x) length(unique(x)))
names(schools) <- make.names(c("id", "number", "name", "street", "suburb", "postcode", "type", "year",
"sector", "latitude", "longitude"))
hist_type <- schools %>%
ggplot(aes(x=type)) +
geom_bar()
hist_type
hist_sector <- schools %>%
ggplot(aes(x=sector)) +
geom_bar()
hist_sector
hist_year <- schools %>%
ggplot(aes(x=year)) +
geom_bar()
hist_year
count(schools, type)
count(schools, year)
# Replace missing values to category 'Other' in year column
schools$year <- replace(schools$year, schools$year == "", "Other")
# Define UI for application
ui <- fluidPage(
# Application title
titlePanel("Schools Data Explorer"),
tabsetPanel(
tabPanel("Task 1 — schools", p(),
sidebarLayout(
sidebarPanel(
selectInput("type", "Type of Schooling : ",
c("All", schools$type)),
selectInput("sector", "Sector: ", choices = c("All", schools$sector)),
selectInput("year", "Year Levels: ", choices = c("Any", schools$year))
),
mainPanel(
leafletOutput("schoolMap")
)
)
)
)
)
# Define server logic
server <- function(input, output) {
# Create a vector of icons to use Font Awesome ‘hospital-o’ icon
HospitalIcons <- awesomeIconList(
Public = makeAwesomeIcon(icon = 'hospital-o', markerColor = 'green', iconColor = 'white', library = "fa"),
Private = makeAwesomeIcon(icon = 'hospital-o', markerColor = 'orange', iconColor = 'white', library = "fa")
)
# Create a function called map for repeated steps
map <- function(x){
m <- leaflet(x) %>%
addTiles() %>%
addAwesomeMarkers(lng = x$longitude, lat = x$latitude,
icon = ~HospitalIcons[x$sector],
label = ~htmlEscape(x$name),
popup = paste0("School: ", x$name, "<br>",
"Address: ", x$street, " ", x$suburb))
return(m)
}
output$schoolMap <- renderLeaflet({
if (input$type == "All" & input$sector == "All" & input$year == "Any"){
map(schools)
} else if (input$type == "All" & input$year == "Any") {
all_types_any_year <- schools %>% filter(sector == input$sector)
map(all_types_any_year)
} else if (input$type == "All" & input$sector == "All") {
all_types_all_sectors <- schools %>% filter(year == input$year)
map(all_types_all_sectors)
} else if (input$sector == "All" & input$year == "Any") {
all_sectors_any_year <- schools %>% filter(type == input$type)
map(all_sectors_any_year)
} else if (input$type == "All"){
all_types <- schools %>% filter(sector == input$sector & year == input$year)
map(all_types)
} else if (input$sector == "All") {
all_sectors <- schools %>% filter(type == input$type & year == input$year)
map(all_sectors)
} else if (input$year == "Any") {
any_year <- schools %>% filter(type == input$type & sector == input$sector)
map(any_year)
}
else {
filteredData <- schools %>% filter(type == input$type & sector == input$sector & year == input$year)
map(filteredData)
}
})
}
# Run the application
shinyApp(ui = ui, server = server)
I'm not entirely clear what you mean here. If either the sector or the year is changed, the dataset is correspondingly filtered, and then the map is generated on the filtered data, correct? This means that the map will need to be regenerated every time any of the inputs changes. How are you envisioning the map to remain the same if sector or year change?
Incidentally, you can refactor your renderLeaflet as follows:
typeFilter <- ifelse(input$type %in% "All", unique(schools$type), input$type)
sectorFilter <- ifelse(input$sector %in% "All", unique(schools$sector), input$sector)
yearFilter <- ifelse(input$year %in% "Any", unique(schools$year), input$year)
filteredData <- schools %>% filter(type %in% input$type & sector %in% input$sector & year %in% input$year)
map(filteredData)