I need to label several overlapping polygons, but only the label of the biggest one is shown. However when I tested with some simulated data the labels were shown correctly. I compared the data in two cases carefully but cannot find the difference caused the problem.
Here is a minimal example of simulated overlapping polygons:
library(leaflet)
library(sp)
poly_a <- data.frame(lng = c(0, 0.5, 2, 3),
lat = c(0, 4, 4, 0))
poly_b <- data.frame(lng = c(1, 1.5, 1.8),
lat = c(2, 3, 2))
pgons = list(
Polygons(list(Polygon(poly_a)), ID="1"),
Polygons(list(Polygon(poly_b)), ID="2")
)
poly_dat <- data.frame(name = as.factor(c("a", "b")))
rownames(poly_dat) <- c("1", "2")
spgons = SpatialPolygons(pgons)
spgonsdf = SpatialPolygonsDataFrame(spgons, poly_dat, TRUE)
leaflet() %>% addPolygons(data = spgonsdf, label = ~name
# ,
# highlightOptions = highlightOptions(
# color = "red", weight = 2,bringToFront = TRUE)
)
It's working properly:
However it didn't work with my data.
https://github.com/rstudio/leaflet/files/1430888/Gabs.zip
You can drag the zip into this site and use the i button to see it's correctly labeled
library(rgdal)
# download Gabs.zip and extract files to Gabs folder
hr_shape_gabs <- readOGR(dsn = 'Gabs', layer = 'Gabs - OU anisotropic')
hr_shape_gabs_pro <- spTransform(hr_shape_gabs,
CRS("+proj=longlat +datum=WGS84 +no_defs"))
leaflet(hr_shape_gabs_pro) %>%
addTiles() %>%
addPolygons(weight = 1, label = ~name)
Only the biggest polygon label is shown:
The data in both case are SpatialPolygonsDataFrame, the data slot have proper polygon names.
Change the order of polygons in hr_shape_gabs: polygon in position 3 should be the smaller one.
library(leaflet)
library(sp)
library(rgdal)
hr_shape_gabs <- readOGR(dsn = 'Gabs - OU anisotropic.shp',
layer = 'Gabs - OU anisotropic')
# Change the position of the smaller and wider polygons
# Position 1 = wider polygon, position 3 = smaller polygon
pol3 <- hr_shape_gabs#polygons[[3]]
hr_shape_gabs#polygons[[3]] <- hr_shape_gabs#polygons[[1]]
hr_shape_gabs#polygons[[1]] <- pol3
hr_shape_gabs$name <- rev(hr_shape_gabs$name)
hr_shape_gabs_pro <- spTransform(hr_shape_gabs,
CRS("+proj=longlat +datum=WGS84 +no_defs"))
leaflet() %>%
addTiles() %>%
addPolygons(data= hr_shape_gabs_pro, weight = 1, label = ~name)
Here's a scalable solution in sf for many layers, based on this answer.
The idea is to order the polygons by decreasing size, such that the smallest polygons plot last.
library(sf)
library(dplyr)
# calculate area of spatial polygons sf object
poly_df$area <- st_area(poly_df)
poly_df <- arrange(poly_df, -area)
# view with labels in leaflet to see that small polygons plot on top
leaflet(poly_df) %>% addTiles() %>% addPolygons(label = ~id)
Apologies for the lack of reproducibility. This is more of a concept answer.
Related
I would like to be able to find the centre point between two markers on a map (example below). Is there a function in leaflet or in another package that allows this? Thank you in advance
coor_zone6 <- c(3.16680, 3.16176, 42.46667, 42.46997)
matrice_coord_zone6 <- matrix(coor_zone6, nrow=2, ncol = 2)
colnames(matrice_coord_zone6) <- c("long", "lat")
matrice_coord_zone6 <- data.frame(matrice_coord_zone6)
matrice_coord_zone6$name <- c("M_1","M_3")
leaflet(matrice_coord_zone6) %>%
addMouseCoordinates(epsg = NULL, proj4string = NULL, native.crs = FALSE) %>%
addProviderTiles("Esri.WorldImagery") %>%
addMarkers(lng = ~long, lat = ~lat) %>%
addPolylines(~long, ~lat, popup = ~name)
I have not found any leaflet function that can perform this calculation, but it is not difficult to find the intermediate point between both coordinates.
You must add both longitudes and divide them by 2, you will have to do the same with both latitudes.
In your case, if I have not misunderstood, your first coordinate is (3.16680, 42.46667) and your second coordinate is (3.16176, 42.46997) so the calculation would be as follows:
(3,16680 + 3,16176) / 2 = 3,16428
(42,46667 + 42,46997) / 2 = 42,46832
So the intermediate point would be the following: (3.16428, 42.46832)
I have a raster layer that contains 24-hour snow accumulations across the United States. The data can be pulled from here:
https://www.nohrsc.noaa.gov/snowfall_v2/data/202105/sfav2_CONUS_24h_2021052412.tif
I only want to plot the cells in the raster with values greater than or equal to 4 (inches) on a leaflet map. This is what my current map looks like:
https://i.stack.imgur.com/2Mi4r.png
I changed all values less than 4 to NA thinking that the raster cells wouldn't show up on the map. I want to remove all cells on the map that are greyed-out. The functions subset() and filter() do not work on raster layers. Any ideas? My code below for reference:
library(dplyr)
library(rgdal)
library(raster)
library(ncdf4)
library(leaflet)
library(leaflet.extras)
download.file(obsvSnow_Link, destfile = file.path(folderpath, 'observedSnow.tif'))
obsvSnow <- raster(file.path(folderpath, 'observedSnow.tif'))
names(obsvSnow) <- 'snowfall'
obsvSnow[obsvSnow < 4,] <- NA
colores <- c("transparent","#99CCFF","#3399FF","#0000FF","#FFE066", "#FF9900", "#E06666","#CC0000","#990033")
at <- c(4,8,seq(12,42,6),100)
cb <- colorBin(palette = colores, bins = at, domain = at)
mp <- leaflet(width = "100%",options = leafletOptions(zoomControl = FALSE)) %>%
addTiles() %>%
addRasterImage(x=obsvSnow$snowfall,
colors = cb,
opacity = 0.6) %>%
addLegend(title = 'Inches',
position='bottomright',
pal = cb, values = at) %>%
leaflet.extras::addSearchUSCensusBureau(options = searchOptions(autoCollapse=TRUE, minLength=10)) %>%
addScaleBar(position='bottomleft') %>%
addFullscreenControl()
mp
Is there a way how to have cluster colors in leaflets addHeatmap function, let say we have some values of variables and cluster them to 8 categories (see example), is there a way how to have also 8 color categories in the heatMap? I know this can be done in ggplot - geom_geom_tile
Is there a way ho to reproduce it in leaflet as well?
Example:
library(ggmap)
library(maptools)
library(ggplot2)
d = data.frame(
pred_res = runif(2000, -2, 2),
lat = runif(2000, 49.94, 50.18),
lon = runif(2000, 14.22, 14.71)
)
#top&bottom coding and discreting pred_res....8
d$res_coded<-replace(d$pred_res,d$pred_res<(-1),8)
d$res_coded<-replace(d$res_coded,d$pred_res>=-1,7)
d$res_coded<-replace(d$res_coded,d$pred_res>=-0.4,6)
d$res_coded<-replace(d$res_coded,d$pred_res>=-0.1,5)
d$res_coded<-replace(d$res_coded,d$pred_res>=0,4)
d$res_coded<-replace(d$res_coded,d$pred_res>=0.1,3)
d$res_coded<-replace(d$res_coded,d$pred_res>=0.4,2)
d$res_coded<-replace(d$res_coded,d$pred_res>=1,1)
d %>% head
d$res_coded %>% table
library(leaflet)
library(leaflet.extras)
leaflet() %>% addProviderTiles("CartoDB.Positron") %>%
addHeatmap(lng = d$lon, lat = d$lat, intensity = d$res_coded)
Please see the gradient function from the documentation here.
Here is an example with a different color palette:
leaflet() %>% addProviderTiles("CartoDB.Positron") %>%
addHeatmap(lng = d$lon, lat = d$lat, intensity = d$res_coded, gradient="RdYlGn")
Oklahoma recently legalized medical marijuana, and I'm making a map of where dispensaries can set up. That depends on two things: it has to be in the right zoning area, and can't be too close to a school, church, or playground. I have two maps that show those things, but can't figure out how to layer them together. What I'm trying to achieve is showing how much of the correct zoning area is off-limits because it's too close to a school, church, etc.
The zoning code:
zoning_shapes <- "Primary_Zoning.shp"
zoning <- st_read(zoning_shapes)
library(dplyr)
zoning_1 <- filter(zoning, P_ZONE!="R-1")
zoning_2 <- filter(zoning_1, P_ZONE!="SPUD")
zoning_3 <- filter(zoning_2, P_ZONE!="AA")
zoning_4 <- filter(zoning_3, P_ZONE!="R-2")
zoning_5 <- filter(zoning_4, P_ZONE!="R-4")
zoning_6 <- filter(zoning_5, P_ZONE!="PUD")
zoning_7 <- filter(zoning_6, P_ZONE!="I-3")
zoning_8 <- filter(zoning_7, P_ZONE!="R-A")
zoning_9 <- filter(zoning_8, P_ZONE!="O-1")
zoning_10 <- filter(zoning_9, P_ZONE!="R-3")
zoning_11 <- filter(zoning_10, P_ZONE!="R-A2")
zoning_12 <- filter(zoning_11, P_ZONE!="R-1ZL")
zoning_13 <- filter(zoning_12, P_ZONE!="R-3M")
zoning_14 <- filter(zoning_13, P_ZONE!="R-4M")
zoning_15 <- filter(zoning_14, P_ZONE!="R-MH-1")
zoning_16 <- filter(zoning_15, P_ZONE!="R-MH-2")
zoning_17 <- filter(zoning_16, P_ZONE!="C-HC")
zoning_18 <- filter(zoning_17, P_ZONE!="HP")
zoning_19 <- filter(zoning_18, P_ZONE!="NC")
zoning_20 <- filter(zoning_19, P_ZONE!="AE-1")
zoning_21 <- filter(zoning_20, P_ZONE!="AE-2")
library(ggplot2)
library(sf)
ggplot(zoning_21) + geom_sf() +
theme_void() +
theme(panel.grid.major =
element_line(colour = 'transparent'))
The prohibited-location code:
library(dplyr)
library(tigris)
library(sf)
library(ggplot2)
library(leaflet)
library(readr)
locations <- read_csv("Marijuana_map_CSV.csv")
View(locations)
mew <- colorFactor(c("red", "blue", "purple"), domain=c("School", "Church", "Playground"))
okc_locations <- leaflet(locations) %>%
addTiles() %>%
setView(-97.5164, 35.4676, zoom = 7) %>%
addCircles(~Longitude, ~Latitude, popup=locations$Name,
weight = 3, radius=304.8,
color=~mew(locations$Type), stroke = T,
fillOpacity = 0.8) %>%
addPolygons(data=zoning_21, fillColor = "limegreen",
fillOpacity = 0.5, weight = 0.2,
smoothFactor = 0.2)
okc_locations
The problem I'm running into is that when I try to add the okc_locations code to the zoning_21 code, I get one red dot that's far away and a very compressed version of the city's zoning. When I try adding the zoning polygons to the to the prohibited-points map, they don't show up.
Any ideas of how to get these two maps to play together? Thank you!
Based on our conversation in the comments, it seems that you are having an issue with different projections, in which case you will want to use st_transform (documented here)
First, I made up some fake data:
locations <-
data.frame(Name = c("St. Josephs", "St. Anthony", "Edwards Elementary"),
type = c("Church", "Playground", "School"),
long = c(35.4722725, 35.4751038, 35.4797194),
lat = c(-97.5202865,-97.5239513,-97.4691759))
I downloaded tiger shapefiles for all counties, then narrowed to Oklahoma County:
us_counties <- read_sf("cb_2017_us_county_500k.shp")
ok_county <- subset(us_counties, STATEFP == "40" & NAME == "Oklahoma")
> print(st_crs(ok_county))
Coordinate Reference System:
EPSG: 4269
proj4string: "+proj=longlat +datum=NAD83 +no_defs"
So I then used st_transform:
t2 <- st_transform(ok_county, "+proj=longlat +datum=WGS84")
> print(st_crs(t2))
Coordinate Reference System:
EPSG: 4326
proj4string: "+proj=longlat +datum=WGS84 +no_defs"
And loading it into leaflet as so:
leaflet(locations) %>%
addTiles() %>%
setView(-97.5164, 35.4676, zoom = 11) %>%
addMarkers(~lat, ~long, popup=locations$Name) %>%
addPolygons(data=t2, fillColor = "limegreen",
fillOpacity = 0.5, weight = 0.2,
smoothFactor = 0.2)
Yields this map:
I recently found this shape file of NYC bus routes shape file of NYC bus routes (zip file) that I am interested in plotting with the leaflet package in R.
When I attempt to do so, some routes do not show up on the map. I can tell they're missing because I overlay the bus stop data and some do not line up with the routes.
When I read in the shape file, I notice that the spatial lines data frame that is created has nested lists, which I think leaflet is not mapping.
What do I need to do so that leaflet reads coordinates of these missing routes? Below is the code I used to produce the map with missing routes:
bus <- readOGR(dsn = path.expand("bus_route_shapefile"), layer = "bus_route_shapefile")
bus.pj <- spTransform(bus, CRS("+proj=longlat +datum=WGS84"))
bus.st <- readOGR(dsn = path.expand("bus_stop_shapefile"), layer = "bus_stop_shapefile")
bus.st.pj <- spTransform(bus.st, CRS("+proj=longlat +datum=WGS84"))
bus_map <- leaflet() %>%
setView(lng = -73.932667, lat = 40.717266, zoom = 11) %>%
addPolylines(data = bus.pj, color = "black", opacity = 1) %>%
addCircles(data=bus.st.pj#data,~stop_lon, ~stop_lat, color = "red") %>%
addTiles()
bus_map
It would be easier to help you if you provided not only bus_routes but also bus_stop (zip file). You can solve it by converting bus.pj into new SpatialLinesxxx obj where each class Lines has only one class Line. SLDF below code makes doesn't have bus.pj#data$trip_heads because of unknown.
library(dplyr); library(sp); library(leaflet)
## resolve bus.pj#lines into list(Line.objs) (Don't worry about warnings)
Line_list <- lapply(bus.pj#lines, getLinesLinesSlot) %>% unlist()
## If you want just Lines infromation, finish with this line.
SL <- sapply(1:length(Line_list), function(x) Lines(Line_list[[x]], ID = x)) %>%
SpatialLines()
## make new ids (originalID_nth)
ori_id <- getSLLinesIDSlots(bus.pj) # get original ids
LinLS <- sapply(bus.pj#lines, function(x) length(x#Lines)) # how many Line.obj does each Lines.obj has
new_id <- sapply(1:length(LinLS), function(x) paste0(x, "_", seq.int(LinLS[[x]]))) %>%
unlist()
## make a new data.frame (only route_id)
df <- data.frame(route_id = rep(bus.pj#data$route_id, times = LinLS))
rownames(df) <- new_id
## integrate Line.objs, ids and a data.frame into SpatialLinesDataFrame.obj
SLDF <- mapply(function(x, y) Lines(x, ID = y), x = Line_list, y = new_id) %>%
SpatialLines() %>% SpatialLinesDataFrame(data = df)
leaflet() %>%
setView(lng = -73.932667, lat = 40.717266, zoom = 11) %>%
addPolylines(data = SLDF, color = "black", opacity = 1, weight = 1) %>%
addCircles(data=bus.st.pj#data,~stop_lon, ~stop_lat, color = "red", weight = 0.3)