Search code examples
rggplot2dplyrrasterr-sp

Better way to plot across layers of a raster brick / stack


I'm trying to plot all values in a Raster Brick for specific points. This is to create spectral plots for remote sensing data for specific pixels.

I can do this in a variety of ways, but they are quite clunky and slow (see example below). This is slow primarily because converting large raster files to a matrix is memory intensive.

Is there a better way to do this with baseR or tidy verse & or a built-in way to do this in one of the Raster / remote sensing packages?

Here's a reproducible example:

library (raster)
library (rgdal)
library (sp)
library (tidyr)
library (ggplot2)
library (dplyr)


##############################

### dummy data

##############################


coord1 <- c(50, 47, 45)
coord2 <- c(50, 51, 49)
frame <- data.frame(coord1, coord2)
coords <- coordinates(frame)

x = list(1, 2, 3, 4, 5)
y = list(1, 2, 3, 4, 5)

for (i in 1:length(x)) { # create clusters based on coords

set.seed(i+100)
x[[i]] <- rnorm(5000, mean = coords[, 1], sd = 1)
y[[i]] <- rnorm(5000, mean = coords[, 2], sd = 1)
}

obs <- data.frame(x, y)
names(obs) <- c('x1', 'x2', 'x3', 'x4', 'x5', 'y1', 'y2', 'y3', 'y4', 'y5')
coordinates(obs) <- c('x1', 'y1') # this creates a spatial points data frame

# create blank raster of study area

ex <- extent(c(45, 50, 48, 52))
target <- raster(ex, resolution = 0.5)

# create raster brick

r_list <- list()

for (i in 1:ncol(obs)) {

   r_list[[i]] <- rasterize(obs, target, fun = 'count')
}

obs_frequency <- brick(r_list)

And here's one possible, but slow, solution

############################

### Example Solution

############################

vals_all <- obs_frequency[, ] ### this is very slow ###
vals_all <- data.frame(vals_all)

### sample values

points <- sample_n(vals_all, size = 5)
points <- t(points)
points <- data.frame(points)
points_tidy <- gather(points)
points_tidy$xval <- rep(1:8, times = 5)


### plot

ggplot(points_tidy, aes(x = xval, y = value)) + geom_line(aes(colour = key)) + theme_classic()

Solution

  • I have found a better solution to this using the raster::extract function. This samples values directly & avoids turning the whole raster brick into a memory-busting matrix.

    It was worth noting that here, using a Brick is MUCH faster than using a Raster stack.

    ############################
    
    ### Extract values and plot 
    
    ############################
    
    ### extract values
    
    points <- c(49, 50, 51) #arbitrary points
    pointvals <- raster::extract(obs_frequency, points) ##### USE THE RASTER::EXTRACT FUNCTION
    
    ### manipulate data structure
    
    pointvals <- data.frame(t(pointvals))
    points_tidy <- gather(pointvals)
    points_tidy$xval <- rep(1:8, times = 3)
    
    ### plot
    
    ggplot(points_tidy, aes(x = xval, y = value)) + geom_line(aes(colour = key)) + theme_classic()