Shiny: how to plot several parameters on the same leaflet map? - r

I'm new to shiny. I want to make a shiny app that shows the spatial distribution of different parameters. I used meuse dataset from sp package.
Here is the code I used
library(sp)
library(rgdal)
library(ggmap)
library(leaflet)
library(dplyr)
library(shiny)
ui <- fluidPage(
mainPanel(
titlePanel("Copper (ppm)"),
leafletOutput("copper"),
titlePanel("Lead (ppm)"),
leafletOutput("lead"),
titlePanel("Zinc (ppm)"),
leafletOutput("zinc")
)
)
server <- function(input,output){
output$copper <- renderLeaflet({
data(meuse)
coordinates(meuse) <- 1:2
proj4string(meuse) <- CRS("+init=epsg:28992")
meuse <- spTransform(meuse, CRS("+proj=longlat +datum=WGS84"))
meuse_df <- as.data.frame(meuse)
leaflet(meuse_df) %>%
addProviderTiles("OpenStreetMap", group = "OpenStreetMap") %>%
addProviderTiles("Esri.WorldImagery", group = "Esri.WorldImagery") %>%
addCircleMarkers(~x,
~y,
radius = ~copper/10,
stroke = FALSE,
fillOpacity = 0.4,
group = "meuse_df",
popup = ~as.character(copper)) %>%
addLayersControl(position = "bottomleft",
baseGroups = c("OpenStreetMap",
"Esri.WorldImagery"),
overlayGroups = "meuse_df")
})
output$lead <- renderLeaflet({
leaflet(meuse_df) %>%
addProviderTiles("OpenStreetMap", group = "OpenStreetMap") %>%
addProviderTiles("Esri.WorldImagery", group = "Esri.WorldImagery") %>%
addCircleMarkers(~x,
~y,
radius = ~lead/50,
stroke = FALSE,
fillOpacity = 0.4,
group = "meuse_df",
popup = ~as.character(lead)) %>%
addLayersControl(position = "bottomleft",
baseGroups = c("OpenStreetMap",
"Esri.WorldImagery"),
overlayGroups = "meuse_df")
})
output$zinc <- renderLeaflet({
leaflet(meuse_df) %>%
addProviderTiles("OpenStreetMap", group = "OpenStreetMap") %>%
addProviderTiles("Esri.WorldImagery", group = "Esri.WorldImagery") %>%
addCircleMarkers(~x,
~y,
radius = ~zinc/100,
stroke = FALSE,
fillOpacity = 0.4,
group = "meuse_df",
popup = ~as.character(zinc)) %>%
addLayersControl(position = "bottomleft",
baseGroups = c("OpenStreetMap",
"Esri.WorldImagery"),
overlayGroups = "meuse_df")
})
}
shinyApp(ui = ui, server = server)
and here is the result I got
I wonder if there is a way to plot all parameters (copper, lead and zinc) on one map. Any suggestions would be appreciated.
UPDATE
Thanks to #Symbolix's answer and suggestion of using checkBoxGroupInput. Instead, I used addCircleMarkers three times so I can plot all the metals on one map and I can switch them on and off
ui <- fluidPage(
mainPanel(
titlePanel("All metals (ppm)"),
leafletOutput("metals")
)
)
server <- function(input,output){
output$metals <- renderLeaflet({
data(meuse)
coordinates(meuse) <- 1:2
proj4string(meuse) <- CRS("+init=epsg:28992")
meuse <- spTransform(meuse, CRS("+proj=longlat +datum=WGS84"))
meuse_df <- as.data.frame(meuse)
leaflet(meuse_df) %>%
addProviderTiles("OpenStreetMap", group = "OpenStreetMap") %>%
addProviderTiles("Esri.WorldImagery", group = "Esri.WorldImagery") %>%
addCircleMarkers(~x,
~y,
radius = ~copper/10,
color ="red",
stroke = FALSE,
fillOpacity = 0.4,
group = "copper",
popup = ~as.character(copper)) %>%
addCircleMarkers(~x,
~y,
radius = ~lead/50,
color ="gren",
stroke = FALSE,
fillOpacity = 0.4,
group = "lead",
popup = ~as.character(lead)) %>%
addCircleMarkers(~x,
~y,
radius = ~zinc/100,
color ="blue",
stroke = FALSE,
fillOpacity = 0.4,
group = "zinc",
popup = ~as.character(zinc)) %>%
addLayersControl(position = "bottomleft",
baseGroups = c("OpenStreetMap",
"Esri.WorldImagery"),
overlayGroups = c("copper",
"lead",
"zinc"))
})
}
shinyApp(ui = ui, server = server)

Melt your data so that your metals are in one column and you're good to go.
Here I use library(reshape2) to do the melt.
library(sp)
library(rgdal)
library(ggmap)
library(leaflet)
library(dplyr)
library(shiny)
library(reshape2)
ui <- fluidPage(
mainPanel(
titlePanel("Metals"),
leafletOutput("all_metals")
)
)
server <- function(input,output){
output$all_metals <- renderLeaflet({
data(meuse)
coordinates(meuse) <- 1:2
proj4string(meuse) <- CRS("+init=epsg:28992")
meuse <- spTransform(meuse, CRS("+proj=longlat +datum=WGS84"))
meuse_df <- as.data.frame(meuse)
## melt df so 'metals' are in one column
## using 'reshape2' library
meuse_melt <- melt(meuse_df, measure.vars = c("copper","lead","zinc"), variable.name = "metal")
## specify factor levels for colours
meuse_melt$metal <- factor(sample.int(5L, nrow(meuse_melt), TRUE))
factpal <- colorFactor(topo.colors(5), meuse_melt$metal)
## now you just need one output
leaflet(meuse_melt) %>%
addProviderTiles("OpenStreetMap", group = "OpenStreetMap") %>%
addProviderTiles("Esri.WorldImagery", group = "Esri.WorldImagery") %>%
addCircleMarkers(~x,
~y,
radius = ~value/100,
stroke = FALSE,
fillOpacity = 0.4,
group = "meuse_melt",
popup = ~metal,
color= ~factpal(metal)) %>%
addLayersControl(position = "bottomleft",
baseGroups = c("OpenStreetMap", "Esri.WorldImagery"), overlayGroups = "meuse_melt")
})
}
shinyApp(ui = ui, server = server)

To save you lines of code you could use mapview which provides multi-layer maps out of the box. If you only want certain attributes you can simply supply their names (or column numbers) to the 'zcol' argument. Alternatively, you can use 'burst = TRUE' to display all layers/columns present in the attribute table.
library(mapview)
library(sp)
data(meuse)
coordinates(meuse) <- ~x+y
proj4string(meuse) <- CRS("+init=epsg:28992")
mapview(meuse, zcol = c("copper", "lead", "zinc"))
## all layers
mapview(meuse, burst = TRUE)
mapview can be used with renderLeaflet.

Related

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)

How to create a leaflet choropleth map of US counties

With the code below I get my dataframe with US county data
library(raster)
library(leaflet)
library(tidyverse)
# Get USA polygon data
USA <- getData("GADM", country = "usa", level = 2)
### Get data
mydata <- read.csv("https://www.betydb.org/miscanthus_county_avg_yield.csv",
stringsAsFactors = FALSE)
My object is to crate an interactive leaflet choropleth map of Avg_yield so first I fortify my USA polygon data
library(rgeos)
library(maptools)
library(ggplot2)
states.shp.f <- fortify(USA, region = "NAME_2")
Then I subset my dataset and merge it with the fortified:
mydata2<-mydata[,c("COUNTY_NAME","Avg_yield")]
colnames(mydata2)[1]<-"id"
## merge shape file with data
merge.shp.coef <- merge(states.shp.f, mydata2, by = "id")
but now I have a dataset with every county name many times and also some counties have different values of Avg_yield. Whats the proper way to process those data in order to use the leaflet code like:
leaflet() %>%
addProviderTiles("OpenStreetMap.Mapnik") %>%
setView(lat = 39.8283, lng = -98.5795, zoom = 4) %>%
addPolygons(data = USA, stroke = FALSE, smoothFactor = 0.2, fillOpacity = 0.3,
fillColor = ~mypal(mydata$Avg_yield),
popup = paste("Region: ", USA$NAME_2, "<br>",
"Avg_yield: ", mydata$Avg_yield, "<br>")) %>%
addLegend(position = "bottomleft", pal = mypal, values = mydata$Avg_yield,
title = "Avg_yield",
opacity = 1)
The propoer way to do this is to transform your polygon object into a sf object
with st_as_sf()
Here you have a working example :
(I did used some other data for the polygon, I thought yours too precise and require a lot of resources, plus I made it work with shiny)
library(leaflet)
library(tidyverse)
library(ggplot2)
library(sf)
library(shiny)
USA <- st_read(dsn = '[your path]/cb_2018_us_county_500k.shp')
### Get data
mydata <- read.csv("https://www.betydb.org/miscanthus_county_avg_yield.csv",
stringsAsFactors = FALSE)
states_sf <- st_as_sf(USA)
mydata2<-mydata[,c("COUNTY_NAME","Avg_yield")]
colnames(mydata2)[1]<-"NAME"
## merge shape file with data
states_sf_coef <- left_join(states_sf, mydata2, by = "NAME")
ui <- fluidPage(
leafletOutput("map", height = "100vh")
)
server <- function(input, output, session) {
bins <- c(0, 5, 10, 15, 20, 25, 30, 35, 40)
mypal <- colorBin("YlOrRd", domain = states_sf_coef$Avg_yield, bins = bins)
#Sortie map
output$map <- renderLeaflet({
leaflet()%>%
addProviderTiles("OpenStreetMap.Mapnik")%>%
setView(lat = 39.8283, lng = -98.5795, zoom = 4) %>%
addPolygons(
data = states_sf_coef,
fillColor = ~mypal(states_sf_coef$Avg_yield),
stroke = FALSE,
smoothFactor = 0.2,
fillOpacity = 0.3,
popup = paste("Region: ", states_sf_coef$NAME_2, "<br>",
"Avg_yield: ", states_sf_coef$Avg_yield, "<br>"))%>%
addLegend(position = "bottomleft",
pal = mypal,
values = states_sf_coef$Avg_yield,
title = "Avg_yield",
opacity = 1)
})
}
# Create Shiny app ----
shinyApp(ui = ui, server = server)

Remove specific Layers in R Leaflet

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)

Add different legends in different layers on leaflet map in R

library(leaflet)
library(htmltools)
library(htmlwidgets)
library(dplyr)
#
df1 <- data.frame(points=c("p1", "p2"), lat=c(49.47259, 49.48095), long=c(-103.7054, -103.6126), value=c(50.34, 100.25))
df2 <- data.frame(points=c("p1", "p2"), lat=c(49.47809, 49.66849), long=c(-103.5614, -103.0224), value=c(300.56, 505.34))
#
pal1 <- colorNumeric(
palette = "PRGn",
domain = df1$value
)
#
pal2 <- colorNumeric(
palette = "PRGn",
domain = df2$value
)
#
n <- leaflet() %>% addTiles(group="1st layer") %>% addTiles(group="2nd layer") %>%
addCircles(data=df1, lng=~long, lat=~lat, weight = 3, radius=250, color = ~pal1(value),
stroke = TRUE, fillOpacity = 0.8,group="1st layer") %>%
addCircles(data=df2, lng=~long, lat=~lat, weight = 3, radius=250, color = ~pal2(value),
stroke = TRUE, fillOpacity = 0.8,group="2nd layer") %>%
addLegend("bottomright", pal = pal1, values = df1$value, title = "legend_df1") %>%
addLegend("topright", pal = pal2, values = df2$value, title = "legend_df2") %>%
addLayersControl(baseGroups=c("1st layer","2nd layer"),
options=layersControlOptions(collapsed = F))
n
I want that when I click on "1st layer" then only "legend_df1" will appear and when I click on "2nd layer" then only "legend_df2" will appear and "legend_df1" will be vanished. Therefore, in each layer different legends will appear, not both legends together. Can anybody please help me out?
This is now possible with overlayGroups
library(leaflet)
df1 <- data.frame(points=c("p1", "p2"), lat=c(49.47259, 49.48095), long=c(-103.7054, -103.6126), value=c(50.34, 100.25))
df2 <- data.frame(points=c("p1", "p2"), lat=c(49.47809, 49.66849), long=c(-103.5614, -103.0224), value=c(300.56, 505.34))
pal1 <- colorNumeric(
palette = "inferno",
domain = df1$value
)
pal2 <- colorNumeric(
palette = "viridis",
domain = df2$value
)
leaflet() %>%
addProviderTiles(providers$CartoDB.DarkMatter) %>%
addCircleMarkers(data=df1, lng=~long, lat=~lat,
color = ~pal1(value),
group="group_1") %>%
addCircleMarkers(data=df2, lng=~long, lat=~lat,
color = ~pal2(value),
group="group_2") %>%
addLegend("bottomright", pal = pal1, title="grp1",
values = df1$value, group="group_1") %>%
addLegend("bottomright", pal = pal2, title="grp2",
values = df2$value, group="group_2") %>%
addLayersControl(overlayGroups = c("group_1","group_2"),
options = layersControlOptions(collapsed = FALSE))

Popup when hover with leaflet in R?

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!!

Resources