Memory (RAM) issues using intersect from raster package - r

I have trouble getting the intersection between two large SpatialPolygonsDataFrame on R. My polygons data represent buildings and administrative boundaries, and I am trying to get the intersection polygons between them.
I understand that the intersect function from the raster package and gIntersection from the rgeos package can do this job (with a few differences) but they cannot handle all my polygons at once (about 50.000 polygons/entity).
For this reason, I have to split my calculation within a loop, saving the result for each step. The problem is: these functions keep filling my physical memory, and I cannot clean it. I tried using rm() and gc(), but it does not change a thing. The memory issue crashes my R session, and I cannot do my calculation.
Is there a way to free the RAM during simulation, within loops ? Or to avoid this memory issue ?
Here comes a reproducible example, for random polygons.
library(raster)
library(sp)
library(rgeos)
#Generating 50000 points (for smaller polygons) and 150000 (for larger polygons) in a square of side 100000
size=100000
Nb_points1=50000
Nb_points2=150000
start_point=matrix(c(sample(x = 1:size,size = Nb_points1,replace = T),sample(x = 1:size,size = Nb_points1,replace = T)),ncol=2)
start_point2=matrix(c(sample(x = 1:size,size = Nb_points2,replace = T),sample(x = 1:size,size = Nb_points2,replace = T)),ncol=2)
#Defining different sides length
radius=sample(x = 1:50,size = Nb_points1,replace = T)
radius2=sample(x = 1:150,size = Nb_points2,replace = T)
#Generating list of polygons coordinates
coords=list()
for(y in 1:Nb_points1){
xmin=max(0,start_point[y,1]-radius[y])
xmax=min(size,start_point[y,1]+radius[y])
ymin=max(0,start_point[y,2]-radius[y])
ymax=min(size,start_point[y,2]+radius[y])
coords[[y]]=matrix(c(xmin,xmin,xmax,xmax,ymin,ymax,ymax,ymin),ncol=2)
}
coords2=list()
for(y in 1:Nb_points2){
xmin=max(0,start_point2[y,1]-radius2[y])
xmax=min(size,start_point2[y,1]+radius2[y])
ymin=max(0,start_point2[y,2]-radius2[y])
ymax=min(size,start_point2[y,2]+radius2[y])
coords2[[y]]=matrix(c(xmin,xmin,xmax,xmax,ymin,ymax,ymax,ymin),ncol=2)
}
#Generating 75000 polygons
Poly=SpatialPolygons(Srl = lapply(1:Nb_points1,function(y) Polygons(srl = list(Polygon(coords=coords[y],hole = F)),ID = y)),proj4string = CRS('+init=epsg:2154'))
Poly2=SpatialPolygons(Srl = lapply(1:Nb_points2,function(y)Polygons(srl = list(Polygon(coords=coords2[y],hole = F)),ID = y)),proj4string = CRS('+init=epsg:2154'))
#Union of overlapping polygons
aaa=gUnionCascaded(Poly)
bbb=gUnionCascaded(Poly2)
aaa=disaggregate(aaa)
bbb=disaggregate(bbb)
intersection=gIntersects(spgeom1 = aaa,bbb,byid = T,returnDense = F)
#Loop on the intersect function
pb <- txtProgressBar(min = 0, max = ceiling(length(aaa)/1000), style = 3)
for(j in 1:ceiling(length(aaa)/1000)){
tmp_aaa=aaa[((j-1)*1000+1):(j*1000),]
tmp_bbb=bbb[unique(unlist(intersection[((j-1)*1000+1):(j*1000)])),]
List_inter=intersect(tmp_aaa,tmp_bbb)
gc()
gc()
gc()
setTxtProgressBar(pb, j)
}
Thank you !

You can consider using the st_intersects and st_intersection functions of package sf. For example:
aaa2 <- sf::st_as_sf(aaa)
bbb2 <- sf::st_as_sf(bbb)
intersections_mat <- sf::st_intersects(aaa2, bbb2)
intersections <- list()
for (int in seq_along(intersections_mat)){
if (length(intersections_mat[[int]]) != 0){
intersections[[int]] <- sf::st_intersection(aaa2[int,],
bbb2[intersections_mat[[int]],])
}
}
will give you an intersection_mat of length equal to aaa, and containing , for each feature of aaa, the "indexes" of bbb elements with which it intersects ("empty" if no intersection found):
> intersections_mat
Sparse geometry binary predicate list of length 48503, where the predicate was `intersects'
first 10 elements:
1: 562
2: (empty)
3: 571
4: 731
5: (empty)
6: (empty)
7: (empty)
8: 589
9: 715
10: (empty)
, and an intersection list containing the list of intersecting polygons:
>head(intersections)
[[1]]
Simple feature collection with 1 feature and 0 fields
geometry type: POLYGON
dimension: XY
bbox: xmin: 98873 ymin: 33 xmax: 98946 ymax: 98
epsg (SRID): 2154
proj4string: +proj=lcc +lat_1=49 +lat_2=44 +lat_0=46.5 +lon_0=3 +x_0=700000 +y_0=6600000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs
geometry
1 POLYGON ((98873 33, 98873 9...
[[2]]
NULL
[[3]]
Simple feature collection with 1 feature and 0 fields
geometry type: POLYGON
dimension: XY
bbox: xmin: 11792 ymin: 3 xmax: 11806 ymax: 17
epsg (SRID): 2154
proj4string: +proj=lcc +lat_1=49 +lat_2=44 +lat_0=46.5 +lon_0=3 +x_0=700000 +y_0=6600000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs
geometry
1 POLYGON ((11792 3, 11792 17...
(i.e., intersections[[1]] is the intersection between polygon 1 of aaa and polygon 571 of bbb)
HTH.

The example works fine for me (8 GB RAM), after a few changes to the loop. See below. Tese changes are not related to memory use --- you were not storing the results.
List_inter <- list()
for(j in 1:ceiling(length(aaa)/1000)){
begin <- (j-1) * 1000 + 1
end <- min((j*1000), length(aaa))
tmp_aaa <- aaa[begin:end,]
tmp_bbb <- bbb[unique(unlist(intersection[begin:end])),]
List_inter[[j]] <- intersect(tmp_aaa,tmp_bbb)
cat(j, "\n"); flush.console()
}
x <- do.call(bind, List_inter)
Alternatively, you could write the intermediate results to disk, and deal with them later:
inters <- intersect(tmp_aaa,tmp_bbb)
saveRDS(inters, paste0(j, '.rds'))
Or
shapefile(inters, paste0(j, '.shp'))

Related

raster::rasterToContour; contour lines are not continuous

I am trying to extract contour lines from a raster object using the raster package in R.
rasterToContour appears to work well and plots nicely, but when investigated it appears the contour lines are broken up into irregular segments. Example data from ?rasterToContour
library(raster)
f <- system.file("external/test.grd", package="raster")
r <- raster(f)
x <- rasterToContour(r)
class(x)
plot(r)
plot(x, add=TRUE)
I am trying to extract the contour line of a sample site in the raster. So, we choose a random site, extract its elevation, and run rasterToContour() again, specifying the elevation for the contour line level.
# our sample site - a random cell chosen on the raster
xyFromCell(r, 5000) %>%
SpatialPoints(proj4string = crs(r)) %>%
{. ->> site_sp} %>%
st_as_sf %>%
{. ->> site_sf}
# find elevation of sample site, and extract contour lines
extract(r, site_sf) %>%
{. ->> site_elevation}
# extract contour lines
r %>%
rasterToContour(levels = site_elevation) %>%
{. ->> contours_sp} %>%
st_as_sf %>%
{. ->> contours_sf}
# plot the site and new contour lines (approx elevation 326)
plot(r)
plot(contours_sf, add = TRUE)
plot(site_sf, add = TRUE)
# plot the contour lines and sample site - using sf and ggplot
ggplot()+
geom_sf(data = contours_sf)+
geom_sf(data = site_sf, color = 'red')
Then we use st_intersects to find the lines that intersect the site (with a buffer width of 100 to ensure it touches the line). But, this returns all of the contour lines.
contours_sf %>%
filter(
st_intersects(., site_sf %>% st_buffer(100), sparse = FALSE)[1,]
) %>%
ggplot()+
geom_sf()
I assume all lines are returned because they appear to be a single MULTILINESTRING sf object.
contours_sf
# Simple feature collection with 1 feature and 1 field
# geometry type: MULTILINESTRING
# dimension: XY
# bbox: xmin: 178923.1 ymin: 329720 xmax: 181460 ymax: 333412.3
# CRS: +proj=sterea +lat_0=52.1561605555556 +lon_0=5.38763888888889 +k=0.9999079 +x_0=155000 +y_0=463000 +datum=WGS84 +units=m +no_defs
# level geometry
# C_1 326.849822998047 MULTILINESTRING ((179619.3 ...
So, I have split the contours_sf MULTILINESTRING into individual lines using ngeo::st_segments() (I couldn't find any sf way to do this, but am open to using alternative methods, especially if this is the problem).
Unexpectedly this returns 394 features; from looking at the figure I would expect approximately 15 separate lines.
contours_sf %>%
nngeo::st_segments()
# Simple feature collection with 394 features and 1 field
# geometry type: LINESTRING
# dimension: XY
# bbox: xmin: 178923.1 ymin: 329720 xmax: 181460 ymax: 333412.3
# CRS: +proj=sterea +lat_0=52.1561605555556 +lon_0=5.38763888888889 +k=0.9999079 +x_0=155000 +y_0=463000 +datum=WGS84 +units=m +no_defs
# First 10 features:
# level result
# 1 326.849822998047 LINESTRING (179619.3 329739...
# 2 326.849822998047 LINESTRING (179580 329720.4...
# 3 326.849822998047 LINESTRING (179540 329720, ...
# 4 326.849822998047 LINESTRING (179500 329735.8...
# 5 326.849822998047 LINESTRING (179495.3 329740...
# 6 326.849822998047 LINESTRING (179460 329764, ...
# 7 326.849822998047 LINESTRING (179442.6 329780...
# 8 326.849822998047 LINESTRING (179420 329810, ...
# 9 326.849822998047 LINESTRING (179410.2 329820...
# 10 326.849822998047 LINESTRING (179380 329847.3...
Then, when we filter to keep only the lines which intersect the site (with a buffer width of 100), only a small section of the expected contour line is returned (red section of line, I assume reflective of the 100 buffer width).
contours_sf %>%
nngeo::st_segments() %>%
filter(
# this syntax used as recommended by this answer https://stackoverflow.com/a/57025700/13478749
st_intersects(., site_sf %>% st_buffer(100), sparse = FALSE)
) %>%
ggplot()+
geom_sf(colour = 'red', size = 3)+
geom_sf(data = contours_sf)+
geom_sf(data = site_sf, colour = 'cyan')+
geom_sf(data = site_sf %>% st_buffer(100), colour = 'cyan', fill = NA)
Anyone got ideas for the following points:
Explain why the contour lines are 'broken'
Provide an efficient method for 'joining' the broken pieces together
An alternative to nngeo::st_segments(), if this is in fact the source of the 394 lines not ~15
Converting the MULTILINESTRING to a LINESTRING seems to do what you need:
contours_sf %>% st_cast("LINESTRING") %>%
filter(st_intersects(., st_buffer(site_sf, 100), sparse=FALSE)[,1]) %>%
ggplot()+
geom_sf(data = contours_sf)+
geom_sf(data = site_sf, color = 'red') +
geom_sf(color = 'pink')
Perhaps it works better if you start by disaggregating the lines
library(raster)
f <- system.file("external/test.grd", package="raster")
r <- raster(f)
x <- rasterToContour(r)
x <- disaggregate(x)
Or with terra
library(terra)
r <- rast(f)
x <- as.contour(r)
x
# class : SpatVector
# geometry : lines
# dimensions : 8, 1 (geometries, attributes)
x <- disaggregate(x)
x
# class : SpatVector
# geometry : lines
# dimensions : 56, 1 (geometries, attributes)
And you can continue like this
y <- st_as_sf(x)
Or like this
r <- rast(system.file("ex/meuse.tif", package="terra"))
site <- vect(xyFromCell(r, 5000), crs=crs(r))
elevation <- extract(r, site)
v <- disaggregate(as.contour(r, levels=elevation))
i <- which.min(distance(site, v))
vv <- v[i]
plot(r)
lines(v)
lines(vv, col="red", lwd=2)
points(site, col="blue", cex=2)

Converting coordinates, radius and site type data from .csv to raster in R

I am having a bit of a problem converting .csv files into raster in R... My .csv file contains coordinates (long and lat) radius (in deg) and site type. I was able to convert the coordinates into raster and was able to plot the circles using st_buffer() but I am facing two problems:
I can't convert the circles into a raster... I tried with rasterize() and fasterize() and both did not work all I'm getting is an empty raster layer
I can't seem to classify the coordinates and circles according to the site type
Any idea of what I might be doing wrong? and how can I classify my circles?
Thank you in advance!
Here is the code I used:
> head(sp_csv_data)
Longitude Latitude Radius Site_Type
1 -177.87567 -24.715167 10 MIG
2 -83.21360 14.401800 1 OBS
3 -82.59392 9.589192 1 NES
4 -82.41060 9.492750 1 NES;BRE
5 -81.17555 7.196750 5 OBS
6 -80.95770 8.852700 1 NES
##Projection systems used
rob_pacific <- "+proj=robin +lon_0=180 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs" # Best to define these first so you don't make mistakes below
longlat <- "+proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0"
####Converting to raster####
# Creating a empty raster at 0.5° resolution (you can increase the resolution to get a better border precision)
rs <- raster(ncol = 360*2, nrow = 180*2)
rs[] <- 1:ncell(rs)
crs(rs) <- CRS(longlat)
##Converting to raster
sp_raster <- rasterize(sp_csv_data[,1:2], rs, sp_csv_data[,3])
# Resampling to make sure that it's in the same resolution as sampling area
sp_raster <- resample(sp_raster, rs, resample = "ngb")
#converting into an sf spatial polygon dataframe
sp_raster <- as(sp_raster, "SpatialPolygonsDataFrame")
species_sp <- spTransform(sp_raster, CRS(longlat))
# Define a long & slim polygon that overlaps the meridian line & set its CRS to match that of world
polygon <- st_polygon(x = list(rbind(c(-0.0001, 90),
c(0, 90),
c(0, -90),
c(-0.0001, -90),
c(-0.0001, 90)))) %>%
st_sfc() %>%
st_set_crs(longlat)
# Transform the species distribution polygon object to a Pacific-centred projection polygon object
sp_robinson <- species_sp %>%
st_as_sf() %>%
st_difference(polygon) %>%
st_transform(crs = rob_pacific)
# There is a line in the middle of Antarctica. This is because we have split the map after reprojection. We need to fix this:
bbox1 <- st_bbox(sp_robinson)
bbox1[c(1,3)] <- c(-1e-5,1e-5)
polygon1 <- st_as_sfc(bbox1)
crosses1 <- sp_robinson %>%
st_intersects(polygon1) %>%
sapply(length) %>%
as.logical %>%
which
# Adding buffer 0
sp_robinson[crosses1, ] %<>%
st_buffer(0)
# Adding the circles to the coordinates
sp_robinson2 <- st_buffer(sp_robinson, dist = radius)
> print(sp_robinson2)
Simple feature collection with 143 features and 1 field
geometry type: POLYGON
dimension: XY
bbox: xmin: -17188220 ymin: -5706207 xmax: 17263210 ymax: 6179000
CRS: +proj=robin +lon_0=180 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs
First 10 features:
layer geometry
1 5 POLYGON ((3556791 4766657, ...
2 10 POLYGON ((13713529 4995696,...
3 10 POLYGON ((12834403 4946927,...
4 10 POLYGON ((9991443 4801974, ...
5 5 POLYGON ((4254202 4304190, ...
6 5 POLYGON ((11423719 4327354,...
7 10 POLYGON ((9582710 4282247, ...
8 10 POLYGON ((588877.2 4166512,...
9 5 POLYGON ((4522824 3894919, ...
10 10 POLYGON ((3828685 3886205, ...
sp_robinson3 <- fasterize(sp_robinson2, rs)
> print(sp_robinson3)
class : RasterLayer
dimensions : 360, 720, 259200 (nrow, ncol, ncell)
resolution : 0.5, 0.5 (x, y)
extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
crs : +proj=robin +lon_0=180 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs
source : memory
names : layer
values : NA, NA (min, max)
I want to convert sp_robinson2 into a raster called sp_robinson3 but as you can see both fasterize()and rasterize()are giving me an empty raster layer...
The reason why rasterize does not work in the end is obvious: the crs of the vector and raster do not match. But can you edit your question a bit more to explain what you want to achieve? It is very odd to create a raster and then polygons and then rasterize these again. My impression is that you are making things much more complicated than need be. You also talk about circles. Which circles? I am guessing you may want circles around your points, but that is not what you are doing. It would probably be helpful to figure out things step by step, first figure out how to get the general result you want, then how to get it Pacific centered.
Below is a cleaned up version of the first part of your code. It also makes it reproducible. You need to create example in code, like this:
lon <- c(-177.87567, -83.2136, -82.59392, -82.4106, -81.17555, -80.9577)
lat <- c(-24.715167, 14.4018, 9.589192, 9.49275, 7.19675, 8.8527)
radius <- c(10, 1, 1, 1, 5, 1)
site <- c("MIG", "OBS", "NES", "NES;BRE", "OBS", "NES")
sp_csv_data <- data.frame(lon, lat, radius, site)
## cleaned up projection definitions
rob_pacific <- "+proj=robin +lon_0=180 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs"
longlat <- "+proj=longlat +datum=WGS84"
##Converting to raster
# Creating a empty raster at 0.5° resolution
rs <- raster(res=0.5, crs=lonlat)
values(rs) <- 1:ncell(rs)
sp_raster <- rasterize(sp_csv_data[,1:2], rs, sp_csv_data[,3])
## makes no sense: sp_raster <- resample(sp_raster, rs, resample = "ngb")
#converting into an SpatialPolygonsDataframe
species_sp <- as(sp_raster, "SpatialPolygonsDataFrame")
## makes no sense: species_sp <- spTransform(sp_raster, CRS(longlat))

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