Add Icons to Layer Control in Leaflet R - r

how to add icons to the layer control in package Leaflet R?.
I made icons with the following code:
rojos <- makeAwesomeIcon(icon='ion-waterdrop', library='ion', markerColor = 'red', iconColor = 'white')
verdes <- makeAwesomeIcon(icon='ion-waterdrop', library='ion', markerColor = 'green', iconColor = 'white')
and with the following code I made the map
agua <-leaflet(options = leafletOptions(zoomControl = TRUE,
minZoom = 10, maxZoom = 17,
dragging = TRUE))%>%
addTiles()%>%
setView(-101.145,19.793, 10) %>%
# MAPAS BASE
addProviderTiles(providers$OpenStreetMap.BlackAndWhite, group = "Calles") %>%
addProviderTiles(providers$Esri.WorldImagery, group = "Imagen satelital") %>%
###########################################################################################################
addGeoJSONv2(
jsonlite::toJSON(rojo),
markerType="marker",
markerIcons = rojos,
popupProperty='popup',
labelProperty='NOMBRE DEL CUERPO DE AGUA',
group = "Agua contaminada") %>%
addGeoJSONv2(
jsonlite::toJSON(verde),
markerType="marker",
markerIcons = verdes,
popupProperty='popup',
labelProperty='NOMBRE DEL CUERPO DE AGUA',
group = "Agua no contaminada") %>%
#POLIGONOS
addPolygons(data = cuitzeo, col="green",fillColor="Transparent", group = "Cuenca de Cuitzeo",
weight = 3, opacity = 1)%>%
addPolygons(data = pol_mor, col="#000000",fillColor="Transparent",
group = "Límite Municipal Morelia",
weight = 2, opacity = 1, fillOpacity = .8) %>%
# CONTROL DE CAPAS
addLayersControl(
baseGroups = c("Calles","Imagen satelital"),
overlayGroups = c("Agua contaminada","Agua no contaminada","Cuenca de Cuitzeo","Límite Municipal Morelia"),
options = layersControlOptions(collapsed = F)
)
the result of this is the following:
I would like to get something of this style, but with my icons:

There is a relatively easy way to do this that uses the functionality of leaflet in r and doesn't rely on custom javascript controls: include html tags in your group names.
Instead of naming a group: "Group A", name it:
<div style='position: relative; display: inline-block' class='awesome-marker-icon-blue awesome-marker'>
<i class='glyphicon glyphicon-glass icon-black '></i>
</div>
Group A
You could create this name programmatically fairly easily based on an icon name for example. Only a few things change in each name: the colors, the library (fa, ion, glyphicon), the icon class (eg: fa-glass, ion-checkmark, glyphicon-fire), and the displayed group name.
This approach creates a layer control that looks like what you want:
To make things easier, store the names in a named list/vector and use that to define the groups when appending layers and again when defining which groups should be in the control. Here's a basic example:
library(leaflet)
IconSet <- awesomeIconList(
"Cruise Ship" = makeAwesomeIcon(icon= 'glass', markerColor = 'blue', iconColor = 'black', library = "glyphicon"),
"Pirate Ship" = makeAwesomeIcon(icon= 'fire', markerColor = 'black', iconColor = 'white', library = "glyphicon")
)
# Some fake data
df <- sp::SpatialPointsDataFrame(
cbind(
(runif(20) - .5) * 10 - 90.620130, # lng
(runif(20) - .5) * 3.8 + 25.638077 # lat
),
data.frame(type = factor(
ifelse(runif(20) > 0.75, "Pirate Ship", "Cruise Ship"),
c("Cruise Ship", "Pirate Ship")
))
)
# group names:
groups <- c("Cruise Ship" <- "<div style='position: relative; display: inline-block' class='awesome-marker-icon-blue awesome-marker'><i class='glyphicon glyphicon-glass icon-black '></i></div>Cruise Ship",
"Pirate Ship" <- "<div style='position: relative; display: inline-block' class='awesome-marker-icon-black awesome-marker'><i class='glyphicon glyphicon-fire icon-white '></i></div>Pirate Ship")
leaflet(df) %>% addTiles() %>%
addAwesomeMarkers(icon = ~IconSet[type], group=~groups[type]) %>%
addLayersControl(
overlayGroups = groups,
options = layersControlOptions(collapsed = FALSE)
)
Again, if working a few layers, or dynamic layers, it shouldn't be too hard to create a function that takes the icon data and makes a corresponding name to be used later, as opposed to hard coding the names above.
Regardless, this should be usable as a way to implement icons in controls.

Related

Leaflet map crashes on recoloring after translation (Shiny, Leaflet, shiny.i18n)

I'm currently trying to make a Shiny app for Leaflet cards with simple translations. Each leaflet card has several base groups that are linked to different variables. To avoid re-rendering the leaflet maps every time the base group changes, I have adopted a function I found here which only changes the fill of the polygons.
As long as I only use one language, the app works without problems, but when multiple translations options are implemented, the app crashes. The problem seems to occur when I try to link input$map_groups to variables needed for colouring.
My code looks like this:
library(shiny)
library(shinyWidgets)
library(leaflet)
library(sf)
library(dplyr)
library(shiny.i18n)
#--- Loading Generic Shape File For Demonstration
shape <- st_read(system.file("shape/nc.shp", package = "sf"),
stringsAsFactors = FALSE) %>%
#--- Mutating Two Variables To Factors As My Map Uses Factors
mutate(One = as.factor(SID74), Two = as.factor(SID79)) %>%
#--- Keep Just This Three Variables
select(c(CNTY_ID, One, Two))
#--- Color Palette For Filling Polygons
scale.color <- colorFactor(palette = "RdYlBu", levels = seq(1:60))
#--- Loading And Rgistering Translation File
lang <- Translator$new(translation_json_path = "./translations.json")
lang$set_translation_language("gb")
language <- c("English", "Deutsch", "Français" , "Español")
#--- Naming Vector For Base Groups And Related Variables
layer_calls <- setNames(c('One', 'Two'), c("First", "Second"))
#--- A Function For Recoloring An Existing Polygon And Related JS-Code
#----- Source: https://github.com/rstudio/leaflet/issues/496#issuecomment-650122985
setShapeStyle <- function(map, data = getMapData(map), layerId, stroke = NULL, color = NULL, weight = NULL,
opacity = NULL, fill = NULL, fillColor = NULL, fillOpacity = NULL, dashArray = NULL,
smoothFactor = NULL, noClip = NULL, options = NULL){
options <- c(list(layerId = layerId),
options,
filterNULL(list(stroke = stroke, color = color, weight = weight, opacity = opacity,
fill = fill, fillColor = fillColor, fillOpacity = fillOpacity,
dashArray = dashArray, smoothFactor = smoothFactor, noClip = noClip)))
# Evaluate All Options
options <- evalFormula(options, data = data)
options <- do.call(data.frame, c(options, list(stringsAsFactors = FALSE)))
layerId <- options[[1]]
style <- options[-1] # drop layer column
leaflet::invokeMethod(map, data, "setStyle", "shape", layerId, style);
}
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)){ // in case a single layerid is given
layerId = [layerId];
}
//convert columnstore to row store
style = HTMLWidgets.dataframeToD3(style);
//console.log(style);
layerId.forEach(function(d,i){
var layer = map.layerManager.getLayer(category, d);
if (layer){ // or should this raise an error?
layer.setStyle(style[i]);
}
});
};
'
)))
#--- Defining UI
ui <- fluidPage(
leafletjs,
usei18n(lang),
pickerInput(inputId = 'selected_language', width = 125,
choices = c("gb", "de", "fr", "es"),
selected = lang$get_key_translation()),
leafletOutput("map")
)
#--- Defining Server Logic
server <- function(input, output, session){
output$map <- renderLeaflet({
leaflet(data = shape) %>%
#--- Initial Unfilled Polygon Map
addPolygons(layerId = ~CNTY_ID, stroke = TRUE, color = "white", weight = 1.25,
highlightOptions = highlightOptions(stroke = 5, weight = 10)) %>%
#--- Initial Layer Controls
addLayersControl(baseGroups = lang$t(names(layer_calls)))
})
#--- Filling Polygons Based On Base Layer-Variable After Translation
observe({
req(input$selected_language)
update_lang(session, input$selected_language)
leafletProxy("map", data = shape) %>%
#--- This Part Always Crashes Shiny!!!
setShapeStyle(layerId = ~CNTY_ID, fillOpacity = 1)#, fillColor = ~scale.color(get(layer_calls[lang$t(input$map_groups)])))
})
}
# Run the application
shinyApp(ui = ui, server = server)
My basic translation scheme would be provided by a JSON file which looks like this:
{
"languages": [
"gb",
"de",
"fr",
"es"
],
"translation": [
{
"gb": "First",
"de": "Erste",
"fr": "Premier",
"es": "Primera"
},
{
"gb": "Second",
"de": "Zweite",
"fr": "Deuxième",
"es": "Segundo"
}
]
}
In my One-Langue-App I can simply use , fillColor = ~scale.color(get(layer_calls[[input$map_groups]])) to trigger a recoloring after the base group has been changed. Unfortunately, I have no idea how to connect the selected base group to a call of the needed variable to trigger the recoloring. Any kind of help is greatly appreciated!

How to set custom color in AddTimeLine

I am trying to create a time line plot using leaflet and leaftime packages. I want to set custom color in addTimeline to specify each point to his groups, as follows:
library(leaflet)
library(leaftime)
library(geojsonio)
power_d <- data.frame(
"Latitude" = c(
33.515556, 38.060556, 47.903056, 49.71, 49.041667, 31.934167,
54.140586, 54.140586, 48.494444, 48.494444
),
"Longitude" = c(
129.837222, -77.789444, 7.563056, 8.415278, 9.175, -82.343889,
13.664422, 13.664422, 17.681944, 17.681944
),
"start" = seq.Date(as.Date("2015-01-01"), by = "day", length.out = 10),
"end" = seq.Date(as.Date("2015-01-01"), by = "day", length.out = 10) + 1,
color_temp=rep(c("red","blue","green"),len=10)
)
power_geo <- geojsonio::geojson_json(power_d ,lat="Latitude",lon="Longitude")
leaflet() %>%
addTiles() %>%
setView(44.0665,23.74667,2) %>%
addTimeline(data = power_geo,
timelineOpts = timelineOptions(
styleOptions = styleOptions(
radius = 5,
color=color_temp,
fillColor = color_temp,
fillOpacity = 1
)
)
)
Unfortunately I got following error:
Error in lapply(x, f) : object 'color_temp' not found
I also try replacing color_temp with power_d$color_temp, the code run without error, but the color of points do not change. The color arguments not work in above code, why? and how to fix it?
It doesn't seem as if you can pass a vector of colours with the standard styleOptions, however, an example from the help page for ?addTimeline show how you can add colours based on the data using a little JavaScript (which thankfully is provided in the example).
Using the example that starts "# to style each point differently based on the data" you need to change it slightly to point to your colour vector e.g. change data.properties.color to data.properties.color_temp. Running the code below leads to
# code
leaflet(power_geo) %>%
addTiles() %>%
setView(44.0665,23.74667,2) %>%
addTimeline(
timelineOpts = timelineOptions(
styleOptions = NULL,
pointToLayer = htmlwidgets::JS(
"
function(data, latlng) {
return L.circleMarker(
latlng,
{
radius: 25,
color: data.properties.color_temp,
fillColor: data.properties.color_temp,
fillOpacity: 1
}
);
}
"
)
)
)

Repeating values on map:leaflet map

I am trying to make a map using leaflet. I uploaded a shapefile of 216 districts. I also have a dataset with information from 7 out the 216 districts.
I was hoping for the map to have districts that don't have values or 0% in grey saying not enough information". While having districts with actual values (>0%) showing up as colour following their corresponding bins.
When I tried to do upload my dataset and shapfile, I got a map with coloured districts everywhere. Based on my dataset, there are suppose to be 4 districts (>0%) in colour. But this is not what I see on my map.
How do I make sure that only the districts in my dataset light up where it is suppose to light up, without repeating all over the map? (while maintaining the backdrop of all the other districts in grey)
So far this is the code I used to achieved the map:
districtsg <-readOGR("sample/copyfile/Districts/Map_of_Districts_.shp")
districtsg <- sp::spTransform(districtsg, CRS("+proj=longlat +datum=WGS84"))
wpnew <- wpnew [order(match(wpnew$District,districtsg$NAME)),]
bins <- c(0.1,2.0,5.0,10.0,25.0,40.0,50.0)
pal<- colorBin("YlOrRd",domain=wpnew$per.content,bins=bins)
m<- leaflet() %>%
setView(lng = -1.0232,lat=7.9465,zoom = 6) %>%
addProviderTiles(providers$Stamen.Toner) %>%
addPolygons(data =districtsg,
weight = 1,
smoothFactor = 0.5,
color = "White",
fillOpacity = 0.8,
fillColor= ~pal(wpnew$per.content),
highlight = highlightOptions(
weight = 5,
color = "#666666",
dashArray = "",
fillOpacity = 0.7,
bringToFront = TRUE
))
m
labels <- paste( "<p>","District:", districtsg$NAME,"</p>",
"<p>", "% of reports that are content:",round(wpnew$per.content,digits = 3),"</p>",
"<p>", "Total reports labelled as a content:",round(wpnew$totalcontent,digits = 3),"</p>",
"<p>", "Total reports from this district:",round(wpnew$totalreports,digits = 3),"</p>",sep = "" )
m<- leaflet() %>%
setView(lng = -1.0232,lat=7.9465,zoom = 6) %>%
addProviderTiles(providers$Stamen.Toner) %>%
addPolygons(data =districtsg,
weight = 1,
smoothFactor = 0.5,
color = "White",
fillOpacity = 0.8,
fillColor= pal(wpnew$per.content),
label = lapply(labels,HTML)) %>%
addLegend(pal=pal,
values = wpnew$per.content,
opacity = 0.7,
"topright")
m
districts totalreports totalcontent per.content
1 Jomoro 4 2 50.00000
2 Ellembelle 2 1 50.00000
3 Tarkwa Nsuaem 1 0 0.00000
4 Bia West 1 0 0.00000
5 Bodi 2 0 0.00000
6 Accra Metropolis 3 1 33.33333
7 Adenta 3 1 33.33333
shapefile can be downloaded here:
https://data.gov.gh/dataset/shapefiles-all-districts-ghana-2012-216-districts
I handling the joining of shape file and the data file differently and I create my base map using tmap. but perhaps this will be helpful.
library(rgdal)
library(tmap)
library(leaflet)
####Access shape map
elem <- readOGR(dsn = "Data/P3Map", layer = "Boundary___ES")
####Preschool Status for Elementary Schools####
schoolAdresses_PK_2021 <- read_excel("Data/P3Map/schoolAdresses_PK_2021.xlsx") %>%
mutate(PreK= factor(PreK)) %>%
clean_names("lower_camel") %>%
mutate(programType = factor(programType))
##### Merge shape with PreK info######
map <- merge(elem, by.x = "ES_Name", schoolAdresses_PK_2021, by.y = "esName" )
#### Render Map####
MyColors <- c('#e2a331', '#d3d3d3','#3688c8') #yellow, #grey, #blue
PKMap <- tm_shape(map)+
tm_fill(col="preK",
title = " ",
palette = MyColors)+
tm_shape(JeffcoMap)+
tm_borders(col = "white")+
tm_layout("Jeffco PreK Expansion 2019-2020", legend.text.size = -0.5)+
tm_text(text = "ES_ShortNa", size = 0.5, group = "Site Names")
PKMap %>% tmap_leaflet() %>%
setView(lng = -105.10033, lat = 39.6, zoom =9) %>% #lat and long of my district
addProviderTiles('Esri.WorldGrayCanvas', group='Grayscale Map') %>%
addProviderTiles('OpenStreetMap', group='Street Map') %>%
addMarkers(lng = -105.155927, #add marker for PK detached from elementary
lat = 39.746347,
icon = YellowIcon,
label = "Litz",
popup = "<b>Program type:</b><br>Ext. Day",
popupOptions = labelOptions(direction = "bottom",
textsize = "8px"),
group = "Stand alone PreK")
from here you can add leaflet layers
It's tough without your data, but I hope this is helpful. In my case, I am mapping 95 elementary schools in one district.
Your 'districtsg' = My 'elem'
Your 'wpnew' = My 'map'
Example map
Here is my attempt while using your datasets:
library(rgdal)
library(tmap)
library(leaflet)
library(sp)
districtsg <-readOGR('data/Map_of_Districts_216.shp')
wpnew <- read.csv('data/dataFromStack.csv')
map <- sp::merge(x = districtsg, y = wpnew, by = "NAME")
MyColors <- c('#e2a331', '#d3d3d3','#3688c8') #yellow, #grey, #blue
tm_shape(map)+
tm_fill(col="totalcontent",
title = " ",
palette = MyColors)+
tm_shape(districtsg)+
tm_borders(col = "white")
Here is the result that I get.. It does take a moment to render in the R Studio Viewer

Add two addLayersControl to one map (have markers be in more than one group)

I have a dataset that includes both a date and a species for each bird observed in a county. I've mapped them using leaflet, but want to use two AddLayersControl to control for both the date and the species. Right now I can only control for the year or the species. I would like the second group of checkboxes so I can control the species as well. I want the marker to go away if either its year group is unchecked or its species group is unchecked.
What I think I need to do is to assign each marker to two different groups that I could control independently. I don't think I am able to assign certain markers as base layers because I don't want a certain subset of them always available. I have also tried just adding another AddLayersControl - sadly the second one will always win and it doesn't seem like you can have two on the same map.
library(leaflet)
library(magrittr)
library(dplyr)
library(htmltools)
# Data
birds <- data.frame(observed_on = c("4/4/2009",
"4/1/2009",
"3/6/2016",
"2/9/2016"),
url = c("http://www.inaturalist.org/observations/2236",
"http://www.inaturalist.org/observations/2237",
"http://www.inaturalist.org/observations/2778201",
"https://www.inaturalist.org/observations/9796150"),
latitude = c(43.08267975,
43.0844841,
43.055512,
43.0180932),
longitude = c(-89.43265533,
-89.43793488,
-89.314878,
-89.52836138),
scientific_name = c("Agelaius phoeniceus",
"Bubo virginianus",
"Quiscalus quiscula",
"Strix varia"),
common_name = c("Red-winged Blackbird",
"Great Horned Owl",
"Common Grackle",
"Barred Owl"),
taxon_order_name = c("Passeriformes",
"Strigiformes",
"Passeriformes",
"Strigiformes"),
taxon_species_name = c("Agelaius phoeniceus",
"Bubo virginianus",
"Quiscalus quiscula",
"Strix varia" ),
year = c("2009", "2009", "2016", "2016"))
# Leaflet Chart Formatting --------------------------------------------------------
palette <- colorFactor(palette = rainbow(length(unique(birds$taxon_order_name))),
domain = birds$taxon_order_name)
# Leaflet Chart -------------------------------------------------------------------
mymap <- leaflet(birds) %>%
addProviderTiles(providers$CartoDB.Positron) %>%
setView(lng = -89.398721,
lat = 43.071580,
zoom = 13)
for (t in unique(birds$year)){
sub <- birds[birds$year == t,]
labels <- mapply(function(x, y, z, a) {
HTML(sprintf("%s<br><em>%s</em><br>%s<br><a href=%s>link</a>",
htmlEscape(x),
htmlEscape(y),
htmlEscape(z),
htmlEscape(a)))},
sub$common_name,
sub$taxon_species_name,
sub$observed_on,
sub$url,
SIMPLIFY = FALSE)
mymap <- mymap %>%
addCircleMarkers(data = sub,
lng = ~longitude,
lat = ~latitude,
fillOpacity = 0.6,
radius = 8,
fillColor = ~palette(taxon_order_name),
color = "black",
weight = 1,
opacity = 0.5,
popup = labels,
group = as.character(t))
}
mymap %>%
addLegend(pal = palette,
values = ~taxon_order_name,
title = "Taxon Order") %>%
addLayersControl(overlayGroups = as.character(unique(birds$year)),
options = layersControlOptions(collapsed = FALSE))
# addLayersControl(overlayGroups = unique(birds$taxon_order_name), options = layersControlOptions(collapsed = FALSE))
map showing points with both year and species info but layers control for the only year
does this work?
addLayersControl(overlayGroups = as.character(c(unique(birds$year),unique(birds$taxon_order_name)), options = layersControlOptions(collapsed = FALSE))

R Leaflet choroplete map with timeslider?

I got time related data (7 years) displayed in a choropleth map, using R and Leaflet-for-R-package. Therefore use a kmz-file for geometry and csv data for attributes. So far I tried it with data for 2 years, using this tutorial:
http://journocode.com/2016/01/28/your-first-choropleth-map/
Following the example, I used my data instead of the given one in the tutorial. Everything worked fine. But longterm, I want to add all my
7 years data, therefore it would be useful to replace the radio button-based layer control by a (time)slider - changing the overlays according to the year.
In a comparable case here on stackoverflow, someone worked with geojson-files as geometry in order to use the timeslider plugin for Leaflet:
Leaflet slider group by year
So do I need to change my geom data into geojson as well?
And do so, how I link my csv-data to geojson and will R be able to cover all?
I hope you might have some suggestions...
https://github.com/Pippo87/R-leaflet-choropleth
Here is my R-script:
library(rgdal)
berlin <- readOGR("LOR-Planungsraeume.kml","LOR_Planungsraum", encoding="utf-8")
plot(berlin)
Auslaender2007 <- read.csv("LOR_Auslaender_2007.csv", encoding="latin1", sep=",", dec=".")
Auslaender2008 <- read.csv("LOR_Auslaender_2008.csv", encoding="latin1", sep=",", dec=".")
library(leaflet)
palette <- colorBin(c('#fef0d9',
'#fdd49e',
'#fdbb84',
'#fc8d59',
'#e34a33',
'#b30000'),
Auslaender2008$ANTEIL, bins = 6, pretty=TRUE, alpha = TRUE)
popup2007 <- paste0("<strong>Auslaender 2007</strong></span>",
"<br><strong>LOR </strong></span>",
Auslaender2007$LORNAME,
"<br><strong> Relativer Auslaenderanteil </strong></span>",
Auslaender2007$ANTEIL
,"<br><strong>Absoluter Auslaenderanteil</strong></span>",
Auslaender2007$AUSLAENDER)
popup2008 <- paste0("<strong>Auslaender 2007</strong></span>",
"<br><strong>LOR </strong></span>",
Auslaender2008$LORNAME,
"<br><strong> Relativer Auslaenderanteil </strong></span>",
Auslaender2008$ANTEIL
,"<br><strong>Absoluter Auslaenderanteil</strong></span>",
Auslaender2008$AUSLAENDER)
mymap <- leaflet() %>%
addProviderTiles("Esri.WorldGrayCanvas", options = tileOptions(minZoom=10, maxZoom=16)) %>%
addPolygons(data = berlin,
fillColor = ~palette(Auslaender2007$ANTEIL),
fillOpacity = 1,
color = "darkgrey",
weight = 1.5,
group="<span style='font-size: 11pt'><strong>2007</strong></span>")%>%
addPolygons(data = berlin,
fillColor = ~palette(Auslaender2008$ANTEIL),
fillOpacity = 1,
color = "darkgrey",
weight = 1.5,
popup = popup2008,
group="<span style='font-size: 11pt'><strong>2008</strong></span>")%>%
addLayersControl(
baseGroups = c("<span style='font-size: 11pt'><strong>2007</strong></span>", "<span style='font-size: 11pt'><strong>2008</strong></span>"),
options = layersControlOptions(collapsed = FALSE))%>%
addLegend(position = 'topleft', pal = palette, values = Auslaender2008$ANTEIL, opacity = 1, title = "Relativer<br>Auslaenderanteil")
print(mymap)

Resources