{gdalraster}
provides bindings to the Raster API of the Geospatial Data Abstraction Library (GDAL). Using the API natively enables fast and scalable raster I/O from R. This vignette is an R port of the GDAL Raster API tutorial for C++, C and Python, (c) 1998-2023 Frank Warmerdam, Even Rouault, and others, https://gdal.org/license.html.
Before opening a GDAL-supported data store it is necessary to register drivers. There is a driver for each supported raster format. {gdalraster}
automatically registers drivers when the package is loaded. A raster dataset is opened by creating a new instance of class GDALRaster
passing the name of the file and the access desired (read_only = TRUE
, or read_only = FALSE
for update access).
library(gdalraster)
#> GDAL 3.6.4, released 2023/04/17
system.file("extdata/storml_elev.tif", package="gdalraster")
elev_file <- new(GDALRaster, filename = elev_file, read_only = TRUE) ds <-
An error is returned if the dataset cannot be opened (and creation of the GDALRaster
object fails). Also, note that filename
may not actually be the name of a physical file (though it usually is). Its interpretation is driver dependent, and it might be a URL, a database connection string, a filename with additional parameters, etc.
As described in the GDAL Raster Data Model, a GDAL dataset contains a list of raster bands, all pertaining to the same area and having the same resolution. It also has metadata, a coordinate system, a georeferencing transform, size of raster and various other information. Class GDALRaster
encapsulates a GDAL dataset object and its associated raster band objects.
In the particular but common case of a “north up” raster without any rotation or shearing, the georeferencing transform (see Geotransform Tutorial) takes the following form with 1-based indexing in R:
ds$getGeoTransform()
gt <-1] # x-coordinate of upper-left corner of the upper-left pixel
gt[#> [1] 323476.1
2] # pixel width (w-e resolution)
gt[#> [1] 30
3] # 0 for north-up
gt[#> [1] 0
4] # y-coordinate of upper-left corner of the upper-left pixel
gt[#> [1] 5105082
5] # 0 for north-up
gt[#> [1] 0
6] # pixel height (n-s resolution, negative value)
gt[#> [1] -30
In the general case, this is an affine transform. Class GDALRaster
also provides convenience methods for the case of a north-up raster:
$bbox() # xmin, ymin, xmax, ymax
ds#> [1] 323476.1 5101872.0 327766.1 5105082.0
$res() # pixel width, pixel height as positive values
ds#> [1] 30 30
The following code retrieves some additional information about the dataset:
# GDAL format driver
$getDriverShortName()
ds#> [1] "GTiff"
$getDriverLongName()
ds#> [1] "GeoTIFF"
# raster size in pixels, number of bands
$getRasterXSize()
ds#> [1] 143
$getRasterYSize()
ds#> [1] 107
$getRasterCount()
ds#> [1] 1
$dim()
ds#> [1] 143 107 1
# coordinate reference system
$getProjectionRef()
ds#> [1] "PROJCS[\"NAD83 / UTM zone 12N\",GEOGCS[\"NAD83\",DATUM[\"North_American_Datum_1983\",SPHEROID[\"GRS 1980\",6378137,298.257222101,AUTHORITY[\"EPSG\",\"7019\"]],AUTHORITY[\"EPSG\",\"6269\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4269\"]],PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"latitude_of_origin\",0],PARAMETER[\"central_meridian\",-111],PARAMETER[\"scale_factor\",0.9996],PARAMETER[\"false_easting\",500000],PARAMETER[\"false_northing\",0],UNIT[\"metre\",1,AUTHORITY[\"EPSG\",\"9001\"]],AXIS[\"Easting\",EAST],AXIS[\"Northing\",NORTH],AUTHORITY[\"EPSG\",\"26912\"]]"
# origin and pixel size from the geotransform
print(paste("Origin:", gt[1], gt[4]))
#> [1] "Origin: 323476.071970863 5105081.98303138"
print(paste("Pixel size:", gt[2], gt[6]))
#> [1] "Pixel size: 30 -30"
At this time access to raster data via GDAL is done one band at a time. Also, metadata, block sizes, nodata values and various other information are available on a per-band basis. Class GDALRaster
provides methods to access raster band objects from the dataset (numbered 1 through ds$getRasterCount()
), by specifying a band
number as the first argument:
# block size
$getBlockSize(band=1)
ds#> [1] 143 28
# data type
$getDataTypeName(band=1)
ds#> [1] "Int16"
# nodata value
$getNoDataValue(band=1)
ds#> [1] 32767
# min, max, mean, sd of pixel values in the band
$getStatistics(band=1, approx_ok = FALSE, force = TRUE)
ds#> 0...10...20...30...40...50...60...70...80...90...100 - done.
#> [1] 2438.0000 3046.0000 2675.9713 133.0185
# does this band have overviews? (aka "pyramids")
$getOverviewCount(band=1)
ds#> [1] 0
# gdalraster currently does not support access to color tables
GDALRaster$read()
is a wrapper for the GDALRasterBand::RasterIO()
method in the underlying API. This method will automatically take care of data type conversion, up/down sampling and windowing. The following code will read the first row of data into a similarly sized vector. GDALRaster$read()
will return data as R integer
type if possible for the raster data type (Byte, Int8, Int16, UInt16, Int32), otherwise the returned vector will be of type double
(UInt32, Float32, Float64) or complex
(CInt16, CInt32, CFloat32, CFloat64). The input data are organized in left to right, top to bottom pixel order. NA
will be returned in place of the nodata value if the raster dataset has a nodata value defined for the band:
ds$getRasterXSize()
ncols <- ds$read(band=1,
rowdata <-xoff=0, yoff=0,
xsize=ncols, ysize=1,
out_xsize=ncols, out_ysize=1)
length(rowdata)
#> [1] 143
typeof(rowdata)
#> [1] "integer"
head(rowdata)
#> [1] NA NA NA NA 2495 2511
Writing data with GDALRaster$write()
is similar to read()
with an additional argument specifying a vector of pixel data to write. The xoff
, yoff
, xsize
, ysize
arguments describe the window of raster data on disk to read (or write). It doesn’t have to fall on tile boundaries, though access may be more efficient in some cases if it does. Note that GDAL uses memory caching algorithms during raster I/O to improve performance. The operation of the caching mechanism and potential configuration of cache memory size should be considered when scaling I/O to large datasets (see GDAL Block Cache).
The out_xsize
and out_ysize
values describe the size of the buffer (an R vector of length out_xsize * out_ysize
that data will be read into). When loading data at full resolution this would be the same as the window size (xsize
, ysize
). However, to load a reduced resolution overview this could be set to smaller than the window on disk. In this case the read method will utilize overviews to do the I/O more efficiently if the overviews are suitable.
read_ds()
is a convenience wrapper for GDALRaster$read()
.
plot_raster()
can be used to display data that have been read into a vector.
Calling GDALRaster$close()
will result in proper cleanup, and flushing of any pending writes. Forgetting to call close
on a dataset opened in update mode in a popular format like GTiff will likely result in being unable to open it afterwards.
# close the dataset for proper cleanup
$close() ds
New files in GDAL-supported formats may be created if the format driver supports creation. There are two general techniques for creating files, using CreateCopy() and Create(). The CreateCopy method in R involves calling gdalraster::createCopy()
, passing in a source raster file that should be copied. The Create method involves calling gdalraster::create()
, and then explicitly writing all the metadata and raster data with separate calls. All drivers that support creating new files support the CreateCopy method, but only a few support the Create method.
Consult the table of GDAL raster format drivers to determine if a particular driver supports Create or CreateCopy. Note that a number of drivers are read-only and won’t support either creation method.
gdalraster::createCopy()
is simple to use as most information is collected from the source file. It includes an argument for passing a list of format specific creation options. It can be used to copy a raster to a different format, and/or change options such as the block size and arrangement, compression, various metadata, etc. The following code copies a multi-band raster in FARSITE v.4 LCP format (basically a raw format without support for compression or nodata values) to LZW-compressed GeoTiff:
system.file("extdata/storm_lake.lcp", package="gdalraster")
lcp_file <- paste0(tempdir(), "/", "storml_lndscp.tif")
tif_file <- c("COMPRESS=LZW")
options <-createCopy(format="GTiff", dst_filename=tif_file, src_filename=lcp_file,
options=options)
#> 0...10...20...30...40...50...60...70...80...90...100 - done.
file.size(lcp_file)
#> [1] 252132
file.size(tif_file)
#> [1] 108510
new(GDALRaster, tif_file, read_only=FALSE)
ds <-
# band=0 for dataset-level metadata:
$getMetadata(band=0, domain="IMAGE_STRUCTURE")
ds#> [1] "COMPRESSION=LZW" "INTERLEAVE=PIXEL"
# set nodata value for all bands
for (band in 1:ds$getRasterCount())
$setNoDataValue(band, -9999)
ds
# band 2 of an LCP file is slope degrees
$getStatistics(band=2, approx_ok=FALSE, force=TRUE)
ds#> 0...10...20...30...40...50...60...70...80...90...100 - done.
#> [1] 0.00000 54.00000 22.93012 12.51330
$close() ds
gdalraster::create()
can be used to create a new raster dataset manually. This function takes a list of creation options like createCopy()
, but the raster size, number of bands and band type must be provided explicitly:
paste0(tempdir(), "/", "newdata.tif")
new_file <-create(format="GTiff", dst_filename=new_file, xsize=143, ysize=107, nbands=1,
dataType="Int16")
Once the dataset is successfully created, all appropriate metadata and raster data must be written to the file. What this is will vary according to usage, but a simple case with a projection, geotransform and raster data is covered here:
new(GDALRaster, new_file, read_only=FALSE)
ds <-
# EPSG:26912 - NAD83 / UTM zone 12N
$setProjection(epsg_to_wkt(26912))
ds#> [1] TRUE
c(323476.1, 30, 0, 5105082.0, 0, -30)
gt <-$setGeoTransform(gt)
ds#> [1] TRUE
$setNoDataValue(band=1, -9999)
ds#> [1] TRUE
$fillRaster(band=1, -9999, 0)
ds
# ...
# close the dataset when done
$close() ds
{gdalraster}
provides two additional functions for creating raster datasets:
rasterFromRaster()
creates a new raster with spatial reference, extent and resolution taken from a template raster, without copying data. It optionally changes the format, number of bands, data type and nodata value, sets driver-specific dataset creation options, and initializes to a value.
rasterToVRT()
creates a virtual raster dataset (VRT) derived from a source raster with options for virtual subsetting, virtually resampling the source data at a different pixel resolution, or applying a virtual kernel filter.