I'm trying to produce a Shiny app with Leaflet that renders a choropleth map based on different input criteria. The map displays incidents of different types (input$type) and backgrounds (input$background). When additional types or backgrounds are specified, polygons are filled with updated incident data. It is working correctly with one snag. When I switch the date input from date range (input$dateInput) to presidential period (input$president), the choropleth for presidential period renders once, displaying polygons with no data, and then again with the polygons filled with the correct data for the pre-selected period ("President1"). How do I avoid the map rendering twice like this when the Presidency tab is pressed?
Question also listed here on RStudio Community.
The raw data and shapefile used can be accessed here: https://github.com/cjbarrie/shiny_egy.
Working example:
Name of raw data: wikiraw
Name of shapefile: shapefile
Global:
library(shiny)
library(shinydashboard)
library(shinythemes)
library(leaflet)
library(rgdal)
library(rmapshaper)
library(sp)
library(dplyr)
library(lubridate)
wikiraw <-read.csv("~/wikisample_SO.csv")
shapefile <- readOGR("~/EGY_adm2.shp")
shapefile<-spTransform(shapefile, CRS("+init=epsg:4326"))
## Simplify shapefile to speed up rendering
shapefile <- ms_simplify(shapefile, keep = 0.01, keep_shapes = TRUE)
wikbounds<-bbox(shapefile)
wikiraw$incident_date <- as.Date(wikiraw$incident_date,
format = "%m/%d/%Y")
wikiraw$presidency <- rep(NA, nrow(wikiraw))
wikiraw$incident_date1 <- as.numeric(wikiraw$incident_date)
wikiraw$event <- rep(1,nrow(wikiraw))
## Generate presidency categorical var.
wikiraw$presidency <- cut(wikiraw$incident_date1,
breaks = c(-Inf, 15016, 15521, 15889, 16229, Inf),
labels = c("President1", "President2", "President3", "President4", "President5"),
right = FALSE)
Snippet of data.frame wikiraw:
ID_2 incident_date incident_background incident_type presidency event
1 168 2013-11-26 Cultural Group President4 1
2 133 2013-11-29 Cultural Group President4 1
3 137 2014-01-25 Cultural Group President4 1
4 168 2011-01-28 Cultural Collective President1 1
5 168 2016-04-25 Cultural Group President5 1
6 163 2015-02-08 Political Individual President5 1
UI:
ui <- dashboardPage(
dashboardHeader(title = "Map tool"),
dashboardSidebar(sidebarMenu(menuItem("Map", tabName = "map"),
selectInput("input_type", "Date input type",
c("Date", "Presidency")),
uiOutput("dateSelect"),
uiOutput("typeSelect"),
uiOutput("backgroundSelect"),
uiOutput("presidentSelect"))),
dashboardBody(tabItems(
tabItem(tabName = "map",
leafletOutput("mymap", height=500)))))
Server:
server <- function(input, output, session) {
output$dateSelect <- renderUI({
switch(input$input_type,
"Date" = dateRangeInput("dateInput", "Dates:",
min=min(wikiraw$incident_date), max = max(wikiraw$incident_date),
start = min(wikiraw$incident_date), end = max(wikiraw$incident_date)),
"Presidency" = checkboxGroupInput("president", "Presidency",
choices = levels(wikiraw$presidency),
selected = "President1"))
})
output$typeSelect <- renderUI({
selectInput("type", "Incident type",
choices = unique(wikiraw$incident_type), multiple = TRUE,
selected = wikiraw$incident_type[1])})
output$backgroundSelect <- renderUI({
checkboxGroupInput("background", "Incident background",
choices = unique(wikiraw$incident_background),
selected = wikiraw$incident_background[1])})
selected <- reactive({
wikiagg <- wikiraw %>% group_by(ID_2, incident_date, incident_type, incident_background, presidency) %>%
summarize(sum_event = sum(event))
if(input$input_type=="Date"){wikiagg <- filter(wikiagg,
incident_date >= min(input$dateInput),
incident_date <= max(input$dateInput),
incident_type%in%input$type,
incident_background%in%input$background)}
if(input$input_type=="Presidency"){wikiagg <- filter(wikiagg,
incident_type%in%input$type,
incident_background%in%input$background,
presidency%in%input$president)}
wikiagg <- wikiagg %>% group_by(ID_2) %>%
summarize(sum_event = sum(sum_event))
wikiagg
})
output$mymap <- renderLeaflet({
leaflet() %>%
addTiles() %>%
setView(mean(wikbounds[1,]),
mean(wikbounds[2,]),
zoom=6
)
})
observe({
if(!is.null(input$dateInput)){
shapefile#data <- left_join(shapefile#data, selected(), by="ID_2")
##Define palette across range of data
wikiaggpal <- wikiraw %>% group_by(ID_2) %>%
summarize(sum_event = sum(event))
pal <- colorBin("YlOrRd", wikiaggpal$sum_event, bins=5, na.color = "#bdbdbd")
leafletProxy("mymap", data = shapefile) %>%
addTiles() %>%
clearShapes() %>%
addPolygons(data = shapefile, fillColor = ~pal(sum_event), fillOpacity = 0.7,
color = "white", weight = 2)
}})
}
shinyApp(ui, server)
Gif of issue:
https://imgur.com/a/FnfOGKi
Any help would be hugely appreciated!
What if you change the reactive to a reactiveValue and assign the data in an observe? I don't know if it is working correctly as I dont know which shapes & colors to expect, but I am not seeing that double rendering anymore.
(Data & Preparation from question is used)
library(shiny)
library(shinydashboard)
library(shinythemes)
library(leaflet)
library(rgdal)
library(rmapshaper)
library(sp)
library(dplyr)
library(lubridate)
ui <- dashboardPage(
dashboardHeader(title = "Map tool"),
dashboardSidebar(sidebarMenu(menuItem("Map", tabName = "map"),
selectInput("input_type", "Date input type",
c("Date", "Presidency")),
uiOutput("dateSelect"),
uiOutput("typeSelect"),
uiOutput("backgroundSelect"),
uiOutput("presidentSelect"))),
dashboardBody(tabItems(
tabItem(tabName = "map",
leafletOutput("mymap", height=500)))))
server <- function(input, output, session) {
output$dateSelect <- renderUI({
switch(input$input_type,
"Date" = dateRangeInput("dateInput", "Dates:",
min=min(wikiraw$incident_date), max = max(wikiraw$incident_date),
start = min(wikiraw$incident_date), end = max(wikiraw$incident_date)),
"Presidency" = checkboxGroupInput("president", "Presidency",
choices = levels(wikiraw$presidency),
selected = "President1"))
})
output$typeSelect <- renderUI({
selectInput("type", "Incident type",
choices = unique(wikiraw$incident_type), multiple = TRUE,
selected = wikiraw$incident_type[1])})
output$backgroundSelect <- renderUI({
checkboxGroupInput("background", "Incident background",
choices = unique(wikiraw$incident_background),
selected = wikiraw$incident_background[1])})
sel_reactval = reactiveValues(s = NULL)
# selected <- reactive({
observe({
wikiagg <- wikiraw %>% group_by(ID_2, incident_date, incident_type, incident_background, presidency) %>%
summarize(sum_event = sum(event))
if(input$input_type=="Date"){wikiagg <- filter(wikiagg,
incident_date >= min(input$dateInput),
incident_date <= max(input$dateInput),
incident_type%in%input$type,
incident_background%in%input$background)}
if(input$input_type=="Presidency"){wikiagg <- filter(wikiagg,
incident_type%in%input$type,
incident_background%in%input$background,
presidency%in%input$president)}
wikiagg <- wikiagg %>% group_by(ID_2) %>%
summarize(sum_event = sum(sum_event))
sel_reactval$s = wikiagg
# wikiagg
})
output$mymap <- renderLeaflet({
leaflet() %>%
addTiles() %>%
setView(mean(wikbounds[1,]),
mean(wikbounds[2,]),
zoom=6
)
})
observe({
req(!is.null(input$dateInput))
req(nrow(as.data.frame(sel_reactval$s))!=0)
# if(!is.null(input$dateInput)){
# shapefile#data <- left_join(shapefile#data, selected(), by="ID_2")
shapefile#data <- left_join(shapefile#data, sel_reactval$s, by="ID_2")
##Define palette across range of data
wikiaggpal <- wikiraw %>% group_by(ID_2) %>%
summarize(sum_event = sum(event))
pal <- colorBin("YlOrRd", wikiaggpal$sum_event, bins=5, na.color = "#bdbdbd")
leafletProxy("mymap") %>%
addTiles() %>%
clearShapes() %>%
addPolygons(data = shapefile, fillColor = ~pal(sum_event), fillOpacity = 1,
color = "white", weight = 2)
# }
})
}
shinyApp(ui, server)
Related
I have successfully created an interactive choropleth map using Leaflet in R that projects a single variable across a set of polygons.
library(RSocrata)
library(rgdal)
library(leaflet)
library(sp)
library(dplyr)
#library(mapview)
area_bound <- rgdal::readOGR("https://data.cityofchicago.org/resource/igwz-8jzy.geojson")
area_bound$area_num_1 <- as.numeric(area_bound$area_numbe)
health <- read.socrata("https://data.cityofchicago.org/resource/iqnk-2tcu.json")
data_num <- as.data.frame(apply(health[3:29], 2, as.numeric))
data_num <- bind_cols(health[1:2], data_num)
health_area <- sp::merge(area_bound, data_num, by.x = "area_numbe", by.y = "community_area")
pal <- colorNumeric("viridis", NULL)
leaflet(health_area) %>%
addTiles() %>%
addPolygons(stroke = FALSE, smoothFactor = 0.3, fillOpacity = 1,
fillColor = ~pal(as.numeric(firearm_related)),
label = ~paste0(community, ": ", formatC(firearm_related, big.mark = ",")))
The health data set has multiple variables and I would like to create a shiny app that allows users to choose a different variable to produce a choropleth map. Using the code provided by Kyle Walker as a model for my server, I came up with the code below that allows users to choose from a list of two variables. Unfortunately I am having problems running it, getting a Warning: Error in min: invalid 'type' (list) of argument error. Any help in resolving this would be appreciated. I have also looked at the RStudio, Using Leaflet With Shiny tutorial, but the examples provided are not choropleth maps.
Here is my non-working code:
## app.R ##
library(shiny) # for shiny apps
library(leaflet) # renderLeaflet function
library(RSocrata)
library(rgdal)
library(sp)
library(dplyr)
area_bound <- rgdal::readOGR("https://data.cityofchicago.org/resource/igwz-8jzy.geojson")
area_bound$area_num_1 <- as.numeric(area_bound$area_numbe)
health <- read.socrata("https://data.cityofchicago.org/resource/iqnk-2tcu.json")
data_num <- as.data.frame(apply(health[3:29], 2, as.numeric))
data_num <- bind_cols(health[1:2], data_num)
health_area <- sp::merge(area_bound, data_num, by.x = "area_numbe", by.y = "community_area")
groups <- c("Breast Cancer" = "breast_cancer_in_females", "Firearm" = "firearm_related")
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
radioButtons(
inputId = "group",
label = "Select a group to map",
choices = groups
)
),
mainPanel(
leafletOutput("map", height = "600")
)
)
)
server = function(input, output) {
group_to_map <- reactive({
input$group
})
output$map <- renderLeaflet({
leaflet(options = leafletOptions(zoomControl = FALSE)) %>%
addProviderTiles(providers$Stamen.TonerLite) %>%
setView(lng = -87.623177,
lat = 41.881832,
zoom = 8.5)
})
observeEvent(input$group, {
pal <- colorNumeric("viridis", group_to_map)
leafletProxy("map") %>%
clearShapes() %>%
clearControls() %>%
addPolygons(data = group_to_map,
color = ~pal(),
weight = 0.5,
fillOpacity = 0.5,
smoothFactor = 0.2) %>%
addLegend(
position = "bottomright",
pal = pal,
values = group_to_map,
title = "% of population"
)
})
}
shinyApp(ui, server)
There are several issues with your shiny code. First, to refer to values from a reactive you have to call it like a function, i.e. you have to do group_to_map(). Next, group_to_map() is just a character. To use the data column whose name is stored in group_to_map() you have to do health_area[[group_to_map()]]. I also fixed the issue with your palette functions. Finally, note that I switched to sf for reading the geo data as I'm more familiar with sf objects:
## app.R ##
library(shiny) # for shiny apps
library(leaflet) # renderLeaflet function
library(RSocrata)
library(dplyr)
area_bound <- sf::st_read("https://data.cityofchicago.org/resource/igwz-8jzy.geojson")
health <- read.socrata("https://data.cityofchicago.org/resource/iqnk-2tcu.json")
health[3:29] <- lapply(health[3:29], as.numeric)
#> Warning in lapply(health[3:29], as.numeric): NAs introduced by coercion
health_area <- left_join(area_bound, health, by = c("area_num_1" = "community_area"))
groups <- c("Breast Cancer" = "breast_cancer_in_females", "Firearm" = "firearm_related")
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
radioButtons(
inputId = "group",
label = "Select a group to map",
choices = groups
)
),
mainPanel(
leafletOutput("map", height = "600")
)
)
)
server = function(input, output) {
group_to_map <- reactive({
input$group
})
output$map <- renderLeaflet({
leaflet(options = leafletOptions(zoomControl = FALSE)) %>%
addProviderTiles(providers$Stamen.TonerLite) %>%
setView(lng = -87.623177,
lat = 41.881832,
zoom = 8.5)
})
observeEvent(input$group, {
pal <- colorNumeric("viridis", range(health_area[[group_to_map()]]))
leafletProxy("map") %>%
clearShapes() %>%
clearControls() %>%
addPolygons(data = health_area,
color = ~pal(health_area[[group_to_map()]]),
weight = 0.5,
fillOpacity = 0.5,
smoothFactor = 0.2) %>%
addLegend(
position = "bottomright",
pal = pal,
values = health_area[[group_to_map()]],
title = "% of population"
)
})
}
shinyApp(ui, server)
#>
#> Listening on http://127.0.0.1:5938
I would like to create a Leaflet Map which renders at a default location, at a zoom level of 4, and then when the user clicks the go button, pans from location to another, both of which have been selected from a dropdown.
I've tried using the following code, the data for which can be found # https://github.com/eoefelein/COVID_Business_Recovery_and_Social_Capital/tree/master/socialCapitalEmployment/data
library(sf)
library(tigris)
library(shiny)
library(shinydashboard)
library(tidyverse)
library(leaflet)
# data loading and processing
USA <- st_read(dsn = 'data/cb_2018_us_county_5m.shp')
counties_sf <- st_as_sf(USA)
counties_reproject_sf <- st_transform(counties_sf, 4326) %>% filter(COUNTYFP < 60010)
emp_rate <- read_csv('data/synthetic_emp_rate_pred.csv')
emp_rate$countyfips <- sprintf("%05d", emp_rate$countyfips)
states_sf_coef <- geo_join(counties_reproject_sf, emp_rate, "GEOID", "countyfips", how='inner')
ui <- fluidPage(
dashboardPage(
dashboardHeader(title="Employee Rate Data"),
dashboardSidebar(
sidebarMenu(
menuItem(
"Maps",
tabName = "maps",
icon=icon("globe")
)
)
),
dashboardBody(
tabItems(
tabItem(
tabName = "maps",
tags$style(type="text/css","#all_airports {height:calc(100vh - 80px) !important;}"),
fluidRow(column(4),
column(8,
selectInput(inputId = "FromCounty",
label="from",
choices=c(unique(emp_rate$countyname)),
selected = 'Travis County, Texas'
),
selectInput(inputId = "ToCounty",
label = "to",
choices=c(unique(emp_rate$countyname))
))),
actionButton("zoomer","go"),
leafletOutput("map")
)
)
)
)
)
server <- function(input, output, session) {
# map
output$map <- renderLeaflet({
mypal <- colorNumeric(palette="viridis", domain=states_sf_coef$rand_pred, na.color="transparent")
# mypalette(c(45,43))
leaflet() %>%
addProviderTiles("OpenStreetMap.Mapnik") %>%
setView(lat = 38.2393,
lng = -96.3795,
zoom = 4) %>%
addPolygons(
data = states_sf_coef,
fillColor = ~mypal(rand_pred),
# fillColor = ~ mypal(data$value),
stroke = FALSE,
smoothFactor = 0.2,
fillOpacity = 0.3,
popup = paste(
"Region: ",
states_sf_coef$countyname,
"<br>",
"Social Index: ",
states_sf_coef$rand_pred,
"<br>"
)
)
# %>%
# addLayersControl(
# baseGroups = c("Employment Prediction Data (default)", "To-From"),
# options = layersControlOptions(collapsed = FALSE)
# )
})
map_proxy <- leafletProxy("map")
observeEvent(input$zoomer, { # add Smith, county, kansas and default to zoom = 1?
# fromCounty
fromCountyInput <- reactive({
states_sf_coef %>% dplyr::filter(countyname == input$FromCounty)
})
fromData <- fromCountyInput()
fromCoords <- st_coordinates(st_centroid(fromData$geometry))
# toCounty
toCountyInput <- reactive({
states_sf_coef %>% dplyr::filter(countyname == input$ToCounty)
})
toData <- toCountyInput()
toCoords <- st_coordinates(st_centroid(toData$geometry))
map_proxy %>%
flyTo(lng = fromCoords[1], lat = fromCoords[2], zoom = 10)
flyTo(lng = toCoords[1], lat = toCoords[2], zoom = 10)
})
}
# Run the application
shinyApp(ui = ui, server = server)
Right now I'm getting the following error:
Warning: Error in dispatch: argument "map" is missing, with no default. Any guidance would be much appreciated!
I can't access your data to check that this works but I found a solution my (similar) problem by using shinyjs::delay(). This requires that you include the useShinyjs() in the ui as I have done below.
library(sf)
library(tigris)
library(shiny)
library(shinydashboard)
library(tidyverse)
library(leaflet)
library(shinyjs)
# data loading and processing
USA <- st_read(dsn = 'data/cb_2018_us_county_5m.shp')
counties_sf <- st_as_sf(USA)
counties_reproject_sf <- st_transform(counties_sf, 4326) %>% filter(COUNTYFP < 60010)
emp_rate <- read_csv('data/synthetic_emp_rate_pred.csv')
emp_rate$countyfips <- sprintf("%05d", emp_rate$countyfips)
states_sf_coef <- geo_join(counties_reproject_sf, emp_rate, "GEOID", "countyfips", how='inner')
ui <- fluidPage(
dashboardPage(
useShinyjs(),
dashboardHeader(title="Employee Rate Data"),
dashboardSidebar(
sidebarMenu(
menuItem(
"Maps",
tabName = "maps",
icon=icon("globe")
)
)
),
dashboardBody(
tabItems(
tabItem(
tabName = "maps",
tags$style(type="text/css","#all_airports {height:calc(100vh - 80px) !important;}"),
fluidRow(column(4),
column(8,
selectInput(inputId = "FromCounty",
label="from",
choices=c(unique(emp_rate$countyname)),
selected = 'Travis County, Texas'
),
selectInput(inputId = "ToCounty",
label = "to",
choices=c(unique(emp_rate$countyname))
))),
actionButton("zoomer","go"),
leafletOutput("map")
)
)
)
)
)
server <- function(input, output, session) {
# map
output$map <- renderLeaflet({
mypal <- colorNumeric(palette="viridis", domain=states_sf_coef$rand_pred, na.color="transparent")
# mypalette(c(45,43))
leaflet() %>%
addProviderTiles("OpenStreetMap.Mapnik") %>%
setView(lat = 38.2393,
lng = -96.3795,
zoom = 4) %>%
addPolygons(
data = states_sf_coef,
fillColor = ~mypal(rand_pred),
# fillColor = ~ mypal(data$value),
stroke = FALSE,
smoothFactor = 0.2,
fillOpacity = 0.3,
popup = paste(
"Region: ",
states_sf_coef$countyname,
"<br>",
"Social Index: ",
states_sf_coef$rand_pred,
"<br>"
)
)
# %>%
# addLayersControl(
# baseGroups = c("Employment Prediction Data (default)", "To-From"),
# options = layersControlOptions(collapsed = FALSE)
# )
})
map_proxy <- leafletProxy("map")
observeEvent(input$zoomer, { # add Smith, county, kansas and default to zoom = 1?
# fromCounty
fromCountyInput <- reactive({
states_sf_coef %>% dplyr::filter(countyname == input$FromCounty)
})
fromData <- fromCountyInput()
fromCoords <- st_coordinates(st_centroid(fromData$geometry))
# toCounty
toCountyInput <- reactive({
states_sf_coef %>% dplyr::filter(countyname == input$ToCounty)
})
toData <- toCountyInput()
toCoords <- st_coordinates(st_centroid(toData$geometry))
map_proxy %>%
flyTo(lng = fromCoords[1], lat = fromCoords[2], zoom = 10)
delay(5000, {map_proxy %>% flyTo(lng = toCoords[1], lat = toCoords[2], zoom = 10)})
})
}
# Run the application
shinyApp(ui = ui, server = server)
I have created a shiny app where the user can select from a date range to show crimes that occurred in Chicago by Longitude and Latitude.
The problem I am having is to make the dateRangeInput reactive within the leafletOutput. I have looked up a LOT of different option and found that these work the best but the problems I am having are:
Map generates with markers but is not reactive (when commenting out the clearMarkers())
Map generates without markers so I cant even tell if its reactive or not (when using clearMarkers())
I have tried both approaches of using observe() and observeEvent().
Please help... what am I missing.
Data can be found at https://data.cityofchicago.org/Public-Safety/Crimes-2001-to-Present/ijzp-q8t2
**** Interested in date range 01/01/20 to 09/30/20.... the file referenced in a data
crimes.df <- read.csv("Crimes_2020.csv", stringsAsFactors = TRUE)
#Seprating Date and Time into multiple columns
dup_crimes.df$datetime <- as.POSIXct(dup_crimes.df$Date, format = "%m/%d/%Y %H:%M")
dup2_crimes.df <- transform(dup_crimes.df, time = format(dup_crimes.df$datetime, "%T"),
date = format(dup_crimes.df$datetime, "%m/%d/%Y"))
class(dup2_crimes.df$date)
dup2_crimes.df$Month <- as.numeric(format(as.Date(dup2_crimes.df$date), format = "%y"))
dup2_crimes.df$Month.Name <- month.abb[dup2_crimes.df$Month]
#Filter out locations NOT related to Chicago
dup3_crimes.df <- filter(dup2_crimes.df, dup2_crimes.df$Latitude >= 41)
unique(dup3_crimes.df$Primary.Type)
ui <- fluidPage(
titlePanel("2020 Crimes in Chicago"),
tabsetPanel(type = "tabs",
tabPanel("Map of Location of crimes by date",
dateRangeInput(inputId = "date",
label = "Date",
start = '2020-02-25',
end = '2020-07-04',
min = '2020-01-01',
max = '2020-09-30'
),
leafletOutput("Map"))
)
)
server <- function(input,output){
datefileter1 <- reactive({
dup3_crimes.df[
dup3_crimes.df$date >= input$date[1] &
dup3_crimes.df$date <= input$date[2],]
})
#https://www.youtube.com/watch?v=G5BDubIyQZY
#Static Map
output$Map <- renderLeaflet({
leaflet(data = dup3_crimes.df) %>%
addTiles() %>%
addCircleMarkers(lng = ~Longitude, lat = ~Latitude)
})
#Put Dynamic Content
# observe(leafletProxy("Map", data = datefileter1()) %>%
# clearMarkers() %>%
# addCircleMarkers(lng = ~Longitude, lat = ~Latitude)
# )
observeEvent(input$date,
leafletProxy("Map", data = datefileter1()) %>%
clearMarkers() %>%
addCircleMarkers(lng = ~Longitude, lat = ~Latitude)
)
# observe({
#
# leafletProxy("Map", data = datefilter()) %>%
# clearShapes() %>%
# addCircles(radius = ~10^mag/10, weight = 1, color = "#777777",
# fillColor = ~pal(mag), fillOpacity = 0.7, popup = ~paste(mag)
# )
# })
#
}
#Run Shiny App
shinyApp(ui = ui , server =server)
---->> With clearMarkers()
---->> Without clearMarkers() - shows all the locations and NOT reactive (intentionally selected 7/4/20)
Try this, it should work. You can include the reactive df in a simple leaflet call:
ui <- fluidPage(
titlePanel("2020 Crimes in Chicago"),
tabsetPanel(type = "tabs",
tabPanel("Map of Location of crimes by date",
dateRangeInput(inputId = "date",
label = "Date",
start = '2020-02-25',
end = '2020-07-04',
min = '2020-01-01',
max = '2020-09-30'
),
leafletOutput("Map"),
tableOutput("tab"))
)
)
server <- function(input,output){
datefileter1 <- reactive({
dup3_crimes.df[
dup3_crimes.df$date >= input$date[1] &
dup3_crimes.df$date <= input$date[2],]
})
output$tab <- renderTable(datefileter1())
output$Map <- renderLeaflet({
leaflet(data = datefileter1()) %>%
addTiles() %>%
addCircleMarkers(lng = ~Longitude, lat = ~Latitude)
})
}
#Run Shiny App
shinyApp(ui = ui , server =server)
In continuation to my previous post where this was applied on map, I am trying to filter a table in R Shiny using Dropdown input: How to build dynamic Leaflet Map in RShiny?
Code:
library(shiny)
library(shinydashboard)
library(tidyverse)
library(leaflet)
library(readxl)
library(RCurl)
library(DT)
URL <- "https://www.mohfw.gov.in/pdf/PMJAYPRIVATEHOSPITALSCONSOLIDATED.xlsx"
download.file(URL, destfile = "../../timesnow_PMJAYPRIVATEHOSPITALSCONSOLIDATED.xlsx",method = "curl")
# Data
ind_vaccination_center <- readxl::read_xlsx(path = "../../timesnow_PMJAYPRIVATEHOSPITALSCONSOLIDATED.xlsx",
sheet = 1)
ind_vaccination_leaflet <- ind_vaccination_center %>%
mutate(label_display = paste(
"<h2>", ind_vaccination_center$`Name of the Vaccination Site*`, "</h2>",
"<h4>",ind_vaccination_center$`District*`,",", ind_vaccination_center$`State*`, "</h4>",
"<p>", "Address: ", ind_vaccination_center$Address,",", ind_vaccination_center$`PinCode*`, "</p>",
"<p>", "Mobile: ", ind_vaccination_center$`Mobile Number`, "</p>",
"<p>", "Contact Person: ", ind_vaccination_center$`Contact Person`, "</p>"
)
)
# Define UI for application
ui <- fluidPage(
# Application title
titlePanel("Covid19 Vaccination Centers in India"),
# Sidebar with a Dropdown
sidebarLayout(
sidebarPanel(
selectInput(inputId = "state_selection",
label = "Select State",
choices = ind_vaccination_center$`State*`),
h3("List of Vaccination Centers is plotted on Map & also listed in searchable table."),
"source of list:",
a("https://www.timesnownews.com/india/article/covid-19-vaccination-in-uttar-pradesh-check-complete-list-of-govt-and-private-hospitals-for-jab/726412"),
br(),
br(),
a("https://www.oneindia.com/india/full-list-of-private-hospitals-where-the-covid-19-vaccine-will-be-administered-3223706.html"),
br(),
br(),
"P.S - There might be more center's added to this list, kindly recheck from other sources as well like:",
br(),
a("https://www.cowin.gov.in/home")
),
# Show Map & table
mainPanel(
tabsetPanel(type = "tabs",
tabPanel("Map", leafletOutput("map",height = 800, width = "100%")),
tabPanel("Data Table", tableOutput("mytable"))
)
)
)
)
# Define server logic
server <- function(input, output) {
# solution from: https://stackoverflow.com/questions/66732758/how-to-build-dynamic-leaflet-map-in-rshiny/66733086#66733086
output$map <- renderLeaflet({
req(input$state_selection)
data <- ind_vaccination_leaflet %>%
filter(`State*` == input$state_selection)
# Creating map object & adding layers
leaflet(data) %>%
setView(lat = 26.64510, lng = 80.17012, zoom = 4) %>%
addTiles(group = "OSM") %>%
addProviderTiles(providers$CartoDB.DarkMatter, group = "Dark") %>%
addProviderTiles(providers$CartoDB.Positron, group = "Light") %>%
addProviderTiles("Stamen.Terrain", group = "Terrain") %>%
addProviderTiles("Esri.WorldImagery", group = "WorldImagery") %>%
addLayersControl(baseGroups = c("OSM","WorldImagery","Dark","Light","Terrain")) %>%
addCircleMarkers(
lng = ~`Longitude*`,
lat = ~`Latitude*`,
label = lapply(data$label_display, htmltools::HTML),
color = "midnightblue",
weight = 1,
radius = 8
)%>%
addMiniMap(tiles = providers$OpenStreetMap, width = 120, height=80)
})
output$mytable = DT::renderDataTable({
req(input$state_selection)
data <- ind_vaccination_leaflet %>%
filter(`State*` == input$state_selection)
data
})
}
# Run the application
shinyApp(ui = ui, server = server)
You need to do two changes.
tabPanel("Data Table", dataTableOutput("mytable"))
and
output$mytable = DT::renderDataTable({
req(input$state_selection)
data <- ind_vaccination_leaflet %>%
filter(`State*` == input$state_selection)
datatable(data)
})
I am trying to create an interactive shiny application that displays a leaflet plot based on a user's date and plot type specification. Ideally, I would like the user to specify whether they would like to view a state-wide or a county-wide plot. Then, based on their answers, I would like them to decide whether to use the regular data or the standardized data. After this, they would hit a submit button and the plot would render. I don't want the plot to render until the user presses the "Submit" action button. This is my idea so far, but it fails whenever I try to implement.
library(ggplot2)
library(shapefiles)
library(sp)
library(CARBayes)
library(leaflet)
library(rgdal)
library(leaflet)
library(shiny)
## County Data
dta <- read.csv()
## County Data (percentage)
perc <-read.csv()
## Date Specification Function
selectdates <- function(data, start, end){
keep <- data[, 1:5]
data <- data[, -c(1:5)]
tmp1 <- as.Date(names(data))
tmp2 <- which(tmp1 >= as.Date(start) & tmp1 <= as.Date(end))
tmp <- data[, tmp2]
Sum <- rowSums(tmp)
tmp <- cbind(keep, Sum)
return(tmp)
}
# Define UI for application that draws a histogram
ui <- fluidPage(
# Application title
titlePanel("Mapping"),
tags$em(""),
tags$hr(),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
dateRangeInput("daterange", "Date Range:",
start = as.character(Sys.Date() - 6),
end = as.character(Sys.Date())),
selectInput("ptChoice", "Type of Plot:", choices = c("", "County-Wise", "State-Wise")),
selectInput("typeChoice", "Data Type:", choices = c("", "Raw", "Percentage")),
actionButton("submitButton", "Submit", class = "btn btn-primary")
),
# Display leaflet plot of cases
mainPanel(
leafletOutput("countyPlot"),
leafletOutput("statePlot")
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output) {
observeEvent(input$ptChoice, {
req(input$ptchoice)
if(input$ptChoice == "County-Wide"){
hide("statePlot")
show("countyPlot")
}
else{
hide("countyPlot")
show("statePlot")
}
})
fdta <- eventReactive(input$typeChoice, {
if (input$typeChoice == "Raw"){
df <- selectdates(data = tmp, start = input$daterange[1], end = input$daterange[2])
row.names(df) <- df$FIPS
}else if (input$typeChoice == "Percentage"){
df <- selectdates(data = perc, start = input$daterange[1], end = input$daterange[2])
}else {return(NULL)}
df
})
observeEvent(input$submitButton, {
output$statePlot <- renderLeaflet({
## INSERT STATE PLOT CODE HERE
})
output$countyPlot <- renderLeaflet({
## Loads SHP and DBF File
shp <- read.shp()
dbf <- read.dbf()
sp <- combine.data.shapefile(data = fdta, shp = shp, dbf = dbf)
proj4string(sp) <- CRS("+proj=longlat +datum=WGS84 +no_defs")
sp <- spTransform(sp, CRS("+proj=longlat +datum=WGS84 +no_defs"))
colours <- colorNumeric(palette = "YlOrRd", domain = sp#data$Sum)
leaflet(sp) %>%
addTiles() %>%
addPolygons(
fillColor = ~ colours(Sum),
weight = 1,
opacity = 0.7,
color = "white",
dashArray = '3',
fillOpacity = 0.7,
highlight = highlightOptions(
weight = 5,
color = "#666",
dashArray = "",
fillOpacity = 0.7,
bringToFront = TRUE
)
) %>%
addLegend(
pal = colours,
values = sp#data$Sum,
opacity = 1,
title = "Count"
) %>%
addScaleBar(position = "bottomleft")
})
})
}
# Run the application
shinyApp(ui = ui, server = server)
You can put the two plots inside an observeEvent, if you want it only after someone clicks on submit button. To use the appropriate dataframe, create a reactive dataframe and then use it as dfa() to generate the appropriate plot. Try this
server = function(input, output) {
observeEvent(input$ptChoice,{
req(input$ptChoice)
if(input$ptChoice == "County-Wide"){
hide("statePlot")
show("countyPlot")
}else{
hide("countyPlot")
show("statePlot")
}
})
dfa <- eventReactive(input$typechoice, {
if (input$typechoice == "Regular") {
df <- dta
}else if (input$typechoice == "Standardized") {
df <- dta2
}else {return(NULL)}
df
})
observeEvent(input$submitButton,{
output$stateplot <- renderLeaflet({
state <- CODE FOR STATE PLOT
})
output$countyPlot <- renderLeaflet({
county <- CODE FOR COUNTY PLOT
})
})
}
You might want to have your leaflet plot be stored in reactiveValues (rv) - then, you can have one output for your plot, and show what is stored in rv.
To change the plot when the submit button is pressed, be sure to reference the input$submitButton with your observeEvent.
Here is a working example that can be adapted. You could use an additional function to generate the plots based on your input values.
library(ggplot2)
library(leaflet)
library(shiny)
ui = fluidPage(
titlePanel("Leaflet Plot"),
tags$em(""),
tags$hr(),
sidebarLayout(
sidebarPanel(
selectInput("plotChoice", "Type of Plot:", choices = c("", "Boston", "Chicago")),
actionButton("submitButton", "Submit", class = "btn btn-primary")
),
# Display leaflet plot of cases
mainPanel(
leafletOutput("leafletPlot")
)
)
)
server = function(input, output) {
rv <- reactiveValues(plot = NULL)
output$leafletPlot <- renderLeaflet({
rv$plot
})
observeEvent(input$submitButton, {
if (input$plotChoice == "Boston") {
rv$plot <- leaflet() %>% setView(lng = -71.0589, lat = 42.3601, zoom = 12) %>% addTiles()
} else {
rv$plot <- leaflet() %>% setView(lng = -87.6298, lat = 41.8781, zoom = 12) %>% addTiles()
}
})
}
shinyApp(ui = ui, server = server)