apply a function over a list of raster layers - r

I have a list of 34 RasterLayers like this:
[[34]]
class : RasterLayer
band : 1 (of 10 bands)
dimensions : 6899, 9663, 66665037 (nrow, ncol, ncell)
resolution : 0.0002694946, 0.0002694946 (x, y)
extent : -6.685352, -4.081226, 39.39795, 41.2572 (xmin, xmax, ymin, ymax)
crs : +proj=longlat +datum=WGS84 +no_defs
source : D:/TFM/Imagenes/Imagenes_sinClip/2017.tif
names : X2017
I want to crop all the RasterLayers of the list using a simple feature like this:
> aoi
Simple feature collection with 1 feature and 2 fields
Geometry type: POLYGON
Dimension: XY
Bounding box: xmin: -6.571744 ymin: 39.44875 xmax: -4.10362 ymax: 41.22031
Geodetic CRS: WGS 84
Id area geometry
1 0 29488.98 POLYGON ((-6.122013 41.2203...
To do that, I used lapply:
crop <- lapply(x = myrasterList, y = aoi, FUN = crop(x, y))
But I get the following error:
Error in h(simpleError(msg, call)) :
error in evaluating the argument 'x' in selecting a method for function 'crop': objeto 'x' no encontrado

The FUN argument of lapply does not work like that when you add arguments to the function. You need to do something like
crop <- lapply(myrasterList, y = aoi, FUN = function(i) crop(i, y))

Related

How to re-project a raster in r

I'm working with a raster layer that looks like this:
class : RasterLayer
dimensions : 7040, 9020, 63500800 (nrow, ncol, ncell)
resolution : 1, 1 (x, y)
extent : 0.5, 9020.5, 0.5, 7040.5 (xmin, xmax, ymin, ymax)
crs : +proj=longlat +datum=WGS84 +no_defs
source : omi_surface_no2_2005.nc
names : surface_no2_ppb
zvar : surface_no2_ppb
And I need to re-project it so that I can crop it to this shape file:
Simple feature collection with 1 feature and 0 fields
Geometry type: MULTIPOLYGON
Dimension: XY
Bounding box: xmin: -80.24869 ymin: 43.05051 xmax: -78.43696 ymax: 44.51657
Geodetic CRS: NAD83
geometry
1 MULTIPOLYGON (((-79.38536 4...
But when I try to re-project it, it doesn't work.
This is the code that I used:
omi_reproj <- projectRaster(omi, crs = crs(gtha_shp))
Has the raster layer been assigned the CRS incorrectly? I'm not sure what I'm doing wrong. If you need the data layers, I can provide a link.
Link to raster: link
This file does not follow the CF conventions for storing raster data.
library(terra)
#terra 1.7.11
x <- rast("omi_surface_no2_2005.nc")
#[1] "vobjtovarid4: **** WARNING **** I was asked to get a varid for dimension named dim1 BUT this dimension HAS NO DIMVAR! Code will probably fail at this point"
#Warning messages:
#1: In min(rs) : no non-missing arguments to min; returning Inf
#2: In min(rs) : no non-missing arguments to min; returning Inf
#3: In max(rs) : no non-missing arguments to max; returning -Inf
#4: [rast] cells are not equally spaced; extent is not defined
You can still read the values with the ncdf4 package and create a SpatRaster "by hand".
Open the ncdf file and inspect its contents
library(ncdf4)
nc <- nc_open("omi_surface_no2_2005.nc")
nc
# 3 variables (excluding dimension variables):
# double surface_no2_ppb[lon_dim,lat_dim] (Chunking: [752,587])
# double LON_CENTER[dim1,latdim] (Chunking: [1,9020])
# double LAT_CENTER[londim,dim1] (Chunking: [7040,1])
Read the relevant data and close the file
lon <- ncdf4::ncvar_get(nc, nc$var[["LON_CENTER"]])
lat <- ncdf4::ncvar_get(nc, nc$var[["LAT_CENTER"]])
d <- ncdf4::ncvar_get(nc, nc$var[["surface_no2_ppb"]])
nc_close(nc)
Create a SpatRaster
library(terra)
x <- rast(t(d[, ncol(d):1]), ext=c(range(lon), range(lat)), crs="+proj=lonlat")
plot(sqrt(x))

R language, unreasonable (?) raster resolutions

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)

R terra SpatVectorCollection: How to convert SpatVectorCollection to SpatVector (multiple polygons)

In general, is it possible to convert a terra SpatVectorCollection to a multi-polygon SpatVector so that it can be plotted etc?
Specifically, I have a data.frame of extents (bounding boxes) that I need to convert to a set of polygons.
I can create a terra SpatVectorCollection but can't get any further.
Or, should I be doing this in sf not terra?
library(terra)
library(sf)
exts <- data.frame(xmin = c(-82,80), xmax = c(-80,-78), ymin = c(-2,-2), ymax = c(0,0))
exts.svc <- apply(exts, 1, ext) %>% lapply(as.polygons) %>% svc()
merge(exts.svc) # doesn't work
union(exts.svc) # doesn't work
vect(exts.svc) # doesn't work
If you can avoid the call to svc() it is a little easier to get to sf polygons. If not, the beginnings of a method to get polygons from the SpatVectorCollection is included below as well.
library(terra)
library(sf)
library(tidyverse) #just dplyr should work too
exts <- data.frame(xmin = c(-82,80), xmax = c(-80,-78), ymin = c(-2,-2), ymax = c(0,0))
# This gives a spatrastercollection, but is more difficult to work with
exts.svc <- apply(exts, 1, ext) %>% lapply(as.polygons) %>% svc()
# Avoiding spatrastercollection using exts directly
# create extent, make polygons, make sf, bind, and set crs to 4326
exts_sf <- apply(exts, 1, ext) %>%
lapply(as.polygons) %>%
lapply(st_as_sf) %>%
bind_rows() %>%
st_set_crs(4326)
head(exts_sf)
#> Simple feature collection with 2 features and 0 fields
#> Geometry type: POLYGON
#> Dimension: XY
#> Bounding box: xmin: -82 ymin: -2 xmax: 80 ymax: 0
#> Geodetic CRS: WGS 84
#> geometry
#> 1 POLYGON ((-82 -2, -82 0, -8...
#> 2 POLYGON ((80 -2, 80 0, -78 ...
Above returns an sf object of POLYGON type, use st_union on exts_sf if you need MULTIPOLYGON.
# Working with exts.svc
# two slots
length(exts.svc)
#> [1] 2
# transforming the first polygon/slot to an sf polygon
exts.svc[1] %>% st_as_sf() %>% st_set_crs(4326)
#> Simple feature collection with 1 feature and 0 fields
#> Geometry type: POLYGON
#> Dimension: XY
#> Bounding box: xmin: -82 ymin: -2 xmax: -80 ymax: 0
#> Geodetic CRS: WGS 84
#> geometry
#> 1 POLYGON ((-82 -2, -82 0, -8...
Maybe a loop, apply, or map function would work to programmatically get each slot of exts.svc to return an sf polygon object if you're stuck with an object like exts.svc.
Created on 2022-03-31 by the reprex package (v2.0.1)
Taking your data:
exts <- data.frame(xmin = c(-82,80), xmax = c(-80,-78), ymin = c(-2,-2), ymax = c(0,0))
#as expected
exts
xmin xmax ymin ymax
1 -82 -80 -2 0
2 80 -78 -2 0
# then your apply
> exts.ext <- apply(exts, 1, ext)
> exts.ext
[[1]]
SpatExtent : -82, -80, -2, 0 (xmin, xmax, ymin, ymax)
[[2]]
SpatExtent : 80, -78, -2, 0 (xmin, xmax, ymin, ymax)
# then you lapply using just as.polygons
> exts.polys <- lapply(exts.ext, as.polygons)
exts.polys
[[1]]
class : SpatVector
geometry : polygons
dimensions : 1, 0 (geometries, attributes)
extent : -82, -80, -2, 0 (xmin, xmax, ymin, ymax)
coord. ref. :
[[2]]
class : SpatVector
geometry : polygons
dimensions : 1, 0 (geometries, attributes)
extent : -78, 80, -2, 0 (xmin, xmax, ymin, ymax)
coord. ref. :
#then, I suppose svc()
exts.svc <- lapply(exts.polys, svc)
> exts.svc
[[1]]
class : SpatVectorCollection
length : 1
geometry : polygons (1)
[[2]]
class : SpatVectorCollection
length : 1
geometry : polygons (1)
And then do whatever other operations. When working out (even simple) workflows, I generally do this step by step before introducing %>% or |> so I can check the results of intermediate steps and that they are progressing as expected.

create random points and extract information from a raster

I need to create random points inside a polygon and then extract the information related to the point from a raster.
But I have an error with the function extract(). I try to transform the random points file to a SpatialPoints, but when I try this I have the same error:
Error in (function (classes, fdef, mtable):
unable to find an inherited method for function ‘extract’ for signature ‘"RasterLayer", "sfc_POINT"’
my skript is:
map <- raster("/home.../mosaic.tif")
#class : RasterLayer
#dimensions : 30734, 52746, 1621095564 (nrow, ncol, ncell)
#resolution : 1, 1 (x, y)
#extent : 367836.4, 420582.4, 5805983, 5836717 (xmin, xmax, ymin, ymax)
#crs : +proj=utm +zone=33 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0
#source : /home/.../mosaic.tif
#names : mosaic
#values : 0, 65535 (min, max)
#EPSG:32632
pol <- st_read("/home/.../polygon_without_buldings.shp")
#Reading layer `polygon_without_buldings_tegel' from data source `/home/.../polygon_without_buldings_tegel.shp' using driver `ESRI Shapefile'
#Simple feature collection with 4 features and 2 fields
#geometry type: MULTIPOLYGON
#dimension: XY
#bbox: xmin: 383943.5 ymin: 5827189 xmax: 384882.8 ymax: 5828116
#CRS: 32633
#transform the polygon to map's crs EPSG:32632
pol <- st_transform(pol, crs = 32632)
#Simple feature collection with 4 features and 2 fields
#geometry type: MULTIPOLYGON
#dimension: XY
#bbox: xmin: 790333.1 ymin: 5834483 xmax: 791275.4 ymax: 5835389
#CRS: EPSG:32632
#id id_2 geometry
#1 1000 NA MULTIPOLYGON (((790333.1 58...
#2 1 NA MULTIPOLYGON (((790528.6 58...#
rp <- st_sample(pol, size =100, type='random')
#Geometry set for 100 features
#geometry type: POINT
#dimension: XY
#bbox: xmin: 790397.7 ymin: 5834492 xmax: 791188.3 ymax: 5835357
#CRS: EPSG:32632
#First 5 geometries:
rp_sp<-SpatialPoints(rp, proj4string=CRS(map#crs))
buffer <- extract(map, rp, buffer=10.5, fun=mean)
#Error in (function (classes, fdef, mtable) :
#unable to find an inherited method for function ‘extract’ for signature ‘"RasterLayer", "sfc_POINT"’
Maybe is some basic error, but I'm new with spatial data with R. Thanks in advance for your help.
Here is a minimal, reproducible, self-contained example
library(raster)
library(sf)
p <- shapefile(system.file("external/lux.shp", package="raster"))
s <- as(p, "sf")
r <- raster(p, ncol=100, nrow=100)
values(r) <- 1:ncell(r)
There are different solutions, but one thing you can do is this
rp <- st_sample(s, size =100, type='random')
sp <- as(s, "Spatial")
buffer <- extract(r, sp, buffer=0.1, fun=mean)

Zonal operation using an overlapped-ratified raster which comes from two other ratified rasters

I have the following reclassify & ratified rasters that I am trying to intercept/overlay/overlap to get a new one. The idea is to get a new overlayed raster from the interception areas of the rasters R1 and R2. Once done this, I would do zonal operations. Here the R1, R2, ED rasters.
R1:
class : RasterLayer
dimensions : 1399, 1855, 2595145 (nrow, ncol, ncell)
resolution : 0.008333333, 0.008333333 (x, y)
extent : -13.69167, 1.766667, 49.86667, 61.525 (xmin, xmax, ymin, ymax)
crs : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0
source : memory
names : UK_GDP_2010_PPP_percapita_km2
values : 1, 6 (min, max)
attributes :
ID AG
from: 1 a
to : 6 f
R2:
class : RasterLayer
dimensions : 1399, 1855, 2595145 (nrow, ncol, ncell)
resolution : 0.008333333, 0.008333333 (x, y)
extent : -13.69167, 1.766667, 49.86667, 61.525 (xmin, xmax, ymin, ymax)
crs : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0
source : memory
names : layer
values : 1, 5 (min, max)
attributes :
ID AG
1 A
2 B
3 C
4 D
5 E
Here the code to intercept/overlay/overlap
1st approach
library(sf)
library(tidyverse)
R1_SPDF <- as(R1,'SpatialPolygonsDataFrame')
R1_SPDF <- st_as_sf(R1_SPDF)
R2_SPDF <- as(R2,'SpatialPolygonsDataFrame')
R2_SPDF <- st_as_sf(R2_SPDF)
R3 <- st_intersection(R1_SPDF, R2_SPDF)
R3:
Simple feature collection with 1174501 features and 2 fields
geometry type: POLYGON
dimension: XY
bbox: xmin: -8.166667 ymin: 50.01667 xmax: 1.541667 ymax: 59.55
epsg (SRID): 4326
proj4string: +proj=longlat +datum=WGS84 +no_defs
First 10 features:
UK_GDP_2010_PPP_percapita_km2 layer
1 1 1
2 1 1
2.1 1 1
3 1 1
3.1 1 1
4 1 1
4.1 1 1
1.1 1 1
5 1 1
6 1 1
geometry
1 POLYGON ((-1.641667 59.55, ...
2 POLYGON ((-1.633333 59.55, ...
2.1 POLYGON ((-1.633333 59.55, ...
3 POLYGON ((-1.625 59.55, -1....
3.1 POLYGON ((-1.625 59.55, -1....
4 POLYGON ((-1.616667 59.55, ...
4.1 POLYGON ((-1.616667 59.55, ...
1.1 POLYGON ((-1.641667 59.5416...
5 POLYGON ((-1.65 59.54167, -...
6 POLYGON ((-1.641667 59.5416...
However, I am not sure if this result is what I am looking for, because I expect a new ratified raster R3 with the overlayed areas formed with the combination/interception of R1 and R2 areas (R3 areas ratify: Aa,.. Af,…,Ea,…Ef) or something like that.
Expected R3:
class : RasterLayer
dimensions : #from intersection
resolution : 0.008333333, 0.008333333 (x, y)
extent : -13.69167, 1.766667, 49.86667, 61.525 (xmin, xmax, ymin, ymax)
crs : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0
names : layer
values : 1, 30 (min, max) #aproximately 30 because R1: ID=6, and R2: ID=5.
attributes :
ID AGnew
1 Aa
2 Ab
. .
. .
. .
30 Ef
Here a second try using the raster package:
2nd approach
library(raster)
R3.1 <- intersect(R1_SPDF, R2_SPDF)
R3.1:
Simple feature collection with 485611 features and 0 fields
geometry type: POLYGON
dimension: XY
bbox: xmin: -8.65 ymin: 49.875 xmax: 1.766667 ymax: 60.84167
epsg (SRID): 4326
proj4string: +proj=longlat +datum=WGS84 +no_defs
First 10 features:
geometry
1 POLYGON ((-0.9 60.84167, -0...
2 POLYGON ((-0.8916667 60.841...
3 POLYGON ((-0.8833333 60.841...
4 POLYGON ((-0.875 60.84167, ...
5 POLYGON ((-0.85 60.84167, -...
6 POLYGON ((-0.8416667 60.841...
7 POLYGON ((-0.9 60.83333, -0...
8 POLYGON ((-0.8916667 60.833...
9 POLYGON ((-0.8833333 60.833...
10 POLYGON ((-0.875 60.83333, ...
Once I got the R3, I expect to do the following zonal operation. Sum the values of ED raster within the R3 overlayed areas.
sum_R <- zonal(ED, R3, "sum")
Any recommendation is very welcome.
I think the answer in not clear at all, though I also think you already have the answer.
Perhaps your main issue here is that you are working with relative large datasets and you do not manage to see what is going on at every stage.
So for the sake of simplicity I propose a smaller instance of your problem. Notice that when asking in stackoverflow this approach may be more useful to get help. As a matter of fact your files may be too heavey to download and use in some computers, avoiding people to get involved.
But let's go to the code.
library(tidyverse)
library(raster)
library(sf)
library(tmap)
You basically have two rasters with the same resolution, location and extent as the followings:
R1 <- raster(ncol=10, nrow=10, xmn = 0, xmx=10, ymn = 0, ymx = 10)
R2 <- raster(ncol = 10, nrow = 10, xmn = 0, xmx=10, ymn = 0, ymx = 10)
values(R1) <- c(rep(1,ncell(R1)/2), rep(2,ncell(R1)/2))
values(R2) <- rep(10,ncell(R2))
with these kind of files you can perfomer directly many operations. The same extent and resolution is a plus:
Rsum <- R1 + R2
plot(R1) #See the legend of the plot
plot(R2) #See the legend of the plot
plot(Rsum) #See the legend of the plot
I do not see why you need to perform many other operation to get to a zonal operation.
It would make sense if your rasters were different. For example:
R2_Alt <- raster(ncol = 5, nrow = 2, xmn = 0, xmx=10, ymn = 0, ymx = 10) #Alt for alternative
values(R2_Alt) <- rep(10,ncell(R2))
In the case of using R2_Al a simple operation could produce a mistake:
Test <- R2_Alt + R1
So it make sense to move to vector files:
R1_sp <- as(R1, "SpatialPolygonsDataFrame")
R2_Alt_sp <- as(R2_Alt, "SpatialPolygonsDataFrame")
R1_sf <- st_as_sf(R1_sp)
R2_Alt_sf <- st_as_sf(R2_Alt_sp)
names(R1_sf)[1] <- "V1" #Just to get differente variable names
names(R2_Alt_sf)[1] <- "V2_A"
tm_shape(R1_sf) + tm_polygons(border.col = "black") +
tm_shape(R2_Alt_sf) + tm_polygons(border.col = "red", lwd = 4, alpha = 0)
And here is where having a smaller instance of your problem could shed light on your issues:
Int <- st_intersection(R2_Alt_sf, R1_sf)
View(Int)
plot(st_geometry(Int))
You can also see the outcome with the former R2 raster:
R2_sp <- as(R2, "SpatialPolygonsDataFrame")
R2_sf <- st_as_sf(R2_sp)
names(R2_Alt_sf)[1] <- "V2_A"
Int2 <- st_intersection(R2_sf,R1_sf)
Lastly, be sure that the operation you need is intersection. see
This.
I know this answer is not really an answer, but I hope that it helps you to get closer.
Let me know what you think and put here all the feedback.
all the best

Resources