Creating sf object from dataframe (UTM) - r

I am new to the sf package in r attempting to create an object from a set of points gives to me in UTM by a collaborator. I've seen how people can use similar methods with lat/long coordinates but have not been able to achieve the same results because of the zone portion of point definitions
can.df <- data.frame(
rbind(
c("NW", "9V", 586518, 7077103),
c("NE", "13W", 645544, 7118728),
c("SW", "11T", 680262, 4865141),
c("SE", "14T", 314095, 497555)),
stringsAsFactors = F)
colnames(can.df) <- c("Corner", "Zone", "Northing", "Easting")
## make xy numeric
num.cols <- c("Northing", "Easting")
can.df[num.cols] <- sapply(can.df[num.cols], as.numeric)
can.df["Zone"] <- as.character(can.df["Zone"])
test <- st_as_sf(can.df,
coords = c("Easting", "Northing", "Zone"),
epsg = 2955)
This will give me the error:
Error in points_cpp(pts, gdim): Not compatible with requested type:
[type=character; target=double].
and if I strip the letters from the zone definition, and use it as numeric. Then I receive:
Error in st_sf(x, ..., agr = agr, sf_column_name = sf_column_name): no
simple features geometry column present
Can anyone shed some light as to what I'm missing?

Try removing "Zone" form coords and change epsg to crs. epsg is not a parameter accepted by st_sf.
library(sf)
#> Linking to GEOS 3.8.0, GDAL 3.0.1, PROJ 6.2.0
can.df <- data.frame(
rbind(
c("NW", "9V", 586518, 7077103),
c("NE", "13W", 645544, 7118728),
c("SW", "11T", 680262, 4865141),
c("SE", "14T", 314095, 497555)),
stringsAsFactors = F)
colnames(can.df) <- c("Corner", "Zone", "Northing", "Easting")
## make xy numeric
num.cols <- c("Northing", "Easting")
can.df[num.cols] <- sapply(can.df[num.cols], as.numeric)
can.df["Zone"] <- as.character(can.df["Zone"])
test <- st_as_sf(can.df,
coords = c("Easting", "Northing", "Zone"),
crs = 2955)
#> Warning in lapply(x[coords], as.numeric): NAs introduced by coercion
#> Error in st_as_sf.data.frame(can.df, coords = c("Easting", "Northing", : missing values in coordinates not allowed
test <- st_as_sf(can.df,
coords = c("Easting", "Northing"),
crs = 2955)
test
#> Simple feature collection with 4 features and 2 fields
#> geometry type: POINT
#> dimension: XY
#> bbox: xmin: 497555 ymin: 314095 xmax: 7118728 ymax: 680262
#> epsg (SRID): 2955
#> proj4string: +proj=utm +zone=11 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs
#> Corner Zone geometry
#> 1 NW c("9V", "13W", "11T", "14T") POINT (7077103 586518)
#> 2 NE c("9V", "13W", "11T", "14T") POINT (7118728 645544)
#> 3 SW c("9V", "13W", "11T", "14T") POINT (4865141 680262)
#> 4 SE c("9V", "13W", "11T", "14T") POINT (497555 314095)
Created on 2019-10-15 by the reprex package (v0.3.0)

Related

How can I rasterize a SpatialPolygonsDataFrame so that I can fill a shapefile with points?

I have a chunk of R code that used to work but does not work anymore and I cannot find the issue. The purpose of the code is to fill a shapefile with regularly spaced points.
My shapefile can be accessed here: https://drive.google.com/drive/folders/1SAbuyIQHevK4fz-0w3TTqpEhz0wKLEII?usp=sharing
If I begin with loading my shapefile:
GUA = raster::shapefile('Guam3BufferPoly.shp')
Then I set a variable for the coordinate reference system for this SpatialPolygonDataFrame:
projGUA = crs(GUA)
Transform to planar crs
putm <- spTransform(GUA, projGUA)
Create a raster (this is where it doesn't work)
ext = extent(putm)
r <- raster(ext, res=500)
Rasterize the polygon and transform to points
r2 <- rasterize(putm, r)
pts <- rasterToPoints(r2, spatial=TRUE)
Transform the points to lon/lat and plot the results
pts_lonlat <- spTransform(pts, "+proj=longlat +datum=WGS84")
plot(pts_lonlat,pch='*')
The raster, r, is empty (breaking all the code downstream).
Please let me know if you can help me. And please be kind (this is my first time posting here and I apologize if I have not formatted my question correctly). Thank you!
Welcome!
Basically, it seems like you're working in a coordinate reference system not appropriate for the steps you execute.
library(raster)
GUA <- shapefile("Guam3BufferPoly.shp")
crs(GUA)
#> Coordinate Reference System:
#> Deprecated Proj.4 representation: +proj=longlat +datum=WGS84 +no_defs
#> WKT2 2019 representation:
#> GEOGCRS["GCS_unknown",
#> DATUM["World Geodetic System 1984",
#> ELLIPSOID["WGS 84",6378137,298.257223563,
#> LENGTHUNIT["metre",1]],
#> ID["EPSG",6326]],
#> PRIMEM["Greenwich",0,
#> ANGLEUNIT["Degree",0.0174532925199433]],
#> CS[ellipsoidal,2],
#> AXIS["longitude",east,
#> ORDER[1],
#> ANGLEUNIT["Degree",0.0174532925199433]],
#> AXIS["latitude",north,
#> ORDER[2],
#> ANGLEUNIT["Degree",0.0174532925199433]]]
Seems like the crs provided Guam3BufferPoly.prj is not quite up to standard, but I'm not 100 % sure here. However, you're working with lat/lon coordinates on WGS 84. Hence, spTransform(GUA, projGUA) has absolutely no effect, since you're reprojecting your feature to the same crs again.
This leads to a follow-up issue: You're working in degrees as units and specify a raster of 500 units (here: degrees, not meters, as probably intended). And this is exactly what raster() does, even if it makes no sense:
ext <- extent(GUA)
ext
#> class : Extent
#> xmin : 144.5962
#> xmax : 145
#> ymin : 13.19925
#> ymax : 13.70405
r <- raster(ext, res = 500)
r
#> class : RasterLayer
#> dimensions : 1, 1, 1 (nrow, ncol, ncell)
#> resolution : 500, 500 (x, y)
#> extent : 144.5962, 644.5962, -486.2959, 13.70405 (xmin, xmax, ymin, ymax)
#> crs : NA
To solve this, you should use a projected coordinate reference system suitable for Guam. Not sure how good of a fit this is, you'll probably know better, but let me try WGS 84 / UTM 55 S (EPSG: 32755):
putm <- spTransform(GUA, CRS("+proj=utm +zone=55 +south +datum=WGS84 +units=m +no_defs"))
ext <- extent(putm)
ext
#> class : Extent
#> xmin : 239608.8
#> xmax : 283618.4
#> ymin : 11460271
#> ymax : 11516045
r <- raster(ext, res = 500)
r
#> class : RasterLayer
#> dimensions : 112, 88, 9856 (nrow, ncol, ncell)
#> resolution : 500, 500 (x, y)
#> extent : 239608.8, 283608.8, 11460045, 11516045 (xmin, xmax, ymin, ymax)
#> crs : NA
r2 <- rasterize(putm, r)
pts <- rasterToPoints(r2, spatial = TRUE)
pts_lonlat <- spTransform(pts, "+proj=longlat +datum=WGS84")
plot(pts_lonlat, pch='*')
Edit:
You can simplify the process using sf instead of raster and sp IMHO. Individual steps include data import, reprojection to a metric crs, grid creation covering the whole extent of your dataset and "spatial filtering" by intersecting your buffer with the grid centroids.
library(sf)
sf <- st_read("Guam3BufferPoly.shp", crs = "epsg:4326") |> st_transform("epsg:32755")
#> Reading layer `Guam3BufferPoly' from data source
#> `Guam3BufferPoly.shp' using driver `ESRI Shapefile'
#> Simple feature collection with 1 feature and 1 field
#> Geometry type: POLYGON
#> Dimension: XY
#> Bounding box: xmin: 144.5962 ymin: 13.19925 xmax: 145 ymax: 13.70405
#> Geodetic CRS: WGS 84
grid <- st_make_grid(sf, cellsize = 500, what = "centers") |> st_intersection(x = sf, y = _)
grid
#> Simple feature collection with 3839 features and 1 field
#> Geometry type: POINT
#> Dimension: XY
#> Bounding box: xmin: 239858.8 ymin: 11460520 xmax: 283358.8 ymax: 11516020
#> Projected CRS: WGS 84 / UTM zone 55S
#> First 10 features:
#> ID geometry
#> 1 1 POINT (246358.8 11460521)
#> 1.1 1 POINT (246858.8 11460521)
#> 1.2 1 POINT (247358.8 11460521)
#> 1.3 1 POINT (247858.8 11460521)
#> 1.4 1 POINT (248358.8 11460521)
#> 1.5 1 POINT (248858.8 11460521)
#> 1.6 1 POINT (249358.8 11460521)
#> 1.7 1 POINT (249858.8 11460521)
#> 1.8 1 POINT (250358.8 11460521)
#> 1.9 1 POINT (250858.8 11460521)
Created on 2022-08-18 by the reprex package (v2.0.1)

Unknown CRS in QGIS when projecting to EPSG:25833 in R

I want to project a spatial data frame to EPSG 25833 in R but QGIS does not seem to know it (for reproducibility, I use the code jazzurro created in his/her answer to this question with minor changes)
library(rgdal)
mydf <- structure(list(longitude = c(128.6979, 153.0046, 104.3261, 124.9019,
126.7328, 153.2439, 142.8673, 152.689), latitude = c(-7.4197,
-4.7089, -6.7541, 4.7817, 2.1643, -5.65, 23.3882, -5.571)), .Names = c("longitude",
"latitude"), class = "data.frame", row.names = c(NA, -8L))
### Get long and lat from your data.frame. Make sure that the order is in lon/lat.
xy <- mydf[,c(1,2)]
# Here I use the projection EPSG:25833
spdf <- SpatialPointsDataFrame(coords = xy, data = mydf,
proj4string = CRS("+proj=utm +zone=33 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs"))
#Export as shapefile
writeOGR(spdf, "file location", "proj_test", driver="ESRI Shapefile",overwrite_layer = T) #now I write the subsetted network as a shapefile again
Now when I load the shapefile into QGIS it doesn´t know the projection.
Any ideas?
In making your SpatialPointsDataFrame:
# Wrong!
spdf <- SpatialPointsDataFrame(coords = xy, data = mydf,
proj4string = CRS("+proj=utm +zone=33 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs"))`
You are telling the data frame what crs your points are in, so you should specify 4326 since your original data is lon/lat.
So it should be:
spdf <- SpatialPointsDataFrame(coords = xy, data = mydf,
proj4string = CRS("+proj=longlat +datum=WGS84"))
And then you can transform the data to another CRS using spTransform:
spTransform(spdf, CRS('+proj=utm +zone=33 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs'))
For this particular data, we get an error because one of the points doesn't convert to your target CRS:
Error in spTransform(xSP, CRSobj, ...) : failure in points 3 In
addition: Warning message: In spTransform(xSP, CRSobj, ...) : 1
projected point(s) not finite
I prefer working in sf so we could also do:
library(sf)
sfdf <- st_as_sf(mydf, coords = c('longitude', 'latitude'), crs=4326, remove=F)
sfdf_25833 <- sfdf %>% st_transform(25833)
sfdf_25833
#> Simple feature collection with 8 features and 2 fields (with 1 geometry empty)
#> geometry type: POINT
#> dimension: XY
#> bbox: xmin: 5589731 ymin: -19294970 xmax: 11478870 ymax: 19337710
#> epsg (SRID): 25833
#> proj4string: +proj=utm +zone=33 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs
#> longitude latitude geometry
#> 1 128.6979 -7.4197 POINT (10198485 -17980649)
#> 2 153.0046 -4.7089 POINT (5636527 -19294974)
#> 3 104.3261 -6.7541 POINT EMPTY
#> 4 124.9019 4.7817 POINT (11478868 18432292)
#> 5 126.7328 2.1643 POINT (11046583 19337712)
#> 6 153.2439 -5.6500 POINT (5589731 -19158700)
#> 7 142.8673 23.3882 POINT (6353660 16093116)
#> 8 152.6890 -5.5710 POINT (5673080 -19163103)
and you can write and open with QGIS using:
write_sf(sfdf_25833, 'mysf.gpkg')

Identifying maximum/minimum coordinates of polygon/owin edge [R]

I am working with a polygon, and would like to identify the outermost point of the polygon (in my case it is in owin (spatstat) format but can be converted to any of the spatial formats.
For example here is my polygon:
How would I go about identifying the coordinates of the "tip" of this polygon? I know I can use the minimum Y axis value, but I'm not sure how to get the X. The code is difficult to provide a sample of, but I can if need be.
Using st_cast(.,"POINT"), st_coordinates() and the tip provided by #Allan_Cameron:
library(sf)
#reprex
yourshape.sfc <- st_geometry(st_read(system.file("shape/nc.shp",
package = "sf")))[1]
# Cast to points
yourpoints <- st_cast(yourshape.sfc, "POINT")
#Get unique coords
coords = as.data.frame(unique(st_coordinates(yourpoints)))
#Asses minimimun and unique
index <- which(coords$Y == min(coords$Y))
minims = yourpoints[index]
minims
#> Geometry set for 1 feature
#> geometry type: POINT
#> dimension: XY
#> bbox: xmin: -81.47276 ymin: 36.23436 xmax: -81.47276 ymax: 36.23436
#> epsg (SRID): 4267
#> proj4string: +proj=longlat +datum=NAD27 +no_defs
#> POINT (-81.47276 36.23436)
plot(st_geometry(yourshape.sfc))
plot(minims, col = "green", pch = 20, cex = 2, add = TRUE)
plot(yourpoints, col = "red", pch = 20, add = TRUE)
Created on 2020-03-03 by the reprex package (v0.3.0)

Cannot output spatial dataframe to .shp

I've used gConvexHull() to create a home range polygon that is classed as an SP polygon. In order to output as an .shp file, I converted it to a SpatialPolygonsDataFrame and its new class is "sf" "data.frame".
But when I try to output it using writeOGR(), it comes up with the error message:
Error in writeOGR(obj = HRDF, dsn = "C:/Users/RKirton/Documents/Data files", :
inherits(obj, "Spatial") is not TRUE
I also tried st_write() and got this new error message:
Error in CPL_write_ogr(obj, dsn, layer, driver, as.character(dataset_options), :
argument dsn, layer or driver not of length 1.
I'm fairly new to R and am unsure how to resolve these error messages.
Here is my code:
for(i in 1:length(unique(mydata$ID))) {
hunt <- mydata[which(mydata$Season2 == "Hunt" & mydata$ID ==
unique(mydata$ID)[i]), ]
hunt_spdf <- SpatialPointsDataFrame(coords = cbind(hunt$X, hunt$Y), data =
hunt, proj4string = CRS("+init=epsg:32614"))
HR = gConvexHull(hunt_spdf, byid = FALSE)
plot(hunt_spdf)
plot(HR, add = TRUE)
HRDF = SpatialPolygonsDataFrame(HR, data = data.frame(IDs="Deer_HHR"))
HRDF = st_as_sf(HR)
HRDF
HRDF$NEWCOL = "ID"
HRDF
st_write(obj = HRDF, dsn="C:/Users/RKirton/Documents/Data files",
layer=paste0('DeerHHR_', hunt$ID), driver="ESRI Shapefile")
}
If you want to tag someone in a comment you need to use the # symbol, as in #SymbolixAU, then they'll get notified.
Also, it's hard to find the errors in your code without having a reproducible example.
To try and help, here's a working example of creating an sf object from a data.frame, then finding the convex hull, then saving the .shp file(s) to a directory. If you want specific help you need to supply some data for others to work with.
This example is only using sf objects, not sp
library(sf)
library(sfheaders)
## An example data.frame
df <- data.frame(
id = c( rep(1, 15), rep(2, 11))
, x = rnorm(26)
, y = rnorm(26)
)
sf <- sfheaders::sf_multipoint(obj = df, multipoint_id = "id", x = "x", y = "y")
sf <- sf::st_set_crs( sf, 32614 )
sf
# Simple feature collection with 2 features and 1 field
# geometry type: MULTIPOINT
# dimension: XY
# bbox: xmin: 1 ymin: 1 xmax: 26 ymax: 26
# z_range: zmin: NA zmax: NA
# m_range: mmin: NA mmax: NA
# epsg (SRID): 32614
# proj4string: +proj=utm +zone=14 +datum=WGS84 +units=m +no_defs
# id geometry
# 1 1 MULTIPOINT (1 26, 2 25, 3 2...
# 2 2 MULTIPOINT (16 11, 17 10, 1...
sf_hull <- sf::st_convex_hull( sf )
sf_hull
sf::st_write( obj = sf_hull, dsn = "~/Desktop/my_hull_dir/my_hull.shp")

Create voronoi polygon with simple feature in R

I'm not sure if I completely understood the help page to create voronoi polygons.
library(sf)
# function to get polygon from boundary box
bbox_polygon <- function(x) {
bb <- sf::st_bbox(x)
p <- matrix(
c(bb["xmin"], bb["ymin"],
bb["xmin"], bb["ymax"],
bb["xmax"], bb["ymax"],
bb["xmax"], bb["ymin"],
bb["xmin"], bb["ymin"]),
ncol = 2, byrow = T
)
sf::st_polygon(list(p))
}
nc <- st_centroid(st_read(system.file("shape/nc.shp", package="sf")))["BIR79"]
box <- st_sfc(bbox_polygon(nc))
v <- st_voronoi(nc, box)
plot(v)
output
Any idea to fix it?
Using the st_voronoi() example from the sf doc pages as a starting point, it seems that st_voronoi() doesn't work with an sf object consisting of points.
library(sf)
# function to get polygon from boundary box
bbox_polygon <- function(x) {
bb <- sf::st_bbox(x)
p <- matrix(
c(bb["xmin"], bb["ymin"],
bb["xmin"], bb["ymax"],
bb["xmax"], bb["ymax"],
bb["xmax"], bb["ymin"],
bb["xmin"], bb["ymin"]),
ncol = 2, byrow = T
)
sf::st_polygon(list(p))
}
nc <- st_read(system.file("shape/nc.shp", package="sf"))["BIR79"]
nc_centroids <- st_centroid(nc)
box <- st_sfc(bbox_polygon(nc_centroids))
head(nc_centroids)
Each point has a separate geometry entry.
Simple feature collection with 6 features and 1 field
geometry type: POINT
dimension: XY
bbox: xmin: -81.49826 ymin: 36.36145 xmax: -76.0275 ymax: 36.49101
epsg (SRID): 4267
proj4string: +proj=longlat +datum=NAD27 +no_defs
BIR79 geometry
1 1364 POINT(-81.4982613405682 36....
2 542 POINT(-81.125145134236 36.4...
3 3616 POINT(-80.6857465738484 36....
4 830 POINT(-76.0275025784544 36....
5 1606 POINT(-77.4105635619488 36....
6 1838 POINT(-76.9947769754215 36....
This combines the points into a multipoint geometry:
head(st_union(nc_centroids))
Output:
Geometry set for 1 feature
geometry type: MULTIPOINT
dimension: XY
bbox: xmin: -84.05976 ymin: 34.07663 xmax: -75.80982 ymax: 36.49101
epsg (SRID): 4267
proj4string: +proj=longlat +datum=NAD27 +no_defs
MULTIPOINT(-84.0597597853139 35.131067104959, -...
Using the union of points instead of the original sf object works:
v <- st_voronoi(st_union(nc_centroids), box)
plot(v, col = 0)
And here's how to get the correct state boundary instead of the original bounding box.
plot(st_intersection(st_cast(v), st_union(nc)), col = 0) # clip to smaller box
plot(nc_centroids, add = TRUE)
I'm trying to do something similar with marked points and I need to preserve the attributes of the points for the resulting tiles. Haven't figured that out yet.

Resources