Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Read only a crop or extent of a raster in R

I am working with a huge amount of data in daily tif files (thousands of daily files). I am analyzing the mean of the raster in a shapefile area, repeated over potentially thousands of shape layers.

My current .tif files are for an entire country when in reality I only need a small area of the of each tif file for each shapefile layer. Each shape layer has a different set of the days to extract from, i.e. data frame like this:

df <- data.frame(shplayer=c("shp_layerbuffer1","shp_layerbuffer2", "shp_layerbuffer3"), start=c("2000_02_18", "2004_03_19", "2010_08_20"), end=c("2010_01_09", "2005_03_15", "2012_09_04"))

Is there a way, in R, to crop a .tif (or any raster type file) BEFORE reading the file? This way I could read just the cropped area of each of the tif files

I envisoned something like (repeating across the entire set of dates):

library(sf)
library(raster)
shp_layerbuffer1 <- st_read("myshpfolder", layer="shp_layerbuffer1", quiet=T)

###EXAMPLE BUT doesn't work to crop the raster as it comes in
tempraster <- raster::raster("mytif_2000_02_18.tif", ext=extent(shp_layerbuffer1))

Then the usual velox (or raster) extract, repeat.

like image 478
Neal Barsch Avatar asked Jun 13 '18 01:06

Neal Barsch


People also ask

How do I crop raster data in R?

We can use the crop() function to crop a raster to the extent of another spatial object. To do this, we need to specify the raster to be cropped and the spatial object that will be used to crop the raster. R will use the extent of the spatial object as the cropping boundary.

How do I read a raster image in R?

Raster files are most easily read in to R with the raster() function from the raster package. You simply pass in the filename (including the extension) of the raster as the first argument, x .

What function do you use to extract extent information from a raster image?

Use the Clip raster function to clip a raster to a specified extent or boundary layer.


2 Answers

In such a case, I would create a virtual raster file (VRT) with the gdalUtils package. It is the quickest way to create a subset (or even virtual mosaic) of one or multiple raster data sets. For this VRT you can set the desired extent using the sf::st_bbox.

Minimal (not reproducible) example would be:

library(gdalUitls)
library(raster)
library(sf)

shp_layerbuffer1 <- st_read("myshpfolder", layer="shp_layerbuffer1", quiet=T)

gdalbuildvrt(gdalfile = "yourraster.tif", 
             output.vrt = "tmp.vrt", 
             te = st_bbox(shp_layerbuffer1))

tempraster <- raster("tmp.vrt")

The VRT basically creates a virtual canvas for a new "raster" file. It then references the corresponding rows and columns from the (one or multiple) underlying raster file(s). Hence, you do not need to create a whole new raster but simply reference existing files. The file size of your VRT should not exceed some kBytes.

like image 76
loki Avatar answered Sep 21 '22 11:09

loki


If you're interested in the data rather than a raster object (or vrt/tiff), then this could be an approach:

If you "load" a raster from file, it doesn't necessarily mean that it gets loaded into memory, as the documentation of raster explains:

In many cases, e.g. when a RasterLayer is created from a file, it does (initially) not contain any cell (pixel) values in (RAM) memory, it only has the parameters that describe the RasterLayer. You can access cell-values with getValues, extract and related functions. You can assign new values with setValues and with replacement.

So you could first "index" the raster and then use getValuesBlock to read the values which fall into your area of interest.

library(raster)

f <- system.file('external/test.grd',package = 'raster')

# index
r <- raster(f)

# check if in memory

inMemory(r)
#[1] FALSE # output

# this would be an extent from your overlapping shapefile
e <- extent(r,58,68,40,50)

# get cells from extent; either use cells as index directly or convert to rowcol

rowcol <- rowColFromCell(r,cellsFromExtent(r,e))

v <- getValuesBlock(r,row=rowcol[1,1],nrows=(rowcol[nrow(rowcol),1] - rowcol[1,1]),
                    col=rowcol[1,2],ncols=(rowcol[nrow(rowcol),2] - rowcol[1,2]))

v
# [1] 295.392 225.710 258.595 310.336 324.666 322.702 307.217 283.611 263.987 156.609 322.978 297.565 301.797 315.971
# [15] 323.605 326.920 317.894 297.138 270.027 225.769 337.503 323.388 314.900 308.877 314.556 343.555 344.035 315.400
# [29] 291.188 270.876 337.866 324.632 307.220 278.294 264.379 348.519 356.456 322.450 301.790 285.815 331.383 318.950
# [43] 299.246 262.026 230.869 294.012 320.274 312.777 300.513 285.317 321.075 311.447 296.952 278.519 270.279 283.797
# [57] 296.415 298.861 293.150 277.573 306.692 300.772 289.376 273.141 258.457 258.638 272.966 283.977 284.621 271.690
# [71] 286.749 286.617 275.618 247.307 198.884 193.865 240.465 268.687 277.303 271.431 260.336 271.458 263.977 231.071
# [85] 161.407 154.181 222.417 258.672 271.711 272.642 235.458 258.810 257.763 239.553 209.409 205.905 234.162 255.668
# [99] 266.260 270.532

EDIT:

# check if raster was loaded after getValuesBlock
inMemory(r)
#[1] FALSE
like image 40
Val Avatar answered Sep 20 '22 11:09

Val