R - create boxplot with rasters - r

this might be rather simple, but I am a novice in R. I have tried for awhile now to plot two rasters against each other using boxplot from the package raster.
I have a DEM raster and a categorical raster that contains 4 cluster groups, which I would like to use as 'zones' as described in the manual:
boxplot(x, y=NULL, maxpixels=100000, ...)
x Raster* object
y If x is a RasterLayer object, y can be an additional RasterLayer to group the
values of x by ’zone’
> DEM
class : RasterLayer
dimensions : 12381, 61922, 766656282 (nrow, ncol, ncell)
resolution : 0.1, 0.1 (x, y)
extent : 478307.4, 484499.6, 6131862, 6133100 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=utm +zone=32 +ellps=GRS80 +units=m +no_defs
data source : /Users/Yvonne/Desktop/Boxplot/Ribe_DEM_0.1m.tif
names : Ribe_DEM_0.1m
values : -7.523334, -0.36 (min, max)
> Cluster
class : RasterLayer
dimensions : 12381, 61922, 766656282 (nrow, ncol, ncell)
resolution : 0.1, 0.1 (x, y)
extent : 478307.4, 484499.6, 6131862, 6133100 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=utm +zone=32 +ellps=GRS80 +units=m +no_defs
data source : /Users/Yvonne/Desktop/Boxplot/final_cluster.tif
names : final_cluster
values : 1, 4 (min, max)
attributes :
ID Rowid COUNT
1 0 463524
2 1 4118997
3 2 3390160
4 3 3218998
> boxplot(DEM, Cluster, xlab="Cluster", ylab="Elevation")
Error in parse(text = x, keep.source = FALSE) :
<text>:2:0: unexpected end of input
1: ~
^
In addition: Warning message:
In .local(x, ...) : taking a sample of 1e+05 cells
Update:
I just found a working example, which does exactly what I want. However if I run it with my own data I always get above error. Maybe someone could explain the error message. Would be really appreciated.
r1 <- r2 <- r3 <- raster(ncol=10, nrow=10)
r1[] <- rnorm(ncell(r1), 100, 40)
r2[] <- rnorm(ncell(r1), 80, 10)
r3[] <- rnorm(ncell(r1), 120, 30)
s <- stack(r1, r2, r3)
names(s) <- c('A', 'B', 'C')
rc <- round(r1[[1]]/100)
hist(rc)
summary(rc)
boxplot(s[[1]],rc)

Okey I found an answer, I don't know exactly why but it works for me:
I had to create a brick and then I could use the boxplot as mentioned above.
s <- stack(DEM, Cluster)
sbrick <- brick(s)
boxplot(sbrick[[1]], sbrick[[2]], xlab="Cluster", ylab="Elevation")
Resulting in this plot boxplot DEM against cluster groups
Thanks everyone for their help!

You can use bwplot function in rasterVis library.
Here is an example from rasterVis:
library(raster)
library(rasterVis)
r <- raster(system.file("external/test.grd", package="raster"))
s <- stack(r, r*2)
bwplot(s,violin=FALSE,strip=strip.custom(strip.levels=TRUE))

It is not clear to me why you get that error. Perhaps you can run the code below and see for yourself:
x <- stack(DEM, Cluster)
s <- sampleRegular(s, 100000, useGDAL=TRUE)
cn <- colnames(s)
f <- as.formula(paste(cn[1], '~', cn[2]))
boxplot(f, data=s)

Perhaps you should only provide your raster values as a vector and let the boxplot() function do the rest by:
boxplot(values(DEM) ~ values(Cluster), xlab="Cluster", ylab="Elevation")
Note that this will only work if both DEM and Cluster are exactly the same extent and resolution.

Related

Convert multidimensional NetCDF to Tif in R

I have .nc file sizing around 651 MB with a couple of datasets (daily) (rr_mrg_19810101_20181231_ENACT.nc) data. I need to convert (rr_mrg_19810101_20181231_ENACT.nc) dataset to multiple GeoTIFF (one .tif for each time slice, monthly). Similarly, i want to read the time series. But I found
Error in .local(x, time, ...) :
time must has the same length as the number of layers in RasterBrick][1]
Here is what i did
library(raster)
library(zoo)
library(rts)
TRF = brick("rr_mrg_19810101_20181231_ENACT.nc")
crs(TRF) <- "+proj=longlat +datum=WGS84 +no_defs +ellps=WGS84
+towgs84=0,0,0"
Awash_Extent<-c(37,44, 7,12)
Awash_E_resize<- crop(TRF,Awash_Extent)
Awash_Month<-seq(as.Date('1981-01-01'),as.Date('2018-12-31'),by =
"month")
rt <- rts(Awash_E_resize, Awash_Month)
write.rts(Awash_E_resize, filename='Awash_TRF_1981_2018_mon.tif',
overwrite=TRUE)
Can you help me on the issue?
Something as simple as this can do that
library(raster)
b <- brick("rr_mrg_19810101_20181231_ENACT.nc")
writeRaster(b, "timeslice.tif", bylayer=TRUE)
Based on your expanded question:
Read the values with terra (no need for other packages)
library(terra)
TRF = rast("rr_mrg_19810101_20181231_ENACT.nc")
Awash_Extent<-c(37,44, 7,12)
Awash_E_resize<- crop(TRF,Awash_Extent)
I create something similar here:
A <- rast(ext(37,44, 7,12), nlyr=365)
values(A) <- runif(size(A))
terra::time(A) <- seq(as.Date('1981-01-01'), as.Date('1981-12-31'), 1)
Now aggregate by month:
m <- months(time(A))
f <- factor(m, levels=unique(m))
B <- tapp(A, m, fun=sum)
B
#class : SpatRaster
#dimensions : 10, 10, 12 (nrow, ncol, nlyr)
#resolution : 0.7, 0.5 (x, y)
#extent : 37, 44, 7, 12 (xmin, xmax, ymin, ymax)
#coord. ref. : lon/lat WGS 84
#source : memory
#names : January, February, March, April, May, June, ...
#min values : 12.49764, 10.47718, 11.80974, 11.29624, 11.01105, 10.83298, ...
#max values : 18.90536, 16.95743, 20.57114, 18.12099, 18.46543, 18.98500, ...
You could add a filename= argument to tapp, but if you want to save the layers as separate files you can use writeRaster instead. But with terra you need to provide the filenames yourself.
fnames <- paste0("rain_", 1:nlyr(B), ".tif")
writeRaster(B, fnames, overwrite=T)
(there is a warning about file_ext that you can ignore)

Extract raster value based on list of coordinates - spTransform?

I wish to extract raster values based on a list of coordinates. I’ve found online some scripts that include coordinates(), SpatialPoints(), crs() and spTransform() and other that don’t. Could someone kindly explain if script 1 or script 2 is correct and why? Thank you very much!
SCRIPT 1
sites <- read.csv("df.csv")
coordinates(sites)= ~ Longitude+ Latitude
mypoints = SpatialPoints(sites,proj4string = CRS("+init=epsg:4326"))
myproj = CRS(myraster)
points.proj = spTransform(mypoints, myproj)
myvalues = extract(myraster, points.proj)
SCRIPT 2
sites <- read.csv("df.csv")
myvalues = extract(myraster, cbind(sites$Longitude, y=sites$Latitude), df=TRUE, method='simple', cellnumbers=T)
Either could be correct. With RasterLayer r and data.frame sites you can do
v <- extract(r, sites[, c("Longitude", "Latitude")])
Under the assumption that "Longitude" and "Latitude" are variables in sites.
However that only works when r also has a ("Longitude", "Latitude") coordinate reference system. That may not be the case. Consider this RasterLayer
f <- system.file("external/test.grd", package="raster")
r <- raster(f)
r
#class : RasterLayer
#dimensions : 115, 80, 9200 (nrow, ncol, ncell)
#resolution : 40, 40 (x, y)
#extent : 178400, 181600, 329400, 334000 (xmin, xmax, ymin, ymax)
#crs : +proj=sterea +lat_0=52.15616055555555 +lon_0=5.38763888888889 +k=0.9999079 +x_0=155000 +y_0=463000 +ellps=bessel +units=m +towgs84=565.237,50.0087,465.658,-0.406857,0.350733,-1.87035,4.0812 +no_defs
#source : C:/soft/R/R-3.6.1/library/raster/external/test.grd
#names : test
#values : 128.434, 1805.78 (min, max)
The crs is "sterea ..." and the extent "178400, 181600, ...) shows that the coordinates are clearly not longitude and latitude (they are expressed in meters away from the origin of the crs.)
In this case, you might have a point in the area covered by r
site <- data.frame(Longitude=5.745039, Latitude=50.96254)
But extract returns NA because the crs do not match
extract(r, site)
# [,1]
#[1,] NA
So we do
pts <- SpatialPoints(site)
crs(pts) <- "+proj=longlat +datum=WGS84"
rcrs <- crs(r)
ptrans <- spTransform(pts, rcrs)
And now it works
extract(r, ptrans)
#1529.66

Band math with calc and / or overlay returning single-valued images

When I try to run band math the result is always an image of a color and the values min and max very different from the one predicted.
I did not find any question here that showed this problem.
I worked out this way
r.stack <- stack("path to raster file"))
I use resampling instead of crop to cut out the white edges that were in the original images
prj <- "+proj=utm +zone=23 +south +datum=WGS84 +units=m"
r <- raster(res=11.47, ext=extent(c(301496, 323919, 9888968, 9913982)), crs=prj, vals=NA
r.stack <- resample(r.stack, r)
After that the images have this configuration:
> class : RasterBrick
> dimensions : 2181, 1955, 4263855, 4 (nrow, ncol, ncell, nlayers)
> resolution : 11.47, 11.47 (x, y)
> extent : 301496, 323919.8, 9888966, 9913982 (xmin, xmax, ymin, ymax)
>coord. ref. : +proj=utm +zone=23 +south +datum=WGS84 +units=m +ellps=WGS84 +towgs84=0,0,0
>data source : in memory
>names : l.1, l.2, l.3, l.4
>min values : -36.12217, -45.12768, -46.30455, -35.26328
>max values : 10.567671, 4.050200, 3.878345, 11.613799
and than use the function below for calc
f <- function(x){
(x[[2]])/(x[[1]])
}
s <- r.stack[[c(1,2)]]
r2 <- calc(s, f)
and I also run overlay whit the fun
f <- function(x,y){
y/x
}
r2 <- overlay(r.stack[[1]], r.stack[[2]], fun= f)
Any of the methods result in a image of one value
Am I missing some steps?
Here is your code with some example data (without that it is hard to answer questions). I have simplified one function, a bit, but the results are the same.
library(raster)
b <- brick(system.file("external/rlogo.grd", package="raster"))
b <- b/10 + 1
f <- function(x){ x[2]/ x[1] }
s <- b[[c(1,2)]]
r1 <- calc(s, f)
f <- function(x,y){ y / x }
r2 <- overlay(b[[1]], b[[2]], fun= f)
Or simply
r3 <- b[[2]] / b[[1]]
r3
#class : RasterLayer
#dimensions : 77, 101, 7777 (nrow, ncol, ncell)
#resolution : 1, 1 (x, y)
#extent : 0, 101, 0, 77 (xmin, xmax, ymin, ymax)
#coord. ref. : +proj=merc +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0
#data source : in memory
#names : layer
#values : 0.7692308, 1.7 (min, max)
r1 and r2 are the same.
The reason that you get a "single color" is because most values are near 1, but there are a few big outliers; probably because of a division by a number between -1 and 1? This might illustrate it:
q <- quantile(r3, c(0.1, 0.9))
d <- clamp(r3, q[1], q[2])
plot(d)
And look at the extremes
i <- which.max(r3)
b[i][,2:1]

Apply boot::inv.logit() to a raster in R

I have a Formal Class Raster and I am trying to apply the boot::inv.logit() function to its raster cells, for example:
r1 <- raster(nrows=25, ncols=25, vals=rtnorm(n = 625, .1, .9))
r2 <- boot::inv.logit(r1)
However, when I try that, it retruns an error:
> Error in plogis(x) : Non-numeric argument to mathematical function
If I turn the raster into a matrix, and then back to raster, it gets the job done, but I loose all the other info associated with the "Formal Class Raster" I had at the beginning, which is not ideal:
r2 <- boot::inv.logit(as.matrix(r1))
r2 <- as.raster(r2)
Is there an easy way to either recover the Formal Class Raster info I had before or apply the inv.logit() to the raster without the as.matrix() transformation? Thank you in advance.
If you want to apply the function to the raster, use the calc method from raster:
r2 <- calc(r1,boot::inv.logit)
> r2
# class : RasterLayer
# dimensions : 25, 25, 625 (nrow, ncol, ncell)
# resolution : 14.4, 7.2 (x, y)
# extent : -180, 180, -90, 90 (xmin, xmax, ymin, ymax)
# coord. ref. : +proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0
# data source : in memory
# names : layer
# values : 0.07434905, 0.9498965 (min, max)
Alternatively, you can make an empty copy of r1, and just fill in the values coming out of inv.logit:
r2 <- raster(r1)
r2[] <- boot::inv.logit(as.matrix(r1))

Error when extracting values from a rasterBrick or rasterStack

I am having trouble extracting values or a point from a multi band raster of class rasterStack or rasterBrick. 'extract' works well with the individual rasters but posts an error when applied to the rasterStack or brick.
> all.var
class : RasterBrick
dimensions : 89, 180, 16020, 34 (nrow, ncol, ncell, nlayers)
resolution : 2, 2 (x, y)
extent : -179, 181, -89, 89 (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0
data source : in memory
names : period_max, pct_signif_periodmax, pct_coi_periodmax, pct_ispos_signif, events_pos_periodmax, events_neg_periodmax, events_pos_all, events_neg_all, maxpower_pos, maxpower_neg, maxpower_events_pos, maxpower_events_neg, maxpower_pos_norm, maxpower_neg_norm, maxpower_events_pos_norm, ...
> point
Lon Lat
1 166.2790 -10.2690
2 26.9000 -33.6000
3 153.6209 -28.7001
4 113.8333 -28.6833
5 153.6335 -28.6591
6 153.5836 -28.4643
7 32.6833 -27.5333
8 32.6880 -27.5260
9 32.6880 -27.5260
10 32.6880 -27.5260
> point.extract<-extract(all.var, point, buffer=50000,na.rm=TRUE,fun=mean)
Error in apply(x, 2, fun2) : dim(X) must have a positive length
This works with individual rasters but fails with stack/brick and elicits an error only when I use a buffer argument.
Here is a working R example that illustrates the error:
library(raster)
b <- brick(nrow=89, ncol=180, nl=34, xmn=-179, xmx=181, ymn=-89, ymx=89, crs="+proj=longlat +datum=WGS84")
b[] <- 1
p <- matrix(c(166.2790,-10.2690,26.9000,-33.6000,153.6209,-28.7001,113.8333,-28.6833,153.6335,-28.6591,153.5836,-28.4643,32.6833,-27.5333,32.6880,-27.5260,32.6880,-27.5260,32.6880,-27.5260), ncol=2, byrow=TRUE)
v <- extract(b, p, buffer=50000, na.rm=TRUE, fun=mean)
That indeed gives the error you reported, probably due a bug in the raster package. Here is a work-around:
v <- extract(b, p, buffer=15000000)
# get the mean for each point (buffer) by layer
vv <- lapply(v, function(x) ifelse(is.matrix(x), colMeans(x, na.rm=TRUE), x))
# combine
do.call(rbind, vv)

Resources