Using click events in leaflet to dynamically display grouped sums - r

I'm working on a shiny app with basic functionality like this:
library(sf)
library(DT)
library(leaflet)
library(shiny)
library(tidyverse)
nc <- st_read(system.file("shape/nc.shp", package = "sf"), quiet = T) %>%
st_transform(4326) %>%
select(NAME, geometry, id = CNTY_ID) %>%
mutate(x = rnorm(n = nrow(.), mean = 100, sd = 20),
fill = sample(c("green", "red"), n(), replace = T),
fill_2 = if_else(fill == "green", "red", "green"))
# Function to change fill color on click event (taken from https://stackoverflow.com/a/69618323)
change_color <- function(map, id_to_remove, data, colour, new_group){
leafletProxy(map) %>%
removeShape(id_to_remove) %>% # remove previous occurrence
addPolygons(
data = data,
layerId = data$id,
group = new_group, # change group
fillColor = colour,
color = "black",
weight = 1,
fillOpacity = 1)
}
## UI
ui <- fluidPage(
leafletOutput("map"),
DT::dataTableOutput("table")
)
## Server
server <- function(input,output,session){
# Reactives
rv <- reactiveValues(
df = nc,
df.tab = as.data.frame(nc)
)
# Initial map
output$map <- renderLeaflet({
leaflet() %>%
setView(-79.99, 35.52, zoom = 7)
})
observe({
data <- rv$df
leafletProxy("map") %>%
addPolygons(
data = data,
weight = 1, color = "black", fillOpacity = 1, fillColor = ~fill,
layerId = data$id,
group = "unclicked_poly")
})
#first click
observeEvent(input$map_shape_click, {
# execute only if the polygon has never been clicked
req(input$map_shape_click$group == "unclicked_poly")
# filter data
data <- rv$df[rv$df$id==input$map_shape_click$id,]
change_color(map = "map",
id_to_remove = input$map_shape_click$id,
data = data,
colour = ~fill_2,
new_group = "clicked1_poly")
})
#second click: reverse first click
observeEvent(input$map_shape_click, {
req(input$map_shape_click$group == "clicked1_poly")
data <- rv$df[rv$df$id==input$map_shape_click$id,]
leafletProxy("map") %>%
removeShape(input$map_shape_click$id) %>% # remove previous occurrence
addPolygons(
data = data,
weight = 1, color = "black", fillOpacity = 1, fillColor = ~fill,
layerId = data$id,
group = "unclicked_poly") # back to initialize group
})
output$table <- DT::renderDataTable({
rv$df.tab %>%
group_by(fill) %>%
summarise(x = sum(x))
})
}
shinyApp(ui, server)
The idea here is that the user can change the fill color of the polygons with the click of a button. This works as is. However, I also want to dynamically display the fill-specific sum of x in the data tabe below the leaflet map. Currently, the table shows the grouped sums according to the initial data frame. However, when a user changes a polygon from green to red, the calculation should be done anew.
I have tried implementing this idea using a logic similar to the observeEvents() in output(map), but the problem here was that I could only ever access the last click, so previous clicks would not factor into the grouped sums calculation (group_by(fill) %>% summarise(x = sum(x))). Ideally, I would like to have information on whatever the current fill of all polygons is so that the data table reflects the user's input.

I ended up solving this problem in four steps:
Recording each click on a polygon using reactiveValues(Clicks=vector())
Converting vector into data frame, with click frequency determined by table()
Using modulo division on the number of clicks with the %% operator to ascertain current fill color on map (the number of fill options is much higher than two in my real world application)
Merging clicked and unclicked polygons to obtain current map status and using DT::dataTableProxy() to update table
App is now working as intended. Code:
library(sf)
library(DT)
library(leaflet)
library(shiny)
library(tidyverse)
nc <- st_read(system.file("shape/nc.shp", package = "sf"), quiet = T) %>%
st_transform(4326) %>%
select(NAME, geometry, id = CNTY_ID) %>%
mutate(x = rnorm(n = nrow(.), mean = 100, sd = 20),
fill = sample(c("green", "red"), n(), replace = T),
fill_2 = if_else(fill == "green", "red", "green"))
# Function to change fill color on click event (taken from https://stackoverflow.com/a/69618323)
change_color <- function(map, id_to_remove, data, colour, new_group){
leafletProxy(map) %>%
removeShape(id_to_remove) %>% # remove previous occurrence
addPolygons(
data = data,
layerId = data$id,
group = new_group, # change group
fillColor = colour,
color = "black",
weight = 1,
fillOpacity = 1)
}
## UI
ui <- fluidPage(
leafletOutput("map"),
DT::dataTableOutput("table")
)
## Server
server <- function(input,output,session){
# Reactives
rv <- reactiveValues(
df = nc,
df.tab = as.data.frame(nc)
)
# Initial map
output$map <- renderLeaflet({
leaflet() %>%
setView(-79.99, 35.52, zoom = 7)
})
observe({
data <- rv$df
leafletProxy("map") %>%
addPolygons(
data = data,
weight = 1, color = "black", fillOpacity = 1, fillColor = ~fill,
layerId = data$id, label = ~id,
group = "unclicked_poly")
})
#first click
observeEvent(input$map_shape_click, {
# execute only if the polygon has never been clicked
req(input$map_shape_click$group == "unclicked_poly")
# filter data
data <- rv$df[rv$df$id==input$map_shape_click$id,]
change_color(map = "map",
id_to_remove = input$map_shape_click$id,
data = data,
colour = ~fill_2,
new_group = "clicked1_poly")
})
#second click: reverse first click
observeEvent(input$map_shape_click, {
req(input$map_shape_click$group == "clicked1_poly")
data <- rv$df[rv$df$id==input$map_shape_click$id,]
leafletProxy("map") %>%
removeShape(input$map_shape_click$id) %>% # remove previous occurrence
addPolygons(
data = data,
weight = 1, color = "black", fillOpacity = 1, fillColor = ~fill,
layerId = data$id, label = ~id,
group = "unclicked_poly") # back to initialize group
})
output$table <- DT::renderDataTable({
rv$df.tab %>%
group_by(fill) %>%
summarise(x = sum(x)) -> sum
sum
})
proxy <- DT::dataTableProxy("table")
RV<-reactiveValues(Clicks=vector())
observeEvent(input$map_shape_click, {
#create object for clicked polygon
click <- input$map_shape_click
RV$Clicks<- c(RV$Clicks,click$id)
test <- as.data.frame(table(RV$Clicks)) %>%
mutate(current = Freq %% 2,
id = as.double(as.character(Var1)))
rv$df.tab %>%
full_join(test, by = "id") %>%
mutate(fill = case_when(current == 1 ~ fill_2,
TRUE ~ fill)) %>%
group_by(fill) %>%
summarise(x = sum(x)) -> sum
proxy %>% replaceData(sum)
})
}
shinyApp(ui, server)

Related

R leaflet change colour of addCircles() in animation

I have a Shiny app with a leaflet showing ~9,000 points on a grid (each point representing a 100 m x 100 m square). The app is animated, so that each point changes colour over time. The first version of the app used addPolygons() with the setShapeStyle() function from here to allow the polygons to change colour over time, while accounting for area that each point accounts for. The polygon app was great but super slow, so I changed to addCircleMarkers instead, coupled with setCircleMarkerStyle() from the same GitHub page. This is way faster and works well, BUT I have 2 problems - 1) at low zooms, my points overlap, and 2) at high zooms, my points are separated by space.
Can anyway help me apply the same animation solutions offered by the change of style as here, but applied to addCircles() so that I can use a set radius, or a similar solution? Ideas for making the points square, so that I don't end up with empty spaces at high zooms are also welcome.
libraries and fake data:
library(plyr)
library(dplyr)
library(tidyr)
library(lubridate)
library(shiny)
library(leaflet)
library(viridisLite)
nodes <- structure(list(node = 1:9, Lon = c(-60.1760758677342, -60.1768617891598,
-60.1664512653477, -60.1672369749724, -60.1680228296767, -60.1688085769102,
-60.1695943435806, -60.170380129055, -60.1711659327049), Lat = c(43.316878317912,
43.317580709354, 43.309714197049,43.310416744826, 43.311119197611,
43.311821734546, 43.312524176034, 43.3132266121, 43.31392913277
)), row.names = c(NA, -9L), class = "data.frame")
data <- nodes %>%
crossing(Date = seq(as_date("2020-01-01"), as_date("2020-03-15"), "1 day")) %>%
mutate(Density = abs(rnorm(675, 10, 10)),
Exceed = ifelse(Density > 20, 1, 0),
Layer = paste(node, "Tile", sep = "_"))
FirstDay <- data %>%
filter(Date == min(Date))
Helper functions (based on the Github page referenced):
leafletjs <- tags$head(
tags$script(HTML('
window.LeafletWidget.methods.setStyle = function(category, layerId, style){
var map = this;
if (!layerId){
return;
} else if (!(typeof(layerId) === "object" && layerId.length)){
layerId = [layerId];
}
style = HTMLWidgets.dataframeToD3(style);
layerId.forEach(function(d,i){
var layer = map.layerManager.getLayer(category, d);
if (layer){
layer.setStyle(style[i]);
}
});
};
')))
setCircleMarkerStyle <- function(map, layerId
, radius = NULL
, stroke = NULL
, color = NULL
, weight = NULL
, opacity = NULL
, fill = NULL
, fillColor = NULL
, fillOpacity = NULL
, dashArray = NULL
, options = NULL
, data = getMapData(map)
){
options <- c(list(layerId = layerId),
options,
filterNULL(list(stroke = stroke, color = color,
weight = weight, opacity = opacity,
fill = fill, fillColor = fillColor,
fillOpacity = fillOpacity, dashArray = dashArray
)))
if (length(options) < 2) { # no style options set
return()
}
# evaluate all options
options <- evalFormula(options, data = data)
# make them the same length (by building a data.frame)
options <- do.call(data.frame, c(options, list(stringsAsFactors=FALSE)))
layerId <- options[[1]]
style <- options[-1] # drop layer column
#print(list(style=style))
leaflet::invokeMethod(map, data, "setStyle", "marker", layerId, style);
}
UI and server
ui <- fluidPage(
leafletjs,
sidebarLayout(
sidebarPanel(sliderInput("dateSel", "Date",
min = min(data$Date), max = max(data$Date),
value = min(data$Date), step = 1, timeFormat = "%d %b %y",
animate = animationOptions(interval = 100, loop = FALSE))),
mainPanel(leafletOutput("MapAnimate"))))
server <- function(input, output, session) {
filteredData <- reactive({
data %>% filter(Date == input$dateSel)
})
output$MapAnimate <- renderLeaflet({
range <- range(data$Density)
palette <- colorNumeric(palette = viridis(100), domain = range)
leaflet(FirstDay) %>%
addTiles() %>%
addCircleMarkers(lng = ~Lon, lat = ~Lat, layerId = ~Layer,
fillColor = "lightgray", fill = TRUE,
color = "white", stroke = TRUE,
fillOpacity = 1, opacity = 1, weight = 2) %>%
leaflet::addLegend(pal = palette, values = range, opacity = 0.9, position = "topleft")
})
observe({
df.in <- filteredData()
range <- range(data$Density)
palette <- colorNumeric(palette = viridis(100), domain = range)
leafletProxy("MapAnimate", data = df.in) %>%
setCircleMarkerStyle(layerId = ~Layer,
fillColor = ~palette(Density),
color = ~ifelse(Exceed == 1, "red", "white"))
})
}
shinyApp(ui = ui, server = server)

R flexdashboard with two simultaneous input$map_shape_click not working

I am in the process of creating an R flexdashboard. The dashboard contains several maps for Bangladesh, which are linked to a (Highcharts) chart that is activated by clicking on a polygon (e.g. region). I am able to make it work for one page. However, if I set it up for two pages, things no longer work.
It seems that flexdashboard (at least how I set it up) is not able to handle two input$map_shape_click operations at the same time. At the moment it only works on the first page, while the map does not react on the second page although a figure is produced. I welcome any suggestions to make this work.
Below a reproducible example. Note that (1) I omitted the flexdashboard yaml in the example and (2) markdown used by stackoverflow automatically renders the first, second and third header level. They render differently when run in flexdasboard (i.e. A Large Header is a new page in flexdashboard).
# Packages
library(tidyverse)
library(raster)
library(sf)
library(highcharter)
library(leaflet)
library(htmltools)
# Get data
adm1 <- getData('GADM', country='BGD', level=1)
adm1 <- st_as_sf(adm1)
# Create dummy data.frames with link to polygon
df1 <- data.frame(NAME_1 = adm1$NAME_1,
value_1 = c(1:7))
df2 <- data.frame(NAME_1 = adm1$NAME_1,
value_2 = c(8:14))
Page 1
Column {data-width=350}
Map 1
# MAIN MAP --------------------------------------------------------------------------------
output$map <- renderLeaflet({
# Base map
leaflet() %>%
addTiles(group = "OpenStreetMap") %>%
clearShapes() %>%
addPolygons(data = adm1,
smoothFactor = 0,
color = "black",
opacity = 1,
fillColor = "transparent",
weight = 0.5,
stroke = TRUE,
label = ~htmlEscape(NAME_1),
layerId = ~NAME_1,
)
})
leafletOutput('map')
# REGION SELECTION -----------------------------------------------------------------------
# Click event for the map to draw chart
click_poly <- eventReactive(input$map_shape_click, {
x <- input$map_shape_click
y <- x$id
return(y)
}, ignoreNULL = TRUE)
observe({
req(click_poly()) # do this if click_poly() is not null
# Add the clicked poly and remove when a new one is clicked
map <- leafletProxy('map') %>%
removeShape('NAME_1') %>%
addPolygons(data = adm1[adm1$NAME_1 == click_poly(), ],
fill = FALSE,
weight = 4,
color = '#d01010',
opacity = 1,
layerId = 'NAME_1')
})
Column {data-width=350}
Plot 1
data <- reactive({
# Fetch data for the click poly
out <- df1[df1$NAME_1 == click_poly(), ]
print("page 1") # print statement to show which click_poly is used
return(out)
})
output$plot <- renderHighchart({
req(data()) # do this if click_poly() is not null
chart <- highchart() %>%
hc_chart(type = 'column') %>%
hc_legend(enabled = FALSE) %>%
hc_xAxis(categories = c('A'),
title = list(text = 'Title 1')) %>%
hc_yAxis(title = list(text = 'Value 1')) %>%
hc_plotOptions(series = list(dataLabels = list(enabled = TRUE))) %>%
hc_add_series(name = 'Series',
data = c(data()$value_1)) %>%
hc_add_theme(hc_theme_smpl()) %>%
hc_colors(c('#d01010'))
})
highchartOutput('plot')
Page 2
Column {data-width=350}
Map 2
# MAIN MAP --------------------------------------------------------------------------------
output$map2 <- renderLeaflet({
# Base map
leaflet() %>%
addTiles(group = "OpenStreetMap") %>%
clearShapes() %>%
addPolygons(data = adm1,
smoothFactor = 0,
color = "black",
opacity = 1,
fillColor = "transparent",
weight = 0.5,
stroke = TRUE,
label = ~htmlEscape(NAME_1),
layerId = ~NAME_1,
)
})
leafletOutput('map2')
# REGION SELECTION -----------------------------------------------------------------------
# Click event for the map to draw chart
click_poly2 <- eventReactive(input$map_shape_click, {
x <- input$map_shape_click
y <- x$id
return(y)
}, ignoreNULL = TRUE)
observe({
req(click_poly2()) # do this if click_poly() is not null
# Add the clicked poly and remove when a new one is clicked
map <- leafletProxy('map2') %>%
removeShape('NAME_1') %>%
addPolygons(data = adm1[adm1$NAME_1 == click_poly2(), ],
fill = FALSE,
weight = 4,
color = '#d01010',
opacity = 1,
layerId = 'NAME_1')
})
Column {data-width=350}
Plot 2
data2 <- reactive({
# Fetch data for the click poly
out <- df2[df2$NAME_1 == click_poly2(), ]
print("page 2") # print statement to show which click_poly is used
return(out)
})
output$plot2 <- renderHighchart({
req(data2()) # do this if click_poly() is not null
chart <- highchart() %>%
hc_chart(type = 'column') %>%
hc_legend(enabled = FALSE) %>%
hc_xAxis(categories = c('A'),
title = list(text = 'Title 2')) %>%
hc_yAxis(title = list(text = 'Value 2')) %>%
hc_plotOptions(series = list(dataLabels = list(enabled = TRUE))) %>%
hc_add_series(name = 'Series',
data = c(data2()$value_2)) %>%
hc_add_theme(hc_theme_smpl()) %>%
hc_colors(c('#d01010'))
})
highchartOutput('plot2')
In your click_poly2 <- eventReactive(input$map_shape_click, you have click_poly2 being the 2nd map, but you have the same map_shape_click, what if you made it map_shape_click2, hopefully flexdashboard will handle it differently as now they are 2 different maps
I figured out the answer myself following a similar question I found somewhere else. As I am quite new to shiny and based my code on examples I found, I did not realize that 'map_shape_click' applies 'shape_click' on 'map' where 'map' corresponds with the map in output$map. As I have two maps: map and map2, the eventReactive statement for page2 should be changed into
click_poly2 <- eventReactive(input$map2_shape_click, {
x <- input$map2_shape_click
y <- x$id
return(y)
}, ignoreNULL = TRUE)
Now responding to a shape_click on map2

leaflet shiny palette issue

The variable I am trying to plot on a leaflet map is binary but I can't manage to have two distinct colors for each value (1 and 0). When the map loads, missing values are plotted in red, but the actual values are of the same color (something in between green and yellow). The 1 values should be green and 0 should be yellow. Here is the content of my server.R:
server <- function(input, output) {
colorpalette1 <- c("#3EA055", "#C68E17")
output$mymap1 <- renderLeaflet({
leaflet() %>%
setView(0, 28, 2)
})
selected <- reactive({
data2 <- shape_data[[input$year]]
data2
})
observeEvent(input$year, {
bins1 <- c(1, 0)
pal1 <- colorBin(colorpalette1, domain = selected(), bins = bins1, na.color = "#8C001A")
leafletProxy("mymap1") %>%
clearShapes() %>%
addPolygons(data = shape_data,
fillColor = ~pal1(selected()),
weight = 1,
opacity = 1,
color = "black",
fillOpacity = 0.7
)
})
}
input$year is a selectInput that selects the variable to plot on the map.
It would be good to provide a minimally reproducible example, so that we can verify the issue and test the solution. You can try the following:
observeEvent(input$year, {
if (!is.null(input$year)){
bins1 <- c(1, 0)
pal1 <- colorBin(colorpalette1, domain = selected(), bins = bins1, na.color = "#8C001A")
leafletProxy("mymap1") %>%
clearShapes() %>%
addPolygons(data = shape_data,
fillColor = ~pal1(selected()),
weight = 1,
opacity = 1,
color = "black",
fillOpacity = 0.7
)
}else{return(NULL)}
})
I found the answer, colorNumeric() was more suitable than colorBin().
pal1 <- colorNumeric(colorpalette1, domain = shape_data[[input$year]], na.color = "#8C001A")

Rshiny : displaying chart when clicking on a polygon

I'm a Rshiny newbie very eager to learn but right now I'm facing an issue I cannot overcome alone and I would greatly appreciate if someone could help me out ! :)
My problem is (I guess) quite simple:
I have created a map with my polygons and I've managed to display some basic informations when I click on them (have a look on here) but I have no idea how to add a barplot (for example) below my map for each polygon I click.
Could someone help me on how doing that please ? (after hours and hours of attempts my eyesballs are really about to pop out of their sockets !!!)
Many thanks in advance !
Romain
My code:
library(shiny)
library(leaflet)
library(dplyr)
library(magrittr)
library(devtools)
library(RColorBrewer)
library(rgdal)
library(sp)
communes <- readOGR("G:/Ateliers/Projet/communes.shp")
commmunes#data
nom_commune INSEE Variable_1 Variable_2 Variable_3 area_sqkm
1 AUZEVILLE-TOLOSANE 31035 289 8.727212 9.336384 6.979758
2 CASTANET-TOLOSAN 31113 85 4.384877 8.891650 8.460724
3 LABEGE 31254 288 5.047406 2.031651 7.663404
4 PECHBUSQUE 31411 443 6.577743 8.120896 3.099422
5 RAMONVILLE-SAINT-AGNE 31446 95 2.601305 8.909278 6.236784
>
ui <- fluidPage(
leafletOutput("mymap"))
#### SERVEUR R #####
bins <- c(3,3.5,6,6.5,7,7.5,8,8.5)
pal <- colorBin("YlOrRd", domain = communes$area_sqkm, bins = bins)
labels <- sprintf(
"<strong>%s</strong><br/>%g km2",
communes$nom_commun, communes$area_sqkm
) %>% lapply(htmltools::HTML)
server <- function(input, output, session) {
output$mymap<-renderLeaflet(
leaflet(communes) %>%
addProviderTiles(providers$Stamen.TonerLite,
options = providerTileOptions(noWrap = TRUE)
) %>%
setView(1.50, 43.54, zoom = 12) %>%
addTiles() %>%
addPolygons(fillColor = ~pal(area_sqkm),
weight = 2,
opacity = 1,
color = "white",
dashArray = "3",
fillOpacity = 0.7,
highlight = highlightOptions(
weight = 5,
color = "#666",
dashArray = "",
fillOpacity = 0.7,
bringToFront = TRUE),
label = labels,
labelOptions = labelOptions(
style = list("font-weight" = "normal", padding = "3px 8px"),
textsize = "15px",
direction = "auto")) %>%
addLegend(pal = pal, values = ~area_sqkm, opacity = 0.7, title = NULL,
position = "bottomright")
)
}
shinyApp(ui = ui, server=server)
The data I would like to display in my barplots are the variable 1,2 and 3 :
data <- read.csv("G:/Ateliers/Projet/communes.csv", sep=";")
data
nom_commune INSEE Variable_1 Variable_2 Variable_3 area_sqkm
1 AUZEVILLE-TOLOSANE 31035 289 8.727212 9.336384 6.979758
2 CASTANET-TOLOSAN 31113 85 4.384877 8.891650 8.460724
3 LABEGE 31254 288 5.047406 2.031651 7.663404
4 PECHBUSQUE 31411 443 6.577743 8.120896 3.099422
5 RAMONVILLE-SAINT-AGNE 31446 95 2.601305 8.909278 6.236784
>
Here is an example shiny app with other data, since I do not have access to your shape data for the map. I believe this might do what you need it to do and can be adapted for your needs.
I would create a reactiveVal to store the id of the polygon region that is clicked on (this variable stores input$mymap_shape_click$id). You data used in addPolygons should have an id to reference.
In your plot (or in a separate reactive expression), you can filter the data based on the reactiveVal containing the id.
library(shiny)
library(leaflet)
library(rgdal)
library(sf)
library(ggplot2)
library(tidyverse)
arcgis_data = st_read("http://data.phl.opendata.arcgis.com/datasets/bc2b2e8e356742568e43b0128c344d03_0.geojson")
arcgis_data$id <- 1:nrow(arcgis_data) ## Add an 'id' value to each shape
plot_data <- read.table(text =
"id nom_commune INSEE Variable_1 Variable_2 Variable_3 area_sqkm
1 AUZEVILLE-TOLOSANE 31035 289 8.727212 9.336384 6.979758
2 CASTANET-TOLOSAN 31113 85 4.384877 8.891650 8.460724
3 LABEGE 31254 288 5.047406 2.031651 7.663404
4 PECHBUSQUE 31411 443 6.577743 8.120896 3.099422
5 RAMONVILLE-SAINT-AGNE 31446 95 2.601305 8.909278 6.236784", header = T, stringsAsFactors = F
)
ui <- fluidPage(
leafletOutput(outputId = "mymap"),
plotOutput(outputId = "myplot")
)
server <- function(input, output){
## use reactive value to store the id from observing the shape click
rv <- reactiveVal()
output$mymap <- renderLeaflet({
leaflet() %>%
addPolygons(data = arcgis_data %>% slice(1:5), layerId = ~id) %>%
addProviderTiles("CartoDB.Positron")
})
observeEvent(input$mymap_shape_click, {
rv(input$mymap_shape_click$id)
})
## you can now plot your plot based on the id of region selected
output$myplot <- renderPlot({
plot_data %>%
filter(id == rv()) %>%
pivot_longer(cols = starts_with("Variable"), names_to = "Variable", values_to = "Value") %>%
ggplot(aes(x = Variable, y = Value)) +
geom_col()
})
}
shinyApp(ui, server)
Edit: For your uploaded data, you don't need to add a separate id for communes. Instead, you could match by name (nom_commune). You can use that in your layerId instead. This looks like it should work. I did take out some of the additional label information as this appeared to be missing from the .shp file I downloaded.
library(shiny)
library(leaflet)
library(rgdal)
library(sf)
library(ggplot2)
library(tidyverse)
communes <- readOGR("communes_ok.shp")
ui <- fluidPage(
leafletOutput(outputId = "mymap"),
plotOutput(outputId = "myplot")
)
server <- function(input, output){
## use reactive values to store the id from observing the shape click
rv <- reactiveVal()
output$mymap<-renderLeaflet(
leaflet(communes) %>%
addProviderTiles(providers$Stamen.TonerLite,
options = providerTileOptions(noWrap = TRUE)) %>%
setView(1.50, 43.54, zoom = 12) %>%
addTiles() %>%
addPolygons(fillColor = "blue",
weight = 2,
opacity = 1,
color = "white",
dashArray = "3",
fillOpacity = 0.3,
highlight = highlightOptions(
weight = 5,
color = "#666",
dashArray = "",
fillOpacity = 0.7,
bringToFront = TRUE),
layerId = ~nm_cmmn)
)
observeEvent(input$mymap_shape_click, {
rv(input$mymap_shape_click$id)
})
## you can now 'output' your generated data however you want
output$myplot <- renderPlot({
if (is.null(rv())) return (NULL)
plot_data %>%
filter(nom_commune == rv()) %>%
pivot_longer(cols = starts_with("Variable"), names_to = "Variable", values_to = "Value") %>%
ggplot(aes(x = Variable, y = Value)) +
geom_col()
})
}
shinyApp(ui, server)

renderLeaflet: legend is not rendered in shiny

Using the renderLeaflet (following codes), I am trying to create an interactive map within shiny. I want the map to be updated based on users selections of age group, sex, and year. When age group=60 and sex=both sexes and year= 2010 are selected, everything looks great (please see this screen shot).
However, when the other age groups are selected, the legend remains unchanged and is not rendered (Please see the second screen shot).
Here is my code:
mapdata_ <- reactive ({
nhmap$Per <- round(nhmap$Per, 1)
out_map <- nhmap %>%
filter (
Age_Group %in% input$Age_Group_map,
Sex %in% input$sex_map,
Year %in% input$Year_map)
return(out_map)
})
output$int_map <- renderLeaflet ({
leaflet (mapdata_(),
pal8 <- c("#FFFFE5", "#D9F0A3", "#78C679", "#006837") ,
pal <- colorBin(palette = pal8, domain = nhmap$Per, bins=4, right =FALSE, na.color = "#808080", alpha = FALSE, reverse = F)
) %>%
addProviderTiles("CartoDB.Positron") %>%
clearControls() %>%
clearShapes()%>%
addPolygons(fillColor = ~pal(Per),
stroke=T,
weight=1,
smoothFactor=0.2,
fillOpacity = 1,
color="black",
popup=~paste(NAME,"<br>",input$sex_map,
input$Age_Group_map,"=",Per,"%"),
highlightOptions = highlightOptions(color = "red",
weight = T,
bringToFront = T),
label=~NAME) %>%
addTiles() %>%
setView(-82.706838, 40.358615, zoom=7) %>%
addLegend(position = "bottomright",
values = ~pal(Per),
pal = pal,
title = (paste("%",input$Age_Group_map, input$sex_map, "in", input$Year_map)) ,
labFormat = labelFormat())
})

Resources