st_simplify dTolerence with decimal degree - r

I'm trying to reduce the size of sf object by applying st_simplify. CRS is 4267 and try to play around with the right level of dTolerance. I understand that the unit of dTolerance has to be that of the CRS, so I started with 0.1, but I constantly getting this error message.
test <- st_read("comm_sf.shp") %>%
+ st_simplify(preserveTopology = T,
+ dTolerance = 0.1)
Simple feature collection with 11321 features and 21 fields
geometry type: MULTIPOLYGON
dimension: XY
bbox: xmin: -124.4375 ymin: 24.5441 xmax: -66.94983 ymax: 49.00249
epsg (SRID): 4326
proj4string: +proj=longlat +datum=WGS84 +no_defs
Warning message:
In st_simplify.sfc(st_geometry(x), preserveTopology, dTolerance) :
st_simplify does not correctly simplify longitude/latitude data, dTolerance needs to be in decimal degrees
I play around with both setting dTolerance = 1000 (in case it's in meters) and dTolerance = 0.1 (in case it's in long/lat), but I get the same error message. This happens with CRS = 4267 as well. How can I fix this?

Well its a warning rather than an error. But in general you should do Douglas-Peucker on a projected coordinate system - because it uses a distance as a buffer, whereas the actual size of a unit of longitude varies with latitude. Note that the unit used by st_simplify tolerance will always be in the same as the map units.
Here's a reproducible example:
library(sf)
library(maptools)
states = st_as_sf(maps::map("state", plot = FALSE, fill = TRUE))
states_simple = st_simplify(states)
##Warning message:
## In st_simplify.sfc(st_geometry(x), preserveTopology, dTolerance) :
## st_simplify does not correctly simplify longitude/latitude data, dTolerance needs to be in decimal degrees
But if we transform to a projected coordinate system first, then no warning:
states = st_transform(states, 54032) #azimuthal equidistant
states_simple = st_simplify(states)
You can always go back to WGS84 lat-long after the simplification
states = st_transform(states, 4326)

Related

Map is flipped and turned when reading GML data with r

I have downloaded a GML-File from this Website.
Then I use the following code to process this file in R:
library(rgdal)
test <- readOGR(dsn='WLV_GZP.gml')
I am printing the map like this:
test3 <- subset(test, qualitativeValue=='Rote Zone Lawine') #For speeding up the Test-print
plot(test3)
The result is turned 90 degrees to the right and flipped (East-West). How can I get this map to work? Any help is greatly appreciated.
edit: The result is the same when using the sf library:
test4 <- sf::st_read('WLV_GZP.gml')
test4 <- subset(test4, qualitativeValue=='Rote Zone Lawine')
plot(test4)
In order to inspect the bbox I transform the map:
roads <- st_transform(test4, crs = 4326)
This yields a bbox:
Dimension: XY
Bounding box: xmin: -23.4819 ymin: 58.59924 xmax: -18.90591 ymax: 62.56157
Geodetic CRS: WGS 84
Since the map displays Austria this is of course way off...
PS: I would like to post a PNG-File but I received an error when uploading the file.
Pass the GDAL SWAP_COORDINATES option. It can take one of three values:
> d_NO = st_read("./WLV_GZP.gml", options=list("SWAP_COORDINATES=NO"))
> d_YES = st_read("./WLV_GZP.gml", options=list("SWAP_COORDINATES=YES"))
> d_AUTO = st_read("./WLV_GZP.gml", options=list("SWAP_COORDINATES=AUTO"))
resulting in, for your data:
> st_bbox(d_NO)
xmin ymin xmax ymax
4285465 2599037 4824292 2888410
> st_bbox(d_YES)
xmin ymin xmax ymax
2599037 4285465 2888410 4824292
> st_bbox(d_AUTO)
xmin ymin xmax ymax
2599037 4285465 2888410 4824292
The d_NO data are in Austria.
I don't know if there's a definitive way of deciding for a given dataset whether to swap or not, the AUTO default should, I imagine, work for a correctly specified data set but if something is out of spec then who knows...

Smoothing polygons on map with ggplot2 and sf

How can you smooth the polygons of a map produced with ggplot and sf?
I have used the sf package to extract the polygons from a shapefile
geomunicipios <- st_read("ruta/archivo.shp")
Reading layer `archivo' from data source
`ruta\archivo.shp'
using driver `ESRI Shapefile'
Simple feature collection with 45 features and 10 fields
Geometry type: MULTIPOLYGON
Dimension: XY
Bounding box: xmin: -2.344411 ymin: 37.37375 xmax: -0.647983 ymax: 38.75509
Geodetic CRS: WGS 84
And ggplot2 to plot the map:
rmurcia <- ggplot(data = geomunicipios) +
geom_sf(aes(fill=columna),color="#FFFFFF",size=1)
To perform the smoothing of the polygons I have analyzed three alternatives:
i. package "smoothr":
geosmunicipios <- smooth(geomunicipios, method = "ksmooth", smoothness = 12)
ii. package "rmapshaper": geosmunicipios <- ms_simplify(geomunicipios, keep = 0.02500, weighting = 12)
iii. package "sf": geosmunicipios <- st_simplify(geomunicipios, dTolerance = 50, preserveTopology = TRUE)
You have to try different values of the parameters to adjust to the needs and obtain the desired result.
To reproduce the case, the download can be done from: centrodedescargas.cnig.es/CentroDescargas/index.jsp
And follow the links:
Información geográfica de referencia - Límites municipales, provinciales y autonómicos - Descargar: lineas_limite.zip.
And the path in the uncompressed folder:
SIGLIM_Publico_INSPIRE - SHP_ETRS89 - recintos_municipales_inspire_peninbal_etrs89 - recintos_municipales_inspire_peninbal_etrs89.shp
Finally, for this case I have chosen to use rmapshaper, it produces a satisfactory result with a reduced size of the .pdf file, where I include the graphic.

Spatial join longitude and latitude points to multipolygon shapefile

I have a spatial data frame of the longitude and latitude of wildfire origins that I am trying to perform a spatial join on to a US Census TIGER/Line shapefile (places) to see if/where there is spatial intersection of fire origins and places.
I am converting the longitude and latitude to coordinate geometry using st_as_sf then attempting to st_join this to the places file, but am encountering an error as the CRS are different. The shapefile is in NAD83 projection, so I am attempting to match that.
library(tidyverse)
library(sf)
> head(fires)
# Longitude Latitude FireName
#1 -106.46667 34.66000 TRIGO
#2 -81.92972 35.87111 SUNRISE
#3 -103.76944 37.52694 BRIDGER
#4 -122.97556 39.37500 BACK
#5 -121.15611 39.62778 FREY
#6 -106.38306 34.77056 BIG SPRING
#convert df to sf
fires_sf <- st_as_sf(fires, coords = c("Longitude", "Latitude"), crs = 4269, agr = "constant")
head(fires_sf$geometry)
#Geometry set for 6 features
#Geometry type: POINT
#Dimension: XY
#Bounding box: xmin: -122.9756 ymin: 34.66 xmax: -81.92972 ymax: 39.62778
#Geodetic CRS: NAD83
#POINT (-106.4667 34.66)
#POINT (-81.92972 35.87111)
#POINT (-103.7694 37.52694)
#POINT (-122.9756 39.375)
#POINT (-121.1561 39.62778)
head(places$geometry)
#Geometry set for 6 features
#Geometry type: MULTIPOLYGON
#Dimension: XY
#Bounding box: xmin: -1746916 ymin: -395761.6 xmax: -1655669 ymax: -212934.8
#Projected CRS: USA_Contiguous_Albers_Equal_Area_Conic
#First 5 geometries:
#MULTIPOLYGON (((-1657066 -233757.7, -1657192 -2...
#MULTIPOLYGON (((-1668181 -273428.5, -1669420 -2...
#MULTIPOLYGON (((-1735046 -389578.2, -1735146 -3...
#MULTIPOLYGON (((-1732841 -376703.9, -1732642 -3...
#MULTIPOLYGON (((-1693749 -377716, -1693286 -377..
joined <- st_join(places, fires_sf)
Error in st_geos_binop("intersects", x, y, sparse = sparse, prepared = prepared, :
st_crs(x) == st_crs(y) is not TRUE
To work around this, I have tried st_transform to change the projection to longitude and latitude coordinates, as the places shapefile may be using UTM coordinates, and the datum to NAD83 in both spatial frames. I am getting an error for this as well.
#transform CRS projections
places_transform <- st_transform(places, "+proj=longlat +datum=NAD83")
fires_sf_transform <- st_transform(fires_sf, "+proj=longlat +datum=NAD83")
joined_new <- st_join(places_transform, fires_sf_transform)
Error in s2_geography_from_wkb(x, oriented = oriented, check = check) :
Evaluation error: Found 1045 features with invalid spherical geometry.
[3] Loop 0 is not valid: Edge 280 has duplicate vertex with edge 306
I have attempted to convert the geometry from longitude and latitude coordinates in the fires dataset to UTM coordinates to match the places shapefile, but this was also unsuccessful.
Any advice on how I can properly perform the spatial join of these points and multipolygons would be greatly appreciated.

How do I get gCentroid to work at the pole?

I am struggling with gCentroid, because it doesn't seem -- to me -- to give the 'right' answer near a pole of the Earth.
For instance:
library(rgeos)
gCentroid(SpatialPoints(coords=data.frame(longitude=c(-135,-45,45,135),latitute=c(80,80,80,80)),proj4string = CRS('EPSG:4326')))
does not give me the North Pole, it gives:
> SpatialPoints:
> x y
> 1 0 80
> Coordinate Reference System (CRS) arguments: +proj=longlat +datum=WGS84 +no_defs
How do I get gCentroid to work on the surface of the Earth?
The GEOS library is limited to planar geometry operations; this can bring issues in edge cases / the poles being a notorious example.
For the centroid via GEOS to work as intended you need to transform your coordinates from WGS84 to a coordinate reference system appropriate to polar regions; for Arctic regions I suggest EPSG:3995.
library(sp)
library(dplyr)
library(rgeos)
points_sp <- SpatialPoints(coords=data.frame(longitude=c(-135,-45,45,135),latitute=c(80,80,80,80)),proj4string = CRS('EPSG:4326'))
points_updated <- points_sp %>%
spTransform(CRS("EPSG:3995")) # a projected CRS apropriate for Arctic regions
centroid <- gCentroid(points_updated) %>%
spTransform(CRS("EPSG:4326")) # back to safety of WGS84!
centroid # looks better now...
# SpatialPoints:
# x y
# 1 0 90
# Coordinate Reference System (CRS) arguments: +proj=longlat +datum=WGS84 +no_defs
Also note that your workflow - while not wrong in principle - is a bit dated, and the {rgeos} package is approaching its end of life.
It may be good time to give a strong consideration to {sf} package, which is newer, actively developed and can, via interface to s2 library from Google, handle spherical geometry operations.
For an example of {sf} based workflow consider this code; the result (centroid = North Pole) is equivalent to the sp / rgeos one.
library(sf)
points_sf <- points_sp %>% # declared earlier
st_as_sf()
centroid_sf <- points_sf %>%
st_union() %>% # unite featrues / from 4 points >> 1 multipoint
st_centroid()
centroid_sf # the North Pole in a slightly different (sf vs sp) format
# Geometry set for 1 feature
# Geometry type: POINT
# Dimension: XY
# Bounding box: xmin: 0 ymin: 90 xmax: 0 ymax: 90
# Geodetic CRS: WGS 84 (with axis order normalized for visualization)
# POINT (0 90)

R Spatial: Mismatch of latitude / longitude between 2 shapefiles with same CRS

my goal is to count the frequency of extreme weather events within subnational African regions. To do so, I have set up a shapefile containing African provinces, using mostly GADM data and the new geocoded EMDAT GDIS dataset for point-data on weather events.
This is how the region shapefile looks like:
library(sf)
st_geometry(africa_map)
Geometry set for 796 features
Geometry type: GEOMETRY
Dimension: XY
Bounding box: xmin: -25.36042 ymin: -46.96575 xmax: 63.49391 ymax: 37.3452
Geodetic CRS: WGS 84
First 5 geometries:
MULTIPOLYGON (((-4.821226 24.99475, -4.821355 2...
MULTIPOLYGON (((1.853562 35.8605, 1.8424 35.865...
MULTIPOLYGON (((-1.361976 35.3199, -1.358957 35...
MULTIPOLYGON (((2.984874 36.81497, 3.014171 36....
MULTIPOLYGON (((7.262677 37.076, 7.266449 37.07..
And the GDIS dataset after converting longitude and latitude to WGS 84:
gdis_africa_sf <- st_as_sf(x = gdis_africa,
coords = c("longitude", "latitude"),
crs = "+proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0")
st_geometry(gdis_africa_sf)
Geometry set for 5171 features
Geometry type: POINT
Dimension: XY
Bounding box: xmin: -34.04233 ymin: -25.19619 xmax: 37.08849 ymax: 63.4228
CRS: +proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0
First 5 geometries:
POINT (-17.09348 15.66576)
POINT (-16.53153 15.77399)
POINT (-16.20006 15.84419)
POINT (-17.09348 15.66576)
POINT (-16.53153 15.77399)
By now, you can already tell that something's off because the bounding boxes do not correspond at all, even though the projections seem to fit.
st_crs(africa_map)==st_crs(gdis_africa_sf)
[1] TRUE
When plotting the two next to each other, the issue becomes clearer, no matter if I use the new shapefile or just apply longitude and latitude of the data frame.
ggplot() +
geom_sf(data = africa_map) +
geom_sf(data = gdis_africa_sf)
Plot 1
ggplot(data = africa_map) +
geom_sf() +
geom_point(data = gdis_africa, aes(x = longitude, y = latitude),
color = "red",
alpha = 0.3,
size = 2,
shape = 1)
Plot 2
It seems like the weather event coordinates are shifted some thousand kilometers to the North West - but what's the source? And how can I fix the issue and make my two geographical data compatible? Any hints would be much appreciated.
It seems like you've mis-diagnosed the problem, it's not a translation, but a reflection in a diagonal line - you've swapped latitude and longitude in your station points. Try:
gdis_africa_sf <- st_as_sf(x = gdis_africa,
coords = c("latitude", "longitude"),
crs = "+proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0")

Resources