Write RasterStack and preserve metadata in R - r

I would like to write a RasterStack object and preserve names and metadata of the individual layers. How to preserve names is explained here. Is there a way to preserve metadata of individual layers when writing a RasterStack object?
Here is replicable code:
# load library
library(raster)
# create example rasters
ras_1 <- raster(nrows=180, ncols=360, xmn=-180, xmx=180, ymn=-90, ymx=90, resolution=, vals=1)
ras_2 <- raster(nrows=180, ncols=360, xmn=-180, xmx=180, ymn=-90, ymx=90, resolution=, vals=2)
ras_3 <- raster(nrows=180, ncols=360, xmn=-180, xmx=180, ymn=-90, ymx=90, resolution=, vals=3)
# assign names
names(ras_1) <- "raster_A"
names(ras_2) <- "raster_B"
names(ras_3) <- "raster_C"
# assign metadata
metadata(ras_1) <- list("metadata_raster_A")
metadata(ras_2) <- list("metadata_raster_B")
metadata(ras_3) <- list("metadata_raster_C")
# check
ras_1
ras_2
ras_3
metadata(ras_1)
metadata(ras_2)
metadata(ras_3)
# create and check stack
raster_stack <- stack(ras_1,
ras_2,
ras_3)
raster_stack
raster_stack[[1]]
metadata(raster_stack[[1]])
# write raster stack to disk
setwd("~")
# load library
library(terra)
# create rast object
raster_stack_terr <- rast(raster_stack)
# write raster stack
terra::writeRaster(raster_stack_terr, "raster_stack_terr_test.tif")
# load and check raster stack
raster_stack_check <- stack("raster_stack_terr_test.tif")
raster_stack_check
raster_stack_check[[1]]
names(raster_stack_check[[1]])
metadata(raster_stack_check[[1]])
Use terra to preseve names according to the 3rd answer from here.
When opening the RasterStack from disk, the metadata is not preserved. See console output:
> metadata(raster_stack_check[[1]])
list()
How to preserve metadata of individual layers when writing and re-loading a RasterStack object? Thanks!

It does not seem like {terra} offers an equivalent to raster::metadata(). However, from my perspective, the use cases would be limited here, because you would only be able to store structured information in corresponding format-specific tags (at least, this is my understanding) when writing to disk.
TIFF files (c.f. here) seem to offer the following tags:
TIFFTAG_DOCUMENTNAME
TIFFTAG_IMAGEDESCRIPTION
TIFFTAG_SOFTWARE
TIFFTAG_DATETIME
TIFFTAG_ARTIST
TIFFTAG_HOSTCOMPUTER
TIFFTAG_COPYRIGHT
TIFFTAG_XRESOLUTION
TIFFTAG_YRESOLUTION
TIFFTAG_RESOLUTIONUNIT
ESRI-Grids, on the other hand, do not offer any possibilities to store metadata except for the known header and maybe the filename as far as I know.
If you only wanted to store certain metadata with your raster object, you might as well make use of attr(r, "meta") <- "foobar". However, I don't see how this (random) information can be stored in specific formats and restored afterwards.
You already noticed names() when using {terra}, but there is also time() to be mentioned. Maybe this already suits your needs, since you did not specify what exactly you intend to store.
# set up a raster stack with three layers
library(terra)
#> terra 1.6.17
# create raster
r <- rast(nrows = 10, ncols = 10)
values(r) <- rnorm(100)
# set metadata
names(r) <- "foo"
time(r) <- as.Date("2000-01-01")
attr(r, "meta") <- "bar"
# inspect
r
#> class : SpatRaster
#> dimensions : 10, 10, 1 (nrow, ncol, nlyr)
#> resolution : 36, 18 (x, y)
#> extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
#> coord. ref. : lon/lat WGS 84
#> source : memory
#> name : foo
#> min value : -2.503790
#> max value : 1.998731
#> time (days) : 2000-01-01
# write to disk
writeRaster(r, "sample.tif", overwrite = TRUE)
# read from disk
r2 <- rast("sample.tif")
r2
#> class : SpatRaster
#> dimensions : 10, 10, 1 (nrow, ncol, nlyr)
#> resolution : 36, 18 (x, y)
#> extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
#> coord. ref. : lon/lat WGS 84 (EPSG:4326)
#> source : sample.tif
#> name : foo
#> min value : -2.503790
#> max value : 1.998731
#> time (days) : 2000-01-01
# try to access attributes
attr(r2, "meta")
#> NULL
As expected, data stored as attribute has been lost whereas information provided via names() and time() was sustained.

Related

Save raster to USGS DEM Format in R

Similar to this question:
I would like to know how to do the reverse and save an .img raster image into a USGS DEM format.
Based on GDAL docs, it seems like it would be possible but when I run rgdal::getGDALDriverNames() in R I get the following:
name long_name create copy isRaster
139 USGSDEM USGS Optional ASCII DEM (and CDED) FALSE TRUE TRUE
which seems to imply that it won't create these files?
I was hoping to do something like:
library(raster)
# read
img <- raster("Raster_100ft_2022_10_18.img")
# convert to DEM
writeRaster(img, 'test.dem')
But raster doesn't seem to recognize that output format.
Is there some other method to save as USGS DEM files?
Thanks
For me it works with terra. If that's proper "USGSDEM" file, that's another question. From gdal reference it should save the file as well: https://gdal.org/drivers/raster/usgsdem.html
f <- system.file("ex/elev.tif", package="terra")
r <- terra::rast(f)
terra::writeRaster(r, filename = "test.dem", filetype = "USGSDEM", overwrite = TRUE)
raster::raster("test.dem")
#> class : RasterLayer
#> dimensions : 90, 95, 8550 (nrow, ncol, ncell)
#> resolution : 0.008333333, 0.008333333 (x, y)
#> extent : 5.741667, 6.533333, 49.44167, 50.19167 (xmin, xmax, ymin, ymax)
#> crs : +proj=longlat +datum=WGS84 +no_defs
#> source : test.dem
#> names : elevation
#> values : 141, 547 (min, max)
Created on 2022-10-20 with reprex v2.0.2

Extraction of data from multiple netcdf files at five coordinates files and writing them to five separate csv files

I have 365 .nc files located in a folder containing daily soil moisture information. I want to extract data at five-coordinate locations for the whole year and write them into five separate csv files. My code is attached below. However, I am getting this error after the line:
s <- stack(ff)
>Error in if (is.na(get("has_proj_def.dat", envir = .RGDAL_CACHE))) { : argument is of length zero In addition: Warning message: In .varName(nc, varname, warn = warn) : varname used is: sm If that is not correct, you can set it to one of: sm, sm_noise, flag, sensor
No idea how to proceed further.
library(raster)
library(ncdf4)
ptf <- "D://SMOS_ECV_SM//SMOS_ECV_SM//ECV_SM_Data_1978_2010//1978"
ff <- list.files(path=ptf, pattern="[.]nc$", full.names=TRUE)
s <- stack(ff)
points <- rbind(c(0,1), c(100,120), c(80,5), c(85,4), c(82,4))
v <- extract(s, points)
for (i in 1:ncol(v)) {
write.csv(v[,i,drop=FALSE], paste0("file", i, ".csv"))
}
library(raster)
#Loading required package: sp
f <- list.files("try", full=T)
First try for a single file
r <- raster(f[1])
#Loading required namespace: ncdf4
#Warning message:
#In .varName(nc, varname, warn = warn) : varname used is: sm
#If that is not correct, you can set it to one of: sm, sm_noise, flag, sensor
To get rid of the warning:
r <- raster(f[1], varname="sm")
Now for all files
s <- stack(f, varname="sm")
s
#class : RasterStack
#dimensions : 720, 1440, 1036800, 2 (nrow, ncol, ncell, nlayers)
#resolution : 0.25, 0.25 (x, y)
#extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
#crs : +proj=longlat +datum=WGS84 +no_defs
#names : Soil.Moisture.1, Soil.Moisture.2
Extract values
points <- rbind(c(-96.7, 47), c(34.55, 54.85))
v <- extract(s, points)
v
# Soil.Moisture.1 Soil.Moisture.2
#[1,] 0.3254 0.3018
#[2,] 0.3386 0.3386

stack and brick function error despite all of the rasters have been

Good day everyone..
I have 13 bioclimatic variables (in .tiff format) that I will used to perform sdm by using dismo package.
I followed the tutorial written by Robert J. Hijmans and Jane Elith.
However, when I tried to stack all of the variables, I got the following error
Error in .local(.Object, ...) :
Error in .rasterObjectFromFile(x, band = band, objecttype = "RasterLayer", :
Cannot create a RasterLayer object from this file.
All of my file's coordinate system, extent, and cell size have been adjusted so they are all the same..
when I tried to used the alternative brick function, I got the following error :
Error in .rasterObjectFromFile(x, objecttype = "RasterBrick", ...) :
Cannot create a RasterLayer object from this file.
In addition: There were 12 warnings (use warnings() to see them)
I used the warning() message but it was empty..
do any of you have any hints regarding what may be the cause of such errors?
i've tried to google it, but unfortunately, no answer can solve it.
Thank you in advance..
Here presented is the fraction of the transcript
#setting the workspace
setwd("D:/Riset/MaxentSelaginella/newpaperproject_part2/MakalahVI/Workspace_R")
#Loading Libraries
library("sp")
library("raster")
library("maptools")
library("rgdal")
library("dismo")
library("rJava")
#open the csv file
obs.data <- read.csv(file = "data3/Selaginella_plana.csv", sep = ",")
#open Environmental Data
files <- list.files(path = "data3/tif/", pattern = ".tif", full.names=TRUE)
#stacking all the files
predictors <- brick(files)
I guess you need to use stack instead of brick. As per brick help, in fact:
A RasterBrick is a multi-layer raster object. They are typically created from
a multi-layer (band) file; but they can also exist entirely in memory.
They are similar to a RasterStack (that can be created with stack), but processing
time should be shorter when using a RasterBrick. Yet they are less flexible as they can only point to a single file.
So, if we try to “stack” multiple files:
library(raster)
r <- raster(ncols = 100, nrows = 100, vals = 1:10000)
rfile1 <- tempfile(fileext = ".tif")
writeRaster(r, filename = rfile1)
rfile2 <- tempfile(fileext = ".tif")
writeRaster(r, filename = rfile2)
files_to_stack <- c(rfile1, rfile2)
This fails:
brick(files_to_stack)
#> Warning in if (x == "" | x == ".") {: the condition has length > 1 and only
#> the first element will be used
#> Warning in if (!start %in% c("htt", "ftp")) {: the condition has length > 1
#> and only the first element will be used
#> Warning in if (fileext %in% c(".GRD", ".GRI")) {: the condition has length
#> > 1 and only the first element will be used
#> Warning in if (!file.exists(x)) {: the condition has length > 1 and only
#> the first element will be used
.....
#> Error in .rasterObjectFromFile(x, objecttype = "RasterBrick", ...): Cannot create a RasterLayer object from this file.
While this works:
stack(files_to_stack)
#> class : RasterStack
#> dimensions : 100, 100, 10000, 2 (nrow, ncol, ncell, nlayers)
#> resolution : 3.6, 1.8 (x, y)
#> extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
#> coord. ref. : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0
#> names : file46e41bcd78e3, file46e43ea75bad
#> min values : 1, 1
#> max values : 10000, 10000
If you want to have a brick to get some gain in “efficiency” in further
processing, you can save the different "layers" as a multiband tiff, and then open using brick:
rfile_multi <- tempfile(fileext = ".tif")
writeRaster(stack(files_to_stack), filename = rfile_multi)
brick(rfile_multi)
#> class : RasterBrick
#> dimensions : 100, 100, 10000, 2 (nrow, ncol, ncell, nlayers)
#> resolution : 3.6, 1.8 (x, y)
#> extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
#> coord. ref. : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0
#> data source : D:\RTemp\RtmpacXztJ\file4808784f268c.tif
#> names : file4808784f268c.1, file4808784f268c.2
#> min values : 1, 1
#> max values : 10000, 10000
Created on 2018-11-10 by the reprex package (v0.2.1)

R - gdalUtils - gdal_grid example data giving zero values...?

I have been trying to use the gdal_grid in R and while running the example data set I recieve a raster which has only zero values. I have tried experimenting with this with my own data, and have searched the forums with no luck. Can others get the example to work?
I have tried to explicitly call my path to my GDAL library, and have updated the version of GDAL. I am running R studio with version 3.3.1.
library(raster)
library(rgeos)
library(gdalUtils)
# We'll pre-check to make sure there is a valid GDAL install
# and that raster and rgdal are also installed.
# Note this isn't strictly neccessary, as executing the function will
# force a search for a valid GDAL install.
gdal_setInstallation()
valid_install <- !is.null(getOption("gdalUtils_gdalPath"))
if(require(raster) && valid_install)
{
# Create a properly formatted CSV:
temporary_dir <- tempdir()
tempfname_base <- file.path(temporary_dir,"dem")
tempfname_csv <- paste(tempfname_base,".csv",sep="")
pts <- data.frame(
Easting=c(86943.4,87124.3,86962.4,87077.6),
Northing=c(891957,892075,892321,891995),
Elevation=c(139.13,135.01,182.04,135.01)
)
write.csv(pts,file=tempfname_csv,row.names=FALSE)
# Now make a matching VRT file
tempfname_vrt <- paste(tempfname_base,".vrt",sep="")
vrt_header <- c(
'<OGRVRTDataSource>',
'\t<OGRVRTLayer name="dem">',
'\t<SrcDataSource>dem.csv</SrcDataSource>',
'\t<GeometryType>wkbPoint</GeometryType>',
'\t<GeometryField encoding="PointFromColumns" x="Easting" y="Northing" z="Elevation"/>',
'\t</OGRVRTLayer>',
'\t</OGRVRTDataSource>'
)
vrt_filecon <- file(tempfname_vrt,"w")
writeLines(vrt_header,con=vrt_filecon)
close(vrt_filecon)
tempfname_tif <- paste(tempfname_base,".tiff",sep="")
# Now run gdal_grid:
setMinMax(gdal_grid(src_datasource=tempfname_vrt,
dst_filename=tempfname_tif,a="invdist:power=2.0:smoothing=1.0",
txe=c(85000,89000),tye=c(894000,890000),outsize=c(400,400),
of="GTiff",ot="Float64",l="dem",output_Raster=TRUE))
}
r<-raster(tempfname_tif)
r
#class : RasterLayer
#dimensions : 400, 400, 160000 (nrow, ncol, ncell)
#resolution : 10, 10 (x, y)
#extent : 85000, 89000, 890000, 894000 (xmin, xmax, ymin, ymax)
#coord. ref. : NA
#data source : C:\Users\m.modeler\AppData\Local\Temp\RtmpW6HvOc\dem.tiff
#names : dem
#min values : 0
#max values : 0
plot(r)
Raster results plot with zero values:
Thanks much,
I have got the code to run by changing the path from the temp directory to a folder on my hard drive. Example below.
# change to a path on your computer
setwd("C:\\Users\\m.modeler\\Documents\\R\\gdal_Examples")
#######################################################
#create XYZ csv
pts <- data.frame(
Easting=c(86943.4,87124.3,86962.4,87077.6),
Northing=c(891957,892075,892321,891995),
Elevation=c(139.13,135.01,182.04,135.01))
write.csv(pts,file="dem.csv",row.names=FALSE)
#######################################################
#create VRT
fn_vrt<-"dem.vrt"
# Now make a matching VRT file
vrt_header <- c(
'<OGRVRTDataSource>',
'\t<OGRVRTLayer name="dem">',
'\t<SrcDataSource>dem.csv</SrcDataSource>',
'\t<GeometryType>wkbPoint</GeometryType>',
'\t<GeometryField encoding="PointFromColumns" x="Easting" y="Northing" z="Elevation"/>',
'\t</OGRVRTLayer>',
'\t</OGRVRTDataSource>')
vrt_filecon <- file(fn_vrt,"w")
writeLines(vrt_header,con=vrt_filecon)
close(vrt_filecon)
#######################################################
#create interpolated DEM
fn_tif <- "dem.tif"
# Now run gdal_grid:
r.dem <- setMinMax(gdal_grid(src_datasource=fn_vrt,
dst_filename=fn_tif,a="invdist:power=2.0:smoothing=1.0",
txe=c(85000,89000),tye=c(894000,890000),outsize=c(400,400),
of="GTiff",ot="Float64",l="dem",output_Raster=TRUE,verbose=TRUE))
plot(r.dem)

How to plot a spatially explicit hdf5 file? - r - raster

I have an hdf5 data file that has lat/long and a dozen of values, for example temperature. I would like to plot so I can visualize the data in a map style so with lat/long in the axis. Is there a direct way to do it? I only found a very complicated way on a blog. With netcdf data I can just use plot(ncvariable) and it will work, not with a hdf5 file.
I am using the rhdf5. If I read the h5 file and a specific value I only get a vector
> library(rhdf5)
> ncep<-h5read("CB_OL1_1979OCT.h5", "sh")
> head(ncep)
[1] 1.03953242 0.79024571 2.29503083 0.43957919 0.36909071 -0.04498866
I am attaching the file. I am not sure you would call it a 3d, it's a simple raster with x,y,value.
h5 file
It's been some time since you asked, but in case you did not found a solution yet, I'd like to provide two approaches on how to handle this.
Since your hdf5 file is not available anymore, I just picked a random file provided here for illustration.
On the one hand, you could simply use plot(grid = TRUE) from {terra} after having read your hdf5 file using rast():
library(terra)
#> terra 1.6.17
# read netcdf file
r <- rast("AMSR_E_L3_DailyOcean_V04_20020619.hdf")
# get layer names
names(r)
#> [1] "Very_low_res_sst" "Low_res_sst" "Low_res_wind" "Med_res_wind"
#> [5] "Med_res_vapor" "High_res_cloud" "RFI_angle"
# subset dataset by layer name
rs <- r[["Med_res_vapor"]]
rs
#> 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 Unknown datum based upon the Clarke 1866 ellipsoid
#> source : AMSR_E_L3_DailyOcean_V04_20020619.hdf:GlobalGrid:Med_res_vapor
#> varname : AMSR_E_L3_DailyOcean_V04_20020619
#> name : Med_res_vapor
plot(rs, grid = TRUE)
Or you could go for the little bit more complex solution, generating graticules manually using sf::st_graticules() first, followed by making use of {tidyterra} to be able to use {ggplot2} with SpatRaster and SpatVector objects from {terra}:
library(sf)
#> Linking to GEOS 3.9.1, GDAL 3.4.3, PROJ 7.2.1; sf_use_s2() is TRUE
library(ggplot2)
library(tidyterra)
grat <- st_graticule(lon = seq(-180, 180, 30),
lat = seq(-90, 90, 30),
ndiscr = 100) |>
st_transform("epsg:4326") |>
vect()
ggplot() +
geom_spatraster(data = rs) +
geom_spatvector(data = grat, color = alpha("grey60", 0.5)) +
coord_sf(expand = FALSE) +
scale_x_continuous(breaks = seq(-180, 180, 30)) +
scale_y_continuous(breaks = seq(-90, 90, 30))
#> SpatRaster resampled to ncells = 5e+05

Resources