Convert SpatialPolygonsDataFrame to projected coordinates using spTransform - r

Im trying to do a point pattern analysis. To do this I have to convert a SpatialPolygonsDataFrame so it contains projected coordinates instead of curved coordinates. However I keep getting the same error:
Error in as.owin.SpatialPolygons(Netherlands_flat) :
Only projected coordinates may be converted to spatstat class objects
this is the data I used for a border:
download.file("http://www.naturalearthdata.com/http//www.naturalearthdata.com/download/10m/cultural/ne_10m_admin_1_states_provinces.zip",destfile="ne_10m_admin_1_states_provinces.zip")
unzip("ne_10m_admin_1_states_provinces.zip",exdir="NaturalEarth")
border <- shapefile("NaturalEarth/ne_10m_admin_1_states_provinces.shp")
#extract the border of the Netherlands
Netherlands <- border[paste(border$iso_a2)=="NL",]
Im able to plot the plot the Netherlands with the events.
#Plot
plot(babesia$Longitude, babesia$Latitude, pch="+",cex=0.5, xlim=c(3.360782, 7.227095), ylim = c(50.723492, 53.554584))
plot(Netherlands, add = T)
Netherlands with events
But upon using the Spatstat package I keep running into this error.
I tried this code to transform the coordinates
coord_netherlands <- coordinates(Netherlands)
proj4string(Netherlands)
summary(Netherlands)
Netherlands_flat <- spTransform(coord_netherlands, CRS("+proj=longlat +datum=WGS84 +no_defs"))
Netherlands <- as.owin(Netherlands_flat)
Error in as.owin.SpatialPolygons(Netherlands_flat) :
Only projected coordinates may be converted to spatstat class objects
Does anyone know how to solve this? Thank you very much in advance!

You are almost there. You just need to project to another coordinate system when you call spTransform. You currently ask for geographic coordinates on a spheriod model of the earth (long,lat). Instead you should ask for a flat (x,y) coordinate system. This could be utm coordinates in the appropriate zone for the Netherlands or there might well be a better alternative. Your events also need to be transformed from (long,lat) to the same coordinate system. Maybe you can look at the shapefile vignette of the spatstat package for an example. Or look under the spatstat tag on this site. I'm on my phone do I can't give detailed help.
Good luck.
If your events are in a data.frame called xy you can project to UTM zone 31N like this:
xy <- data.frame(lon = 1:2, lat = 1:2)
coordinates(xy) <- ~lon+lat
proj4string(xy) <- CRS("+proj=longlat +datum=WGS84")
xy
# SpatialPoints:
# lon lat
# [1,] 1 1
# [2,] 2 2
# Coordinate Reference System (CRS) arguments: +proj=longlat +datum=WGS84
# +ellps=WGS84 +towgs84=0,0,0
events.utm <- spTransform(xy, CRS("+proj=utm +zone=31N +datum=WGS84"))
events.utm
# SpatialPoints:
# lon lat
# [1,] 277438.3 110598.0
# [2,] 388786.7 221094.9
# Coordinate Reference System (CRS) arguments: +proj=utm +zone=31N
# +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0

Related

Extracting data from a NetCDF file with package raster in R and finding the proper projection

I downloaded a NetCDF-File here and read it via:
library(raster)
b <- brick("precipitationintensity14rcp45modelsensemblemedianannual.nc")
Then I checked the proj4string in order to see the projection and how to provide coordinates:
> proj4string(b)
[1] "+proj=lcc +lat_0=47.5 +lon_0=13.3299999237061 +lat_1=49 +lat_2=46 +x_0=400000 +y_0=400000 +datum=WGS84 +units=m +no_defs"
In order to extract data at a certain point I use long/lat coordinates in WGS84 format:
coords<-data.frame(lon=47.4, lat=11.5)
coordinates(coords)<-c("lon","lat")
Then I try to extract data by:
> extract(b$X1981.07.15,coords)
[,1]
[1,] NA
This leaves me somehow baffeled. Since I expected a value at this given point.
In order to debug my code I try to compare coordinates of the raster object with mine:
> coordinates(b$X1981.07.15)
x y
[1,] 111500 571500
[2,] 112500 571500
[3,] 113500 571500
Now I'm confused since the coordinates provided do not match the proj4string format (WGES84). Could you please help me with:
Providing propper coordinates for extracting data
Explaining me why the coordinates in the raster object are not as I expected
You need to transform the points to the coordinate reference system of the raster (not the other way around!). Below I show how to do that with "terra", the replacement of the "raster" package.
library(terra)
b <- rast("precipitationintensity14rcp45modelsensemblemedianannual.nc")
coords <- data.frame(lon=47.4, lat=11.5)
pts <- vect(coords, crs="+proj=longlat")
#crs(b) = "+proj=lcc +lat_0=47.5 +lon_0=13.3299999237061 ...
lccpts <- project(pts, crs(b))
extract(b$X1981.07.15, lccpts)

I downloaded shapefile but merging with internal dataset based on geometry fails

Apologies as i'm a little new to GIS features within R, so any help and explanation would be very helpful!
I have downloaded this shape file (Simple Feature Polygon) from source like so:
fire <-tempfile()
download.file("http://frap.fire.ca.gov/webdata/data/statewide/fhszs.sn.zip",destfile = fire)
unzip(fire,exdir = ".")
fire_map<-read_shape("fhszs06_3.shp")
Map has small polygons based on Hazard code (i.e.: 1,2,3)
I also have an internal dataframe that is about 15 variables with 3584 rows, I also have lat/lon for all points (commercial properties in california) that I'm trying to convert to either spatial points DF or simple feature in order to figure out which properties lie within a hazard code.
Example of property file:
ln_bal<- c(500000,200000,6000000,12000,130000)
ln_city <-c('Ventura','Torrance','Buena Park','Concord','Lake View Terrace')
lon <- c(-119.213504,-118.311072,-117.985452,-122.057139,-116.893845)
lat <-c(34.278122,33.844817,33.846594,37.979995,32.844287)
cmbs3 <- data.frame(ln_bal,ln_city,lon,lat)
I think my problem is getting the correct CRS and then matching with the shape file.
The CA Fire map has the following:
epsg (SRID): NA
proj4string: +proj=aea +lat_1=34 +lat_2=40.5 +lat_0=0 +lon_0=-120 +x_0=0 +y_0=-4000000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs
I've Tried sf_intersect by creating a SF points DF:
fire_map <-st_read("fhszs06_3.shp")%>%
st_transform(4326) #need to set CRS the same as your dataframe below
#transforms coordinates to ellips code and creates matching values with fire_map:
proj4string(cmbs3)<-CRS("+proj=longlat +datum=WGS84")
cmbs3 <- spTransform(cmbs3, CRS("+proj=utm +zone=51 ellps=WGS84"))
#fire_map is a simple feature data frame need to convert our data to this, and then match
cmbs3<-st_as_sf(cmbs3,precision=0)
cmbs3<-st_set_crs(cmbs3,4326)
inters <- st_intersection(cmbs3,fire_map)
Expected (potential) Results:
ln_bal ln_city lon lat HAZ_CODE HAZ_CLASS
12000 Concord -122.057139 37.97 1 Moderate

Calculate longitude/latitude for geographic centroid

I want to do some spatial statistic analysis with the county-level crop yield data in Nebraska for the STAT class. For that I need the longitude and latitude of the geographic centroids of each county. Anybody know how to do it in R? I know it can be done in ArcGIS but I have no access to it now.
You didn't give any details where you got your shapefile from, but I got one from here and you can use gCentroid from rgeos thusly:
library(rgdal)
library(sp)
library(rgeos)
nebraska <- readOGR("CountyBoundsUTM/", "CountyUTM")
gCentroid(nebraska, byid=TRUE)
## SpatialPoints:
## x y
## 0 721768.5 4636738
## 1 430938.8 4524651
## 2 698036.4 4566570
## 3 370970.6 4641340
## ...
## 89 623301.6 4603228
## 90 618883.0 4486931
## 91 439295.3 4582756
## 92 493680.8 4522680
## Coordinate Reference System (CRS) arguments: +proj=utm +zone=14 +datum=NAD83
## +units=m +no_defs +ellps=GRS80 +towgs84=0,0,0
You can also extract centroids of SpatialPolygons* objects with coordinates, though the centroids won't be returned as SpatialPoints as with rgeos::gCentroid.
For example:
library(rgdal)
download.file('http://dds.cr.usgs.gov/pub/data/nationalatlas/countyp020_nt00009.tar.gz',
f <- tempfile()) # ~ 4.5 Mb
untar(f, exdir=tempdir())
counties <- readOGR(tempdir(), 'countyp020')
xy <- coordinates(counties)
head(xy)
# [,1] [,2]
# 0 -153.3905 69.30193
# 1 -156.0582 71.33094
# 2 -155.6695 71.24763
# 3 -155.5164 71.23148
# 4 -155.1846 71.18189
# 5 -155.6126 71.00725
Note that, as pointed out by #Spacedman in the comments, the polygons should be projected to a planar coordinate system first.
Recent versions of the sf package (I think since version 1) use the S2 library from Google for spherical geometry calculations. The advantage is that centroid calculations are not simply planar. The relevant method is st_centroid(). An example for a region with a significant spatial extent:
library(rnaturalearth)
# ne_countries() returns 'sp'-type data by default
nc <- ne_countries(continent = "Asia", returnclass = "sf")
library(sf)
# long-lat data in WGS84
st_crs(nc)
# use st_geometry() to plot only the polygons and not the associated data
plot(st_geometry(nc), axes = T)
plot(st_centroid(st_geometry(nc)), pch = "+", col = "red", add = T)
# 'sf' integrates nicely with 'ggplot2':
library(ggplot2)
ggplot(nc) + geom_sf() +
geom_sf(aes(geometry = st_centroid(st_geometry(nc))), colour = "red")
You can use the get_map() function from the ggplot2 package to extract the US county map data from the maps package to a dataframe. Then you can calculate the mid points of the ranges of the lat/lon columns by county (or whatever method you want to use to define geographic center).

Error when re-projecting spatial points using spTransform in rgdal R

G'day,
I have a large number of lon/lat coordinates that are in the CRS Australian Geodetic Datum 66/84 (AGD66 for brevity). I want to change these coordinates from AGD66 to WGS84 because there is about a 200m difference between them and I have other coordinates and layers in WGS84. I have tried to do this by:
lon lat
147.1428 -43.49083
library(rgdal)
pts<-read.table(file.choose(),header=TRUE,sep=',')
# I first project the pts in their original CRS
pts66<-project(cbind(pts$lon,pts$lat), "+init=epsg:4202")
# Then to transform it to WGS84
pts84 = spTransform(pts66,CRS("+init=epsg:3033"))
Error in function (classes, fdef, mtable) :
unable to find an inherited method for function "spTransform", for signature "matrix", "CRS"
Does anyone know why I get this error or have any suggestions for how I can change these coordinates from AGD66 to WGS84? Thanks for your help in advance.
Cheers,
Adam
I have removed part of an incorrect answer.
The function project() cannot do datum conversions so you may have a problem there and I think what you have is wrong.
The problem is that you can only project() from/to longlat on WGS84, so your first use of project is incorrect. If I guess this right, you have coordinates that are in AGD66 so you must first assign that projection and then you can transform. You cannot do datum transformations with project(), but spTransform() can.
I think you need this:
pts = read.table(text = "lon lat
147.1428 -43.49083", header = TRUE)
## assign original coordinate system
pts66 = SpatialPoints(cbind(pts$lon,pts$lat), CRS("+init=epsg:4202"))
## Then to transform it to WGS84
pts84 = spTransform(pts66, CRS("+init=epsg:3033"))
pts66
SpatialPoints:
coords.x1 coords.x2
[1,] 147.1428 -43.49083
Coordinate Reference System (CRS) arguments: +init=epsg:4202 +proj=longlat +ellps=aust_SA
+no_defs
pts84
SpatialPoints:
coords.x1 coords.x2
[1,] 11126605 2971806
Coordinate Reference System (CRS) arguments: +init=epsg:3033 +proj=lcc +lat_1=-68.5 +lat_2=-74.5
+lat_0=-50 +lon_0=70 +x_0=6000000 +y_0=6000000 +ellps=WGS84 +datum=WGS84 +units=m +no_defs
+towgs84=0,0,0
This means that pts66 are not changed from their original values, but they have the metadata correct for the next step which transforms them to your target (which is Lambert Conformal Conic btw). You might need a bit more investigation to figure out what's required.
CRS("+init=epsg:4202")
CRS arguments:
+init=epsg:4202 +proj=longlat +ellps=aust_SA +no_defs
CRS("+init=epsg:3033")
CRS arguments:
+init=epsg:3033 +proj=lcc +lat_1=-68.5 +lat_2=-74.5 +lat_0=-50
+lon_0=70 +x_0=6000000 +y_0=6000000 +ellps=WGS84 +datum=WGS84 +units=m
+no_defs +towgs84=0,0,0
Your original project() was incorrectly attempting to transform from longlat on WGS84 to longlat on AGD66, but that function cannot do that so it's just added confusion in the mix. A datum is not a projection, it is a critical part of a projection's definition and in this sense "longlat on AGD66" is a projection just as "Lambert Conformal Conic on WGS84" is.

Map raw data and mean data based on the shapefile

sI have the dataset (pts) like this:
x <- seq(-124.25,length=115,by=0.5)
y <- seq(26.25,length=46,by=0.5)
z = 1:5290
longlat <- expand.grid(x = x, y = y) # Create an X,Y grid
pts=data.frame(longlat,z)
names(pts) <- c( "x","y","data")
I knew that I can map the dataframe (pts) into a map by doing:
library(sp)
library(rgdal)
library(raster)
library(maps)
coordinates(pts)=~x+y
proj4string(pts)=CRS("+init=epsg:4326") # set it to long, lat
pts = spTransform(pts,CRS(" +init=epsg:4326 +proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs +towgs84=0,0,0"))
pts <- as(pts, "SpatialPixelsDataFrame")
r = raster(pts)
projection(r) = CRS(" +init=epsg:4326 +proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs +towgs84=0,0,0")
plot(r)
map("usa",add=T)
Now I would like to create a separate map which shows the means of pts across different regions. The shapefile I want to use is from ftp://ftp.epa.gov/wed/ecoregions/cec_na/NA_CEC_Eco_Level2.zip , however, this is a north america map. How can I create the map showing only US based on this north america map? Or is there another better way to do this? thanks so much.
I think that cutting out the non-US data based on the data in the shapefile alone would be hard, since the regions do not correspond to political boundaries - that could be done with rgeos though.
Assuming that "eco" is a SpatialPolygonsDataFrame read in by rgdal::readOGR or maptools::readShapeSpatial, see the available key data for indexing:
sapply(as.data.frame(eco), function(x) if(!is.numeric(x)) unique(x) else NULL)
If you just want to plot it, set up a map with only the US region to start with and then overplot.
library(maps)
map("usa", col = "transparent")
We see that the data is in Lambert Azimuthal Equal Area:
proj4string(eco)
[1] " +proj=laea +lat_0=45 +lon_0=-100 +x_0=0 +y_0=0 +a=6370997 +b=6370997 +units=m +no_defs"
So
require(rgdal)
eco.laea <- spTransform(eco, CRS("+proj=longlat +ellpse=WGS84"))
plot(eco.laea, add = TRUE)
If you want to plot in the original Lambert Azimuthal Equal Area you'll need to get the bounding box in that projection and start the plot based on that, I just used existing data to make an easy example. I'm pretty sure the data could also be cropped with rgeos against another boundary too, but depends what you actually want.

Resources