Reordering an aggregated stars object - r

I'm performing temporal aggregations on netcdf rasters using the stars package in R. Typically the objects have (X, Y, Time) dimensions and, after doing the temporal averages, get an object with dimensions ordered as (Time, X, Y). How would one go about changing the order of the dimensions back to the original order (X, Y, T)?
I've been searching through the package vignettes and the likely function examples for a method, but haven't had any luck. I feel like I'm probably missing something simple and obvious...
Here's a reprex:
library(stars)
#> Loading required package: abind
#> Warning: package 'abind' was built under R version 4.0.3
#> Loading required package: sf
#> Warning: package 'sf' was built under R version 4.0.4
#> Linking to GEOS 3.8.0, GDAL 3.0.4, PROJ 6.3.1
tif = system.file("tif/L7_ETMs.tif", package = "stars")
x = read_stars(c(tif, tif, tif), along = "band")
x
#> stars object with 3 dimensions and 1 attribute
#> attribute(s), summary of first 1e+05 cells:
#> L7_ETMs.tif
#> Min. : 47.00
#> 1st Qu.: 65.00
#> Median : 76.00
#> Mean : 77.34
#> 3rd Qu.: 87.00
#> Max. :255.00
#> dimension(s):
#> from to offset delta refsys point values x/y
#> x 1 349 288776 28.5 UTM Zone 25, Southern Hem... FALSE NULL [x]
#> y 1 352 9120761 -28.5 UTM Zone 25, Southern Hem... FALSE NULL [y]
#> band 1 18 NA NA NA NA NULL
time = as.Date("2021-03-24") + 1:18
x = st_set_dimensions(x, "band", values = time)
y = aggregate(x, by = "3 days", "mean")
y
#> stars object with 3 dimensions and 1 attribute
#> attribute(s):
#> L7_ETMs.tif
#> Min. : 5.00
#> 1st Qu.: 56.67
#> Median : 71.67
#> Mean : 68.91
#> 3rd Qu.: 84.00
#> Max. :255.00
#> dimension(s):
#> from to offset delta refsys point values x/y
#> time 1 6 2021-03-25 3 days Date NA NULL
#> x 1 349 288776 28.5 UTM Zone 25, Southern Hem... FALSE NULL [x]
#> y 1 352 9120761 -28.5 UTM Zone 25, Southern Hem... FALSE NULL [y]
Created on 2021-03-24 by the reprex package (v0.3.0)

The answer was simple and I should have known it! Because stars objects are, in part, a list of arrays, the dimensions can be reordered using aperm in the same way you would with a normal n-dimensionsal array.
aperm(y, c(2, 3, 1))
#> stars object with 3 dimensions and 1 attribute
#> attribute(s):
#> L7_ETMs.tif
#> Min. : 5.00
#> 1st Qu.: 56.67
#> Median : 71.67
#> Mean : 68.91
#> 3rd Qu.: 84.00
#> Max. :255.00
#> dimension(s):
#> from to offset delta refsys point values x/y
#> x 1 349 288776 28.5 UTM Zone 25, Southern Hem... FALSE NULL [x]
#> y 1 352 9120761 -28.5 UTM Zone 25, Southern Hem... FALSE NULL [y]
#> time 1 6 2021-03-25 3 days Date NA NULL

Related

How to import sinusoidal remotesensed data into raster in R?

I am trying to read a NetCDF file from the Climate Change Initiative (CCI) into R with the terra package.
Given that the data is not on a regular grid, I am trying to find the proper way to project such data onto a regular grid.
library(terra)
#> terra 1.6.47
# Read the data
r <- rast("/vsicurl/https://dap.ceda.ac.uk/neodc/esacci/ocean_colour/data/v5.0-release/sinusoidal/netcdf/chlor_a/daily/v5.0/2007/ESACCI-OC-L3S-CHLOR_A-MERGED-1D_DAILY_4km_SIN_PML_OCx-20070104-fv5.0.nc?download=1", lyrs = "chlor_a")
#> Warning: [rast] unknown extent
As we can see here, there is no projection associated to the raster.
r
#> class : SpatRaster
#> dimensions : 1, 23761676, 1 (nrow, ncol, nlyr)
#> resolution : 1, 1 (x, y)
#> extent : 0, 23761676, 0, 1 (xmin, xmax, ymin, ymax)
#> coord. ref. :
#> source : https://ESACCI-OC-L3S-CHLOR_A-MERGED-1D_DAILY_4km_SIN_PML_OCx-20070104-fv5.0.nc?download=1://chlor_a
#> varname : chlor_a
#> name : chlor_a
I am guessing this should be the “original” projection to use.
sincrs <- "+proj=sinu +lon_0=0 +x_0=0 +y_0=0 +a=6371007.181 +b=6371007.181 +units=m"
At this point, I am not sure how to proceed to properly project the data on a regular grid. Any help would be appreciated.
Created on 2022-12-06 with reprex v2.0.2
I get
url = "https://dap.ceda.ac.uk/neodc/esacci/ocean_colour/data/v5.0-release/sinusoidal/netcdf/chlor_a/daily/v5.0/2007/ESACCI-OC-L3S-CHLOR_A-MERGED-1D_DAILY_4km_SIN_PML_OCx-20070104-fv5.0.nc"
download.file(url, basename(url), mode="wb")
library(terra)
r = rast(f, "chlor_a" )
#[1] "vobjtovarid4: **** WARNING **** I was asked to get a varid for dimension named bin_index 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 max(rs) : no non-missing arguments to max; returning -Inf
#3: In min(rs) : no non-missing arguments to min; returning Inf
#4: [rast] cells are not equally spaced; extent is not defined
This suggest that data are not on a regular raster.
Based (i.e entirely copied) on #mdsumner suggestion:
library(terra)
#> terra 1.6.47
library(tidync)
library(palr)
url <- "https://dap.ceda.ac.uk/neodc/esacci/ocean_colour/data/v5.0-release/sinusoidal/netcdf/chlor_a/daily/v5.0/2007/ESACCI-OC-L3S-CHLOR_A-MERGED-1D_DAILY_4km_SIN_PML_OCx-20070704-fv5.0.nc?download=1"
f <- curl::curl_download(url, tempfile(fileext = ".nc"))
bins <- tidync(f) |>
activate("D1") |>
hyper_tibble()
bins
#> # A tibble: 23,761,676 × 3
#> lat lon bin_index
#> <dbl> <dbl> <int>
#> 1 -90.0 -120 1
#> 2 -90.0 0 2
#> 3 -90.0 120 3
#> 4 -89.9 -160 4
#> 5 -89.9 -120 5
#> 6 -89.9 -80 6
#> 7 -89.9 -40 7
#> 8 -89.9 0 8
#> 9 -89.9 40 9
#> 10 -89.9 80 10
#> # … with 23,761,666 more rows
## the bin is for joining on which bin_index is used here
d <- tidync::tidync(f) |>
activate("D1,D0") |>
hyper_tibble(select_var = c("chlor_a")) |>
dplyr::inner_join(bins, "bin_index")
d
#> # A tibble: 3,953,869 × 5
#> chlor_a bin_index time lat lon
#> <dbl> <int> <dbl> <dbl> <dbl>
#> 1 0.202 3028676 13698 -48.1 -173.
#> 2 0.246 3028677 13698 -48.1 -173.
#> 3 0.268 3028678 13698 -48.1 -173.
#> 4 0.370 3034441 13698 -48.1 -173.
#> 5 0.370 3034442 13698 -48.1 -173.
#> 6 0.322 3034443 13698 -48.1 -173.
#> 7 0.108 3035236 13698 -48.1 -123.
#> 8 0.166 3035237 13698 -48.1 -123.
#> 9 0.131 3035238 13698 -48.1 -123.
#> 10 0.119 3035239 13698 -48.1 -123.
#> # … with 3,953,859 more rows
d$time <- NULL
plot(d$lon, d$lat, pch = ".", col = palr::chl_pal(d$chlor_a))
## define a raster
r <- terra::rast(
terra::ext(c(-180, 180, -90, 90)),
nrows = 900,
ncols = 1800,
crs = "OGC:CRS84"
)
r
#> class : SpatRaster
#> dimensions : 900, 1800, 1 (nrow, ncol, nlyr)
#> resolution : 0.2, 0.2 (x, y)
#> extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
#> coord. ref. : lon/lat WGS 84
cells <- tibble::tibble(
cell = terra::cellFromXY(r, cbind(d$lon, d$lat)),
chlor_a = d$chlor_a
) |>
dplyr::group_by(cell) |>
dplyr::summarize(chlor_a = mean(chlor_a))
r[cells$cell] <- cells$chlor_a
pal <- palr::chl_pal(palette = TRUE)
image(r, col = pal$cols[-1], breaks = pal$breaks)
Created on 2022-12-12 with reprex v2.0.2

Is it possible to create a stars object in R that is the minimum values of two other stars objects?

I have two stars objects that are read in to R as tifs:
tif1 <- stars::read_stars("/data.tif")
tif2 <- stars::read_stars("/data2.tif")
They cover the same extent and have the same resolution. I know that I can do algebra with the objects -- for example, to create a new object that is the average of the values of the first two, I can use:
tif.avg <- (tif1 + tif2)/2
However, I want to know if it's possible to create a new object that extracts the minimum value from them instead. I've tried it a couple of different ways but I've hit a brick wall with this. Does anybody know if this is even possible?
O.K. thanks for the clarification #Ben Lee.
So, as a follow-up of your comment, please find below (cf. Reprex) one solution to your problem :
REPREX:
library(raster)
#> Le chargement a nécessité le package : sp
library(stars)
#> Le chargement a nécessité le package : abind
#> Le chargement a nécessité le package : sf
#> Linking to GEOS 3.9.1, GDAL 3.2.1, PROJ 7.2.1
# 1. Creating two stars objects
r1 <- raster(ncols = 3, nrows = 3)
values(r1) <- seq(length(r1))
r2 <- raster(ncols = 3, nrows = 3)
values(r2) <- rev(seq(length(r2)))
r_stack <- stack(r1, r2)
writeRaster(r_stack, "raster.tif",
bylayer = TRUE, suffix = 1:nlayers(r_stack))
tif1 <- read_stars("raster_1.tif")
tif2 <- read_stars("raster_2.tif")
# Array of the first stars object
tif1[[1]]
#> [,1] [,2] [,3]
#> [1,] 1 4 7
#> [2,] 2 5 8
#> [3,] 3 6 9
# Array of the second stars object
tif2[[1]]
#> [,1] [,2] [,3]
#> [1,] 9 6 3
#> [2,] 8 5 2
#> [3,] 7 4 1
# 2. Creating a 'stars' object with the minimum values
# of the two previous stars objects
# 2.1. retrieving the min values between the two stars object
tif_min <- pmin(tif1[[1]], tif2[[1]])
# 2.2. converting the resulting array 'tif_min' into a stars object
tif_min <- st_as_stars(tif_min)
# 2.3. retrieving the dimensions from one of the two previous
# stars object (here, tif1) and setting a name
st_dimensions(tif_min) <- st_dimensions(tif1)
setNames(tif_min, "tif_min")
#> stars object with 2 dimensions and 1 attribute
#> attribute(s):
#> Min. 1st Qu. Median Mean 3rd Qu. Max.
#> tif_min 1 2 3 2.777778 4 5
#> dimension(s):
#> from to offset delta refsys point values x/y
#> x 1 3 -180 120 WGS 84 FALSE NULL [x]
#> y 1 3 90 -60 WGS 84 FALSE NULL [y]
# 2.4 a little check!
tif_min[[1]]
#> [,1] [,2] [,3]
#> [1,] 1 4 3
#> [2,] 2 5 2
#> [3,] 3 4 1
#>These are the minimum values of the two "star" input objects
Created on 2021-09-20 by the reprex package (v2.0.1)
Please confirm that this is what you were looking for (and if so, please do not forget to validate the answer to make it easier for other users to find this solution)

Products of all pairwise combinations of bands in two rasters with R stars package

I have two multiband rasters of class stars. They have the same resolution and extent in their first two dimensions (x and y). Each raster has multiple bands. I would like to take all pairwise combinations of bands from each of the rasters and find the product of each of those combinations. Is there a way to do this with a function like outer() or possibly st_apply(), without having to use nested for-loops?
Hoping that it is not too late and that my answer will still be useful for you #qdread, I suggest the following solution (see Reprex below).
As you wished, I used st_apply() to compute the products of all pairwise combinations of bands of the two rasters of class stars.
For your convenience, I have built a function (i.e. named crossBandsProducts()) that wraps the whole process.
This function has the following features:
Input:
Two stars objects or two stars_proxy objects
the number of bands can be the same or different between the two rasters
Output:
One stars object with a dimension named "bandsProducts" containing all pairwise combinations of products between the bands of the two rasters.
Each product has a name (i.e. a value - see Reprex below) of the form r2bX*r1bY where X and Y are respectively the band numbers of rasters 2 and 1.
REPREX:
library(stars)
#> Le chargement a nécessité le package : abind
#> Le chargement a nécessité le package : sf
#> Linking to GEOS 3.9.1, GDAL 3.2.1, PROJ 7.2.1
# 1. Importing two stars objects with 6 and 3 bands respectively
tif <- system.file("tif/L7_ETMs.tif", package = "stars")
tif1 <- read_stars(tif, proxy = FALSE)
tif2 <- read_stars(tif, proxy = FALSE, RasterIO = list(bands = c(1, 3, 4)))
# 2. Building the 'crossBandsProducts' function
crossBandsProducts <- function(r1, r2) {
products <-
st_apply(r2, 3, function(x)
x * as.data.frame(split(r1, "band"))[, -grep("x|y", colnames(as.data.frame(split(r1, "band"))))])
if (class(r1)[1] == "stars_proxy"){
products <- st_as_stars(products)
}
products <- as.data.frame(split(products[[1]], "band"))
colnames(products) <-
paste0(rep(paste0("r2b", 1:dim(r2)["band"]), each = dim(r1)["band"]),
rep(paste0("*r1b", 1:dim(r1)["band"]), times = dim(r2)["band"]))
products <-
cbind(as.data.frame(split(r1, "band"))[, grep("x|y", colnames(as.data.frame(split(r1, "band"))))], products)
products <- st_as_stars(products, dims = c("x", "y"))
st_dimensions(products) <- st_dimensions(r1)[c("x", "y")]
products <- st_set_dimensions(merge(products),
names = c("x", "y", "bandsProducts"))
return(products)
}
# 3. Use of the function 'crossBandProducts'
(products <- crossBandsProducts(r1=tif1, r2=tif2))
#> stars object with 3 dimensions and 1 attribute
#> attribute(s), summary of first 1e+05 cells:
#> Min. 1st Qu. Median Mean 3rd Qu. Max.
#> X 2209 4225 5776 6176.508 7569 65025
#> dimension(s):
#> from to offset delta refsys point
#> x 1 349 288776 28.5 UTM Zone 25, Southern Hem... FALSE
#> y 1 352 9120761 -28.5 UTM Zone 25, Southern Hem... FALSE
#> bandsProducts 1 18 NA NA NA NA
#> values x/y
#> x NULL [x]
#> y NULL [y]
#> bandsProducts r2b1*r1b1,...,r2b3*r1b6
#>
#> NB: The dimension 'bandsProducts' has 18 values, which is consistent since the
#> rasters tif1 and tif2 have 6 and 3 bands respectively.
# 4. Example of extraction : two possibilities
# 4.1. via the number(s) of 'bandsProducts'
products[,,,4]
#> stars object with 3 dimensions and 1 attribute
#> attribute(s):
#> Min. 1st Qu. Median Mean 3rd Qu. Max.
#> X 649 3904 4788 4528.267 5525 65025
#> dimension(s):
#> from to offset delta refsys point
#> x 1 349 288776 28.5 UTM Zone 25, Southern Hem... FALSE
#> y 1 352 9120761 -28.5 UTM Zone 25, Southern Hem... FALSE
#> bandsProducts 4 4 NA NA NA NA
#> values x/y
#> x NULL [x]
#> y NULL [y]
#> bandsProducts r2b1*r1b4
# 4.2. via the name(s) (i.e. value(s)) of 'bandsProducts'
products[,,, values = c("r2b1*r1b4", "r2b3*r1b6")]
#> stars object with 3 dimensions and 1 attribute
#> attribute(s), summary of first 1e+05 cells:
#> Min. 1st Qu. Median Mean 3rd Qu. Max.
#> X 2209 4225 5776 6176.508 7569 65025
#> dimension(s):
#> from to offset delta refsys point
#> x 1 349 288776 28.5 UTM Zone 25, Southern Hem... FALSE
#> y 1 352 9120761 -28.5 UTM Zone 25, Southern Hem... FALSE
#> bandsProducts 1 18 NA NA NA NA
#> values x/y
#> x NULL [x]
#> y NULL [y]
#> bandsProducts r2b1*r1b1,...,r2b3*r1b6
# 5. Example of visualization
# 5.1. All pairwise combinations of bands products
plot(products, axes = TRUE, key.pos = NULL)
#> downsample set to c(2,2,1)
# 5.2. Selected pairwise combinations of bands products (selection by names/values)
plot(products[,,, values = c("r2b1*r1b4", "r2b3*r1b6")], axes = TRUE, key.pos = NULL)
#> downsample set to c(2,2,1)
#>
#> NB: Don't know why this second figure doesn't appear in the reprex, but in any
#> case it displays without any problem on my computer, so you shouldn't have any
#> problem to display it when running this reprex locally.
Created on 2021-09-24 by the reprex package (v2.0.1)

How to identify the polygons in which raster values were extracted with the stars R package?

Following-up a previous question (on stackoverflow), I am trying to understand how subsetting using polygons works with the stars R package. The following code opens a raster file and crops it to a smaller dimension.
library(stars)
#> Loading required package: abind
#> Loading required package: sf
#> Linking to GEOS 3.9.0, GDAL 3.2.1, PROJ 7.2.1
library(sf)
library(ggplot2)
tif <- system.file("tif/L7_ETMs.tif", package = "stars")
r <- read_stars(tif)[, , , 1]
r <- r %>%
st_crop(st_bbox(c(
xmin = 294000,
xmax = 294500,
ymin = 9110800,
ymax = 9111200
), crs = st_crs(r)))
Now I randomly pick 4 points on this grid.
set.seed(123)
pts <- st_sample(st_as_sfc(st_bbox(r)), 4)
plot(r, key.pos = NULL, reset = FALSE)
plot(pts, add = TRUE, pch = 21, cex = 2, bg = "red", col = "red")
I will use these four points to create 30 meters buffers around each of them.
poly <- st_buffer(pts, dist = 30)
I can then extract the values under the buffers as follows (which create a stars object).
r[poly]
#> stars object with 3 dimensions and 1 attribute
#> attribute(s):
#> L7_ETMs.tif
#> Min. :71.00
#> 1st Qu.:72.00
#> Median :74.50
#> Mean :75.36
#> 3rd Qu.:77.75
#> Max. :85.00
#> NA's :241
#> dimension(s):
#> from to offset delta refsys point values x/y
#> x 184 200 288776 28.5 UTM Zone 25, Southern Hem... FALSE NULL [x]
#> y 336 350 9120761 -28.5 UTM Zone 25, Southern Hem... FALSE NULL [y]
#> band 1 1 NA NA NA NA NULL
Using st_as_sf(), I can convert the results into polygons.
sf_poly <- st_as_sf(r[poly])
sf_poly
#> Simple feature collection with 14 features and 1 field
#> geometry type: POLYGON
#> dimension: XY
#> bbox: xmin: 293991.8 ymin: 9110786 xmax: 294476.3 ymax: 9111213
#> projected CRS: UTM Zone 25, Southern Hemisphere
#> First 10 features:
#> V1 geometry
#> 1 80 POLYGON ((294105.8 9111213,...
#> 2 85 POLYGON ((294134.3 9111213,...
#> 3 79 POLYGON ((294105.8 9111185,...
#> 4 71 POLYGON ((294134.3 9111185,...
#> 5 78 POLYGON ((294419.3 9111185,...
#> 6 73 POLYGON ((294447.8 9111185,...
#> 7 77 POLYGON ((294419.3 9111156,...
#> 8 72 POLYGON ((294162.8 9111042,...
#> 9 72 POLYGON ((294191.3 9111042,...
#> 10 76 POLYGON ((294162.8 9111014,...
We can see that there are 14 pixels that have been extracted.
ggplot() +
geom_sf(data = sf_poly) +
geom_sf(data = st_sfc(poly), fill = NA, color = "red") +
theme_minimal()
The question I am asking is how can I find out to which buffer is associated each of these pixels. For example, an id between 1 and 4.
Created on 2021-03-06 by the reprex package (v1.0.0)
Maybe a bit late... but I propose you the solution below and hope it will still be useful.
You just need to add the following lines of code at the end of your reprex and it should work.
library(dplyr)
# convert 'poly' from sfc to sf class object
poly <- st_as_sf(poly)
# create id's for the buffers (id's are equal to rows number)
poly <- mutate(poly, id = row_number())
# intersects 'poly' with 'sf_poly' (i.e. identification of the pixels
# intersected by each buffer)
(st_intersects(poly, sf_poly))
#> Sparse geometry binary predicate list of length 4, where the predicate
#> was `intersects'
#> 1: 1, 2, 3, 4
#> 2: 12, 13, 14
#> 3: 8, 9, 10, 11
#> 4: 5, 6, 7
# visualization
ggplot() +
geom_sf(data = sf_poly) +
geom_sf(data = st_geometry(poly), fill = NA, color = "red") +
geom_sf_label(aes(label = poly$id, geometry = poly$x)) +
theme_minimal()
Created on 2021-09-21 by the reprex package (v2.0.1)

stars package: how to define additional dimensions based on an attribute (filename)?

I have a set of raster files (in this case downloaded from http://www.paleoclim.org/) that I am reading into R using the stars package.
library("tidyverse")
library("fs")
library("stars")
data_path <- "./paleoclim"
(data_files <- list.files(data_path, pattern = "*.tif"))
#> [1] "BA_v1_2_5m_bio_1_badia.tif"
#> [2] "BA_v1_2_5m_bio_10_badia.tif"
#> [3] "BA_v1_2_5m_bio_11_badia.tif"
#> [...]
#> [39] "EH_v1_2_5m_bio_1_badia.tif"
#> [40] "EH_v1_2_5m_bio_10_badia.tif"
#> [41] "EH_v1_2_5m_bio_11_badia.tif"
#> [...]
#> [58] "HS1_v1_2_5m_bio_1_badia.tif"
#> [59] "HS1_v1_2_5m_bio_10_badia.tif"
#> [60] "HS1_v1_2_5m_bio_11_badia.tif"
#> [...]
(paleoclim <- read_stars(path(data_path, data_files)))
#> stars object with 2 dimensions and 133 attributes
#> attribute(s):
#> BA_v1_2_5m_bio_1_badia.tif BA_v1_2_5m_bio_10_badia.tif
#> Min. :101.0 Min. :213.0
#> 1st Qu.:166.0 1st Qu.:278.0
#> Median :173.0 Median :298.0
#> Mean :171.8 Mean :290.3
#> 3rd Qu.:180.0 3rd Qu.:304.0
#> Max. :200.0 Max. :325.0
#> [...]
#> dimension(s):
#> from to offset delta refsys point values
#> x 1 72 36 0.0416667 WGS 84 FALSE NULL [x]
#> y 1 48 33 -0.0416667 WGS 84 FALSE NULL [y]
Created on 2020-12-07 by the reprex package (v0.3.0)
The filenames contain two pieces of information that I would like to represent as dimensions of the stars object, e.g. HS1_v1_2_5m_bio_1_badia.tif refers to period "HS1" and bioclimatic variable "bio_1".
I've got as far as using st_redimension() to create the new dimensions and levels:
periods <- str_extract(names(paleoclim), "[^_]+")
biovars <- str_extract(names(paleoclim), "bio_[0-9]+")
paleoclim %>%
merge() %>%
st_redimension(
new_dims = st_dimensions(x = 1:72, y = 1:48,
period = unique(periods),
biovar = unique(biovars))
)
#> stars object with 4 dimensions and 1 attribute
#> attribute(s):
#> X
#> Min. : -91.0
#> 1st Qu.: 26.0
#> Median : 78.0
#> Mean : 588.2
#> 3rd Qu.: 256.0
#> Max. :11275.0
#> dimension(s):
#> from to offset delta refsys point values
#> x 1 72 1 1 NA FALSE NULL [x]
#> y 1 48 1 1 NA FALSE NULL [y]
#> period 1 7 NA NA NA FALSE BA,...,YDS
#> biovar 1 19 NA NA NA FALSE bio_1,...,bio_9
But this doesn't actually map the values of the attributes (filenames) to the levels of the new dimensions. Also, most of the information (e.g. CRS) about the original x and y dimensions are lost because I have to recreate them manually.
How do you properly define new dimensions of a stars object based on another dimension or attribute?
Don't see a straightforward way to split one dimension into two after all files have been read into a three-dimensional stars object. An alternative approach you could use is:
read one folder at a time, where all files of that folder go into the variable third dimension, stored as separate stars objects in a list,
then combine the resulting stars objects, where the stars objects go into the period fourth dimension.
For this example, I downloaded the following two products and unzipped into two separate folders:
http://sdmtoolbox.org/paleoclim.org/data/BA/BA_v1_10m.zip
http://sdmtoolbox.org/paleoclim.org/data/HS1/HS1_v1_10m.zip
Here is the code:
library(stars)
# Directories with GeoTIFF files
paths = c(
"/home/michael/Downloads/BA_v1_10m",
"/home/michael/Downloads/HS1_v1_10m"
)
# Read the files and set 3rd dimension
r = list()
for(i in paths) {
files = list.files(path = i, pattern = "\\.tif$", full.names = TRUE)
r[[i]] = read_stars(files)
names(r[[i]]) = basename(files)
r[[i]] = st_redimension(r[[i]])
}
# Combine the list
r = do.call(c, r)
# Attributes to 4th dimension
names(r) = basename(paths)
r = st_redimension(r)
# Clean dimension names
r = st_set_dimensions(r, names = c("x", "y", "variable", "period"))
r
and the printout of the result:
## stars object with 4 dimensions and 1 attribute
## attribute(s), summary of first 1e+05 cells:
## BA_v1_10m.HS1_v1_10m
## Min. :-344.0
## 1st Qu.:-290.0
## Median :-274.0
## Mean :-264.8
## 3rd Qu.:-252.0
## Max. :-128.0
## NA's :94073
## dimension(s):
## from to offset delta refsys point values x/y
## x 1 2160 -180 0.166667 WGS 84 FALSE NULL [x]
## y 1 1072 88.6667 -0.166667 WGS 84 FALSE NULL [y]
## variable 1 19 NA NA NA NA bio_1.tif,...,bio_9.tif
## period 1 2 NA NA NA NA BA_v1_10m , HS1_v1_10m
The result is a stars object with four dimensions, including x, y, variable, and period.
Here are plots, separately for each of the two levels in the period dimension:
plot(r[,,,,1,drop=TRUE])
plot(r[,,,,2,drop=TRUE])

Resources