How to mask or clip rasters in R? - r

I am working with a marine species that has a shallow distribution, and I would like to delimit modelling of several ascii layers (e.g.SST, SSS) to a 50m depth threshold along the coastline using a bathymetric dataset (e.g. Bio-Oracle, MARSPEC or GEBCO). I am working in R. I do not want bathymetry to be part of the model though.
Does anyone know how to do this?
This is the bathymetric raster (with values down to 100m depth):
class : RasterLayer
dimensions : 600, 420, 252000 (nrow, ncol, ncell)
resolution : 0.08333333, 0.08333333 (x, y)
extent : -20, 15, 10, 60 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0
data source : in memory
names : bathy
values : -100, -1 (min, max)
AND THIS IS RASTER STACK
class : RasterStack
dimensions : 600, 420, 252000, 4 (nrow, ncol, ncell, nlayers)
resolution : 0.08333333, 0.08333333 (x, y)
extent : -20, 15, 10, 60 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0
names : SST.min, SST.max, SST.range, BO_dissox
min values : -0.120, 10.940, 0.000, 4.052
max values : 26.640, 30.320, 21.460, 8.058
Cheers,
Rita

library(raster)
library(marmap)
library(rgdal)
# your coordinate reference setup
this_crs <- crs("+proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0")
this_extent <- extent(-20, 15, 10, 60)
# a simple raster stack for example purpose
r <- raster(ncol=420, nrow=600, ext = this_extent, crs = this_crs)
values(r) <- (1:ncell(r))/100
r_SST <- sin(r)
r_SSS <- r + runif(ncell(r), 0, 100)^2
r_stack <- stack(r_SST, r_SSS)
# Get some sample bathymetric data to match your stack
# the marmaps package is handy but you could use your own
download_bathy <- getNOAA.bathy(-20, 15, 10, 60, res = 5, keep = TRUE)
bath_mask <- marmap::as.raster(download_bathy)
bath_mask <- projectRaster(from = bath_mask, to = r_stack)
# clip your raster stack to the desired bathymetric limits
bath_mask[bath_mask > 0 | bath_mask < -50] <- NA
clipped_stack <- mask(r_stack, bath_mask)
# check the result with a plot
plot(clipped_stack)

First use SDMPlay:::delim.area in which the first layer of the stack is used to delimit the 100m depth.
Then isolate the bathymetry layer with subset.
User raster:::mask to delimit all rasters to bathymetric area.
And finally remove bathymetry from stack, raster:::dropLayer.
Thanks to all and specially to Guillaumot Charlene!
Rita

Related

Aggregate to custom (decimal) resolution

I have a raster of 30m cell size, with either value 0 or 1. I try to aggregate this into a 1000m cell size. I can then see the sum of '1's, in a 1000m cell size raster.
But the Aggregate function only lets me use a round number as a factor, so the closest I get is with factor 33x (to cell size 990m).
I would then need to resample 990m to 1000m but then obviously the values will shift and be incorrect.
Is there a way to use a decimal factor such as 33,3333, or better yet, use a raster with resolution 1000m as a template for the aggregation?
FOR ILLUSTRATION:
Here's an example of one aggregated cell sourced from 30x30m cells with 0/1 values, now in an aggregate raster at 990x990m cell size:
The two original cells are correctly aggregated into a 990x990m cell, and the sum of all values that were of interest (value '1') is 2. You can see these same two cells in the resampled cell on the right, in the top of the cell. But due to the resampling, the raster has shifted and includes more of the 30x30m cells. Yet, the cell value for the now resampled aggregate raster is still 2, while this is an incorrect value and should be 5.
You can use resample.
Example data:
library(terra)
r <- rast(crs="+proj=utm +zone=1", resolution=30, xmin=0, ymin=0, xmax=1020, ymax=1020)
values(r) <- 1:ncell(r)
I first aggregate to a value close to what you want (in this example, I go from 30 to 100 m spatial resolution), and then use resample
a <- aggregate(r, 3, mean)
rr <- rast(crs="+proj=utm +zone=1", resolution=100, xmin=0, ymin=0, xmax=1000, ymax=1000)
b <- resample(r, rr)
r
#class : SpatRaster
#dimensions : 34, 34, 1 (nrow, ncol, nlyr)
#resolution : 30, 30 (x, y)
#extent : 0, 1020, 0, 1020 (xmin, xmax, ymin, ymax)
#coord. ref. : +proj=utm +zone=1 +datum=WGS84 +units=m +no_defs
#source : memory
#name : lyr.1
#min value : 1
#max value : 1156
b
#class : SpatRaster
#dimensions : 10, 10, 1 (nrow, ncol, nlyr)
#resolution : 100, 100 (x, y)
#extent : 0, 1000, 0, 1000 (xmin, xmax, ymin, ymax)
#coord. ref. : +proj=utm +zone=1 +datum=WGS84 +units=m +no_defs
#source : memory
#name : lyr.1
#min value : 68.89777
#max value : 1103.335
You could also first disaggregate and then aggregate. With the above example you could do
d <- disaggregate(r, 3)
da <- aggregate(d, 10)
da
#class : SpatRaster
#dimensions : 11, 11, 1 (nrow, ncol, nlyr)
#resolution : 100, 100 (x, y)
#extent : 0, 1100, -80, 1020 (xmin, xmax, ymin, ymax)
#coord. ref. : +proj=utm +zone=1 +datum=WGS84 +units=m +no_defs
#source : memory
#name : lyr.1
#min value : 43
#max value : 1093
The solution was pretty simple, and I highly suspect the phrasing of my question was just not very clear, apologies for that.
When using the aggregate function (whether it is by mean, sum,...) you cannot resample afterwards and expect the agreggated values to still be correct. The values will be preserved, but because cells shift a little or a lot due to resampling, they will not be correct.
The trick as such, is incredibly simple: resample before you aggregate, not afterwards.

Combining 2 raster data sets with different extent, resolution and point regularity

I'm having trouble merging two raster datasets that have different resolution and extent, and have irregular point data. Below is info on each raster. I need these datasets to merge according to the grid points so that I can run a fire spread model (which requires both wind and slope data).
I have tried converting to normal dataframes (using rasterToPoints) before merging but the differences lead to loss of a lot of grid points.
I have tried to align the rasters with project raster and rasterize, but I haven't managed to get it to work. If anyone has an idea that could help, I would really appreciate your answer!
'''
Data from https://globalwindatlas.info/downloads/gis-files
> wind <- raster("ZAF_wind-speed_10m.tif"); wind
class : RasterLayer
dimensions : 11271, 11804, 133042884 (nrow, ncol, ncell)
resolution : 0.0025, 0.0025 (x, y)
extent : 13.33407, 42.84407, -50.31423, -22.13673 (xmin, xmax, ymin, ymax)
crs : +proj=longlat +datum=WGS84 +no_defs
source : C:/Users/s2000128/Documents/Flammability modelling/ZAF/ZAF_wind-speed_10m.tif
names : ZAF_wind.speed_10m
Data from https://datacatalog.worldbank.org/dataset/world-slope-model
> slope <- raster("ZAF1_msk_alt.grd"); slope
class : RasterLayer
dimensions : 1548, 1992, 3083616 (nrow, ncol, ncell)
resolution : 0.008333333, 0.008333333 (x, y)
extent : 16.4, 33, -34.9, -22 (xmin, xmax, ymin, ymax)
crs : +proj=longlat +ellps=WGS84 +no_defs
source : C:/Users/s2000128/Documents/Flammability modelling/slope_deg_0/slope_deg/ZAF1_msk_alt.grd
names : ZAF1_msk_alt
values : -26, 3264 (min, max)
Here are some examples of what I have tried:
1
windresampled <- projectRaster(wind,slope,method = 'ngb'); windresampled
2
wind_points <- rasterToPoints(wind);
coordinates(wind_points) = ~x+y;
proj4string(wind_points) = CRS("+init=epsg:4326");
gridded(wind_points) = TRUE;
g_wind <- raster(wind_points); g_wind;
extent(wind) <- c(16.4,33, -34.9,-22);
res(wind) <- c(0.0025, 0.0025);
r_wind <- rasterize(wind_points, g_wind, field = wind_points$z, fun = mean, na.rm = TRUE); r_wind

How does R assign a resolution to raster objects?

Suppose one runs the following R code
install.packages("raster")
library(raster)
r <- raster(ncol=18, nrow=18)
res(r)
The output of the res function is
[1] 20 10
How are these values defined? How does the raster function calculate them? In what units are they expressed?
As pointed out by Guillaume Devailly, the horizontal resolution is the horizontal extent divided by the number of columns. The vertical resolution is the vertical extent divided by the number of rows. The units are the units of your coordinate reference system. The default is degrees (for longitude/latitude). To add more to Guillaume's answer:
Create a raster with 10 rows and columns that goes from 0 to 10. The resolution is 1.
library(raster)
r <- raster(ncol=10, nrow=10, xmn=0, xmx=10, ymn=0, ymx=10)
r
#class : RasterLayer
#dimensions : 10, 10, 100 (nrow, ncol, ncell)
#resolution : 1, 1 (x, y)
#extent : 0, 10, 0, 10 (xmin, xmax, ymin, ymax)
#crs : +proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0
Change the resolution to 0.5; the number of rows and columns double
res(r) <- 0.5
r
#class : RasterLayer
#dimensions : 20, 20, 400 (nrow, ncol, ncell)
#resolution : 0.5, 0.5 (x, y)
#extent : 0, 10, 0, 10 (xmin, xmax, ymin, ymax)
#crs : +proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0
You can change the resolution indirectly by adjusting the extent
extent(r) <- c(0,5,0,5)
r
#class : RasterLayer
#dimensions : 20, 20, 400 (nrow, ncol, ncell)
#resolution : 0.25, 0.25 (x, y)
#extent : 0, 5, 0, 5 (xmin, xmax, ymin, ymax)
#crs : +proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0
The x and y resolution can be set to a different value
res(r) <- c(1, 0.5)
When you change the resolution directly, via res any cell values associated with the Raster* object are lost; because the number of rows or columns has to change. If you change it indirectly, by changing the extent, the values stay.
From what I understand from the vignette
The default settings will create a global raster data structure with a longitude/latitude coordinate reference system and 1 by 1 degree cells.
r
# class : RasterLayer
# dimensions : 18, 18, 324 (nrow, ncol, ncell)
# resolution : 20, 10 (x, y)
# extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
# coord. ref. : +proj=longlat +datum=WGS84
r x extent goes to from -180 to +180 degrees by default (a total of 360 degrees), and 360 degrees / 18 points = a x resolution of 20 degrees.
r y extent goes form -90 to +90 degrees by default, and 180 degrees / 18 points results in a y resolution of 10 degrees.

Convert matrix to raster with assigning LCC projection

I would like to convert data-only matrix (not a xyz type of table) to raster layer. Each column and row represents longitude and latitude.
However, while rasterizing the matrix, I'm struggling with assigning CRS on it.
My data should be projected in LCC projection. And all the parameters that I know are below.
DX: 7500.f (meter)
DY: 7500.f (meter)
CEN_LAT: 37.99787f
CEN_LON: 127.4592f
TRUELAT1: 30.f
TRUELAT2: 60.f
So I assigned mycrs with CRS() function, and assigned it as below.
I could not assign res=7500 argument in raster() because it returned an error.
mx <- matrix(rep(1, 13770), nrow=90, ncol=153) # reproducible example of mx
mycrs <- CRS("+proj=lcc +lat_1=30 +lat_2=60 +lat_0=37.99787 +lon_0=127.4592 +datum=WGS84 +units=m +no_defs")
r <- raster(mx, crs=mycrs)
class : RasterLayer
dimensions : 90, 153, 13770 (nrow, ncol, ncell)
resolution : 0.006535948, 0.01111111 (x, y)
extent : 0, 1, 0, 1 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=lcc +lat_1=30 +lat_2=60 +lat_0=37.99787 +lon_0=127.4592 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0
data source : in memory
names : layer
values : 1, 1 (min, max)
Well, the console did not return any warning, but the result was awkward.
The dimensions seems ok but resolution and extent must be wrong.
The domain of the layer should be like
(123.25, 43.23) ------- (131.78, 43.17)
: :
: :
(123.80, 32.73) ------- (131.01, 32.68)
Is there any other method to convert mx into raster with the given CRS parameters?
You need to know the extent in terms of the coordinate reference system (crs), llc in this case. The data source should provide that for the data to be usable. You have the extent in lon/lat, but not in llc. We can estimate it:
library(raster)
e <- extent(123.25, 131.78, 32.68, 43.23)
p <- as(e, "SpatialPolygons")
crs(p) <- "+proj=longlat +datum=WGS84"
library(rgdal)
llc <- "+proj=lcc +lat_1=30 +lat_2=60 +lat_0=37.99787 +lon_0=127.4592 +datum=WGS84"
pp <- spTransform(p, llc)
And create a RasterLayer
r <- raster(pp)
Now set the resolution (from what you provide I understand that it is 7500 m)
res(r) <- 7500
r
#class : RasterLayer
#dimensions : 152, 105, 15960 (nrow, ncol, ncell)
#resolution : 7500, 7500 (x, y)
#extent : -390412.6, 397087.4, -567400.8, 572599.2 (xmin, xmax, ymin, ymax)
#crs : +proj=lcc +lat_1=30 +lat_2=60 +lat_0=37.99787 +lon_0=127.4592 +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0
This does not match the number of rows and columns that you provided (but where did you get these?).
The extent could be approximately correct, but that it is not guaranteed at all. The data provider should really give it to you to be exact. If you actually know the number of rows and columns, then it is obviously wrong.

raster extract by attributes in R

I have been trying to create a new raster object that contains only a couple of values from an existing raster.
I am using the class raster found here: https://www.ga.gov.au/products/servlet/controller?event=FILE_SELECTION&catno=71071.
class : RasterLayer dimensions : 14902, 19161, 285537222 (nrow, ncol, ncell)
resolution : 0.002349, 0.002349 (x, y)
extent : 110, 155.0092, -45.0048, -9.999999 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0
values : G:\Spatial data\environmental_layers\Australian data\Land cover\Class\DLCDv1_Class.tif
min value : 1
max value : 34
I have tried:
pr <- rasterToPoints(r) # but the file is to big
and
s <- r[r>30 & r<33] # but the file is to big
and
rc <- reclass(r, c(-Inf,30,NA, 31,32, 1, 33,Inf,NA))
which produces a raster with properties:
class : RasterLayer
dimensions : 14902, 19161, 285537222 (nrow, ncol, ncell)
resolution : 0.002349, 0.002349 (x, y)
extent : 110, 155.0092, -45.0048, -9.999999 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0
values : C:\Users\Adam\AppData\Local\Temp\R_raster_tmp\raster_tmp_61931056968.grd
min value : 1
max value : 33
I thought this would produced a raster layer with values of NA and 1, but it has 33 values. I have been struggling to find a way to 'extract by attribute' using R on such a large file. Does anyone have suggestions of how I could do this?
reclassify() may work for you with a very large raster, but you need to specify the "is" "becomes" matrix correctly. Though I am not exactly sure from your question whether this is in fact your goal when you say "raster extract."
However, here is how to do the reclassification:
For example:
## Create sample raster with values from 0 to 9
r <- raster(nrow=100, ncol=100)
r[] <- trunc(runif(ncell(r))*10)
## Create reclassification table
## Set values 0 to 4 equal to 1
## Set values 5 to 9 equal to NA
isBecomes <- cbind(c(0, 1, 2, 3, 4, 5, 6, 7, 8, 9),
c(1, 1, 1, 1, 1, NA, NA, NA, NA, NA))
r2 <- reclassify(r, rcl=isBecomes)
I have not tested this in a raster too large to fit in memory, however I believe that reclassify() may be able to handle this.

Resources