How to index individual layers from a SpatRaster object by time? - r

I found out the other day, more or less by chance, that it is possible to query layers from SpatRaster objects based on the time attribute in general (c.f. here), e.g based on years (r["2017"]) and yearmonths (r["2017-10"]).
Now I wanted to deep-dive a little bit into this because of the great flexibility you receive when working with spatio-temporal data. Unfortunately, I seem to be failing from the beginning and can't reproduce the behaviour from before because of the following error: [subset] no (valid) layer selected
library(terra)
#> terra 1.6.3
r <- rast(ncols = 10, nrows = 10, nlyr = 365)
time(r) <- seq(from = as.POSIXlt("2001-01-01", tz = "UTC"),
to = as.POSIXlt("2001-12-31", tz = "UTC"),
by = "day")
r
#> class : SpatRaster
#> dimensions : 10, 10, 365 (nrow, ncol, nlyr)
#> resolution : 36, 18 (x, y)
#> extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
#> coord. ref. : lon/lat WGS 84
#> time : 2001-01-01 to 2001-12-31 UTC
time(r) |> class()
#> [1] "POSIXct" "POSIXt"
r["2001"]
#> Error: [subset] no (valid) layer selected
time(r) <- as.Date("2002-01-01") + 0:364
r
#> class : SpatRaster
#> dimensions : 10, 10, 365 (nrow, ncol, nlyr)
#> resolution : 36, 18 (x, y)
#> extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
#> coord. ref. : lon/lat WGS 84
#> time (days) : 2002-01-01 to 2002-12-31
time(r) |> class()
#> [1] "Date"
r["2002"]
#> Error: [subset] no (valid) layer selected
I had a look at ?time as well as at the docs at rspatial.org but was not able to find relevant documentation related to indexing.
What am I missing here?

You are mixing up layer names (that may look like a time-stamp) with an actual time-stamp.
Here is how you can use time-stamps (using Date here, as it is a bit less verbose)
library(terra)
r <- rast(ncols = 10, nrows = 10, nlyr = 365)
time(r) <- as.Date("2001-01-01") + 0:364
head(names(r))
# "lyr.1" "lyr.2" "lyr.3" "lyr.4" "lyr.5" "lyr.6"
You can subset layers by name like this
r[["lyr.1"]]
Note the double brackets for sub-setting layers, although you can use single brackets when using a name as opposed to a numerical index.
To subset by time, you can do
r[[time(r) == as.Date("2001-06-01")]]
#class : SpatRaster
#dimensions : 10, 10, 1 (nrow, ncol, nlyr)
#resolution : 36, 18 (x, y)
#extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
#coord. ref. : lon/lat WGS 84
#time (days) : 2001-06-01
With dates, you do not even need to use "as.Date"
r[[time(r) >= "2001-12-01"]]
#class : SpatRaster
#dimensions : 10, 10, 31 (nrow, ncol, nlyr)
#resolution : 36, 18 (x, y)
#extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
#coord. ref. : lon/lat WGS 84
#time (days) : 2001-12-01 to 2001-12-31

Related

Reorder each pixel of a SpatRaster by size

I have a SpatRaster with 100 layers, each corresponding to a result of a bootstrapping analysis (all slightly different variations but pretty much the same). I want to reorder each pixel so that the first layer is the smallest of each respective pixel, second layer is second smallest, etc.
It can be converted to a data.frame with 102 columns (x, y, result1, ...), but I don't know how to order each row of a data.frame by size and exclude columns at the same time.
You can use sort to order the values of each grid cell. Illustrated below
Example data
library(terra)
r <- rast(ncol=5, nrow=5)
values(r) <- 30
x <- rast(c(a=r, b=r/10, c=r/100))
x
#class : SpatRaster
#dimensions : 5, 5, 3 (nrow, ncol, nlyr)
#resolution : 72, 36 (x, y)
#extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
#coord. ref. : lon/lat WGS 84
#sources : memory
# memory
# memory
#names : a, b, c
#min values : 30, 3, 0.3
#max values : 30, 3, 0.3
Solution
y <- sort(x)
y
#class : SpatRaster
#dimensions : 5, 5, 3 (nrow, ncol, nlyr)
#resolution : 72, 36 (x, y)
#extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
#coord. ref. : lon/lat WGS 84
#source : memory
#names : a, b, c
#min values : 0.3, 3, 30
#max values : 0.3, 3, 30

match extent of two rasters in R

I have two raster:
raster1
class : SpatRaster
dimensions : 21600, 43200, 1 (nrow, ncol, nlyr)
resolution : 0.008333333, 0.008333333 (x, y)
extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
raster2
class : SpatRaster
dimensions : 720, 1440, 1 (nrow, ncol, nlyr)
resolution : 0.25, 0.25 (x, y)
extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
coord. ref. : lon/lat WGS 84
I want to run zonal stastics to calculate sum of smaller raster raster1 on bigger raster raster2:
terra::zonal(raster1, raster2, fun = sum, as.raster=T, filename = 'zonal.tif')
Error: [zonal] dimensions and/or extent do not match
I wasn't sure why the extent are not matching until I did this
terra::ext(raster1)
SpatExtent : -180.000001017276, 180.000001017276, -90.0000010172997, 90.0000010172997 (xmin, xmax, ymin, ymax)
terra::ext(raster2)
SpatExtent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
which shows that raster1 extent have some imprecision. What are different ways I can fix this?
EDIT: I tried the suggestion in the comment
terra::crs(raster2) <- sf::st_crs(4326)$wkt
terra::crs(raster1) <- sf::st_crs(4326)$wkt
terra::ext(raster2)
SpatExtent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
terra::ext(raster1)
SpatExtent : -180.000001017276, 180.000001017276, -90.0000010172997, 90.0000010172997 (xmin, xmax, ymin, ymax)
But my extent are still not matching
The error message is
Error: [zonal] dimensions and/or extent do not match
In this case, that clearly refers to the difference is dimensions, which are
#dimensions : 21600, 43200, 1 (nrow, ncol, nlyr)
#dimensions : 720, 1440, 1 (nrow, ncol, nlyr)
I do not think the small difference in the extent is relevant at all.
To make the dimensions match you can use disagg or aggregate with a factor of 30.
If the crs of raster2 is different from that of raster1 you can (in this case, where you clearly have two global lon/lat rasters) fix that with
crs(raster2) <- crs(raster1)
And for good measure, you could in this case also do
ext(raster2) <- ext(raster1)
Mismatching extents don't stop zonal working, so I think that error message is wrong. Here's two rasters that only differ in their CRS:
> library(terra)
terra 1.5.21
> raster1 = rast()
> raster1[]=1:360
> raster2 = rast()
> raster2[]=1:360
> crs(raster1) = ""
> zonal(raster1, raster2)
Error: [zonal] dimensions and/or extent do not match
I guess it could be argued that a different CRS means a different extent in the same way that "23" is different to "23 km". But the extent and the dimensions are all the same according to these tests:
> ext(raster1) == ext(raster2)
[1] TRUE
> dim(raster1) == dim(raster2)
[1] TRUE TRUE TRUE
Rasters with a different extent work fine with zonal (once I've set the CRSs to match):
> ext(raster2) = c(-180.01, 180.01, -90.01, 90.01)
> crs(raster2) = ""
> z = zonal(raster1, raster2)
>
If you do want to change an extent, you can use ext(r) = ... as above, but you should try and figure out why extents don't match. Likely its because you have data on points and you may have cells extending out from points...

disaggregating raster causes insufficient disk space

I am trying to disaggregate a raster using terra package. My original raster is:
library(terra)
my_raster
class : SpatRaster
dimensions : 180, 360, 1 (nrow, ncol, nlyr)
resolution : 1, 1 (x, y)
extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
coord. ref. : lon/lat WGS 84
source : EHF2_2020_max.nc_rotated.nc
varname : X2020
name : X2020
I want to drop the resolution to the following target raster
target_raster
class : SpatRaster
dimensions : 21600, 43200, 1 (nrow, ncol, nlyr)
resolution : 0.008333333, 0.008333333 (x, y)
extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
coord. ref. : lon/lat WGS 84
source : GDP_PPP_30arcsec_v3.nc
varname : GDP_PPP (Gross Domestic Production (GDP) (PPP))
name : GDP_PPP_3
unit : constant 2011 international US dollar
When I did this, I get below error:
disagg_raster <- disagg(my_raster, fact = c(21600,43200))
Error: [disagg] insufficient disk space (perhaps from temporary files?)
I have a fresh R session and other than these two objects, nothing else is loaded in my environment. What is causing this error?
However, when I disaggregate raster using resample, I do not get any memory issue
resample_raster <- resample(my_raster, target_raster, method='bilinear')
I get below error:
disagg_raster <- disagg(my_raster, fact = c(21600,43200))
# Error: [disagg] insufficient disk space (perhaps from temporary files?)
That says there is not enough disk space to write the file. Output SpatRasters are are written to disk if they are deemed too large to keep in memory. As you do not provide a filename argument, the file would go to the tempdir() folder and that does not have enough disk space.
This is happening because you use trying to create a monster of a raster (easy to do and see for a raster that has no cell values):
library(terra)
r <- rast()
disagg(r, fact = c(21600,43200))
#class : SpatRaster
#dimensions : 3888000, 15552000, 1 (nrow, ncol, nlyr)
#resolution : 2.314815e-05, 4.62963e-05 (x, y)
#extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
#coord. ref. : lon/lat WGS 84
It appears that you misunderstood the fact argument. To get the spatial resolution of your target raster you can do:
disagg(r, fact = 120)
#class : SpatRaster
#dimensions : 21600, 43200, 1 (nrow, ncol, nlyr)
#resolution : 0.008333333, 0.008333333 (x, y)
#extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
#coord. ref. : lon/lat WGS 84
That is still big enough, but it should not create problems.

Terra Spatial Correlation between two raster

I am trying to calculate the spatial correlation between two rasters. I have two large rasters with the same extent, resolution, etc
class : RasterLayer
dimensions : 45598, 53241, 2427683118 (nrow, ncol, ncell)
resolution : 30, 30 (x, y)
extent : 273366.8, 1870597, 367780.7, 1735721 (xmin, xmax, ymin, ymax)```
These layers have massive NAs cells
I tried to use terra::focalCor with the stack of those layers.
corr=focalCor(layerstack, w=9, cor)
But I have this issue
Error in v[[j - 1]] <- t(sapply(1:nrow(Y), function(i, ...) fun(X[i, ], :
more elements supplied than there are to replace
Any ideas or suggestions?
Cheers
It would have been easier to provide a specific answer with actual data provided to be able to reproduce your issue, but in this case it seems like you imported your gridded data using raster::raster() creating a RasterLayer object, but according to ?focalCor, x has clearly to be a SpatRaster with at least two layers.
So, try terra::rast(c("grid_1.tif", "grid_2.tif")) |> terra::focalCor(w = 9, cor) instead.
Edit:
Thanks for your reprex. I dared to reduce dimensions and modify the extent a little bit in order to reduce processing time:
library(terra)
r <- rast(ncols = 100, nrows = 100,
xmin = 0, xmax = 25, ymin = 0, ymax = 25,
crs = "epsg:4326")
r1 <- init(r, fun = runif)
r2 <- init(r, fun = runif)
r_stack <- c(r1, r2)
r_stack_cor_5 <- focalCor(r_stack, w = 5, cor)
r_stack_cor_5
#> class : SpatRaster
#> dimensions : 100, 100, 1 (nrow, ncol, nlyr)
#> resolution : 0.25, 0.25 (x, y)
#> extent : 0, 25, 0, 25 (xmin, xmax, ymin, ymax)
#> coord. ref. : lon/lat WGS 84 (EPSG:4326)
#> source : memory
#> name : lyr1
#> min value : -0.6476946
#> max value : 0.6948594
r_stack_cor_25 <- focalCor(r_stack, w = 25, cor)
r_stack_cor_25
#> class : SpatRaster
#> dimensions : 100, 100, 1 (nrow, ncol, nlyr)
#> resolution : 0.25, 0.25 (x, y)
#> extent : 0, 25, 0, 25 (xmin, xmax, ymin, ymax)
#> coord. ref. : lon/lat WGS 84 (EPSG:4326)
#> source : memory
#> name : lyr1
#> min value : -0.1020998
#> max value : 0.1045798
I used fun = cor instead of function(x, y) cor(x, y) but the result is the same according to all.equal(). However, your example seems to work - and I'm failing to recognize the issue at the moment.

terra function to extract all bands of one variable? (equivalent to brick('x', varname='y'))

I have a netcdf file that contains 79 variables, and for each variable there are 365 bands (one for each day of the year). I want to read all bands of one variable (i.e., a raster with 365 ayers). With the 'raster' package this would work as follows:
dailyvalues <- brick('GLOBAL_2010_day.nc', varname ='WDEP_PREC')
Result is a RasterBrick with 365 layers:
> dailyvalues
class : RasterBrick
dimensions : 180, 360, 64800, 365 (nrow, ncol, ncell, nlayers)
resolution : 1, 1 (x, y)
extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
crs : +proj=longlat +datum=WGS84 +no_defs
source : GLOBAL_2010_day.nc
names : X2010.01.01, X2010.01.02, X2010.01.03, X2010.01.04, X2010.01.05, X2010.01.06, X2010.01.07, X2010.01.08, X2010.01.09, X2010.01.10, X2010.01.11, X2010.01.12, X2010.01.13, X2010.01.14, X2010.01.15, ...
Date : 2010-01-01, 2010-12-31 (min, max)
varname : WDEP_PREC
But I haven't suceeded to do this with the 'terra' package. I tried
dailyvalues <- rast('GLOBAL_2010_day.nc')
> dailyvalues
class : SpatRaster
dimensions : 180, 360, 28835 (nrow, ncol, nlyr)
resolution : 1, 1 (x, y)
extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +datum=WGS84 +no_defs
sources : GLOBAL_2010_day.nc:WDEP_PREC (365 layers)
GLOBAL_2010_day.nc:WDEP_SOX (365 layers)
GLOBAL_2010_day.nc:WDEP_OXN (365 layers)
... and 76 more source(s)
varnames : WDEP_PREC (WDEP_PREC)
WDEP_SOX (WDEP_SOX)
WDEP_OXN (WDEP_OXN)
...
names : WDEP_PREC_1, WDEP_PREC_2, WDEP_PREC_3, WDEP_PREC_4, WDEP_PREC_5, WDEP_PREC_6, ...
unit : mm, mm, mm, mm, mm, mm, ...
time : 2010-01-01 18:00:00 to 2010-12-31 12:00:00
The resulting SpatRaster has 79 'sources', but what is the syntax to use if I want to extract one 'source'? Adding varname = 'WDEP_PREC' in the rast function doesn't work. I tried dailyvalues$... but that calls single layers only (as listed under 'names').
The argument to use is called subds in terra.
dailyvalues = rast("GLOBAL_2010_day.nc", subds="WDEP_PREC")
You should be able to do (as #dww says)
dailyvalues = rast("GLOBAL_2010_day.nc", subds="WDEP_PREC")
Or you can make a SpatRasterDataset
x = sds("GLOBAL_2010_day.nc")
And then extract the sub-dataset you want with
r <- x["WDEP_PREC"]
or
r <- x[1]
Furthermore, you can do
r <- rast('NETCDF:"GLOBAL_2010_day.nc:WDEP_PREC":WDEP_PREC')
(for the above to work you may need to add the path to the filename, or set your working directory to where it is)

Resources