How to rasterize shape without exact raster mask? - r

I have a polygon of the extent I would like to rasterize and i have a raster with the projection and pixelsize etc that I want to use for the polygon, but the raster is smaller than the polygon.
I need to have a new raster with the extent of the polygon but also with the pixelsize and pixel order and place like the smaller raster.

Example data
library(raster)
p <- readRDS(system.file('external/lux.rds', package='raster'))
r <- raster(p[4,])
res(r) <- 0.05
Say you want to rasterize all of p. r has the desired resolution, but the extent is too small.
To get a larger raster, you can do
rr1 <- setExtent(r, extent(p)+res(r), keepres=TRUE, snap=TRUE)
#or
rr2 <- extend(r, extent(p)+res(r))
followed by
x <- rasterize(p, rr1)
You can also do something a variation on this
r2 <- raster(xmn=5.7, xmx=6.6, ymn=49.4, ymx=50.2)
res(r2) <- 0.03
y <- rasterize(p, r2)

Related

R raster::crop() The upper boundary of my cropped raster is always horizontal- why?

I'm trying to crop a large multipolygon shapefile by a single, smaller polygon. It works using st_intersection, however this takes a very long time, so I'm instead trying to convert the multipolygon to a raster, and crop that raster by the smaller polygon.
## packages - sorry if I've missed any!
library(raster)
library(rgdal)
library(fasterize)
library(sf)
## load files
shp1 <- st_read("pathtoshp", crs = 27700) # a large multipolygon shapefile to crop
### image below created using ggplot- ignore the black boundaries!
shp2 <- st_read("pathtoshp", crs = 27700) # a single, smaller polygon shapefile, to crop shp1 by
plot(shp2)
## convert to raster (faster than st_intersection)
projection1 <- CRS('+init=EPSG:27700')
rst_template <- raster(ncols = 1000, nrows = 1000,
crs = projection1,
ext = extent(shp1))
rst_shp1 <- fasterize(shp1, rst_template)
plot(rst_shp1)
rst_shp2 <- crop(rst_shp1, shp2)
plot(rst_shp2)
When I plot shp2, the upper boundary is flat, rather than fitting the true boundary of the shp2 polygon.
Any help would be greatly appreciated!
Maybe try raster::mask() instead of crop(). crop() uses the second argument as an extent with which to crop a raster; i.e. it's taking the bounding box (extent) of your second argument and cropping that entire rectangle from your raster.
Something important to understand about raster objects is that they are all rectangular. The white space you see surrounding your shape are just NA values.
raster::mask() will take your original raster, and a spatial object (raster, sf, etc.) and replace all values in your raster which don't overlap with your spatial object to NA (by default, you can supply other replacement values). Though I will say, mask() will likely also take awhile to run, so you may be better off just sticking with sf objects.
I would suggest moving to the "terra" package (faster and easier to use than "raster").
Here is an example.
library(terra)
r <- rast(system.file("ex/elev.tif", package="terra"))
v <- vect(system.file("ex/lux.shp", package="terra"))[4]
x <- crop(r, v)
plot(x); lines(v)
As edixon1 points out, a raster is always rectangular. If you want to set cells outside of the polygon to NA, you can do
x <- crop(r, v, mask=TRUE)
plot(x); lines(v)
In this example it makes no sense, but you could first rasterize
x <- crop(r, v)
y <- rasterize(v, x)
m <- mask(x, y)
plot(m); lines(v)
I am not sure if this answers your question. But if it does not, then please edit your question to make it reproducible, for example using the example data above.

calculating road density raster from road shapefile

I'm looking to turn a shapefile with roads (which includes a column of length per road) in the Eastern half of the USA into a raster of 1x1km of road density, using R.
I can't find a straightforward way in Arcmap (Line density works with a radius from the cell center instead of just the cell).
Here is a solution that creates polygons from the raster cells (adapted from my answer here). You may need to to this for subsets of your dataset and then combine.
Example data
library(terra)
v <- vect(system.file("ex/lux.shp", package="terra"))
roads <- as.lines(v)
rs <- rast(v)
Solution
values(rs) <- 1:ncell(rs)
names(rs) <- "rast"
rsp <- as.polygons(rs)
rp <- intersect(roads, rsp)
rp$length <- perim(rp) / 1000 #km
x <- tapply(rp$length, rp$rast, sum)
r <- rast(rs)
r[as.integer(names(x))] <- as.vector(x)
plot(r)
lines(roads)

raster in R: Subset a raster image given a pixel size

I've like to subset a raster image given the coordinates center point and the desired x and y size in pixels. In my example:
library(raster)
set.seed(5)
##Create a raster
r <- raster(ncol=10, nrow=10, crs="+proj=utm +zone=1 +datum=WGS84", xmn=0, xmx=50, ymn=0, ymx=50)
s1 <- stack(lapply(1:4, function(i) setValues(r, runif(ncell(r)))))
# Create 10 random points in the raster
pts <- data.frame(pts=sampleRandom(s1, 10, xy=TRUE)[,1:2], status=rep(c("A","B"),5))
Now, I've like to create the 10 new images that will be a subset of size (X desired width of subset image = 5 pixels and Y desired width of subset image = 5 pixels) with center point (pts$x, pts$y), with the same pixel size. Finally, a save each image as GeoTIFF:
for(i in 1:length(pts)){
writeRaster(r[[i]],filename=paste(pts,"_",i,sep=""),
format="GTiff",datatype="FLT4S",overwrite=TRUE)
}
This is possible?
Hey I was able to do this by creating square buffer around your points, big enough to capture a 5 by 5 raster. I then used those buffers to clip your raster. Here is my code with comments:
library(raster)
library(rgeos)
set.seed(5)
##Create a raster
r <- raster(ncol=10, nrow=10, crs="+proj=utm +zone=1 +datum=WGS84", xmn=0, xmx=50, ymn=0, ymx=50)
s1 <- stack(lapply(1:4, function(i) setValues(r, runif(ncell(r)))))
# Create 10 random points in the raster
pts <- data.frame(pts=sampleRandom(s1, 10, xy=TRUE)[,1:2], status=rep(c("A","B"),5))
pts_points = SpatialPointsDataFrame(pts[,1:2], data.frame(pts[,3]))
## Creating square buffers around your points
pts_buffer = gBuffer(pts_points, byid = TRUE, capStyle = "SQUARE", width = 12.5)
## looping through all your points
for (i in 1:nrow(pts_buffer)){
square = pts_buffer[i,]
val = square#data$pts...3. ## Gets the value of the point ("A" or "B")
## Contains a stack of raster clipped for the current point for the raster stack
clipped = mask(s1, square)
## Export the clipped raster here
}
A width of 12.5 was used for the buffers to make sure a 5 by 5 raster was created. To change the subset size of the rasters, just change the width of the buffer!
This is how the buffer points look like on top of the rasters:
In the code, We loop over each square and clip the raster to the area, here is how the raster stack looks like after being clipped by one of the areas:
Let me know if this helps, or if anything needs to be clarified!

How to subset a raster based on grid cell values

My following question builds on the solution proposed by #jbaums on this post: Global Raster of geographic distances
For the purpose of reproducing the example, I have a raster dataset of distances to the nearest coastline:
library(rasterVis); library(raster); library(maptools)
data(wrld_simpl)
# Create a raster template for rasterizing the polys.
r <- raster(xmn=-180, xmx=180, ymn=-90, ymx=90, res=1)
# Rasterize and set land pixels to NA
r2 <- rasterize(wrld_simpl, r, 1)
r3 <- mask(is.na(r2), r2, maskvalue=1, updatevalue=NA)
# Calculate distance to nearest non-NA pixel
d <- distance(r3) # if claculating distances on land instead of ocean: d <- distance(r3)
# Optionally set non-land pixels to NA (otherwise values are "distance to non-land")
d <- d*r2
levelplot(d/1000, margin=FALSE, at=seq(0, maxValue(d)/1000, length=100),colorkey=list(height=0.6), main='Distance to coast (km)')
The data looks like this:
From here, I need to subset the distance raster (d), or create a new raster, that only contains cells for which the distance to coastline is less than 200 km. I have tried using getValues() to identify the cells for which the value <= 200 (as show below), but so far without success. Can anyone help? Am I on the right track?
#vector of desired cell numbers
my.pts <- which(getValues(d) <= 200)
# create raster the same size as d filled with NAs
bar <- raster(ncols=ncol(d), nrows=nrow(d), res=res(d))
bar[] <- NA
# replace the values with those in d
bar[my.pts] <- d[my.pts]
I think this is what you are looking for, you can treat a raster like a matrix here right after you d <- d*r2 line:
d[d>=200000]<-NA
levelplot(d/1000, margin=FALSE, at=seq(0, maxValue(d)/1000, length=100),colorkey=list(height=0.6), main='Distance to coast (km)')
(in case you forgot: the unit is in meters so the threshold should be 200000, not 200)

Global Raster of geographic distances

Im wondering if someone has built a raster of the continents of the world where each cell equals the distance of that cell cell to the nearest shore. This map would highlight the land areas that are most isolated inland.
I would imagine this would simply rasterize a shapefile of the global boundaries and then calculate the distances.
You can do this with raster::distance, which calculates the distance from each NA cell to the closest non-NA cell. You just need to create a raster that has NA for land pixels, and some other value for non-land pixels.
Here's how:
library(raster)
library(maptools)
data(wrld_simpl)
# Create a raster template for rasterizing the polys.
# (set the desired grid resolution with res)
r <- raster(xmn=-180, xmx=180, ymn=-90, ymx=90, res=1)
# Rasterize and set land pixels to NA
r2 <- rasterize(wrld_simpl, r, 1)
r3 <- mask(is.na(r2), r2, maskvalue=1, updatevalue=NA)
# Calculate distance to nearest non-NA pixel
d <- distance(r3)
# Optionally set non-land pixels to NA (otherwise values are "distance to non-land")
d <- d*r2
To create the plot above (I like rasterVis for plotting, but you could use plot(r)):
library(rasterVis)
levelplot(d/1000, margin=FALSE, at=seq(0, maxValue(d)/1000, length=100),
colorkey=list(height=0.6), main='Distance to coast')

Resources