Problem: We have an area divided into regions, which are further divided into subregions.
Our Task : Create a map of the area, such that when we hover over a point,it should highight the boundary of the region and the tooltip should show the name of the subregion and region.
Solution 1 : Create a shapefile of the regions. Now when we hover over a point it will highlight the boundary of the region but the tooltip will not show the name of the corresponding subregion,it will show the name only of the region.
This is how I can do it with leaflet in R:
library(tigris)
library(dplyr)
library(leaflet)
m1 <- states()
m2 <- counties()
head(m1#data)
head(m2#data)
#Map 1
labels <- sprintf("State name : %s",
m1#data$NAME) %>% lapply(htmltools::HTML)
leaflet(data = m1) %>%
addPolygons(
highlight = highlightOptions(
weight = 5,
color = "#666",
dashArray = "",
fillOpacity = 0.7,
bringToFront = TRUE),
label = labels)
Solution 2 : Create a shapefile of the subregions. Now when we hover over a point it will highlight the boundary of the subregion and NOT the boundary of the region, but it will show the name of the corresponding region and subregion.
This is how I can do it with leaflet in R:
#Map 2
# Keep statefp and the name of the State.
m3 <- m1#data[,c(3,7)]
names(m3)[2] <- "StateName"
m2#data <- left_join(m2#data,m3,by = c("STATEFP"))
labels <- sprintf("State name : %s<br>County Name : %s",
m2#data$StateName,m2#data$NAME) %>% lapply(htmltools::HTML)
leaflet(data = m2) %>%
addPolygons(
highlight = highlightOptions(
weight = 5,
color = "#666",
dashArray = "",
fillOpacity = 0.7,
bringToFront = TRUE),
label = labels)
Query : How can we mix 1 and 2 ? how can we display the boundary of the region but the name of the subregion (and region) when we hover over a point ?
Thanks to Michael Bird for recommending to use tigris.
Related
I've been trying to map with leaflet to add addCircles() but my shapefile doesn't seem to have the latitude lat and longitude lng parameters so I got the centroids for each city as is the code below but it doesn't seem to show me the centroid points so I put in a df these values but I can't automate to get the points for n cities.
The data is here.
library(stringr)
library(leaflet)
library(sf)
library(dplyr)
quito = st_read("C:/Users/crist/Downloads/Administraciones Zonales/Administración_Zonal.shp") %>%
st_simplify(dTolerance = 1000) %>%
sf::st_transform('+init=epsg:4326')
sectores = read.csv("C:/Users/crist/Downloads/sector.csv", header = T,sep = ";", dec = ",", row.names = 1)
sectores
full_data = inner_join(quito, sectores, by = 'NOMBRE') %>%
mutate(label_map = sprintf("<strong>%s </strong><br/>Valor: %g<br/>",NOMBRE, TARIFA_PROMEDIO_POR_HAB_DISPONIBLE_...) %>% lapply(htmltools::HTML))
bins = c(0, 10, 50, 100, 150,250)
pal_quito <- colorBin("Oranges", domain = full_data$TARIFA_PROMEDIO_POR_HAB_OCUPADA_...,
bins = bins)
#I tried to do this because my shp didn't have the longitude and latitude variables
full_data$centroids <- st_transform(full_data, 29101) %>%
st_centroid() %>%
st_geometry()
lngt_q = c(-78.41782, -78.67333, -78.4823, -78.60407, -78.36822, -78.50851, -78.56278, -78.3023)
lat_q = c(-0.08668143, -0.2179538, -0.1585809, 0.09029626, -0.4124271, -0.2112893, -0.311081, -0.2025039)
full_data$lngt_q =lngt_q
full_data$lat_q =lat_q
leaflet(data = full_data) %>%
addTiles() %>%
addProviderTiles(providers$CartoDB.Positron) %>%
addPolygons(data = full_data,
color = "#444444",
weight = 1,
smoothFactor = 0.5,
fillOpacity = 0.2,
label = full_data$label_map,
fillColor = pal_quito(full_data$TARIFA_PROMEDIO_POR_HAB_OCUPADA_...),
stroke = T,
highlightOptions = highlightOptions(
weight = 5,
color = "#666666",
fillOpacity = 0.7)) %>%
addCircles(full_data$centroids, lng = lngt_q, lat = lat_q, color = "#045a8d", weight = 1, radius =1500,
fillOpacity = 0.2)
[updated]
There's a way to get the longitude and latitude of my shapefile automatically.
I think you can do this by adding the centroid geometry to your polygon layer with st_centroid.
library(stringr)
library(leaflet)
library(sf)
library(dplyr)
library(mapview) # I believe this is needed to make code above function
quito = st_read("C:/Users/Brian/Downloads/Administraciones Zonales/Administración_Zonal.shp") %>%
st_simplify(dTolerance = 1000) %>%
#logintud y latitud # this produced an error, thin it is intended as comment
sf::st_transform('+init=epsg:4326')
## Adding the centroid of each polygon as a separate geometry column. This will not be active but can be accessed as needed
quito$geom2 = st_centroid(quito)
You will get a warning indicating that the centroids won't be accurate, because you are in a geographic rather than projected coordinate system and st_centroid assumes projected geometry. I would guess this isn't going to cause problems with reasonably small sized polygons at lower or middle latitudes, but you should be aware of the potential for distortion. If you need more accuracy, you could calculate your centroids before you warp into EPSG:4326 (WGS84). If you are going this route, you probably want to create the centroids as separate points, warp them separately and either join or use the separate points as your dataset to add the circles to your map.
At this point you can continue along the script as written until the last line, when you need to specify the geom2 column we created earlier as the data source
addCircles(data = full_data$geom2, fill = TRUE, stroke = TRUE, color = "#000", fillColor = "blue", radius = 800, weight = 1) ## I increased the radius to get it to display
I don't know best practices to share the leaflet here, but static image shown
I'm trying to create a choropleth map in county level using leaflet R package and I actually do it. But when I check my data file and the hover text of any county I find that the values are not correct. For example check the Conejos county. Any explanation? Or a better way to process tha data and create this map without the mismatches?
Code:
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) %>%
dplyr::select(COUNTY_NAME, Avg_yield)
### Check counties that exist in USA, but not in mydata
### Create a dummy data frame and bind it with mydata
mydata <- data.frame(COUNTY_NAME = setdiff(USA$NAME_2, mydata$COUNTY_NAME),
Avg_yield = NA,
stringsAsFactors = FALSE) %>%
bind_rows(mydata)
### Create a color palette
mypal <- colorNumeric(palette = "viridis", domain = mydata$Avg_yield)
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)
I am working with the leaflet R package. I have a zoning system made of polygons and I'd like to lay their IDs on top of them. Below is an illustration (with another software) of my objective.
Thanks for your suggestions!
Since there is no reproducible data, I decided to use one of my previous posts related to leaflet. There are two things you want to take away from this post: 1) you need to create a data frame containing center points of target regions, 2) you need to use addLabelOnlyMarkers(). You can achieve the first thing using gCentroid(). I added row names of the polygon data set (UK) as character to centers. This is used for labeling. You need to think what labels you use in your own case. Once this data set is ready, you want to use it in addLabelOnlyMarkers().
library(raster)
library(rgeos)
library(leaflet)
# Get UK polygon data
UK <- getData("GADM", country = "GB", level = 2)
# Find a center point for each region
centers <- data.frame(gCentroid(UK, byid = TRUE))
centers$region <- row.names(UK)
### Create dummy data
set.seed(111)
mydf <- data.frame(place = unique(UK$NAME_2),
value = sample.int(n = 1000, size = n_distinct(UK$NAME_2), replace = TRUE))
### Create five colors for fill
mypal <- colorQuantile(palette = "RdYlBu", domain = mydf$value, n = 5, reverse = TRUE)
leaflet() %>%
addProviderTiles("OpenStreetMap.Mapnik") %>%
setView(lat = 55, lng = -3, zoom = 6) %>%
addPolygons(data = UK,
stroke = FALSE, smoothFactor = 0.2, fillOpacity = 0.3,
fillColor = ~mypal(mydf$value),
popup = paste("Region: ", UK$NAME_2, "<br>",
"Value: ", mydf$value, "<br>")) %>%
addLabelOnlyMarkers(data = centers,
lng = ~x, lat = ~y, label = ~region,
labelOptions = labelOptions(noHide = TRUE, direction = 'top', textOnly = TRUE)) %>%
addLegend(position = "bottomright", pal = mypal, values = mydf$value,
title = "UK value",
opacity = 0.3)
I'm trying to add multiple polygon to leaflet world map, according to a number of lists of country code. And I was trying to use R loop to add the polygon. Here's the code that I manually add polygons from list 1:
library(sp)
library(raster)
library(leaflet)
library(maps)
library(tidyverse)
countries_1 <- c('PAK','TUR','BGR')
adm1 <- getData('GADM', country='PAK', level=0)
adm2 <- getData('GADM', country= 'TUR', level=0)
adm3 <- getData('GADM', country= 'BGR', level=0)
leaflet() %>%
addTiles() %>%
addPolygons(data=adm1, weight = 3, fillColor = 'purple', color = 'purple') %>%
addPolygons(data=adm2, weight = 3, fillColor = 'purple', color = 'purple') %>%
addPolygons(data=adm3, weight = 3, fillColor = 'purple', color = 'purple')
I am thinking using the loop to add multiple polygon layers so that for list_n:
countries_n <- ('ctry1','ctry2','ctry3',...'ctryn')
for (i in country_n) {
countries <- basemap %>% addPolygons(data=getData('GADM',country = i, level = 0),
weight = 3, fillColor = 'purple', color = 'purple')
}
The question is how can I embed the loop to "leflet() %>%" ?
*Note here:
If try to add multiple data in addPolygons(), it will plot only the first element in the data, in below case, only country 'PAK' will be ploted:
addPolygons(data=c('PAK','TUR'), weight = 3, fillColor = 'purple', color = 'purple')
Here's a solution using packages sf and mapview. Note that this is currently only possible using the develop version of mapview (see commented out devtools::install_github()
# devtools::install_github("r-spatial/mapview#develop")
library(sf)
library(mapview)
library(raster)
countries_1 <- c('PAK','TUR','BGR')
dat_list = lapply(countries_1, function(i) {
st_as_sf(getData("GADM", country = i, level = 0))
})
m = leaflet() %>% addTiles()
for (i in dat_list) {
m = mapview::addFeatures(map = m,
data = i,
weight = 3,
fillColor = 'purple',
color = 'purple')
}
m
Note that addFeatures is type agnostic, so any combination of points, lines and/or polygons will work here.
How do you set the layer order in R's leaflet package so that tiles show up on top of polygons filled with color?
Here's what I've got so far:
require(leaflet)
require(acs)
require(tigris)
require(rgdal)
census.income.end.year = 2015
county = 17
nd.counties=acs.fetch(geography=geo.make(state="ND", county=county),
table.number="B01003", endyear = 2015)
tracts <- tigris::tracts(state = 'ND', county = county, cb=FALSE, year = 2015)
# create a geographic set to grab tabular data (acs)
geo<-geo.make(state=c("ND"),
county = county,
tract="*")
# add in median income
median.income <- acs.fetch(endyear = census.income.end.year,
geography = geo,
variable = c("B19013_001"))
income_df <- data.frame(paste0(as.character(median.income#geography$state),
str_pad(as.character(median.income#geography$county), 3, 'left', '0'),
str_pad(as.character(median.income#geography$tract), 5, 'left', '0')),
median.income#estimate)
rownames(income_df)<-1:nrow(income_df)
names(income_df)<-c("GEOID", "hhincome")
income_merged <- geo_join(tracts, income_df, "GEOID", "GEOID")
income_merged <- spTransform(income_merged, CRS("+init=epsg:4326"))
qpal <- colorQuantile("plasma", income_df$hhincome, n = 4)
leaflet() %>%
setView( -96.7898, 46.8772, zoom=11) %>%
addPolygons(data = income_merged,
fillColor = qpal(income_merged$hhincome),
fillOpacity = 1,
weight = 0.3) %>%
addProviderTiles(providers$Hydda.RoadsAndLabels)
Ultimately, I'ld like to do this with addTiles (instead of addProviderTiles as in the above code) using a custom MapBox, but I can't figure out how to make that reproducible for this example... given that you need a key to access custom MapBox tiles (BTW, I've created a custom MapBox tile that should be transparent except for roads and labels, so the underlying polygons should "show thru.")
Here is one way to do add a tile on top of a circle with the non-R version of leaflet: http://jsfiddle.net/dcu9pz2w/, but I don't see how to make that work in my context. I think adding "panes" may be the way to go, but I don't see that functionality in R leaflet. Also, I explored z-index values, but that seemed to be a dead end.
Any help is much appreciated!
R leaflet now includes addMapPane function. The solution to this problem is to first set up pane order and then add tiles/polygons. Reproducible example:
library(leaflet)
library(geojsonio)
# get polygon data
# https://github.com/simonepri/geo-maps/blob/master/info/countries-land.md
world <- geojson_read(
"https://github.com/simonepri/geo-maps/releases/download/v0.6.0/countries-land-10km.geo.json",
what = "sp"
)
# generate random values
world#data$value <- runif(nrow(world#data))
# get color palette
color_pal <- colorNumeric(palette = "YlOrRd", domain = NULL)
# get leaflet map
leaflet() %>%
setView(lat = 50, lng = 15, zoom = 4) %>%
addMapPane("background_map", zIndex = 410) %>% # Level 1: bottom
addMapPane("polygons", zIndex = 420) %>% # Level 2: middle
addMapPane("labels", zIndex = 430) %>% # Level 3: top
addProviderTiles(
providers$Esri.WorldTerrain,
options = pathOptions(pane = "background_map")
) %>%
addPolygons(
data = world, stroke = FALSE, smoothFactor = 0.2,
fillOpacity = 0.6, fillColor = ~color_pal(value),
options = pathOptions(pane = "polygons")
) %>%
addProviderTiles(
providers$Stamen.TonerLabels,
options = pathOptions(pane = "labels")
)