match extent of two rasters in R - 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...

Related

Raster::extend does not extend rasters

I am trying to align .asc rasters with different extents but same resolution in R so that they can be used to create a Raster stack. I am working with the "raster" package (Hijmans et al. 2022, version 3.5-29)
The rasters have the following properties:
> r1;r2
class : RasterLayer
dimensions : 1420, 1207, 1713940 (nrow, ncol, ncell)
resolution : 50, 50 (x, y)
extent : -30155.19, 30194.81, -35519.03, 35480.97 (xmin, xmax, ymin, ymax)
crs : NA
source : Naive_IS2018_UDScaled.asc
names : Naive_IS2018_UDScaled
class : RasterLayer
dimensions : 1418, 939, 1331502 (nrow, ncol, ncell)
resolution : 50, 50 (x, y)
extent : -23488.8, 23461.2, -35475.82, 35424.18 (xmin, xmax, ymin, ymax)
crs : NA
source : Naive_IS2019_UDScaled.asc
names : Naive_IS2019_UDScaled
In order to bring them to the same extent, I am creating a raster list and extract the minimum and maximum values:
## align all rasters to same extent
rasterlist <- as.list(r1,r2)
raster_extents <- lapply(rasterlist, raster::extent)
do.call(raster::merge, raster_extents)
sharedextent <- c(-30155.19 , 30194.81 , -35519.03 , 35480.97)
Now I am using the enxtend() to extend the extents of the rasters so that they share the same extents.
r1 <- raster::extend(r1, sharedextent)
r2 <- raster::extend(r2, sharedextent)
However, this does not result in a change of extents. But, it changes the source to "memory" and add a "values" row in r2.
> r1;r2
class : RasterLayer
dimensions : 1420, 1207, 1713940 (nrow, ncol, ncell)
resolution : 50, 50 (x, y)
extent : -30155.19, 30194.81, -35519.03, 35480.97 (xmin, xmax, ymin, ymax)
crs : NA
source : Naive_IS2018_UDScaled.asc
names : Naive_IS2018_UDScaled
class : RasterLayer
dimensions : 1420, 1207, 1713940 (nrow, ncol, ncell)
resolution : 50, 50 (x, y)
extent : -30138.8, 30211.2, -35525.82, 35474.18 (xmin, xmax, ymin, ymax)
crs : NA
source : memory
names : Naive_IS2019_UDScaled
values : 0, 0.0006528347 (min, max)
Any help would be greatly appreciated.
Is that you are looking for? (Updated with keepres = TRUE). Please keep in mind that changing extent will either change resolution, either number of rows/columns.
library(raster)
#> Loading required package: sp
r1 <- raster(nrows = 1420, ncols = 1207, resolution = 50, ext = extent(c(-30155.19, 30194.81, -35519.03, 35480.97)))
r2 <- raster(nrows = 1418, ncols = 939, resolution = 50, ext = extent(c(-23488.8, 23461.2, -35475.82, 35424.18)))
r2
#> class : RasterLayer
#> dimensions : 1418, 939, 1331502 (nrow, ncol, ncell)
#> resolution : 50, 50 (x, y)
#> extent : -23488.8, 23461.2, -35475.82, 35424.18 (xmin, xmax, ymin, ymax)
#> crs : NA
r2 <- setExtent(r2, r1, keepres=TRUE)
r2
#> class : RasterLayer
#> dimensions : 1420, 1207, 1713940 (nrow, ncol, ncell)
#> resolution : 50, 50 (x, y)
#> extent : -30155.19, 30194.81, -35519.03, 35480.97 (xmin, xmax, ymin, ymax)
#> crs : NA
Created on 2022-09-06 with reprex v2.0.2

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.

convert raster from coarse to finer resolution

This is my raster properties:
class : RasterLayer
dimensions : 3001, 3000, 9003000 (nrow, ncol, ncell)
resolution : 0.12, 0.034 (x, y)
extent : -180, 180, -40.034, 62 (xmin, xmax, ymin, ymax)
crs : +proj=longlat +datum=WGS84 +no_defs
source : test.tif
names : test
I want to convert this into a raster with a resolution of 0.008333333 in both x and y direction
library(raster)
tar_res <- 0.008333333
disagg_raster <- disaggregate(my_raster,
fact = c(res(my_raster)[1]/tar_res, res(my_raster)[2]/tar_res))
disagg_raster
class : RasterLayer
dimensions : 12004, 42000, 504168000 (nrow, ncol, ncell)
resolution : 0.008571429, 0.0085 (x, y)
extent : -180, 180, -40.034, 62 (xmin, xmax, ymin, ymax)
crs : +proj=longlat +datum=WGS84 +no_defs
How do I get the resolution to be 0.008333333 in both x and y direction?
If you cannot get there by (dis) aggregating you can use resample instead.
# example data
library(terra)
r <- rast(nrow=3001, ncol=3000, ymin=-40.034, ymax=62)
# create empty template with the desired geometry
tmp <- rast(r)
res(tmp) <- 1/120
ymax(tmp) <- ymax(r)
# resample
x <- resample(r, tmp)
See here for a more general and longer answer.

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.

Reproject MODIS data using R (results in NAs or no spatial extent)

I am using GLASS albedo data stored here for pre-2000 (AVHRR) data and here for post-2000 data (MODIS). My end goal is to create a raster stack of each month that contains white sky albedo data from 1982-2015. The problem I have run into is that the MODIS and AVHRR data are in different spatial reference systems and I can't seem to reproject them to be in the same system.
I convert from hdf to tif using R like this:
fileavhrr <- ".../GLASS02B05.V04.A1990161.2018062.hdf"
filemodis<-".../GLASS02B06.V04.A2013169.2017128.hdf"
gdal_translate(get_subdatasets(filemodis)[10], dst_dataset =
".../modis.tif")
gdal_translate(get_subdatasets(fileavhrr)[8], projwin = c(-180,90,180,50), dst_dataset = ".../avhrr.tif") #ideally I'd only like data north of 50 degrees
avhrr<- raster(".../avhrr.tif")
#class : RasterLayer
#dimensions : 800, 7200, 5760000 (nrow, ncol, ncell)
#resolution : 0.05, 0.05 (x, y)
#extent : -180, 180, 50, 90 (xmin, xmax, ymin, ymax)
#coord. ref. : +proj=longlat +ellps=clrk66 +no_defs
#values : -32768, 32767 (min, max)
modis<- raster(".../modis.tif")
#class : RasterLayer
#dimensions : 3600, 7200, 25920000 (nrow, ncol, ncell)
#resolution : 154.4376, 308.8751 (x, y)
#extent : -20015109, -18903159, 8895604, 10007555 (xmin, xmax, ymin, ymax)
#coord. ref. : +proj=sinu +lon_0=0 +x_0=0 +y_0=0 +a=6371007.181
+b=6371007.181 +units=m +no_defs
#values : -32768, 32767 (min, max)
Here are things I have tried:
1.) Use the MODIS Reprojection Tool. For whatever reason, this tool seems to think the subdatasets of the MODIS .hdf files are only one tile (the upper left most tile, tile 0,0) and not the global dataset. My understanding is that the MODIS data are global (not in tiles?), so I do not know why the MRT is doing this.
2.) Use the raster package in R.
projectedMODIS <- projectRaster(modis,avhrr,method="bilinear")
This returns a raster with values that are all NA:
class : RasterLayer
dimensions : 800, 7200, 5760000 (nrow,> ncol, ncell)
resolution : 0.05, 0.05 (x, y)
extent : -180, 180,> 50, 90 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +ellps=clrk66 +no_defs
values : NA, NA (min, max)
3.) Use the gdalUtils package in R:
gdalwarp(srcfile=get_subdatasets(filemodis)[10], dstfile= ".../gdalMODIS_avhrr.tif", s_srs = crs(modis), t_srs =crs(avhrr) )
This returns a raster with essentially no spatial extent.
gdalMODISavhrr<-raster(".../gdalMODIS_avhrr.tif")
#class : RasterLayer
#dimensions : 357, 12850, 4587450 (nrow, ncol, ncell)
#resolution : 0.02801551, 0.02801573 (x, y)
#extent : -180, 179.9993, 79.99838, 90 (xmin, xmax, ymin, ymax)
#coord. ref. : +proj=longlat +ellps=clrk66 +no_defs
#values : -32768, 32767 (min, max)
Any ideas on why reprojecting this MODIS data is so difficult?
I have not tried this, but from looking at the package gdalUtils, the function gdalwarp() might do what you need?

Resources