I am trying to represent points as a cross (+) on a leaflet map. I have started following the example here. There are two things I would like to sort out;
1) why all the points are not showing up as crosses.
2) Can I fix the marker size, so that when I zoom out or in the markers stay the size of the initial creation, ie. not dynamic markers. Currently if I zoom out they get large but I want to avoid that.
Reproducible code below.
Poly = data.frame(Strat = c("A","A","A","A","A","B","B","B","B","B"), long = c(174.5012, 174.5026, 174.5026, 174.5014,174.5012,174.5012 ,174.5020, 174.5020,174.5012,174.5012),lat = c(-35.84014, -35.84018, -35.84137,-35.84138,-35.84014,-35.84014,-35.84014,-35.84197,-35.84197,-35.84014))
Points = data.frame(long = c(174.5014 ,174.5017, 174.5021, 174.5023, 174.5020, 174.5017 ,174.5021 ,174.5017, 174.5021, 174.5019), lat = c(-35.84187, -35.84165, -35.84220 ,-35.84121, -35.84133, -35.84034, -35.84082, -35.84101, -35.84112, -35.84084))
library('leaflet')
library('shiny')
library('webshot')
library('htmlwidgets')
# A function to create png images for each shape and color
# for the leaflet maps
pchIcons = function(pch = 1, width = 30, height = 30, bg = "transparent", col = "black", ...) {
n = length(pch)
files = character(n)
# create a sequence of png images
for (i in seq_len(n)) {
f = tempfile(fileext = '.png')
png(f, width = width, height = height, bg = bg)
par(mar = c(0, 0, 0, 0))
plot.new()
points(.5, .5, pch = pch[i], col = col[i], cex = min(width, height) / 8, ...)
dev.off()
files[i] = f
}
return(list("iconUrl" = files, "iconWidth" = width, "iconHeight" = height))
}
##### UI
ui <- fluidPage(
mainPanel(leafletOutput("map"))
)
##### Server
server = function(input, output){
output$map <- renderLeaflet({
mymap()
})
mymap <- reactive({
leaflet() %>% addTiles(urlTemplate = "http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", attribution = NULL, layerId = NULL, group = NULL, options = tileOptions()) %>%
clearShapes() %>%
clearMarkers() %>%
fitBounds(lng1 = 174.5042, lat1= -35.83814,lng2= 174.5001, lat2 = -35.8424)
})
myfun <- function(map) {
print("adding points")
map %>% clearShapes() %>%
clearControls() %>%
clearMarkers() %>%
addCircles(lng = Points$long, lat = Points$lat, color = "blue",fillOpacity = 1,radius = 1) %>%
addMarkers(lng = Points$long, lat = Points$lat,icon = makeIcon(iconUrl = pchIcons(pch= 3,col="blue", height = 20, width = 20),popupAnchorX = 10, popupAnchorY = 0))
}
AddStrataPoly <- function(map) {
print("adding polygons")
for(i in 1:length(unique(Poly$Strat))) {
map <- map %>% addPolygons(lng = Poly[Poly$Strat == unique(Poly$Strat)[i],]$long, lat = Poly[Poly$Strat == unique(Poly$Strat)[i],]$lat, layerId = unique(Poly$Strat)[i], color = 'gray60', options = list(fillOpacity = 0.1))
}
map
}
observe({
leafletProxy("map") %>% myfun() %>% AddStrataPoly()
})
newmap <- reactive({
mymap() %>% myfun() %>% AddStrataPoly()
})
}
shinyApp(ui, server)
Try this (skipping the two dataframes Poly and Points to keep it shorter):
library('leaflet')
library('shiny')
library('webshot')
library('htmlwidgets')
# A function to create png images for each shape and color
# for the leaflet maps
pchIcons = function(pch = 3,
width = 30,
height = 30,
bg = "transparent",
col = "black",
...) {
n = length(pch)
files = character(n)
# create a sequence of png images
for (i in seq_len(n)) {
f = tempfile(fileext = '.png')
png(f,
width = width,
height = height,
bg = bg)
par(mar = c(0, 0, 0, 0))
plot.new()
points(
.5,
.5,
pch = pch[i],
col = col[i],
cex = min(width, height) / 8,
...
)
dev.off()
files[i] = f
}
return(list(iconUrl = files, iconWidth = width, iconHeight = height))
}
##### UI
ui <- fluidPage(mainPanel(leafletOutput("map")))
##### Server
server = function(input, output) {
output$map <- renderLeaflet({
mymap()
})
mymap <- reactive({
leaflet() %>% addTiles(
urlTemplate = "http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
attribution = NULL,
layerId = NULL,
group = NULL,
options = tileOptions()
) %>%
clearShapes() %>%
clearMarkers() %>%
fitBounds(
lng1 = 174.5042,
lat1 = -35.83814,
lng2 = 174.5001,
lat2 = -35.8424
)
})
myfun <- function(map) {
print("adding points")
map %>% clearShapes() %>%
clearControls() %>%
clearMarkers() %>%
addCircles(
lng = Points$long,
lat = Points$lat,
color = "blue",
fillOpacity = 1,
radius = 1
) %>%
addMarkers(
lng = Points$long,
lat = Points$lat,
icon = makeIcon(
iconUrl = pchIcons()$iconUrl,
iconWidth = pchIcons()$iconWidth,
iconHeight = pchIcons()$iconHeight,
popupAnchorX = 10,
popupAnchorY = 0
)
)
}
AddStrataPoly <- function(map) {
print("adding polygons")
for (i in 1:length(unique(Poly$Strat))) {
map <-
map %>% addPolygons(
lng = Poly[Poly$Strat == unique(Poly$Strat)[i], ]$long,
lat = Poly[Poly$Strat == unique(Poly$Strat)[i], ]$lat,
layerId = unique(Poly$Strat)[i],
color = 'gray60',
options = list(fillOpacity = 0.1)
)
}
map
}
observe({
leafletProxy("map") %>% myfun() %>% AddStrataPoly()
})
newmap <- reactive({
mymap() %>% myfun() %>% AddStrataPoly()
})
}
shinyApp(ui, server)
Related
I am currently trying to set something up in my Shiny application where I can click using the input$map_shape_click event on a smaller leaflet map to filter another leaflet map. However, I have hit a bit of a brick wall and the solution I thought might work is resulting in no change to the map. The full replicable application can be found here:
https://github.com/JoeMarangos/SNA_Test_App
The full code is here:
library(tidyverse)
library(vroom)
library(sf)
library(tigris)
library(leaflet)
library(htmlwidgets)
library(shiny)
library(googleway)
library(leaflet.extras)
library(leaflet.extras2)
library(mapboxapi)
library(fontawesome)
library(mapview)
library(shinyjs)
library(prettymapr)
#Set the working directory
SNALayer <- readRDS("data/SNALayer.RDS")
ULEZLayer <- readRDS("data/ULEZ.RDS")
BoroughLayer <- readRDS("data/borough.RDS")
vars1 <- c(
"Disable layer..." = "None",
"Average NO2" = "NO2 Mean",
"Average NOx" = "NOx Mean"
)
vars2 <- c(
"Mapbox Standard" = "standard",
"Mapbox Light" = "light",
"Mapbox Streets" = "streets",
"Mapbox Dark" = "dark",
"Mapbox Satellite" = "satellite"
)
# Define UI for application that draws a histogram
ui <- fluidPage(
useShinyjs(),
title = "TfL SNA Tool",
titlePanel(h5("TfL SNA Tool",align = "center",style="background-color:#10006A;color:#FFFFFF;font-size:5em;font-weight:bold;")),
sidebarPanel(id="sidebar",h5("Pollution Map",style="color:#FFFFFF;font-size:30px;font-weight:bold;"),
width = 3,
h5("The pollution map includes a number of air and noise pollution datasets that are aggregated to the SNA cells as average values.
The headline data is LAEI data produced to show key air quality metrics such as NO2, NOx and PM2.5/10. More information about the LAEI data
can be found in the latest Travel in London report:",
style="color:#FFFFFF;font-size:16px;"),
tags$a(href="https://tfl.gov.uk/corporate/publications-and-reports/travel-in-london-reports", h5("Travel in London Report",style="color:#68e2ed;font-size:16px;"),target="blank"),
h5("Toggle Map Options:",style="color:#FFFFFF;font-size:20px;font-weight:bold;"),
checkboxInput(label = h5("On map legend*",style="color:#FFFFFF;font-size:16px;position:relative;top:-7px;"),
inputId = "maplegend",
value=FALSE),
checkboxInput(label = h5("Scalebar*",style="color:#FFFFFF;font-size:16px;position:relative;top:-7px;"),
inputId = "mapscale",
value=FALSE),
checkboxInput(label = h5("Auto-generated title*",style="color:#FFFFFF;font-size:16px;position:relative;top:-7px;"),
inputId = "title",
value=FALSE),
h5("* These items will render when the map is downloaded. It is recomended that these items be switched on before the Download Map option is used.",
style="color:#FFFFFF;font-size:16px;"),
h5("Toggle App Options:",style="color:#FFFFFF;font-size:20px;font-weight:bold;"),
checkboxInput(label = h5("Map Controls**",style="color:#FFFFFF;font-size:16px;position:relative;top:-7px;"),
inputId = "mapcontrol",
value=TRUE),
checkboxInput(label = h5("SNA Layer Controls**",style="color:#FFFFFF;font-size:16px;position:relative;top:-7px;"),
inputId = "snalayercontrol",
value=TRUE),
h5("** These items will not render when the map is downloaded.",
style="color:#FFFFFF;font-size:16px;"),
tags$div(actionButton(inputId = "exp",label = "Set Default Export Options",icon = shiny::icon("fa-solid fa-map-location-dot",verify_fa = FALSE)),align="center",style="padding:5px;"),
tags$div(actionButton(inputId = "exp_can",label = "Clear Default Export Options",icon = shiny::icon("fa-solid fa-map",verify_fa = FALSE)),align="center",style="padding:5px;"),
tags$div(actionButton(inputId = "dl",label = "Download Map",icon = shiny::icon("fa-solid fa-download",verify_fa = FALSE)),align="center",style="padding:5px;")),
tags$head(tags$style(HTML("#sidebar{background-color:#10006A;"))),
mainPanel(
leafletOutput("SNA",width = "auto",height = "auto"),tags$style(type = "text/css", "#SNA {height: calc(97vh - 80px) !important;}"),width = 9),
absolutePanel(id = "controls",class ="panel panel-default",fixed = TRUE,
draggable = TRUE,top = 110,left = "auto",right = 35, bottom = "auto",width = 250,height = "auto",
tags$div("SNA Layer Control",align = "center",style="background-color:#10006A;color:#FFFFFF;font-size:2em;font-weight:bold;padding:10px;"),
selectInput("baselayer",h5("Base Map",style="color:#FFFFFF;font-weight:bold;"),vars2),
selectInput("snalayer",h5("SNA Selection",style="color:#FFFFFF;font-weight:bold;"),vars1,selected = "NO2 Mean")),
absolutePanel(id = "mapcontrols",class ="panel panel-default",fixed = TRUE,
draggable = TRUE,top = 110,left = "auto",right = "70.0%", bottom = "auto",width = 100,height = "auto",
tags$div("Map",tags$br(),"Controls",align = "center",style="background-color:#10006A;color:#FFFFFF;font-size:1em;font-weight:bold;padding:10px;"),
tags$div(actionButton(inputId = "map_zoom_in",shiny::icon("fa-solid fa-plus",verify_fa = FALSE),title ="Zoom In"),actionButton(inputId = "map_zoom_out",shiny::icon("fa-solid fa-minus",verify_fa = FALSE),title ="Zoom Out"),align="center"),
tags$div(actionButton(inputId = "reset",shiny::icon("fa-solid fa-arrows-to-circle",verify_fa = FALSE)),align="center", style = "padding:10px",title ="Reset Default Extent")),
absolutePanel(id = "boroughselect",class ="panel panel-default",fixed = TRUE,
draggable = TRUE,top = 975,left = "auto",right = "60.0%", bottom = "auto",width = 350,height = "auto",
tags$div("Borough Select",align = "center",style="background-color:#10006A;color:#FFFFFF;font-size:2em;font-weight:bold;padding:10px;"),
tags$div(leafletOutput("Borough1",width = 300,height = 250),align="center")),
tags$head(tags$style(HTML("#controls {opacity:0.6;background-color:#10006A;padding:0 20px 20px 20px;transition:opacity 1000ms;transition-delay:500ms;z-index:9998 !important;}#controls:hover{opacity:1;transition:opacity 1000ms;}"))),
tags$head(tags$style(HTML("#mapcontrols {opacity:0.6;background-color:#10006A;padding:0 10px 10px 10px;transition:opacity 1000ms;transition-delay:500ms;z-index:9999 !important;}#mapcontrols:hover{opacity:1;transition:opacity 1000ms;}"))),
tags$head(tags$style(HTML("#boroughselect {opacity:0.6;background-color:#10006A;padding:0 10px 10px 10px;transition:opacity 1000ms;transition-delay:500ms;z-index:9999 !important;}#boroughselect:hover{opacity:1;transition:opacity 1000ms;}"))),
tags$head(tags$style(HTML("#Borough1 {background:#10006A;}")))
)
# Define server logic required to draw a histogram
server <- function(input, output) {
output$SNA <- renderLeaflet({
leaflet(options = leafletOptions(minZoom = 11,zoomControl=FALSE)) %>%
addMapPane("base",zIndex = 410) %>%
addMapPane("pollution",zIndex = 420) %>%
addMapPane("overlay",zIndex = 430) %>%
setView(lng = -0.10932017,
lat = 51.500493,
zoom = 11) %>%
setMaxBounds(lng1 = -0.64469747,
lat1 = 51.832822,
lng2 = 0.46418831,
lat2 = 51.244695) %>%
addEasyprint(options = easyprintOptions(hidden = TRUE,exportOnly = TRUE,sizeModes = "CurrentSize",hideControlContainer = FALSE))
})
output$Borough1 <- renderLeaflet({
labels4 <- sprintf("<strong>Borough Name:</strong> %s",
BoroughLayer$BOROUGH) %>%
lapply(htmltools::HTML)
leaflet(options = leafletOptions(minZoom = 8.75,maxZoom = 8.75, zoomControl=FALSE,dragging=FALSE,keyboard=FALSE,tap=FALSE,touchzoom=FALSE,doubleClickZoom=FALSE)) %>%
setView(lng = -0.10932017,
lat = 51.500493,
zoom = 8.75) %>%
setMaxBounds(lng1 = -0.64469747,
lat1 = 51.832822,
lng2 = 0.46418831,
lat2 = 51.244695) %>%
addPolygons(data = BoroughLayer,
stroke=TRUE,
color="white",
weight=1,
label = labels4,
layerId = BoroughLayer$BOROUGH,
highlightOptions = highlightOptions(weight = 2,
color="yellow",
bringToFront = TRUE,
fillColor = "#001630"
))
})
sna_click <- reactiveVal()
observeEvent(input$Borough1_shape_click,{
if(!is.null(sna_click()) && sna_click() == input$Borough1_shape_click$id) {
sna_click(NULL)
}
else {
sna_click(input$Borough1_shape_click$id)
}
})
filtered_sna <- reactive({
if (is.null(sna_click())) {
SNALayer
}
else if (!is.null(sna_click())){
SNALayer %>% dplyr::filter(SNALayer$SNAMaster_Borough %in% sna_click())
}
})
observeEvent(input$exp,{
updateCheckboxInput(getDefaultReactiveDomain(),"mapscale",value = TRUE)
})
observeEvent(input$exp,{
updateCheckboxInput(getDefaultReactiveDomain(),"maplegend",value = TRUE)
})
observeEvent(input$exp,{
updateCheckboxInput(getDefaultReactiveDomain(),"title",value = TRUE)
})
observeEvent(input$exp_can,{
updateCheckboxInput(getDefaultReactiveDomain(),"mapscale",value = FALSE)
})
observeEvent(input$exp_can,{
updateCheckboxInput(getDefaultReactiveDomain(),"maplegend",value = FALSE)
})
observeEvent(input$exp_can,{
updateCheckboxInput(getDefaultReactiveDomain(),"title",value = FALSE)
})
observeEvent(input$mapcontrol,{
if (input$mapcontrol == TRUE){
show("mapcontrols",anim = TRUE,animType = "slide")
}
else {
hide("mapcontrols",anim = TRUE,animType = "slide")
}
})
observeEvent(input$snalayercontrol,{
if (input$snalayercontrol == TRUE){
show("controls",anim = TRUE,animType = "slide")
}
else {
hide("controls",anim = TRUE,animType = "slide")
}
})
TitleName <- reactive({
if (input$snalayer == "None"){
TitleName <- sprintf("No SNA Layer Selected...")
}
else if (input$snalayer == "NO2 Mean"){
TitleName <- sprintf("Annual Mean NO<sub style='font-size:20px;'>2</sub> (<span>µ</span>g/m<sup style='font-size:20px;'>3</sup>) LAEI 2019")
}
else if (input$snalayer == "NOx Mean"){
TitleName <- sprintf("Annual Mean NO<sub style='font-size:20px;'>X</sub> (<span>µ</span>g/m<sup style='font-size:20px;'>3</sup>) LAEI 2019")
}
})
observeEvent(input$reset,{
leafletProxy("SNA") %>%
setView(lng = -0.10932017,
lat = 51.500493,
zoom = 11)
})
observeEvent(input$map_zoom_in,{
leafletProxy("SNA") %>%
setView(lat = (input$SNA_bounds$north + input$SNA_bounds$south) / 2,
lng = (input$SNA_bounds$east + input$SNA_bounds$wes) / 2,
zoom = input$SNA_zoom + 1)
})
observeEvent(input$map_zoom_out,{
leafletProxy("SNA") %>%
setView(lat = (input$SNA_bounds$north + input$SNA_bounds$south) / 2,
lng = (input$SNA_bounds$east + input$SNA_bounds$wes) / 2,
zoom = input$SNA_zoom - 1)
})
observe({
proxy4 <- leafletProxy("SNA")
if (input$mapscale == TRUE){
proxy4 %>%
addScaleBar(position = "bottomleft",options = scaleBarOptions(maxWidth = 250, metric = TRUE, imperial = TRUE,updateWhenIdle = FALSE))
}
else {
proxy4 %>%
removeScaleBar()
}
})
observe({
proxy6 <- leafletProxy("SNA")
if (input$title == TRUE){
proxy6 %>%
removeControl("title1") %>%
addControl(sprintf("<strong style='font-size:40px;color:white;text-shadow:-1px 0 black, 0 1px black, 1px 0 black, 0 -1px black;font-family:arial;'>SNA Pollution Map: %s</strong>",TitleName()),position = "topleft",layerId = "title1",className = "fieldset{border:0}")
}
else {
proxy6 %>%
removeControl("title1")
}
})
observeEvent(input$baselayer,{
proxy2 <- leafletProxy("SNA")
if (input$baselayer == "standard"){
proxy2 %>%
clearTiles() %>%
addMapboxTiles(style_url = "mapbox://styles/joemarangos/cl2g1ochw001s14muumlqzopk", access_token = "hidden",group = "standard",options = pathOptions(pane = "base"))
}
else if (input$baselayer == "light"){
proxy2 %>%
clearTiles() %>%
addMapboxTiles(style_url = "mapbox://styles/joemarangos/cl2g1wt17002m14piyxlvvdat", access_token = "hidden",group = "light",options = pathOptions(pane = "base"))
}
else if (input$baselayer == "streets"){
proxy2 %>%
clearTiles() %>%
addMapboxTiles(style_url = "mapbox://styles/joemarangos/cl2g1z2ai002b14ksruxzlpe9", access_token = "hidden",group = "streets",options = pathOptions(pane = "base"))
}
else if (input$baselayer == "dark"){
proxy2 %>%
clearTiles() %>%
addMapboxTiles(style_url = "mapbox://styles/joemarangos/cl2ex322t001814piusq8f1p0", access_token = "hidden",group = "dark",options = pathOptions(pane = "base"))
}
else if (input$baselayer == "satellite"){
proxy2 %>%
clearTiles() %>%
addMapboxTiles(style_url = "mapbox://styles/joemarangos/cl2g1ucmp00d817prb81qbg43", access_token = "hidden",group = "satellite",options = pathOptions(pane = "base"))
}
})
observeEvent(input$snalayer, {
proxy1 <- leafletProxy("SNA")
labels <- sprintf("<strong>SNA ID:</strong> %s <br/> <strong>Average Polution Value:</strong> %s",
SNALayer$SNA_ID,SNALayer$SNAMaster_NO2_mean) %>%
lapply(htmltools::HTML)
labels2 <- sprintf("<strong>ULEZ</strong>") %>%
lapply(htmltools::HTML)
labels3 <- sprintf("<strong>SNA ID:</strong> %s <br/> <strong>Average Polution Value:</strong> %s",
SNALayer$SNA_ID,SNALayer$SNAMaster_NOX_mean) %>%
lapply(htmltools::HTML)
if (input$snalayer == "NO2 Mean"){
proxy1 %>%
clearShapes() %>%
addPolygons(data = filtered_sna(), label = labels,
stroke=TRUE,
color = "white",
weight = .5,
smoothFactor = .5,
opacity = 1,
fillOpacity = 0.6,
fillColor = SNALayer$LegendColNO2,
group = "NO2 Mean",
popup = labels,
options = pathOptions(pane = "pollution"),
highlightOptions = highlightOptions(weight = 2,
fillOpacity = 0.8,
color = "yellow",
opacity = 1,
bringToFront = TRUE))}
else if (input$snalayer == "NOx Mean"){
proxy1 %>%
clearShapes() %>%
addPolygons(data = filtered_sna(), label = labels3,
stroke = TRUE,
color = "white",
weight = .5,
smoothFactor = .5,
opacity = 1,
fillOpacity = 0.6,
fillColor = SNALayer$LegendColNOX,
group = "NOx Mean",
popup = labels3,
options = pathOptions(pane = "pollution"),
highlightOptions = highlightOptions(weight = 2,
fillOpacity = 0.8,
color = "yellow",
opacity = 1,
bringToFront = TRUE))
}
else if (input$snalayer == "None"){
proxy1 %>%
clearShapes()
}
})
observeEvent(input$dl,{
leafletProxy("SNA") %>%
easyprintMap(sizeModes = "CurrentSize",filename = paste0(Sys.Date(),"_SNA_Custom"))
})
}
# Run the application
shinyApp(ui = ui, server = server)
The code in question specifically related to the map interaction is here:
sna_click <- reactiveVal()
observeEvent(input$Borough1_shape_click,{
if(!is.null(sna_click()) && sna_click() == input$Borough1_shape_click$id) {
sna_click(NULL)
}
else {
sna_click(input$Borough1_shape_click$id)
}
})
filtered_sna <- reactive({
if (is.null(sna_click())) {
SNALayer
}
else if (!is.null(sna_click())){
SNALayer %>% dplyr::filter(SNALayer$SNAMaster_Borough %in% sna_click())
}
})
observeEvent(input$snalayer, {
proxy1 <- leafletProxy("SNA")
labels <- sprintf("<strong>SNA ID:</strong> %s <br/> <strong>Average Polution Value:</strong> %s",
SNALayer$SNA_ID,SNALayer$SNAMaster_NO2_mean) %>%
lapply(htmltools::HTML)
labels2 <- sprintf("<strong>ULEZ</strong>") %>%
lapply(htmltools::HTML)
labels3 <- sprintf("<strong>SNA ID:</strong> %s <br/> <strong>Average Polution Value:</strong> %s",
SNALayer$SNA_ID,SNALayer$SNAMaster_NOX_mean) %>%
lapply(htmltools::HTML)
if (input$snalayer == "NO2 Mean"){
proxy1 %>%
clearShapes() %>%
addPolygons(data = filtered_sna(), label = labels,
stroke=TRUE,
color = "white",
weight = .5,
smoothFactor = .5,
opacity = 1,
fillOpacity = 0.6,
fillColor = SNALayer$LegendColNO2,
group = "NO2 Mean",
popup = labels,
options = pathOptions(pane = "pollution"),
highlightOptions = highlightOptions(weight = 2,
fillOpacity = 0.8,
color = "yellow",
opacity = 1,
bringToFront = TRUE))}
else if (input$snalayer == "NOx Mean"){
proxy1 %>%
clearShapes() %>%
addPolygons(data = filtered_sna(), label = labels3,
stroke = TRUE,
color = "white",
weight = .5,
smoothFactor = .5,
opacity = 1,
fillOpacity = 0.6,
fillColor = SNALayer$LegendColNOX,
group = "NOx Mean",
popup = labels3,
options = pathOptions(pane = "pollution"),
highlightOptions = highlightOptions(weight = 2,
fillOpacity = 0.8,
color = "yellow",
opacity = 1,
bringToFront = TRUE))
}
else if (input$snalayer == "None"){
proxy1 %>%
clearShapes()
}
})
The idea is that clicking on the borough map will result in the borough ID being stored as a reactive value and then this value filters the dataset used in the Leaflet Proxy. When I click a map shape on the borough map, it should filter the SNA map to the correct data but instead a click results in nothing changing. Please refer to my github link to get a full oversight of the code and data. I feel like I'm missing something painfuly obvious here, what is it?
Thanks,
Joe
I've resolved my own issue. For those trying to replicate, or curious how I resolved this, I added a second observeEvent function for the map_shape_click that also adds polygon proxy to the map.
observeEvent(input$Borough1_shape_click, {
proxy1 <- leafletProxy("SNA")
labels <- sprintf("<strong>SNA ID:</strong> %s <br/> <strong>Average Polution Value:</strong> %s",
SNALayer$SNA_ID,SNALayer$SNAMaster_NO2_mean) %>%
lapply(htmltools::HTML)
labels2 <- sprintf("<strong>ULEZ</strong>") %>%
lapply(htmltools::HTML)
labels3 <- sprintf("<strong>SNA ID:</strong> %s <br/> <strong>Average Polution Value:</strong> %s",
SNALayer$SNA_ID,SNALayer$SNAMaster_NOX_mean) %>%
lapply(htmltools::HTML)
if (input$snalayer == "NO2 Mean"){
proxy1 %>%
clearShapes() %>%
addPolygons(data = filtered_sna(), label = labels,
stroke=TRUE,
color = "white",
weight = .5,
smoothFactor = .5,
opacity = 1,
fillOpacity = 0.6,
fillColor = SNALayer$LegendColNO2,
group = "NO2 Mean",
popup = labels,
options = pathOptions(pane = "pollution"),
highlightOptions = highlightOptions(weight = 2,
fillOpacity = 0.8,
color = "yellow",
opacity = 1,
bringToFront = TRUE))}
else if (input$snalayer == "NOx Mean"){
proxy1 %>%
clearShapes() %>%
addPolygons(data = filtered_sna(), label = labels3,
stroke = TRUE,
color = "white",
weight = .5,
smoothFactor = .5,
opacity = 1,
fillOpacity = 0.6,
fillColor = SNALayer$LegendColNOX,
group = "NOx Mean",
popup = labels3,
options = pathOptions(pane = "pollution"),
highlightOptions = highlightOptions(weight = 2,
fillOpacity = 0.8,
color = "yellow",
opacity = 1,
bringToFront = TRUE))
}
else if (input$snalayer == "None"){
proxy1 %>%
clearShapes()
}
})
I am working on Shiny and I would like to capture with a ObserveEvent the group/BaseGroup that the user is clicking in the legend of the following map:
output$map <- renderLeaflet({
p <- leaflet(paises_total_casos()) %>%
addTiles() %>%
setView( lat=10, lng=0 , zoom=2) %>%
addCircles(lng = ~cent$x, lat = ~cent$y, weight = 1, radius = ~sqrt(total_casos) * 40, color = "blue", group = "New_cases",
label = ~htmlEscape(paste(location, ":", format(as.numeric(total_casos), big.mark=","), sep = " "))) %>%
addCircles(lng = ~cent$x, lat = ~cent$y, weight = 1, radius = ~sqrt(total_fallecidos) * 40, color = "red", group = "New_deaths",
label = ~htmlEscape(paste(location, ":", format(as.numeric(total_fallecidos), big.mark=","), sep = " "))) %>%
addCircles(lng = ~cent$x, lat = ~cent$y, weight = 1, radius = ~sqrt(tests) * 40, color = "green", group = "New_tests",
label = ~htmlEscape(paste(location, ":", format(as.numeric(tests), big.mark=","), sep = " "))) %>%
#Afegim el Layers Control
addLayersControl(baseGroups = c("New_cases", "New_deaths", "New_tests"),
options = layersControlOptions(collapsed = FALSE))
})
Let's say I would like to capture if the map is showing the group New_cases, New_deaths or New_tests.
Is there a possibility to do that with ObserveEvent?
Thank you
You can include an observer for your map. You can use input$map_groups (adding "_groups" to the outputId used) and place inside observe. See complete example below which will print the map layer shown.
library(shiny)
library(leaflet)
ui <- fluidPage(leafletOutput("map"))
server <- function(input, output, session) {
output$map <- renderLeaflet({
leaflet() %>%
addTiles(group = "OpenStreetMap") %>%
addProviderTiles("Stamen.Toner", group = "Toner by Stamen") %>%
addMarkers(runif(20, -75, -74), runif(20, 41, 42), group = "Markers") %>%
addLayersControl(
baseGroups = c("OpenStreetMap", "Toner by Stamen"),
overlayGroups = c("Markers")
)
})
observe({
print(input$map_groups)
})
}
shinyApp(ui, server)
My shinyApp is composed of two zone, a map and a chart.
You can select an area in the chart which will update data on the map coresponding to the selected chart area.
So the map is using an observe and a leafletProxy to add filtered Data so as a ClearMarkers() to remove previous filtered data.
The problem is : I have an other MarkersLayer part of an overlayGroup and which can be displayed by the overlayGroupWidget but it doesn't show up.
Why? Due of the ClearMarkers() which remove every markers on the map (T0New and T1New)
So I would like to remove specific layers which are T0New and MapData.
I tried removeMarker() and clearGroup() but it didn't worked out...
Any ideas?
Here is an example of my code whith sample data :
library(shiny)
library(leaflet)
library(leaflet.extras)
library(tidyverse)
library(sf)
#Create T0New data
lat <- c(49.823, 58.478, 57.478, 45.823)
lng <- c(-10.854,-10.854,2.021,2.02)
date_start_min <- c(125,135,168,149)
T0New <- data.frame(lat,lng)
#Create T1New data
lat <- c(48.956, 56.356, 57.445, 45.253)
lng <- c(-9.762,-8.884,1.971,2.17)
T1New <- data.frame(lat,lng)
ui <- fluidPage(
leafletOutput("map", height = "50vh"),
plotOutput("distribPlot", height = "47vh",
brush = brushOpts(id = "distribPlot_brush", direction = "x", resetOnNew = FALSE))
)
server <- function(input, output, session) {
#filtrer les données par attribut du graphique
filteredGraphData <- reactive({
noSelection <- TRUE
currentlyFiltered <- T0New
if(!is.null(input$distribPlot_brush)){
thisSel <- input$distribPlot_brush
currentlyFiltered <- currentlyFiltered %>%
filter(date_start_min >= thisSel$xmin, date_start_min <= thisSel$xmax)
noSelection <- FALSE
}
if(!noSelection){
return(currentlyFiltered)
}
})
#Sortie map
output$map <- renderLeaflet({
leaflet()%>%
addLayersControl(
position = "bottomright",
overlayGroups = "T1New",
options = layersControlOptions(collapsed = F)
) %>%
hideGroup("T1New") %>%
addProviderTiles(providers$CartoDB.Positron) %>%
addCircleMarkers(
lat = T0New$lat,
lng = T0New$lng,
radius = 4,
color = 'red',
stroke = FALSE,
fillOpacity = 1
)%>%
addCircleMarkers(
lat = T1New$lat,
lng = T1New$lng,
radius = 5,
color = 'blue',
stroke = FALSE,
fillOpacity = 1,
group = "T1New"
)
})
observe({
if(length(filteredGraphData()) > 1){
mapData <- filteredGraphData()
mapProxy <- leafletProxy("map", session = session, data = c(mapData, T0New))
mapProxy %>%
clearMarkers() %>%
addCircleMarkers(
data = T0New,
lat = T0New$lat,
lng = T0New$lng,
radius = 1,
color = 'black',
stroke = FALSE,
fillOpacity = 1
) %>%
addCircleMarkers(
data = mapData,
lat = mapData$lat,
lng = mapData$lng,
radius = 4,
color = 'red',
stroke = FALSE,
fillOpacity = 1
)
}else{
mapProxy <- leafletProxy("map", session = session, data = T0New)
mapProxy %>%
clearMarkers() %>%
addCircleMarkers(
radius = 4,
color = 'red',
stroke = FALSE,
fillOpacity = 1
)
}
})
#Sortie graph
output$distribPlot <- renderPlot({
distribPlot <- ggplot(T0New,aes(date_start_min)) +
geom_density(col = "#053144", fill = "#43a2ca", alpha = 0.3, adjust = 0.75)
return(distribPlot)
})
}
# Create Shiny app ----
shinyApp(ui = ui, server = server)
I finally was able to find a solution : it is in clearGroup()
I don't know why it didn't worked in the first place, her it is :
library(shiny)
library(leaflet)
library(leaflet.extras)
library(tidyverse)
library(sf)
#Create T0New data
lat <- c(49.823, 58.478, 57.478, 45.823)
lng <- c(-10.854,-10.854,2.021,2.02)
date_start_min <- c(125,135,168,149)
T0New <- data.frame(lat,lng)
#Create T1New data
lat <- c(48.956, 56.356, 57.445, 45.253)
lng <- c(-9.762,-8.884,1.971,2.17)
T1New <- data.frame(lat,lng)
ui <- fluidPage(
leafletOutput("map", height = "50vh"),
plotOutput("distribPlot", height = "47vh",
brush = brushOpts(id = "distribPlot_brush", direction = "x", resetOnNew = FALSE))
)
server <- function(input, output, session) {
#filtrer les données par attribut du graphique
filteredGraphData <- reactive({
noSelection <- TRUE
currentlyFiltered <- T0New
if(!is.null(input$distribPlot_brush)){
thisSel <- input$distribPlot_brush
currentlyFiltered <- currentlyFiltered %>%
filter(date_start_min >= thisSel$xmin, date_start_min <= thisSel$xmax)
noSelection <- FALSE
}
if(!noSelection){
return(currentlyFiltered)
}
})
#Sortie map
output$map <- renderLeaflet({
leaflet()%>%
addLayersControl(
position = "bottomright",
overlayGroups = "T1New",
options = layersControlOptions(collapsed = F)
) %>%
hideGroup("T1New") %>%
addProviderTiles(providers$CartoDB.Positron) %>%
addCircleMarkers(
lat = T0New$lat,
lng = T0New$lng,
radius = 4,
color = 'red',
stroke = FALSE,
fillOpacity = 1,
group = 'A'
)%>%
addCircleMarkers(
lat = T1New$lat,
lng = T1New$lng,
radius = 5,
color = 'blue',
stroke = FALSE,
fillOpacity = 1,
group = "T1New"
)
})
observe({
if(length(filteredGraphData()) > 1){
mapData <- filteredGraphData()
mapProxy <- leafletProxy("map", session = session, data = c(mapData, T0New))
mapProxy %>%
clearGroup('A') %>%
addCircleMarkers(
data = T0New,
lat = T0New$lat,
lng = T0New$lng,
radius = 1,
color = 'black',
stroke = FALSE,
fillOpacity = 1,
group = 'A'
) %>%
addCircleMarkers(
data = mapData,
lat = mapData$lat,
lng = mapData$lng,
radius = 4,
color = 'red',
stroke = FALSE,
fillOpacity = 1,
group = 'reactive'
)
}else{
mapProxy <- leafletProxy("map", session = session, data = T0New)
mapProxy %>%
clearGroup('A') %>%
addCircleMarkers(
radius = 4,
color = 'red',
stroke = FALSE,
fillOpacity = 1,
group = 'A'
)
}
})
#Sortie graph
output$distribPlot <- renderPlot({
distribPlot <- ggplot(T0New,aes(date_start_min)) +
geom_density(col = "#053144", fill = "#43a2ca", alpha = 0.3, adjust = 0.75)
return(distribPlot)
})
}
# Create Shiny app ----
shinyApp(ui = ui, server = server)
I added points on a map using shiny and leaflet.
Each point is a different type of transit option.
I want to distinguish the different types by color and couldn't figure this out.
Tried using "if" which doesn't work.
Thanks!
This is the basic code I have
library(leaflet)
ui <- fluidPage(
leafletOutput("map"),
headerPanel("Example"),
sidebarPanel(checkboxGroupInput(inputId = "Type", label = "Data
Layer",choices = c("Bike", "Muni", "Bus", "BART"), selected = "Bike")))
server <- function(input, output) {
output$map <- renderLeaflet({
rownumber = which(Stops_and_stations$Type == input$Type)
x <- Stops_and_stations[rownumber,]
leaflet(width = 1000, height = 500) %>%
addTiles() %>%
addCircleMarkers(lng = x$stop_lon,
lat = x$stop_lat,
radius= 3, color = '#ff6633') %>%
setView(lng = -122.4000,
lat = 37.79500,
zoom = 13)
})
}
shinyApp(ui, server)
And this is what I tried to add
.....
if(input$Type == "Bike"){
leaflet(width = 1000, height = 500) %>%
addTiles() %>%
addCircleMarkers(lng = x$stop_lon,
lat = x$stop_lat,
radius= 3, color = '#ff6633') %>%
setView(lng = -122.4000,
lat = 37.79500,
zoom = 13)
}
if(input$Type == "Muni"){
leaflet(width = 1000, height = 500) %>%
addTiles() %>%
addCircleMarkers(lng = x$stop_lon,
lat = x$stop_lat,
radius= 3, color = '#0033ff') %>%
setView(lng = -122.4000,
lat = 37.79500,
zoom = 13)
}
.....
It would be much easier to answer to your question if you provided Stops_and_stations and thus made it a reproducible example..
One approach to use distinct colors for different groups is to add a color column to your data.frame:
Since we don't know your data, I created some random dataset.
Stops_and_stations <- data.frame(
Type = rep(c("Bike", "Muni", "Bus", "BART"), each = 10),
stop_lon = -runif(40, 122.4200, 122.4500),
stop_lat = runif(40, 37.76800, 37.78900),
color = rep(c("Red", "Blue", "Green", "Yellow"), each = 10)
)
Then instead of specifying a concrete color such as #ff6633, you can use the color column.
addCircleMarkers(lng = x$stop_lon,
lat = x$stop_lat,
radius= 3, color = x$color)
I would also like to point out that your subsetting is not right: you are using checkboxGroupInput which can have more values, so you need to use the %in% operator to filter.
x <- Stops_and_stations[Stops_and_stations$Type %in% input$Type,]
My leaflet map looks something like this:
library(sp)
library(leaflet)
circleFun <- function(center = c(0,0),diameter = 1, npoints = 100){
r = diameter / 2
tt <- seq(0,2*pi,length.out = npoints)
xx <- center[1] + r * cos(tt)
yy <- center[2] + r * sin(tt)
Sr1 = Polygon(cbind(xx, yy))
Srs1 = Polygons(list(Sr1), "s1")
SpP = SpatialPolygons(list(Srs1), 1:1)
return(SpP)
}
Circle.Town <- circleFun(c(1,-1),2.3,npoints = 100)
df1 <- data.frame(long=c(0.6,1,1.4), lat=c(-2, -.8, -0.2), other=c('a', 'b', 'c'), VAM=c(10,8,6),
type=c('Public', 'Public', 'Private'), id=c(1:3)) %>%
mutate(X=paste0('<strong>id: </strong>',
id,
'<br><strong>type</strong>: ',
type,
'<br><strong>VAM</strong>: ',
VAM))
# Create a continuous palette function
pal <- colorNumeric(
palette = "RdYlBu",
domain = df1$VAM
)
leaflet(height = "400px") %>%
addTiles() %>%
addPolygons(data = Circle.Town, color = 'green', fillOpacity = .7) %>%
addCircleMarkers(data = df1, lat = ~lat, lng =~long,
radius = ~VAM, popup = ~as.character(X),
fillColor = ~pal(VAM),
stroke = FALSE, fillOpacity = 0.8,
clusterOptions = markerClusterOptions()) %>%
addLegend(position = "topright",
pal = pal, values = df1$VAM,
title = "VAM",
opacity = 1
) %>%
setView(lng = 1, lat = -1, zoom = 8)
Right now, I get a popup when I click one of the circles. Is it possible to get the information when I hover the mouse instead of click? Ideally, I would like something like this.
Thanks!
This may have been added to the leaflet package since this question was posed a year ago, but this can be done via the label argument. I am using leaflet R package version 1.1.0.
Read the data in as above:
library(sp)
library(leaflet)
library(dplyr)
circleFun <- function(center = c(0,0),diameter = 1, npoints = 100){
r = diameter / 2
tt <- seq(0,2*pi,length.out = npoints)
xx <- center[1] + r * cos(tt)
yy <- center[2] + r * sin(tt)
Sr1 = Polygon(cbind(xx, yy))
Srs1 = Polygons(list(Sr1), "s1")
SpP = SpatialPolygons(list(Srs1), 1:1)
return(SpP)
}
Circle.Town <- circleFun(c(1,-1),2.3,npoints = 100)
df1 <- data.frame(long=c(0.6,1,1.4), lat=c(-2, -.8, -0.2), other=c('a', 'b', 'c'), VAM=c(10,8,6),
type=c('Public', 'Public', 'Private'), id=c(1:3)) %>%
mutate(X=paste0('<strong>id: </strong>',
id,
'<br><strong>type</strong>: ',
type,
'<br><strong>VAM</strong>: ',
VAM))
# Create a continuous palette function
pal <- colorNumeric(
palette = "RdYlBu",
domain = df1$VAM
)
But create a list of labels instead of vector:
labs <- as.list(df1$X)
And then lapply the HTML function over that list within the label argument. Note to use label instead of popup.
library(htmltools)
leaflet(height = "400px") %>%
addTiles() %>%
addPolygons(data = Circle.Town, color = 'green', fillOpacity = .7) %>%
addCircleMarkers(data = df1, lat = ~lat, lng =~long,
radius = ~VAM, label = lapply(labs, HTML),
fillColor = ~pal(VAM),
stroke = FALSE, fillOpacity = 0.8,
clusterOptions = markerClusterOptions()) %>%
addLegend(position = "topright",
pal = pal, values = df1$VAM,
title = "VAM",
opacity = 1
) %>%
setView(lng = 1, lat = -1, zoom = 8)
This method is described in an an answer to this SO question: R and Leaflet: How to arrange label text across multiple lines
There is more info on HTML in labels in leaflet documentation:
https://rstudio.github.io/leaflet/popups.html
Here is an alternative:
library(leaflet)
library(htmltools)
library(htmlwidgets)
yourmap <- leaflet(height = "400px") %>%
addTiles() %>%
addPolygons(data = Circle.Town, color = 'green', fillOpacity = .7) %>%
addCircleMarkers(data = df1, lat = ~lat, lng =~long,
radius = ~VAM, popup = ~as.character(X),
fillColor = ~pal(VAM),
stroke = FALSE, fillOpacity = 0.8,
clusterOptions = markerClusterOptions()) %>%
addLegend(position = "topright",
pal = pal, values = df1$VAM,
title = "VAM",
opacity = 1
) %>%
setView(lng = 1, lat = -1, zoom = 8)
setwd("~/Desktop/")
saveWidget(yourmap, file="yourmap.html")
In your desktop, you will have an html and a folder saved under yourmap. Open the leaflet.js file located in /pathTo/yourmap_files/leaflet-binding-1.0.1.9002.
In leaflet.js, scroll down to var popup = df.get(i, 'popup');
and paste just below:
marker.on('mouseover', function (e) {
this.openPopup();
});
marker.on('mouseout', function (e) {
this.closePopup();
});
Save and reopen yourmap.html file. Hover on one of your point!!