I have a SpatRaster with 100 layers, each corresponding to a result of a bootstrapping analysis (all slightly different variations but pretty much the same). I want to reorder each pixel so that the first layer is the smallest of each respective pixel, second layer is second smallest, etc.
It can be converted to a data.frame with 102 columns (x, y, result1, ...), but I don't know how to order each row of a data.frame by size and exclude columns at the same time.
You can use sort to order the values of each grid cell. Illustrated below
Example data
library(terra)
r <- rast(ncol=5, nrow=5)
values(r) <- 30
x <- rast(c(a=r, b=r/10, c=r/100))
x
#class : SpatRaster
#dimensions : 5, 5, 3 (nrow, ncol, nlyr)
#resolution : 72, 36 (x, y)
#extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
#coord. ref. : lon/lat WGS 84
#sources : memory
# memory
# memory
#names : a, b, c
#min values : 30, 3, 0.3
#max values : 30, 3, 0.3
Solution
y <- sort(x)
y
#class : SpatRaster
#dimensions : 5, 5, 3 (nrow, ncol, nlyr)
#resolution : 72, 36 (x, y)
#extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
#coord. ref. : lon/lat WGS 84
#source : memory
#names : a, b, c
#min values : 0.3, 3, 30
#max values : 0.3, 3, 30
Related
I have a raster raster_coarse at 0.25 resolution
class : SpatRaster
dimensions : 26, 31, 1 (nrow, ncol, nlyr)
resolution : 0.25, 0.25 (x, y)
extent : -87.75, -80, 24.5, 31 (xmin, xmax, ymin, ymax)
coord. ref. : lon/lat WGS 84 (EPSG:4326)
source : memory
name : layer1
min value : 0.08839285
max value : 0.11517857
I have another raster raster_fine at finer resolution
class : SpatRaster
dimensions : 2377, 2758, 1 (nrow, ncol, nlyr)
resolution : 0.002777778, 0.002777778 (x, y)
extent : -87.6361, -79.97499, 24.39723, 31.00001 (xmin, xmax, ymin, ymax)
coord. ref. : lon/lat WGS 84 (EPSG:4326)
source : memory
name : finer_res
min value : 0
max value : 1
Here's what I am trying to do. I want to populate every pixel in raster_fine with the values from raster_coarse. The way I approached this is:
# check the resolution difference
res_drop <- res(raster_coarse)[1]/res(raster_fine)[1] # 89.99999.
# disaggregate the raster_coarse
raster_coarse <- terra::disagg(raster_coarse, fact = res_drop)
# convert to points
raster_coarse_df <- as.data.frame(raster_coarse, xy = T, na.rm = TRUE)
raster_coarse_pts <- terra::vect(raster_coarse_df, geom = c("x", "y"), crs(raster_fine))
# create a blank canvas
canvas <- terra::rast(xmin = ext(raster_fine)[1],
xmax = ext(raster_fine)[2],
ymin = ext(raster_fine)[3],
ymax = ext(raster_fine)[4],
resolution = res(raster_fine),
crs = crs(raster_fine))
# populate the blank canvas with raster_coarse_pts
raster_coarse <- terra::rasterize(x = raster_coarse_pts , y = canvas, field = "layer1", fun = max, touches = T, background = NA)
raster_coarse
class : SpatRaster
dimensions : 2377, 2758, 1 (nrow, ncol, nlyr)
resolution : 0.002777778, 0.002777778 (x, y)
extent : -87.6361, -79.97499, 24.39723, 31.00001 (xmin, xmax, ymin, ymax)
coord. ref. : lon/lat WGS 84 (EPSG:4326)
source : memory
name : lyr.1
min value : 0.08839285
max value : 0.11517857
plot(raster_coarse)
I am not able to understand why the vertical white lines are coming from?
Example data
library(terra)
r <- rast(nrow=26, ncol=31, ext=c(-87.75, -80, 24.5, 31))
f <- geodata::gadm("USA", level=1, path=".")
f <- f[f$NAME_1 == "Florida", ]
values(r) <- runif(ncell(r))
r <- mask(r, f)
fine <- rast(nrow=2377, ncol=2758, ext=c(-87.6361, -79.97499, 24.39723, 31.00001))
The solution is to use resample
rr <- resample(r, x, "near")
Instead of the nearest neighbor you could use, for example, bilinear interpolation:
rr <- resample(r, x)
The white lines occur because with your method there will be cells that are not covered. To better understand that you could crop out a small area and plot the points on top of the raster.
I found out the other day, more or less by chance, that it is possible to query layers from SpatRaster objects based on the time attribute in general (c.f. here), e.g based on years (r["2017"]) and yearmonths (r["2017-10"]).
Now I wanted to deep-dive a little bit into this because of the great flexibility you receive when working with spatio-temporal data. Unfortunately, I seem to be failing from the beginning and can't reproduce the behaviour from before because of the following error: [subset] no (valid) layer selected
library(terra)
#> terra 1.6.3
r <- rast(ncols = 10, nrows = 10, nlyr = 365)
time(r) <- seq(from = as.POSIXlt("2001-01-01", tz = "UTC"),
to = as.POSIXlt("2001-12-31", tz = "UTC"),
by = "day")
r
#> class : SpatRaster
#> dimensions : 10, 10, 365 (nrow, ncol, nlyr)
#> resolution : 36, 18 (x, y)
#> extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
#> coord. ref. : lon/lat WGS 84
#> time : 2001-01-01 to 2001-12-31 UTC
time(r) |> class()
#> [1] "POSIXct" "POSIXt"
r["2001"]
#> Error: [subset] no (valid) layer selected
time(r) <- as.Date("2002-01-01") + 0:364
r
#> class : SpatRaster
#> dimensions : 10, 10, 365 (nrow, ncol, nlyr)
#> resolution : 36, 18 (x, y)
#> extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
#> coord. ref. : lon/lat WGS 84
#> time (days) : 2002-01-01 to 2002-12-31
time(r) |> class()
#> [1] "Date"
r["2002"]
#> Error: [subset] no (valid) layer selected
I had a look at ?time as well as at the docs at rspatial.org but was not able to find relevant documentation related to indexing.
What am I missing here?
You are mixing up layer names (that may look like a time-stamp) with an actual time-stamp.
Here is how you can use time-stamps (using Date here, as it is a bit less verbose)
library(terra)
r <- rast(ncols = 10, nrows = 10, nlyr = 365)
time(r) <- as.Date("2001-01-01") + 0:364
head(names(r))
# "lyr.1" "lyr.2" "lyr.3" "lyr.4" "lyr.5" "lyr.6"
You can subset layers by name like this
r[["lyr.1"]]
Note the double brackets for sub-setting layers, although you can use single brackets when using a name as opposed to a numerical index.
To subset by time, you can do
r[[time(r) == as.Date("2001-06-01")]]
#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
#time (days) : 2001-06-01
With dates, you do not even need to use "as.Date"
r[[time(r) >= "2001-12-01"]]
#class : SpatRaster
#dimensions : 10, 10, 31 (nrow, ncol, nlyr)
#resolution : 36, 18 (x, y)
#extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
#coord. ref. : lon/lat WGS 84
#time (days) : 2001-12-01 to 2001-12-31
I have two raster:
raster1
class : SpatRaster
dimensions : 21600, 43200, 1 (nrow, ncol, nlyr)
resolution : 0.008333333, 0.008333333 (x, y)
extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
raster2
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 WGS 84
I want to run zonal stastics to calculate sum of smaller raster raster1 on bigger raster raster2:
terra::zonal(raster1, raster2, fun = sum, as.raster=T, filename = 'zonal.tif')
Error: [zonal] dimensions and/or extent do not match
I wasn't sure why the extent are not matching until I did this
terra::ext(raster1)
SpatExtent : -180.000001017276, 180.000001017276, -90.0000010172997, 90.0000010172997 (xmin, xmax, ymin, ymax)
terra::ext(raster2)
SpatExtent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
which shows that raster1 extent have some imprecision. What are different ways I can fix this?
EDIT: I tried the suggestion in the comment
terra::crs(raster2) <- sf::st_crs(4326)$wkt
terra::crs(raster1) <- sf::st_crs(4326)$wkt
terra::ext(raster2)
SpatExtent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
terra::ext(raster1)
SpatExtent : -180.000001017276, 180.000001017276, -90.0000010172997, 90.0000010172997 (xmin, xmax, ymin, ymax)
But my extent are still not matching
The error message is
Error: [zonal] dimensions and/or extent do not match
In this case, that clearly refers to the difference is dimensions, which are
#dimensions : 21600, 43200, 1 (nrow, ncol, nlyr)
#dimensions : 720, 1440, 1 (nrow, ncol, nlyr)
I do not think the small difference in the extent is relevant at all.
To make the dimensions match you can use disagg or aggregate with a factor of 30.
If the crs of raster2 is different from that of raster1 you can (in this case, where you clearly have two global lon/lat rasters) fix that with
crs(raster2) <- crs(raster1)
And for good measure, you could in this case also do
ext(raster2) <- ext(raster1)
Mismatching extents don't stop zonal working, so I think that error message is wrong. Here's two rasters that only differ in their CRS:
> library(terra)
terra 1.5.21
> raster1 = rast()
> raster1[]=1:360
> raster2 = rast()
> raster2[]=1:360
> crs(raster1) = ""
> zonal(raster1, raster2)
Error: [zonal] dimensions and/or extent do not match
I guess it could be argued that a different CRS means a different extent in the same way that "23" is different to "23 km". But the extent and the dimensions are all the same according to these tests:
> ext(raster1) == ext(raster2)
[1] TRUE
> dim(raster1) == dim(raster2)
[1] TRUE TRUE TRUE
Rasters with a different extent work fine with zonal (once I've set the CRSs to match):
> ext(raster2) = c(-180.01, 180.01, -90.01, 90.01)
> crs(raster2) = ""
> z = zonal(raster1, raster2)
>
If you do want to change an extent, you can use ext(r) = ... as above, but you should try and figure out why extents don't match. Likely its because you have data on points and you may have cells extending out from points...
Suppose one runs the following R code
install.packages("raster")
library(raster)
r <- raster(ncol=18, nrow=18)
res(r)
The output of the res function is
[1] 20 10
How are these values defined? How does the raster function calculate them? In what units are they expressed?
As pointed out by Guillaume Devailly, the horizontal resolution is the horizontal extent divided by the number of columns. The vertical resolution is the vertical extent divided by the number of rows. The units are the units of your coordinate reference system. The default is degrees (for longitude/latitude). To add more to Guillaume's answer:
Create a raster with 10 rows and columns that goes from 0 to 10. The resolution is 1.
library(raster)
r <- raster(ncol=10, nrow=10, xmn=0, xmx=10, ymn=0, ymx=10)
r
#class : RasterLayer
#dimensions : 10, 10, 100 (nrow, ncol, ncell)
#resolution : 1, 1 (x, y)
#extent : 0, 10, 0, 10 (xmin, xmax, ymin, ymax)
#crs : +proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0
Change the resolution to 0.5; the number of rows and columns double
res(r) <- 0.5
r
#class : RasterLayer
#dimensions : 20, 20, 400 (nrow, ncol, ncell)
#resolution : 0.5, 0.5 (x, y)
#extent : 0, 10, 0, 10 (xmin, xmax, ymin, ymax)
#crs : +proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0
You can change the resolution indirectly by adjusting the extent
extent(r) <- c(0,5,0,5)
r
#class : RasterLayer
#dimensions : 20, 20, 400 (nrow, ncol, ncell)
#resolution : 0.25, 0.25 (x, y)
#extent : 0, 5, 0, 5 (xmin, xmax, ymin, ymax)
#crs : +proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0
The x and y resolution can be set to a different value
res(r) <- c(1, 0.5)
When you change the resolution directly, via res any cell values associated with the Raster* object are lost; because the number of rows or columns has to change. If you change it indirectly, by changing the extent, the values stay.
From what I understand from the vignette
The default settings will create a global raster data structure with a longitude/latitude coordinate reference system and 1 by 1 degree cells.
r
# class : RasterLayer
# dimensions : 18, 18, 324 (nrow, ncol, ncell)
# resolution : 20, 10 (x, y)
# extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
# coord. ref. : +proj=longlat +datum=WGS84
r x extent goes to from -180 to +180 degrees by default (a total of 360 degrees), and 360 degrees / 18 points = a x resolution of 20 degrees.
r y extent goes form -90 to +90 degrees by default, and 180 degrees / 18 points results in a y resolution of 10 degrees.
I have a comma delimited text files with the header names
lat,long,z1,z2,z3,z4,z5
These columns contain the lat, long and multiple height values(z1, z2,z3, z4). The lat and long data is spaced at an equal interval of 5 meters.
What is the most efficient way to convert the data into individual rasters or an R raster stack each having the z values, given the projection information is UTM, zone 18.
The sample data can be accessed here.
You can do this:
x <- data.frame(lon=1:11, lat=5:15, z1=runif(11), z2=11:1)
library(raster)
b <- rasterFromXYZ(x)
#> b
#class : RasterBrick
#dimensions : 11, 11, 121, 2 (nrow, ncol, ncell, nlayers)
#resolution : 1, 1 (x, y)
#extent : 0.5, 11.5, 4.5, 15.5 (xmin, xmax, ymin, ymax)
#coord. ref. : NA
#data source : in memory
#names : z1, z2
#min values : 0.08495835, 1.00000000