Leaflet map with R shows country completely grey - r

I am starting to become familiar with leaflet in R although I am experiencing some issues. Data works properly when I am plotting the map with ggplot2. However, I was asked to switch to a more dynamic and interactive map for a shiny dashboard. Here I report the code I performed with the image of the 'grey' results I obtained. I am plotting some Italian provincial data. I retrieved the shape file from the website of the Italian Institute of Statistics (2020, versione generalizzata). Nonetheless, I have uploaded the dataframe and the shape file also on GitHub.
library(dplyr)
library(leaflet)
library(rgdal)
library(sf)
# Import data
load('C:/[...]/data_19.rda') # <--- There are several variables, I selected just one of them
# Import Italy shapefile
ita_map = readOGR('C:/[...]/Limiti01012020_g/ProvCM01012020_g',
'ProvCM01012020_g_WGS84', stringsAsFactors = FALSE)
# Merge
colnames(data_19)[1] = "COD_PROV" # <--- This is the numerical provincial code
ita_map_sf = st_as_sf(ita_map)
ita_map_data <- left_join(ita_map_sf, data_19, by = "COD_PROV")
# Generate map with leaflet
ita_map_data %>%
st_transform(crs = 4326) %>%
leaflet() %>%
addProviderTiles("Esri.WorldGrayCanvas") %>%
setView(lat = 41.8719, lng = 12.5674, zoom = 5) %>%
addPolygons(
fillColor = ita_map_data$unilav_ula,
stroke = FALSE,
smoothFactor = 0.2,
fillOpacity = 0.3
)
Here, instead, the result I am getting from the viewer:
I guess there are some problems in the way I dealt with the polygon data frame. I hope someone could give me some hints. Thank you in advance.

See the R leaflet documentation page for plotting Choropleth Maps:
https://rstudio.github.io/leaflet/choropleths.html
You need to specify a color palette you want to use for the map.
The following code produces the output below.
library(dplyr)
library(leaflet)
library(rgdal)
library(sf)
# Import data
load('C:/[...]/data_19.rda') # <--- There are several variables, I selected just one of them
# Import Italy shapefile
ita_map = readOGR('C:/[...]/Limiti01012020_g/ProvCM01012020_g',
'ProvCM01012020_g_WGS84', stringsAsFactors = FALSE)
# Merge
colnames(data_19)[1] = "COD_PROV" # <--- This is the numerical provincial code
ita_map_sf = st_as_sf(ita_map)
ita_map_sf$COD_PROV <- as.numeric(ita_map_sf$COD_PROV)
ita_map_data <- left_join(ita_map_sf, data_19, by = "COD_PROV")
# Specify Color Palette
pal <- colorQuantile("Blues", domain = ita_map_data$unilav_ula, n=5)
# Generate map with leaflet
ita_map_data %>%
st_transform(crs = 4326) %>%
leaflet() %>%
addProviderTiles("Esri.WorldGrayCanvas") %>%
setView(lat = 41.8719, lng = 12.5674, zoom = 5) %>%
addPolygons(
fillColor = ~pal(unilav_ula),
stroke = FALSE,
smoothFactor = 0.2,
fillOpacity = 0.7,
label=~unilav_ula
)

Related

How to trouble shoot "Don't know how to get path data from object of class standardGeneric" with leaflet

I am trying to create a map showing generation capacity by county with leaflet. There can be multiple generating units per county, but I thought that would not be an issue for mapping county capacity. I pulled county geometries from tidycensus, and joined those with the dataset for county generation capacity. I have included my code below. Any help/insight would be much appreciated!
Texas_counties <- get_acs(state = "TX", geography = "county",
variables = c(totalpop = "B01003_001"), geometry = TRUE)
Texas_counties <- Texas_counties %>%
mutate(NAME = gsub(" County, Texas", "", NAME))
Texas_counties <- Texas_counties %>%
mutate(NAME = toupper(NAME))
Texas_counties$GEOID <- NULL
Texas_counties$variable <- NULL
Texas_counties$estimate <- NULL
Texas_counties$moe <- NULL
colnames(Texas_counties)[1] <- "COUNTY"
ERCOT_counties <- left_join(ERCOT_report, Texas_counties, by = "COUNTY")
pal <- colorNumeric("viridis", NULL)
leaflet(ERCOT_counties) %>%
addTiles() %>%
addPolygons(data = geometry, stroke = FALSE, smoothFactor = 0.3,
fillOpacity = 1,
fillColor = ~pal(COUNTY_CAPACITY))
Error in polygonData.default(data) : Don't know how to get path data from object of class standardGeneric
Since we don't have the contents of your ERGOT_report data frame, it's hard to know, but my guess is that you're getting that error because you're using a simple data frame and not an sf or spatial data frame in your leaflet() call.
Whenever possible, I find it easiest to have my data and spatial features together in one sf object. So here is an example of how you would get the county geometry from tigris, join it with a non-spatial data frame (I just made up some data here) and then make a map. Note when you are joining a spatial data frame and a non-spatial data frame, the order of the join matters. So if you want to output of your join to be spatial, the first data frame must be the sf object and the second is the non-spatial data frame.
library(tidyverse)
library(leaflet)
library(tigris)
library(sf)
# get county geometries using tigris
tx_counties <- counties(state = "TX", cb = TRUE) %>%
transmute(COUNTY = toupper(NAME))
# create some made up data for 50 of the tx counties
ercot_report <- tibble(
COUNTY = tx_counties$COUNTY,
COUNTY_CAPACITY = rpois(nrow(tx_counties), lambda = 10)
) %>%
slice_sample(n = 50)
# join geometry to data
ercot_counties <- tx_counties %>%
inner_join(ercot_report) %>%
st_transform(4326)
# create palette to use in leaflet map
pal <- colorNumeric(
palette = "viridis",
domain = ercot_counties$COUNTY_CAPACITY
)
# map!
leaflet(ercot_counties) %>%
addTiles() %>%
addPolygons(
stroke = FALSE,
smoothFactor = 0.3,
fillOpacity = 1,
fillColor = ~pal(COUNTY_CAPACITY)
)

Cannot visualize geojson in R using leaflet package

I would like to visualize municipalities in R using Leaflet.
This is my code:
library(leaflet)
library(jsonlite)
geojson <- readLines("https://cartomap.github.io/nl/wgs84/gemeente_2020.geojson", warn = FALSE) %>%
paste(collapse = "\n") %>%
fromJSON(simplifyVector = TRUE)
map <- leaflet() %>%
addTiles() %>%
addGeoJSON(geojson, weight = 1, color = "grey") %>%
setView(5.387740, 52.155499, zoom = 7)
map
Alas it is not working. I don't get an error message, but I don't get a map with municipality borders either. Could somebody please point out to me what I am doing wrong?
The addGeoJSON function is expecting a geojson object but jsolite::fromJSON returns a list. This should work:
library(leaflet)
library(sf)
library(geojsonsf)
url <- "https://cartomap.github.io/nl/wgs84/gemeente_2020.geojson"
sf <- st_read(url)
geojson <- sf_geojson(sf)
map <- leaflet() %>%
addTiles() %>%
addGeoJSON(geojson, weight = 1, color = "grey") %>%
setView(5.387740, 52.155499, zoom = 7)
map

Get longitude and latitude from a shapefile with Leaflet in R

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

Data mismatch between dataset and value in the leaflet map

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)

How to "addTiles" on top of "addPolygons" in R's Leaflet?

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")
)

Resources