So I've been trying to add a functionality on my leaflet map in Shiny dashboard where the user would be able to choose what the popup label would show through an input checkbox statement (in this case, they would choose whether they would want to see Area of Land or Area of Water or both - default is set to both). In other words, I would like to have a list of column options that I can choose from to show on the popup label when I hover over the map.
The code I have so far is below
library(dplyr)
library(readxl)
library(shinydashboard)
library(rgdal)
library(leaflet)
library(htmltools)
download.file('https://www2.census.gov/geo/tiger/GENZ2018/shp/cb_2018_us_county_5m.zip',
'cb_2018_us_county_5m.zip')
unzip('cb_2018_us_county_5m.zip',exdir='cb_2018_us_county_5m')
download.file('https://www2.census.gov/programs-surveys/popest/geographies/2019/all-geocodes-v2019.xlsx',
'all-geocodes-v2019.xlsx')
shapes <- rgdal::readOGR("cb_2018_us_county_5m","cb_2018_us_county_5m")
df_geo <- read_excel('all-geocodes-v2019.xlsx',skip=4) %>% # the table starts from row 5
filter(`Summary Level`=='040') %>%
select(`State Code (FIPS)`, `Area Name (including legal/statistical area description)`)
colnames(df_geo) <- c('STATEFP','STATENAME')
shapes@data <- shapes@data %>%
left_join(df_geo) %>%
mutate(ALAND = as.numeric(as.character(ALAND)),
AWATER = as.numeric(as.character(AWATER)),
content = paste0('<b>',NAME,' (',STATENAME,')</b>',
'<br>Area of Land: ', ALAND,
'<br>Area of Water: ', AWATER),
NAME = as.character(NAME))
shapes <- shapes[!is.na(shapes@data$STATENAME),] # remove shapes that are not in a state (e.g., Guam)
names_state <- sort(df_geo$STATENAME)
#### UI ####
header <- dashboardHeader(
title = "Leaflet - Layer Specific Legend",
titleWidth = 300
)
body <- dashboardBody(
fluidRow(
column(width=2,
selectInput("select_state", label='Select State:',
choices = names_state,
selected= 'New York'),
style='margin-left:20px;z-index:100000'
)
),
fluidRow(
column(width = 12,
box(width = NULL, height = 620,
leafletOutput("map",height=595),
status='warning')
)
)
)
ui <- dashboardPage(
title = "Leaflet - Layer Specific Legend",
skin = 'yellow',
header,
dashboardSidebar(disable = TRUE),
body
)
#### Server ####
server <- function(input, output, session) {
#### initialize reactive values ####
rvs <- reactiveValues(poly_state=shapes[shapes@data$STATENAME == 'New York',])
#### output ####
## output: leaflet map
output$map <- renderLeaflet({
rvs$map <- rvs$poly_state %>%
leaflet() %>%
addTiles('http://{s}.tile.openstreetmap.de/tiles/osmde/{z}/{x}/{y}.png') %>%
addPolygons(data = rvs$poly_state,
group = 'Area of Land',
weight=1, opacity = 1.0,color = 'white',
fillOpacity = 0.9, smoothFactor = 0.5,
fillColor = ~colorBin('OrRd',ALAND)(ALAND),
label = lapply(rvs$poly_state$content,HTML)) %>%
addPolygons(data = rvs$poly_state,
group = 'Area of Water',
weight=1, opacity = 1.0,color = 'grey',
fillOpacity = 0.9, smoothFactor = 0.5,
fillColor = ~colorBin('YlGnBu',AWATER)(AWATER),
label = lapply(rvs$poly_state$content,HTML)) %>%
addLayersControl(
position = "bottomright",
baseGroups = c('Area of Land','Area of Water'),
options = layersControlOptions(collapsed = TRUE)) %>%
addLegend(
"topright",
pal = colorBin('OrRd', rvs$poly_state$ALAND),
values = rvs$poly_state$ALAND
) %>%
hideGroup(c('Area of Land','Area of Water')) %>%
showGroup('Area of Land')
})
#### observe mouse events ####
## update rv when the selected state changes
observeEvent(input$select_state, {
rvs$poly_state <- shapes[shapes@data$STATENAME == input$select_state,]
})
## update legend when the selected layer group changes
observeEvent(input$map_groups, {
my_map <- leafletProxy("map") %>% clearControls()
if (input$map_groups == 'Area of Land'){
my_map <- my_map %>%
addLegend(
"topright",
pal = colorBin('OrRd', rvs$poly_state$ALAND),
values = rvs$poly_state$ALAND)
}else{
my_map <- my_map %>%
addLegend(
"topright",
pal = colorBin('YlGnBu', rvs$poly_state$AWATER),
values = rvs$poly_state$AWATER)
}
})
}
#### Run App ####
shinyApp(ui = ui, server = server)
First, you can create a data frame from your spatial data and edit your table. Here I delete the column "content".
shapes_df <- as.data.frame(shapes[,c(1:10)])
Then you create a reactive value that interacts with your input.
popup <- reactive({
return(shapes_df %>% select(input$select_column))
})
Here is a working code for you. I made some changes and commented some lines out.
library(dplyr)
library(readxl)
library(shinydashboard)
library(leaflet)
library(htmltools)
library(sf)
zip_path <- 'cb_2018_us_county_5m.zip'
if (!file.exists(zip_path)) {
download.file('https://www2.census.gov/geo/tiger/GENZ2018/shp/cb_2018_us_county_5m.zip',
)
unzip(zip_path, exdir='cb_2018_us_county_5m')
}
xlsx_path <- 'all-geocodes-v2019.xlsx'
if (!file.exists(xlsx_path)) {
download.file('https://www2.census.gov/programs-surveys/popest/geographies/2019/all-geocodes-v2019.xlsx',
xlsx_path, mode = "wb")
}
shapes <- st_read("cb_2018_us_county_5m","cb_2018_us_county_5m")
df_geo <- read_excel('all-geocodes-v2019.xlsx',skip=4) %>% # the table starts from row 5
filter(`Summary Level`=='040') %>%
select(`State Code (FIPS)`, `Area Name (including legal/statistical area description)`)
colnames(df_geo) <- c('STATEFP','STATENAME')
shapes <- shapes %>%
left_join(df_geo) %>%
mutate(ALAND = as.numeric(as.character(ALAND)),
AWATER = as.numeric(as.character(AWATER)),
content = paste0('<b>',NAME,' (',STATENAME,')</b>',
'<br>Area of Land: ', ALAND,
'<br>Area of Water: ', AWATER),
NAME = as.character(NAME))
# remove shapes that are not in a state (e.g., Guam)
shapes <- shapes %>%
dplyr::filter(!is.na(STATENAME))
names_state <- sort(df_geo$STATENAME)
# here you can select which columns you want to add to your popup
shapes_df <- as.data.frame(shapes[,c(1:10)])
#### UI ####
header <- dashboardHeader(
title = "Leaflet - Layer Specific Legend",
titleWidth = 300
)
body <- dashboardBody(
fluidRow(
column(width=2,
selectInput("select_state", label='Select State:',
choices = names_state,
selected= 'New York'),
selectInput("select_column", label='Select the column you want to see in pop-up:',
choices = c(colnames(shapes))
),
verbatimTextOutput("output"),
style='margin-left:20px;z-index:100000'
)
),
fluidRow(
column(width = 12,
box(width = NULL, height = 620,
leafletOutput("map",height=595),
status='warning')
)
)
)
ui <- dashboardPage(
title = "Leaflet - Layer Specific Legend",
skin = 'yellow',
header,
dashboardSidebar(disable = TRUE),
body
)
#### Server ####
server <- function(input, output, session) {
rvs <- reactive({
shapes %>%
dplyr::filter(STATENAME %in% input$select_state)
})
# we create a reactive value for popup which interacts with the input
popup <- reactive({
return(shapes_df %>% select(input$select_column))
})
#### initialize reactive values ####
#### output ####
## output: leaflet map
output$map <- renderLeaflet({
leaflet() %>%
addTiles('http://{s}.tile.openstreetmap.de/tiles/osmde/{z}/{x}/{y}.png') %>%
addPolygons(data = rvs(),
group = 'Area of Land',
weight=1, opacity = 1.0,color = 'white',
fillOpacity = 0.9, smoothFactor = 0.5,
fillColor = ~colorBin('OrRd',rvs()$ALAND)(rvs()$ALAND),
label = paste(
colnames(popup()),": ", popup()[,1]
)
)%>%
addPolygons(data = rvs(),
group = 'Area of Water',
weight=1, opacity = 1.0,color = 'grey',
fillOpacity = 0.9, smoothFactor = 0.5,
fillColor = ~colorBin('YlGnBu',rvs()$AWATER)(rvs()$AWATER),
label = paste(
colnames(popup()),": ", popup()[,1]
)
) %>%
addLayersControl(
position = "bottomright",
baseGroups = c('Area of Land','Area of Water'),
options = layersControlOptions(collapsed = TRUE)) %>%
addLegend(
"topright",
pal = colorBin('OrRd', rvs()$ALAND),
values =rvs()$ALAND
) %>%
hideGroup(c('Area of Land','Area of Water')) %>%
showGroup('Area of Land')
})
#### observe mouse events ####
## update rv when the selected state changes
# observeEvent(input$select_state, {
# rvs() <- shapes[shapes$STATENAME == input$select_state,]
# })
## update legend when the selected layer group changes
observeEvent(input$map_groups, {
my_map <- leafletProxy("map") %>% clearControls()
if (input$map_groups == 'Area of Land'){
my_map <- my_map %>%
addLegend(
"topright",
pal = colorBin('OrRd', rvs()$ALAND),
values = rvs()$ALAND)
}else{
my_map <- my_map %>%
addLegend(
"topright",
pal = colorBin('YlGnBu', rvs()$AWATER),
values = rvs()$AWATER)
}
})
}
#### Run App ####
shinyApp(ui = ui, server = server)