Create square polygons from single centre coordinates and area in R - r

I am having issues plotting true to geographic extent pixels in R. the files come with a list of daily single coordinates and pixel size (area). There is also a Z element separate from this. The data structure looks this way:
X <- c(1,3,6,7)
Y <- c(3,2,7,8)
Z <- c(38,23,12,12)
Area <- c(32,23,45,67)
The X and Y are in degrees longitude and latitude while the area is in square kilometres. I create the point features easily using:
library(sp)
A <- cbind(X,Y,Z,Area)
B <- SpatialPoints(A)
I plot these easily using the area values to determine the "cex" for plotting. The Z column is intensity and I use these values to determine the colours . How do I create spatial polygons features using the areas for each point in R? I would be using these points to create gridded rasters.

This should do the trick:
library(rgeos) ## for gBuffer()
library(raster) ## for bind()
ww <- sqrt(B$Area)/2 ## Widths of buffers needed to produce desired areas
pp <- list()
for(i in seq_along(B)) {
pp[i] <- gBuffer(B[i], width=ww[i], quadsegs=1, capStyle="SQUARE")
}
PP <- do.call(bind, pp)
## Check that it worked
plot(PP)
plot(B, add=TRUE)
text(B, labels=1:4, adj=c(-1,0), col="red")

Just to update this a bit, here is an sf solution.
Function to create the square buffers
bSquare <- function(x, a) {
a <- sqrt(a)/2
return( sf::st_buffer(x, dist = a, nQuadSegs=1,
endCapStyle = "SQUARE") )
}
Some example data
library(sf)
xy <- st_as_sf(data.frame(x = c(1,3,6,7),
y = c(3,2,7,8), z = c(38,23,12,12),
area = c(32,23,45,67)),
coords = c("x", "y"),
agr = "constant")
With variable buffer
sb.var <- bSquare(xy, xy$area)
plot(st_geometry(sb.var))
plot(st_geometry(xy), pch=20, add=TRUE)
With fixed buffer
sb <- bSquare(xy, 32)
plot(st_geometry(sb))
plot(st_geometry(xy), pch=20, add=TRUE)

Related

Generate random points from a raster with a pre-established distance between the points in R

I want to generate random points over a raster, but I need these points to have a distance between them, like 10000 meters. I've seen that is possible to establish distance between points using the package 'spatstat', but I didn't understand how to use this package to generate points based on a raster.
This is what I did to generate the points without the distance criteria:
#Number of points
n.points = 63
#Generate random points from a raster
sampling = raster::sampleRandom(myraster,size=63,na.rm=TRUE,
cells=FALSE,xy=TRUE,sp=FALSE,asRaster=FALSE)
#Select just the coordinates and transform in a data frame
xy = as.data.frame(sampling[,c(1,2)])
#Spatialize these points
spdf = sp::SpatialPointsDataFrame(coords = xy,
data = as.data.frame(xy),
proj4string =
CRS("+proj=longlat +datum=WGS84 +no_defs"))
Here's some code that tries to select points according to your rule that the closest point to any point is exactly 10000m from it. This code ignores any issues of map projection and curvature of the Earth; that should be fine in a relatively small area, but not over a very large one.
r <- 10000 # distance between points
n.points <- 63
x <- matrix(NA, nrow = n.points, ncol = 2)
# Sample one point randomly in the region. I'll assume the region is
# +/- 100000 in each coordinate; if your region is some other shape,
# change this code:
x[1,] <- runif(2, -100000, 100000)
for (i in 2:n.points) {
# Count how many tries to find the next point
tries <- 0
repeat {
# Pick an existing point
j <- sample(1:(i-1), 1)
# Pick a direction from it
theta <- runif(1, 0, 2*pi)
# Find the point at distance r in that direction
y <- x[j,] + r*c(cos(theta), sin(theta))
# Is the point in the region?
if (any(y < -100000) || any(y > 100000))
next
# Calculate the distances to all other points
dists <- apply(x[1:(i-1), , drop=FALSE],
1,
function(row) sqrt(sum((row - y)^2)))
# If this point is far enough from existing points, keep it
if (all(dists >= r))
break
# If not, try again, but not forever...
tries <- tries + 1
if (tries > 100000)
stop("failed")
}
x[i,] <- y
}
plot(x)
Created on 2022-10-10 with reprex v2.0.2

Create polygon from outermost point spatial coordinates

I have a large dataframe of point coordinates and I am trying to make a polygon out of the edge of the coordinates. Some of the points fall near the middle, so I do not want those points to shape the boundary of the polygon created. These are spatial data and I do convert them into sf or terra objects, but in the simplest form they are just (x,y) coordinates.
I've looked and I can't find any already developed function for this task.
Here's a basic set of coordinates that replicate the problem:
lat <- c(-34.8861,-34.9845,-34.9839,-34.4555,-34.3272,-34.922,-34.7)
lon <- c(118,117.721,117.118,116.789,115.785,115.843,116.5)
plot(lon,lat)
Any ideas for creating a polygon out of the outermost points of these coordinates?
something like this:
library(sf)
df <- data.frame(x = lon, y = lat)
pts1 <- st_as_sf(x = df, coords = c('x', 'y'))
my_hull <- st_convex_hull(st_union(pts1))
plot(my_hull)
With 'terra' it goes like this:
lat <- c(-34.8861,-34.9845,-34.9839,-34.4555,-34.3272,-34.922,-34.7)
lon <- c(118,117.721,117.118,116.789,115.785,115.843,116.5)
library(terra)
v <- vect(cbind(lon, lat), crs="+proj=longlat")
x <- convHull(v)
plot(x, col="red")
points(v, cex=2, col="blue")

Repeat for loop for all rows of a spatial points data frame

I want to calculate the shortestPath distance (using gDistance package) between a set of geographic coordinates, using a transition layer of the ocean to prevent 'movement' across land.
Here is how I created the transition layer:
library(raster); library(gdistance); library(maptools); library(rgdal); library(sp)
mapcrs <- "+proj=longlat +datum=WGS84 +no_defs"
data(wrld_simpl)
world <- wrld_simpl
worldshp <- spTransform(world, mapcrs)
ras <- raster(nrow=300,ncol=300)
crs(ras) <- crs(oceans.shp)
extent(ras) <- extent(worldshp)
landmask <- rasterize(worldshp, ras)
landras <- is.na(landmask)
tr <- transition(landras, transitionFunction = mean, directions = 8, symm = FALSE)
tr = geoCorrection(tr, scl=FALSE)
I then want to calculate the shortestPath distance between every coordinate in my dataset i.e. location 1 to location n, location 2 to location n etc.
Let's produce some hypothetical geographic coordinates and convert to spatial points
x <- rnorm(10, mean = -40, sd=5)
y <- rnorm(10, mean = 20, sd=5)
xy <- cbind(x,y); colnames(xy) <- c("lon","lat")
xy <- SpatialPoints(xy); projection(xy) <- projection(mapcrs)
Using the shortestPath function in gDistance, I can calculate the distance from the first coordinate (i.e. xy[1]) to all other xy coordinates, like so.
dist <- shortestPath(tr, origin = xy, goal = xy, output="SpatialLines")
I then tried to apply a for loop to sequentially calculate distance from location 1 to all other locations, and then calculating distance from location 2 to all other locations etc., which I wrote as follows:
for(i in seq_along(xy)){
AtoB <- shortestPath(tr, origin = xy[i,], goal=xy, output="SpatialLines")
i <- i+1
}
This, however, still only calculates the distances relative to the first xy spatial point and does not 'loop' for all subsequent rows. I don't know what I'm doing wrong. It's probably super-easy, but I'm struggling. Any help would be appreciated.
Thanks in advance,
Tony
---- UPDATE ----
We have come up with a bit of a work around (thanks Charley Clubley) but it still won't produce outputs for every spatial line. This will generate a matrix of distances.
The work around is as follows:
Using xy as a matrix, not spatial points
distances <- matrix(ncol=nrow(xy), nrow=nrow(xy))
xy_b <- xy ## Coords needs to be as a matrix (not spatial points)
## This generates an error indicating there are no more rows to delete once complete, but the computation works
for (i in 1:nrow(xy_b)) {
AtoB <-shortestPath(tr, xy_b, xy, output="SpatialLines")
length <- SpatialLinesLengths(AtoB)
distances[i, ] <- length
xy_b <- xy_b[-1,]
}

Row ordering for polygons

My question is simple. Is there an automatic way to order you data so that it makes "clean" polygons? I have functions that are generating rings (specifically the ahull function), and I would like a way to cleanly produce polygons using such functions. Here is an example.
x <- c(1:3, 3:1, 1)
y <- c(1,1,1,3,3,2, 1)
xy <- cbind(x,y)
Sr1 <- Polygon(xy)
Srs1 = Polygons(list(Sr1), "s1")
SpP = SpatialPolygons(list(Srs1))
plot(SpP)
z <- runif(7)
xyz <- cbind(x,y,z)
xyz <- xyz[order(z),]
xy <- xyz[,-3]
xy <- rbind(xy, xy[1,])
Sr1 <- Polygon(xy)
Srs1 = Polygons(list(Sr1), "s1")
SpP = SpatialPolygons(list(Srs1))
SpP = SpatialPolygons(list(Srs1))
plot(SpP)
Here is my real data: https://drive.google.com/file/d/0B8QG4cbDqH0UOUlobnlWaDgwOWs/edit?usp=sharing
In a sense, you have answered your own question.
Assuming you have a set of points, and you use ahull(...) in the alphahull package to generate the convex hull, you can extract the points on the boundary, in the correct order, directly from the ahull object. Here is an example:
library(sp)
library(alphahull)
set.seed(1) # for reproducible example
X <- rnorm(100)
Y <- rnorm(100)
plot(X,Y)
XY <- cbind(X,Y)
hull <- ahull(XY,alpha=1)
plot(hull)
# extract the row numbers of the boundary points, in convex order.
indx=hull$arcs[,"end1"]
points <- XY[indx,] # extract the boundary points from XY
points <- rbind(points,points[1,]) # add the closing point
# create the SpatialPolygonsDataFrame
SpP = SpatialPolygons(list(Polygons(list(Polygon(points)),ID="s1")))
plot(SpP)
points(XY)
EDIT Response to OP's providing their dataset.
ahull(...) seems to fail, without warning, with your dataset - it does not produce any convex hulls. After a bit if experimentation, it looks like the problem has to do with the magnitude of the x,y values. If I divide everything by 1000, it works. No idea what's going one with that (perhaps someone else will provide an insight??). Anyway, here's the code and the result:
library(sp)
library(alphahull)
df <- read.csv("ahull problem.csv")
hull <- ahull(df[2:3]/1000,alpha=2)
plot(hull)
# extract the row numbers of the boundary points, in convex order.
indx=hull$arcs[,"end1"]
points <- df[indx,2:3] # extract the boundary points from df
points <- rbind(points,points[1,]) # add the closing point
# create the SpatialPolygonsDataFrame
SpP = SpatialPolygons(list(Polygons(list(Polygon(points)),ID="s1")))
plot(SpP)
points(df[2:3])
Note also that alpha=2. Setting alpha=1 with this dataset actually generates 2 hulls, one with 1 point and one with all the other points. Setting alpha=2 creates 1 hull.

Cut polygons using contour line beneath the polygon layers

I would like to cut a polygon layer, according to the elevation, into two parts (upper and lower part). The polygon might convex or concave, and the position to cut might vary from each other. The contour line has an interval of 5m, which means I might need to generate a contour with much condensed contour lines, e.g, 1m interval. Any idea on how to do it, better in ArcGIS, or in R?
Below is the running example for the Q:
library(sp)
library(raster)
r<-raster(ncol=100,nrow=100)
values(r)<-rep(1:100,100)
plot(r) ### I have no idea why half of the value is negative...
p1<-cbind(c(-100,-90,-50,-100),c(60,70,30,30,60))
p2<-cbind(c(0,50,100,0),c(0,-25,10,0))
p1p<-Polygons(list(Polygon(p1,hole=T)),"p1")
p2p<-Polygons(list(Polygon(p2,hole=T)),"p2")
p<-SpatialPolygons(list(p1p,p2p),1:2)
plot(p,add=T)
segments(-90,80,-90,20) ##where the polygon could be devided
segments(50,20,50,-30) ##
Thanks in advance~
Marco
If I understand correctly, you can use the rgeos package and related Spatial tools in R.
I took the trick to buffer an intersected line and then generate the "difference" polygon from this site:
http://www.chopshopgeo.com/blog/?p=89
Generate example raster, and an overlying polygon.
vdata <- list(x = 1:nrow(volcano), y = 1:ncol(volcano), z = volcano)
## raw polygon data created using image(vdata); xy <- locator()
xy <- structure(list(x = c(43.4965355534823, 41.7658494766076, 36.2591210501883,
25.560334393145, 13.7602020508178, 18.7949251835441, 29.179041644792,
40.6645037913237, 44.2832110429707, 47.272577903027, 47.5872480988224
), y = c(30.0641086410103, 34.1278207016757, 37.6989616034726,
40.900674136118, 32.7732500147872, 27.4781100569505, 22.5523984682652,
22.7986840476995, 24.5226831037393, 29.3252519027075, 33.8815351222414
)), .Names = c("x", "y"))
## close the polygon
coords <- cbind(xy$x, xy$y)
coords <- rbind(coords, coords[1,])
library(sp)
## create a Spatial polygons object
poly <- SpatialPolygons(list(Polygons(list(Polygon(coords, hole = FALSE)), "1")))
## create a contour line that cuts the polygon at height 171
cl <- contourLines(vdata, levels = 171)
## for ContourLines2SLDF
library(maptools)
clines <- ContourLines2SLDF(cl)
Now, intersect the polygon with the line, then buffer the line slightly and difference that again with the polygon to give a multipart poly.
library(rgeos)
lpi <- gIntersection(poly, clines)
blpi <- gBuffer(lpi, width = 0.000001)
dpi <- gDifference(poly, blpi)
Plot the original data, and the polygon halves extracted manually from the Spatial object.
par(mfrow = c(2,1))
image(vdata)
plot(poly, add = TRUE)
plot(SpatialPolygons(list(Polygons(list(dpi#polygons[[1]]#Polygons[[1]]), "1"))),
add = TRUE, col = "lightblue")
image(vdata)
plot(poly, add = TRUE)
cl <- contourLines(vdata, levels = 171)
plot(SpatialPolygons(list(Polygons(list(dpi#polygons[[1]]#Polygons[[2]]), "2"))),
add = TRUE, col = "lightgreen")
That works for this fairly simple case, it might be useful for your scenario.

Resources