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

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

Related

sf::st_transform() returns empty geometry

I have transformed the rnaturalearth countries dataset for orthographic plotting using the procedure outlined here.
However, transforming with st_transform() results in at least one of the geometries (mainland Russia) being empty.
This reads and attempts to transform the problematic polygon:
polygon <- st_as_sf(data.frame(st_as_sfc(readLines("https://pastebin.com/raw/APH15G6X"), crs = 4326)))
st_transform(polygon, "+proj=ortho +lat_0=20 +lon_0=0 +x_0=0 +y_0=0 +a=6371000 +b=6371000 +units=m +no_defs")
Simple feature collection with 1 feature and 0 fields (with 1 geometry empty)
Geometry type: MULTIPOLYGON
Dimension: XY
Bounding box: xmin: NA ymin: NA xmax: NA ymax: NA
CRS: +proj=ortho +lat_0=20 +lon_0=0 +x_0=0 +y_0=0 +a=6371000 +b=6371000 +units=m +no_defs
geometry
1 MULTIPOLYGON EMPTY
The geometry seems to be valid and is expected to be fully visible after orthographic projection, so I'm not sure what else could be going on.
The gist you linked is inspiring, and it has helped me a lot in the past. But it is rooted in an obsolete version of {sf} - and with release 1.0 (which introduces S2 backend for geographic CRS) things got somewhat easier.
I have updated the logic somewhat and published it a while back in this answer https://stackoverflow.com/a/70756593/7756889 - when I amend the code to your definition of Ortho projection it shows mainland Russia as expected (= the geometry is not empty, but cut somewhat to hide the invisible parts in Asia). In addition the answer uses the world dataset from Gisco instead of Natural Earth; it should have negligible impact.
library(sf)
library(giscoR) # for the countries dataset only
library(ggplot2)
# projection string used for the polygons & ocean background
crs_string <- "+proj=ortho +lat_0=20 +lon_0=0 +x_0=0 +y_0=0 +a=6371000 +b=6371000 +units=m +no_defs"
# background for the globe - center buffered by earth radius
ocean <- st_point(x = c(0,0)) %>%
st_buffer(dist = 6371000) %>%
st_sfc(crs = crs_string)
# country polygons, cut to size
world <- gisco_countries %>%
st_intersection(ocean %>% st_transform(4326)) %>% # select visible area only
st_transform(crs = crs_string) # reproject to ortho
# now the action!
ggplot(data = world) +
geom_sf(data = ocean, fill = "aliceblue", color = NA) + # background first
geom_sf(fill = "lightyellow", lwd = .1) + # now land over the oceans
theme_void()

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.

R tmap: polygons plotted in tmap_mode("view") but with ("plot") only the first observation

I am trying to plot a polygon with tmap r package.
My object comes from a shapefile, and looks like:
geometry type: POLYGON
dimension: XY
bbox: xmin: 453850.6 ymin: 7168979 xmax: 513813.6 ymax: 7234603
CRS: +proj=utm +zone=36 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs
First 10 features:
NeighCode NameNeigh Locality AdminPost Populacao Shape_Leng Shape_Area geometry
1 3914 Bassane Chichongue Calanga 114 41926.454 111037471 POLYGON ((504325.3 7212444,...
2 3913 Chinguwine Chichongue Calanga 181 16966.423 14526253 POLYGON ((499974.9 7212379,...
3 3912 Sihanine Chichongue Calanga 238 13508.601 9502638 POLYGON ((500542.6 7208832,...
4 3911 Mpalene Chichongue Calanga 352 6961.326 2646152 POLYGON ((499063.9 7208412,...
5 3910 Chichongue Chichongue Calanga 342 12096.768 6473003 POLYGON ((498551.8 7206144,...
When I am trying to plot it with plot(), I get this:
But, when I am doing it with tmap with the following code:
dss_map <- tm_shape(dss_utm) +
tm_polygons("AdminPost") +
tm_layout(frame = F)
dss_map
I get the following map with tmap_mode("plot").
Only the first observation is plotted. With tmap_mode("view") all of them are plotted.
Anyone could tell me what is happening? I could plot this object in tmap_mode("plot") before without any problems. Here is a link (tmap only plotting first polygon in sf geometry column) of a similar question that wasn't answered.
Thanks for your help!

st_simplify dTolerence with decimal degree

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)

Plotting sfc_POLYGON in leaflet

I have a sfc_POLYGON, IHS obtained as a union of a few shapes using the sf package.
Geometry set for 1 feature
geometry type: POLYGON
dimension: XY
bbox: xmin: 270194.7 ymin: 2255850 xmax: 279225 ymax: 2265469
epsg (SRID): 32643
proj4string: +proj=utm +zone=43 +datum=WGS84 +units=m +no_defs
POLYGON((279224.998943279 2261084.1514869, 2792...
While I am able to plot this in mapview, I am facing some problems while plotting the same in leaflet. When I plot this is leaflet, I get a warning sf layer is not long-lat data which it isn't, and I get the base world map. This is the code I used for plotting in leaflet.
IHS%>%leaflet()%>%addTiles()%>%
addProviderTiles(providers$Esri.WorldImagery, group ="ESRI")%>%
addPolygons()
I suspect this has to do something with the CRS. I have tried st_set_crs(IHS, 4326)which changes my projection of IHS from utm to longlat:
Geometry set for 1 feature
geometry type: POLYGON
dimension: XY
bbox: xmin: 270194.7 ymin: 2255850 xmax: 279225 ymax: 2265469
epsg (SRID): 4326
proj4string: +proj=longlat +datum=WGS84 +no_defs
However there is no change in the leaflet warning and output. I am not sure here, but has it got something to do with changing the dimension and bbox (which appears to be in meters)?
"Converting" into Lon/Lat is to change its spatial projection. Once you know that, you can play with spatial data and find in library help the correct way of projecting spatial features.
In your case, using st_set_crs(IHS, 4326) only says that the projection is Lon/lat, without projecting it.
You need to use st_transform:
IHS_wgs84 <- st_transform(IHS, "+init=epsg:4326")

Resources