I have different types of observations and I want to display them on leaflet using different shapes and colors. Is it possible to use diamond, triangle, star and other shapes in leaflet in R?
I have providing dummy data and created circle markers with differnt colors.
library(leaflet)
lat1= 36+runif(n=5,min=-1,max=1)
lon1 =-115+runif(n=5,min=-1,max=1)
lat2= 35+runif(n=5,min=-0.5,max=0.5)
lon2 =-110+runif(n=5,min=-0.5,max=0.5)
lat3= 34+runif(n=5,min=-0.5,max=0.5)
lon3 =-112+runif(n=5,min=-0.5,max=0.5)
data_all=rbind(data.frame(Longitude=lon1,Latitude=lat1,Group=1),
data.frame(Longitude=lon2,Latitude=lat2,Group=2),
data.frame(Longitude=lon3,Latitude=lat3,Group=3))
pal <- colorFactor(c("red","blue","purple"), domain = c(1,2,3))
leaflet(data_all) %>% addTiles() %>%
addCircleMarkers(~Longitude, ~Latitude,popup=~paste0("Group= ",data_all$Group),
radius = 10,
color = ~pal(Group),
stroke = FALSE, fillOpacity = 1
)
Here's a solution using base R plotting symbols. Basically, you create a series of temporary png files with the desired shape which you then use to represent your data according to the group.
library(leaflet)
# this is modified from
# https://github.com/rstudio/leaflet/blob/master/inst/examples/icons.R#L24
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
}
files
}
lat1= 36+runif(n=5,min=-1,max=1)
lon1 =-115+runif(n=5,min=-1,max=1)
lat2= 35+runif(n=5,min=-0.5,max=0.5)
lon2 =-110+runif(n=5,min=-0.5,max=0.5)
lat3= 34+runif(n=5,min=-0.5,max=0.5)
lon3 =-112+runif(n=5,min=-0.5,max=0.5)
data_all=rbind(data.frame(Longitude=lon1,Latitude=lat1,Group=1),
data.frame(Longitude=lon2,Latitude=lat2,Group=2),
data.frame(Longitude=lon3,Latitude=lat3,Group=3))
shapes = c(5, 6, 8) # base R plotting symbols (http://www.statmethods.net/advgraphs/parameters.html)
iconFiles = pchIcons(shapes, 40, 40, col = c("red", "blue", "purple"), lwd = 4)
leaflet(data_all) %>% addTiles() %>%
addMarkers(
data = data_all,
icon = ~ icons(
iconUrl = iconFiles[Group],
popupAnchorX = 20, popupAnchorY = 0
),
popup=~paste0("Group= ",data_all$Group)
)
Obviously, you could use other png files in addMarkers.
This solution is based on a rather hidden example from https://github.com/rstudio/leaflet/blob/master/inst/examples/icons.R#L24
Related
I have been trying for the whole day now to create a map an export it to a pdf. The problem is that I don't really understand how to either set "width" and "height" or use "fitBounds". Also I would like to crop this "Leaflet" logo at the bottom right. I tried to do a random reproducable example where I would like to only crop the blue rectangle. Any ideas?
remove(list = ls())
library(leaflet)
library(sf)
library(mapview)
### create random sf polygon
pol = st_sfc(st_polygon(list(cbind(c(0,3,3,0,0),c(0,0,3,3,0)))))
h = st_sf(r = 5, pol)
### create "map"
df <- leaflet(width = 1000, height = 1000) %>%
#fitBounds(100, 100, 100, 100) %>%
addPolygons(data = h,
color = "blue",
weight = 1,
opacity = 1,
fillOpacity = 1) %>%
setMapWidgetStyle(style = list(background = "transparent"))
### show map and export
df
mapshot(df, file = "leaflet.pdf")
I am trying to change the color of the polygons drawn using leaflet and Mapzen. The colors are clearly visible with the current tiles but not as much with others, such as the addTiles(). How should I change the argument for the three polygons?
For the code to work you must enter a mapzen key.
library(rmapzen)
library(leaflet)
Sys.setenv(MAPZEN_KEY = "mapzen-******")
#https://tarakc02.github.io/rmapzen/#introduction
ucb <- mz_geocode("Via Giovanni Spadolini 7, Milan, Italy")
isos <- mz_isochrone(
ucb,
costing_model = mz_costing$auto(),
contours = mz_contours(c(5, 10, 15)),
polygons = TRUE
)
leaflet(as_sp(isos)) %>%
addProviderTiles("CartoDB.DarkMatter") %>%
addPolygons(color = ~color, weight = 1) %>%
addLegend(colors = ~color,
labels = ~paste(contour, "minutes"),
title = "Drive times from <br/> Centro Leoni")
I realized that the polygons should be added separately and instead of:
leaflet(as_sp(isos))
Solution:
iso10 <- as_sp(mz_isochrone(
ucb,
costing_model = mz_costing$auto(),
contours = mz_contours(10),
polygons = TRUE
))
iso30 <- as_sp(mz_isochrone(
ucb,
costing_model = mz_costing$auto(),
contours = mz_contours(30),
polygons = TRUE
))
iso60 <- as_sp(mz_isochrone(
ucb,
costing_model = mz_costing$auto(),
contours = mz_contours(60),
polygons = TRUE
))
m = leaflet() %>%
addProviderTiles("CartoDB.DarkMatter") %>%
addPolygons(data = iso10, color = "red", fillColor = "red")%>%
addPolygons(data = iso30, color = "green", fillColor = "green")%>%
addPolygons(data = iso60, color = "blue", fillColor = "blue")
I used leaflet package to creates a map widget, and then added two layers with the function addMarkers(). However, I found that the points on the map change their positions when zoom in and out. The relative scripts are as following:
First, create a function pchIcons with r shapes in leaflet
pchIcons <- function(pch = 0:14, width = 30, height = 30, col = 1:15, ...) {
pchLength <- length(pch)
pchFiles <- character(pchLength)
# create a sequence of png images
for (i in seq_len(pchLength)) {
pchTempFile <- tempfile(fileext = '.png')
png(pchTempFile, width = width, height = height, bg = 'transparent')
par(mar = c(0, 0, 0, 0))
plot.new()
points(.5, .5, pch = pch[i], cex = 1.5, col = col[i], ...)
dev.off()
pchFiles[i] = pchTempFile
}
pchFiles
}
Then create a base layer with Paris' position, and add two layers, each layer represents one group.
baseLayer <- leaflet(zero) %>%
addProviderTiles("Stamen.Toner") %>%
setView(posParis[["lng"]], posParis[["lat"]], zoom = 12)
addZeroLayer <- baseLayer %>%
addMarkers(popup = paste(paste(zero$Code, zero$Ecart),
zero$Address,
sep = "<br/>"),
lng = as.numeric(zero$Long),
lat = as.numeric(zero$Lat),
icon = ~ icons(
iconUrl = pchIcons(rep(magasinEcart[1], nrow(zero)),
40,
40,
col = colorZero,
lwd = 2)
),
group = '0')
addOneLayer <- addZeroLayer %>%
addMarkers(popup = paste(paste(one$Code, one$Ecart),
one$Address,
sep = "<br/>"),
lng = as.numeric(one$Long),
lat = as.numeric(one$Lat),
icon = ~ icons(
iconUrl = pchIcons(rep(magasinEcart[2], nrow(one)),
40,
40,
col = colorOne,
lwd = 2)
),
group = '1')
Next, add UI controls to switch layers on and off with addLayersControl() and add legend with addLegend().
mapTourist <- addOneLayer %>%
addLayersControl(overlayGroups = c('0', '1'),
options = layersControlOptions(collapsed = FALSE)) %>%
addLegend("bottomright",
pal = colorFactor(brewer.pal(9, 'Set1')[3:4],
unique(magasinBaseComp$Ecart)),
values = names(magasinEcart),
title = "Ecart",
opacity = 1)
Finally, we can find that when zoom in or out, the points on map moves (as screenshots show).
Does someone know what's the problem and how could I solve it? Any idea is welcomed!
I have icons on a leaflet plot which have different colors and shapes based on some variables in my data frame. I want to include a legend on the plot that shows what each shape and color combination represents. How should I do it?
To demonstrate with dummy data:
library(leaflet)
lat1= 36+runif(n=5,min=-1,max=1)
lon1 =-115+runif(n=5,min=-1,max=1)
lat2= 35+runif(n=5,min=-0.5,max=0.5)
lon2 =-110+runif(n=5,min=-0.5,max=0.5)
lat3= 34+runif(n=5,min=-0.5,max=0.5)
lon3 =-112+runif(n=5,min=-0.5,max=0.5)
data_all=rbind(data.frame(Longitude=lon1,Latitude=lat1,Group=sample(c(16,17,18),5,replace = TRUE),condition=sample(c("red","blue","green"),5,replace = TRUE),stringsAsFactors = FALSE),
data.frame(Longitude=lon2,Latitude=lat1,Group=sample(c(16,17,18),5,replace = TRUE),condition=sample(c("red","blue","green"),5,replace = TRUE),stringsAsFactors = FALSE),
data.frame(Longitude=lon3,Latitude=lat1,Group=sample(c(16,17,18),5,replace = TRUE),condition=sample(c("red","blue","green"),5,replace = TRUE),stringsAsFactors = FALSE))
# A function to create png images for each shape and color
pchIcons = function(pch = 1, width = 30, height = 30, bg = "transparent", col = NULL, ...) {
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
}
files
}
### ---------
leaflet(data_all)%>% addTiles() %>%
addMarkers(
data = data_all,
icon = ~ icons(
iconUrl = pchIcons(pch= Group,width=40,height=40,col=condition,lwd=4),
popupAnchorX = 20, popupAnchorY = 0
))
Based on this post, using base64enc and creating fixed filenames instead of using tempfile:
# A function to create file names
filename <- function(pch,col) paste0(pch, '_', col, '.png')
# A function to create png images for each shape and color
pchIcons = function(pch = 1, width = 30, height = 30, bg = "transparent", col = NULL, ...) {
n = length(pch)
files = character(n)
# create a sequence of png images
for (i in seq_len(n)) {
f = filename(pch[i], col[i])
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
}
files
}
# A function to build the legend
build_legend <- function(){
paste(sapply(strsplit(unique(paste(data_all$Group,data_all$condition)), " "),
function(x){
paste0("<img src='data:image/png;base64,",
base64enc::base64encode(filename(x[[1]], x[[2]])),
"' width='16'; height='16'> ",
"Group=",x[[1]], " Condition=", x[[2]],
"<br/>" )}), collapse = " ")
}
# The plot
leaflet(data_all)%>% addTiles() %>%
addMarkers(
data = data_all,
icon = ~ icons(
iconUrl = pchIcons(pch= Group,width=40,height=40,col=condition,lwd=4),
popupAnchorX = 20, popupAnchorY = 0)) %>%
addControl(html = build_legend(), position = "bottomleft")
When I try to add a legend to a leaflet map for a leaflet map (using the Leaflet for R package) incorporated into a Shiny app, the legend does not show the colors of the color palette. Instead it only shows the colors specified for the NA values, in this case, white.
The app does the following:
First, it filters a set of data based on user inputs
Then it generates a choropleth map from the filtered data
This is the code I used to make the legend:
addLegend(position = "bottomleft",
pal = pal, values = shp.data()$stat.selected,
title = "Legend",
opacity = .5)
Where pal is a quantile color palette as follows
pal <-colorQuantile(c("#B2FF66","#66CC00","#4C9900","#336600","#193300"),
NULL, n = 5, na.color="#FFFFFF")
shp.data() is a reactive expression that is a shapefile filtered based on user inputs and stat_selected is the specific statistic that the user selects for mapping onto colors.
I get the following warnings:
Warning in is.na(x) :
is.na() applied to non-(list or vector) of type 'NULL'
Warning in is.na(values) :
is.na() applied to non-(list or vector) of type 'NULL'
I initially tried to make the legend following the example on the leaflet for R page and used the argument values = ~stat.selected for the addLegend function, but I got this error:
Error in UseMethod("doResolveFormula") :
no applicable method for 'doResolveFormula' applied to an object of class "NULL"
Earlier I had just a simple snippet that showed how to add legends. I did not use the ~ before the legend values as is the norm. I did the traditional dataframe$column and it works nicely.
This is now updated to see how it all fits together. Here is a full-fledged mapping run after creating all of the variable cuts, etc. The final cleansed data frame was called zipData
# create a full popup
# add some HTML for editing the styles
zipData$popUp <- paste('<strong>',zipData$Street, '</strong><br>',
'TIV = $',prettyNum(zipData$tiv, big.mark = ',',preserve.width = 'none'), '<br>',
'City: ', zipData$city, '<br>',
'YrBuilt = ', zipData$YearBuilt, '<br>',
'Construction = ', zipData$ConstructionCode, '<br>',
'Occupancy = ', zipData$OccupancyCode, '<br>',
'Premium = $' , prettyNum(zipData$Premium, big.mark = ',',preserve.width = 'none') , '<br>',
'GrossArea = ', prettyNum(zipData$GrossArea, big.mark = ',', preserve.width = 'none'), '<br>',
'RoofYr = ', zipData$RoofYearBuilt, '<br>')
# set color scale for key factor
colorsConst <- colorFactor(rainbow(4), zipData$ConstructionCode)
# color scales for numerical bins
colorstivValue <- colorFactor(palette = 'Accent', zipData$tivValueLvl)
colorsYrBuilt <- colorFactor(palette = 'Spectral', zipData$yrBuiltLvl)
colorsRoofYrBuilt <- colorFactor(palette = "YlOrRd", zipData$roofYrBuiltLvl)
# begin the leaflet map construction
# create the map opbject
m <- leaflet() %>%
addTiles() %>%
# add different tiles for different color schemes
addProviderTiles(providers$OpenStreetMap, group = 'Open SM') %>%
addProviderTiles(providers$Stamen.Toner, group = 'Toner') %>%
addProviderTiles(providers$CartoDB.Positron, group = 'CartoDB') %>%
addProviderTiles(providers$Esri.NatGeoWorldMap, group = 'NG World') %>%
setView(lng = -90, lat = 30, zoom = 10) %>%
##############################
# this section is for plotting the variables
# each variable below is a layer in the map
# construction
addCircleMarkers(data = zipData, lat = ~Lat, lng = ~Lon,
color = ~colorsConst(ConstructionCode), popup = zipData$popUp,
radius = 5, group = 'Construction') %>%
# tiv
addCircleMarkers(data = zipData, lat = ~Lat, lng = ~Lon,
color = ~colorstivValue(tivLvl), popup = zipData$popUp,
radius = ~tiv/20000, group = 'Bldg Value') %>%
# year built
addCircleMarkers(data = zipData, lat = ~Lat, lng = ~Lon,
color = ~colorsYrBuilt(yrBuiltLvl), popup = zipData$popUp,
radius = ~YearBuilt/250, group = 'Yr Built') %>%
######################################
# layer control
addLayersControl(
baseGroups = c('Open SM', 'Toner', 'Carto DB', 'NG World'),
overlayGroups = c('Construction',
'TIV',
'Yr Built'
),
options = layersControlOptions(collapsed = F)
) %>%
#################################################
add the legends for each of the variables
# construction
addLegend('bottomright', pal = colorsConst, values = zipData$ConstructionCode,
title = 'Construction Code',
opacity = 1) %>%
# tiv
addLegend('bottomleft', pal = colorstivValue, values = zipData$tivLvl,
title = 'TIV',
opacity = 1) %>%
# year built
addLegend('topleft', pal = colorsYrBuilt, values = zipData$yrBuiltLvl,
title = 'Yr Built',
opacity = 1)
m # Print the map
A portion of the map is shown below.
I was able to make the colors showing up by changing the way I was referencing the values column in the arguments of the AddLegend function. I put the stat.selected variable in double brackets, which seemed to fix the problem:
addLegend(position = "bottomleft",
pal = pal, values = shp.data()[[stat.selected]],
title = "Legend",
opacity = 1
)
For clarification, the stat.selected variable comes from the following switch statement:
stat.selected <- isolate(switch(input$var.stat,
"Total employment" = "tot_emp",
"Mean annual wage" = "a_mean",
"Mean hourly wage" = "h_mean",
"Location quotient" = "loc_quotient"
)
where "tot_emp", "a_mean", "h_mean", and "loc_quotient" are column names in the shp.data spatial polygons data frame.
I guess the problem was that I was trying to pass in the column name by variable using a $.
I'm still a fairly novice R user, so if anyone can explain why the example in the Leaflet for R documentation does not work in this case I would appreciate it.
I had the same message
Error in UseMethod("doResolveFormula") : no applicable method for 'doResolveFormula' applied to an object of class "NULL"
with
data <- data.frame(lng1 = c(1, 2, 3),
lng2 = c(2, 3, 4),
lat1 = c(1, 2, 3),
lat2 = c(2, 3, 4),
values = c(1, 2, 3))
pal_grid <- colorNumeric(palette = "YlGn", domain = data$values)
leaflet() %>%
addRectangles(lng1 = data$lng1, lat1 = data$lat1,
lng2 = data$lng2, lat2 = data$lat2,
fillColor = ~pal_grid(data$values),
fillOpacity = 0.2,
weight = 2, opacity = 0.5)
The solution is to provide to leaflet the data that you are using to create the element in the main call to leaflet() or in the call to any element that you add after that.
In the main call to leaflet():
data <- data.frame(lng1 = c(1, 2, 3),
lng2 = c(2, 3, 4),
lat1 = c(1, 2, 3),
lat2 = c(2, 3, 4),
values = c(1, 2, 3))
pal_grid <- colorNumeric(palette = "YlGn", domain = data$values)
leaflet(data = data) %>%
addRectangles(lng1 = data$lng1, lat1 = data$lat1,
lng2 = data$lng2, lat2 = data$lat2,
fillColor = ~pal_grid(data$values),
fillOpacity = 0.2,
weight = 2, opacity = 0.5)
At the moment of add elements:
data <- data.frame(lng1 = c(1, 2, 3),
lng2 = c(2, 3, 4),
lat1 = c(1, 2, 3),
lat2 = c(2, 3, 4),
values = c(1, 2, 3))
pal_grid <- colorNumeric(palette = "YlGn", domain = data$values)
leaflet() %>%
addRectangles(data = data,
lng1 = data$lng1, lat1 = data$lat1,
lng2 = data$lng2, lat2 = data$lat2,
fillColor = ~pal_grid(data$values),
fillOpacity = 0.2,
weight = 2, opacity = 0.5)`