R language, unreasonable (?) raster resolutions - r

Sorry for the very stupid question, but I'm really stuck here... I need to create a Digital Elevation Model for my study area. For this, I downloaded an SRTM (1 arc-seg resolution, freely available from the net) image, which comprises a region wider than my area of interest. The original raster has these characteristics:
class : RasterLayer
dimensions : 3601, 3601, 12967201 (nrow, ncol, ncell)
resolution : 0.0002777778, 0.0002777778 (x, y)
extent : -45.00014, -43.99986, -22.00014, -20.99986 (xmin, xmax, ymin, ymax)
crs : +proj=longlat +datum=WGS84 +no_defs
source : s22_w045_1arc_v3.tif
names : s22_w045_1arc_v3
values : -32768, 32767 (min, max)
I need to (1) increase the resolution (initially of 30.75662 * 28.68392 m) to 1 * 1 m (that is, I really do not care about the exactitude of the elevations) and (2) crop a squared area of 2000 * 2000 m centered at a given coordinate. So, the first step I'm following is to re-project to UTM:
projection(r) <- "+proj=utm +zone=23 +datum=WGS84"
But the resolution units do not change after that:
class : RasterLayer
dimensions : 3601, 3601, 12967201 (nrow, ncol, ncell)
resolution : 0.0002777778, 0.0002777778 (x, y)
extent : -45.00014, -43.99986, -22.00014, -20.99986 (xmin, xmax, ymin, ymax)
crs : +proj=utm +zone=23 +datum=WGS84 +units=m +no_defs
source : s22_w045_1arc_v3.tif
names : s22_w045_1arc_v3
values : -32768, 32767 (min, max)
If I try to set the resolutions in meters manually, then generates an empty raster. Can anybody be so kind as to throw some light on me here?

You are changing (i.e. overwriting) the CRS, not projecting the raster. Usually, it is recommended to create a template raster with the CRS and the resolution you need and reproject the raster using this template.
See here an example, I am switching to terra for the analysis since it is a newer and faster package, but I would show also how to convert it back to raster format:
library(raster)
#> Loading required package: sp
# Faking your data
r <- raster(
nrows = 3601, ncols = 3601,
ext = extent(c(-45.00014, -43.99986, -22.00014, -20.99986))
)
values(r) <- seq(-32768, 32767, length.out = ncell(r))
r
#> class : RasterLayer
#> dimensions : 3601, 3601, 12967201 (nrow, ncol, ncell)
#> resolution : 0.0002777784, 0.0002777784 (x, y)
#> extent : -45.00014, -43.99986, -22.00014, -20.99986 (xmin, xmax, ymin, ymax)
#> crs : +proj=longlat +datum=WGS84 +no_defs
#> source : memory
#> names : layer
#> values : -32768, 32767 (min, max)
plot(r)
# End of faking data
# Change to terra, much faster
library(terra)
#> terra 1.5.21
r_terra <- terra::rast(r)
template <- terra::project(r_terra, "+proj=utm +zone=23 +datum=WGS84")
# Change to the desired res
res(template) <- c(2000, 2000)
# Reproject
r_terra_reproj <- terra::project(r_terra, template)
r_terra_reproj
#> class : SpatRaster
#> dimensions : 56, 52, 1 (nrow, ncol, nlyr)
#> resolution : 2000, 2000 (x, y)
#> extent : 499985.4, 603985.4, -2433195, -2321195 (xmin, xmax, ymin, ymax)
#> coord. ref. : +proj=utm +zone=23 +datum=WGS84 +units=m +no_defs
#> source : memory
#> name : layer
#> min value : -32371.95
#> max value : 32182.81
terra::plot(r_terra_reproj)
# Back to RasterLayer
r_reproj <- raster(r_terra_reproj)
r_reproj
#> class : RasterLayer
#> dimensions : 56, 52, 2912 (nrow, ncol, ncell)
#> resolution : 2000, 2000 (x, y)
#> extent : 499985.4, 603985.4, -2433195, -2321195 (xmin, xmax, ymin, ymax)
#> crs : +proj=utm +zone=23 +datum=WGS84 +units=m +no_defs
#> source : memory
#> names : layer
#> values : -32371.95, 32182.81 (min, max)
Created on 2022-06-10 by the reprex package (v2.0.1)

Related

"Error: [mask] cannot create dataset" when trying to mask a SpatRaster with a SpatVector with Terra

Simply trying to use a vector (.shp) to mask a SpatRaster using terra::mask; get the following error
>Error: \[mask\] cannot create dataset
LCC84 <- rast("C:/Users_forest_VLCE2_1984.tif")
vec <- vect("C:/Users/Land_Management_Units.shp")
vec_proj <- project(vec, LCC84)
LCC84_masked <- terra::mask(LCC84, vec_proj)
Error: [mask] cannot create dataset
vec
#class : SpatVector
#geometry : polygons
#dimensions : 1, 8 (geometries, attributes)
#extent : -117.3165, -115.1691, 50.70613, 52.27127 (xmin, xmax, ymin, ymax)
#coord. ref. : lon/lat NAD83 (EPSG:4269)
LCC84
#class : SpatRaster
#dimensions : 128340, 193936, 1 (nrow, ncol, nlyr)
#resolution : 30, 30 (x, y)
#extent : -2660911, 3157169, -851351.9, 2998848 (xmin, xmax, ymin, ymax)
#coord. ref.: Lambert_Conformal_Conic_2SP
#source : CA_forest_VLCE2_1984.tif
#name : CA_forest_VLCE2_1984
crs(LCC84, proj=TRUE)
[1] "+proj=lcc +lat_0=49 +lon_0=-95 +lat_1=49 +lat_2=77 +x_0=0 +y_0=0 +datum=NAD83 +units=m +no_defs"
You can use the following code
library(terra)
library(sf)
#Read the data
LCC84 <- rast("C:/Users_forest_VLCE2_1984.tif")
vec <- st_read("C:/Users/Land_Management_Units.shp")
#Convert the crs of shapefile
vec_proj <- sf::st_transform(vec, crs(LCC84))
#Masking the raster using the shapefile
LCC84_masked <- terra::mask(LCC84, vec_proj)
It works for me with the data you provided
library(terra)
#terra 1.6.51
v <- vect("Extent_BNP_Extact.shp")
r <- rast("CA_forest_VLCE2_1984.tif")
pv <- project(v, r)
z <- crop(r, pv, mask=T)
r
#class : SpatRaster
#dimensions : 128340, 193936, 1 (nrow, ncol, nlyr)
#resolution : 30, 30 (x, y)
#extent : -2660911, 3157169, -851351.9, 2998848 (xmin, xmax, ymin, ymax)
#coord. ref. : Lambert_Conformal_Conic_2SP
#source : CA_forest_VLCE2_1984.tif
#name : CA_forest_VLCE2_1984
v
# class : SpatVector
# geometry : polygons
# dimensions : 1, 2 (geometries, attributes)
# extent : 474065.5, 635666.6, 5613645, 5798288 (xmin, xmax, ymin, ymax)
# source : Extent_BNP_Extact.shp
# coord. ref. : NAD83 / UTM zone 11N (EPSG:26911)
# names : Shape_Leng Shape_Area
# type : <num> <num>
# values : 6.744e+05 2.828e+10
plot(z)
First cropping seems logical here because the entire dataset has ~25 billion cells. I also tried
mask(r, pv)
It took a while to run, but it worked. If it does not for you, my guess would be that you may not have sufficient disk-space in your temp folder. See terraOptions() for the location of the temp folder.
Also, you do the equivalent of
pv <- project(v, "EPSG:4269")
But that makes no sense, as your raster data do not have the EPSG:4269 coordinate reference system (lon/lat NAD83).

How can I convert metric units of spacial object in R to degree decimal?

I have SpatialPointsDataFrame object loaded in R with with extent in meters. I want them to convert into degree decimals. Please help how can I do that.
Below is how my data looks in console:
class : SpatialPointsDataFrame
features : 23
extent : 351912.5, 457807, 3236835, 3367232 (xmin, xmax, ymin, ymax)
crs : +proj=utm +zone=44 +datum=WGS84 +units=m +no_defs
variables : 1
names : Id
min values : 0
max values : 0
I want to convert them as my rasterStack object which has extent as below:
class : RasterStack
dimensions : 7554, 8341, 63007914, 2 (nrow, ncol, ncell, nlayers)
resolution : 0.0002777778, 0.0002777778 (x, y)
extent : 78.72589, 81.04284, 28.70956, 30.80789 (xmin, xmax, ymin, ymax)
crs : +proj=longlat +datum=WGS84 +no_defs
names : dem_kumaun1, slope
min values : -32768, 0
max values : 32767.00000, 88.75196
please help guys!
Use spTransform function
new_shp <- spTransform(old_shp, CRS("+proj=longlat +datum=WGS84"))
Following code worked fro me.
transformed_shapefile <- spTransform(SpatialPointsDataFrame , CRS(RasterStack#crs#projargs))

rast function error with MOD09GA hdf images in R

I have some MODIS images downloaded. When I try to create a SpatRaster from the hdf files, using terra rast function, it works perfectly for "MOD09A1" but it doesn´t work for "MOD09GA".
terra::rast("C:/Users/User/AppData/Local/Temp/_modis/MOD09GA.A2011025.h08v06.006.2015216102410.hdf")
Error: [rast] number of rows and/or columns do not match
What is the problem? Is there any other function I could use? Thanks!
The problem is that the file has subdatasets with different resolutions.
To get the file your are using
# remotes::install_github("rspatial/luna")
aoi <- c(-106, -105, 26, 27)
f <- luna::getModis("MOD09GA", "2011-01-25", "2011-01-26", aoi, download=TRUE, path=".", user="*", password="*")
f
[1] "./MOD09GA.A2011025.h08v06.006.2015216102410.hdf"
To see the subdatasets:
library(terra)
describe_sds(f)
id name desc nrow ncol nlyr
1 HDF4_EOS:EOS_GRID:...MODIS_Grid_1km_2D:num_observations_1km [1200x1200] num_observations_1km MODIS_Grid_1km_2D (8-bit integer) 1200 1200 1
(...)
12 HDF4_EOS:EOS_GRID:...MODIS_Grid_500m_2D:sur_refl_b01_1 [2400x2400] sur_refl_b01_1 MODIS_Grid_500m_2D (16-bit integer) 2400 2400 1
(...)
So you need to access the different subdatasets seperately, like this
b1 <- rast(f, 12)
b2 <- rast(f, 13)
b1
# class : SpatRaster
# dimensions : 2400, 2400, 1 (nrow, ncol, nlyr)
# resolution : 463.3127, 463.3127 (x, y)
# extent : -11119505, -10007555, 2223901, 3335852 (xmin, xmax, ymin, ymax)
# coord. ref. : +proj=sinu +lon_0=0 +x_0=0 +y_0=0 +R=6371007.181 +units=m +no_defs
# data source : MOD09GA.A2011025.h08v06.006.2015216102410.hdf:MODIS_Grid_500m_2D:sur_refl_b01_1
# names : sur_refl_b01_1
Perhaps followed by
bb <-c(b1, b2)
Or create a SpatDataSet like this
x <- sds(f, 12:22)
In the development version of terra you can then proceed and do
y <- collapse(x)
or something like the below to get a particular set of subdatasets (that have the same spatial resolution)
r <- rast(f, 12:18)
r
#class : SpatRaster
#dimensions : 2400, 2400, 7 (nrow, ncol, nlyr)
#resolution : 463.3127, 463.3127 (x, y)
#extent : -11119505, -10007555, 2223901, 3335852 (xmin, xmax, ymin, ymax)
#coord. ref. : +proj=sinu +lon_0=0 +x_0=0 +y_0=0 +R=6371007.181 +units=m +no_defs
#source(s) : MOD09GA.A2011025.h08v06.006.2015216102410.hdf:MODIS_Grid_500m_2D:sur_refl_b01_1
MOD09GA.A2011025.h08v06.006.2015216102410.hdf:MODIS_Grid_500m_2D:sur_refl_b02_1
MOD09GA.A2011025.h08v06.006.2015216102410.hdf:MODIS_Grid_500m_2D:sur_refl_b03_1
... and 4 more source(s)
#names : sur_refl_b01_1, sur_refl_b02_1, sur_refl_b03_1, sur_refl_b04_1, sur_refl_b05_1, sur_refl_b06_1, ...

Strange issue changing extent projection from UTM to latlon (WGS84) and back again to UTM

I'm trying the following procedure (I apologize for mistakes but it is the very first time here). I've the raster dtm.temp expressed as follows:
> dtm.temp
class : RasterLayer
dimensions : 668, 965, 644620 (nrow, ncol, ncell)
resolution : 64.9, 92.6 (x, y)
extent : 437230.1, 499858.6, 5138842, 5200699 (xmin, xmax, ymin, ymax)
coord. ref. : +init=epsg:32632 +proj=utm +zone=32 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0
data source : in memory
names : elev
values : 362.8404, 3584.865 (min, max)
Using this extent I convert it in longlat in the following way
# I build a spatial dataframe with extent data from dtm.temp
df <- data.frame(ID = 1:2, X = c(dtm.temp#extent#xmin, dtm.temp#extent#xmax),
Y = c(dtm.temp#extent#ymin, dtm.temp#extent#ymax))
coordinates(df) <- c("X", "Y")
crs_text <- crs(dtm.temp, asText=TRUE) # extracting crs from dtm.temp
proj4string(df) <- CRS(crs_text)
ext.lonlat <- spTransform(df, CRS("+proj=longlat +datum=WGS84"))
ext.lonlat
> ext.lonlat
class : SpatialPointsDataFrame
features : 2
extent : 8.183449, 8.998142, 46.40024, 46.95982 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0
variables : 1
names : ID
min values : 1
max values : 2
at this point I use the extent (expressed as longlat) to crop the following raster dtm.temp1 (always in longlat but with a different initial extent and higher resolution)
> dtm.temp1
class : RasterLayer
dimensions : 9956, 14656, 145915136 (nrow, ncol, ncell)
resolution : 0.0002777778, 0.0002777778 (x, y)
extent : 7.857917, 11.92903, 44.27042, 47.03597 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0
data source : in memory
names : elev
values : -18, 4543 (min, max)
then
dtm.temp1.crop <- crop(dtm.temp1, ext.lonlat)
> dtm.temp1.crop
class : RasterLayer
dimensions : 2015, 2933, 5909995 (nrow, ncol, ncell)
resolution : 0.0002777779, 0.0002777772 (x, y)
extent : 8.183473, 8.998195, 46.40014, 46.95986 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0
and then I project again in UTM the raster cropped at the same extent (or at least, so I believed..)
# crs_text as defined above
dtm.temp1.crop.proj <- projectRaster(dtm.temp1.crop, crs=crs_text)
>dtm.temp1.crop.proj
class : RasterLayer
dimensions : 2033, 2968, 6033944 (nrow, ncol, ncell)
resolution : 21.2, 30.9 (x, y)
extent : 437083.4, 500005, 5138362, 5201182 (xmin, xmax, ymin, ymax)
coord. ref. : +init=epsg:32632 +proj=utm +zone=32 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0
data source : in memory
names : elev
values : 360, 3603.655 (min, max)
as you can see the two extent dtm.temp (the starting one) e the final dtm.temp1.crop.proj seems to be too much different.
extent dtm.temp : 437230.1, 499858.6, 5138842, 5200699
extent dtm.temp1.crop.proj: 437083.4, 500005, 5138362, 5201182
The error (in meters) is:
> 437230.1 - 437083.4
[1] 146.7
> 499858.6-500005
[1] -146.4
> 5138842 - 5138362
[1] 480
> 5200699-5201182
[1] -483
I'm sure I'm doing something wrong but I'm going crazy trying to understand what...
Someone is so patient to help me? Thanks in advance!
I add some more information trying to clearify on the basis of the comment of Mike.
Using a different approach (easier but computationally time consuming) I follow this steps:
> dtm.temp.extent <- extent(dtm.temp) # is the extent fixed
> dtm.temp.extent
class : Extent
xmin : 437230.1
xmax : 499858.6
ymin : 5138842
ymax : 5200699
# then I project directly the second raster dtm.temp1 using the crs
# with projectRaster (very slow)
> dtm.temp1.proj <- projectRaster(dtm.temp1,crs=crs_text)
# then I crop to the fixed extent
> dtm.temp1.proj.crop <- crop(dtm.temp1.proj, dtm.temp.extent)
# this is what I obtain
> extent(dtm.temp)
class : Extent
xmin : 437230.1
xmax : 499858.6
ymin : 5138842
ymax : 5200699
> extent(dtm.temp1.proj.crop)
class : Extent
xmin : 437233.6
xmax : 499852
ymin : 5138857
ymax : 5200688
the error now appears to me very reasonable:
> 437230.1 - 437233.6
[1] -3.5
> 499858.6 - 499852
[1] 6.6
> 5138842 - 5138857
[1] -15
> 5200699 - 5200688
[1] 11
The reason of the first approach is only because I'm trying to speedup the code (very time consuming in the second approach).
(Edited) I add, it may be useful for someone, an image of the problem in the first workflow (the two points of the extent - LL and UR - far from raster even if on a different raster respect to the one above in the question) and the solution suggested by Mkennedy that works fine (using four points unprojecting all four corners of the raster, LL, UL, UR, LR and then taking the min/max of the 8 values). I was not catching the rotation that occurs when unprojecting to lat/lon using only the LL and UR coordinates. Taking the true min/max, the results are more closely (as in the 2nd workflow)
Position of the raster vertex following a different approach

Snapping raster grids in R

I am trying to align two raster grids in R. Once aligned I would like to be able to add them together.
I have tried to check whether making a stack would work:
grid_snap <- stack(GLC2000_sdw, afriPop_sdw)
And I get the following error:
Error in compareRaster(x) : different extent
The raster grids have the following properties:
show(habi_sdw)
# class : RasterLayer
# dimensions : 9187, 9717, 89270079 (nrow, ncol, ncell)
# resolution : 0.00892857, 0.00892857 (x, y)
# extent : -28.83706, 57.92186, -36.02464, 46.00214 (xmin, xmax, ymin, ymax)
# coord. ref. : +proj=longlat +ellps=WGS84 +towgs84=0,0,0,0,0,0,0 +no_defs
# data source : C:\Users\di39\AppData\Local\Temp\R_raster_di39\raster_tmp_2015-08-12_172902_12860_17067.grd
# names : layer
# values : 0, 333707.6 (min, max)
show(Pop_sdw)
# class : RasterLayer
# dimensions : 10143, 8858, 89846694 (nrow, ncol, ncell)
# resolution : 0.008333333, 0.008333333 (x, y)
# extent : -17.53524, 56.28143, -46.97893, 37.54607 (xmin, xmax, ymin, ymax)
# coord. ref. : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0
# data source : C:\Users\di39\AppData\Local\Temp\R_raster_di39\raster_tmp_2015-08-12_170421_12860_12760.grd
# names : pop2010ppp
# values : 0, 128925.9 (min, max)
Using alignExtent() in the raster package seems not to be the correct approach.
Do I need to resample because the resolutions are slightly different?
(0.00892857 x 0.00892857) vs (0.008333333 vs 0.008333333)
First use resample(GLC2000_sdw, afriPop_sdw, method="ngb") and then crop (GLC2000_sdw, afriPop_sdw) to make sure they have the same extent.

Resources