11  Handling Rasters

When it comes to working with rasters in R, the terra package offers a powerful set of tools. Similar to the sf package, terra provides functions to read and manipulate spatial data. In this case, the focus is on raster data. In this chapter, we will explore the process of handling rasters using the terra package, with a particular emphasis on reading raster files.

11.1 Reading in data

To begin, let’s discuss the central function of the terra package for reading raster files - rast(). This function is designed to handle a wide range of raster file formats, making it a versatile tool for working with raster data. When a raster file is read using rast(), the resulting object is assigned its own class called SpatRaster.

Now, let’s dive into a practical example. Suppose we want to read in a digital elevation model (DEM) for the Western Indian Ocean Region. With the terra package, this process becomes straightforward. We can start by calling the rast() function and providing the path to our raster file as an argument.

First, make sure the terra package is installed and loaded in your R environment:

Code
require(terra)
require(tidyterra)
require(tidyverse)
require(gt)
Code
# Read in the digital elevation model (DEM) for the Western Indian Ocean Region
dem <- rast("data/bathy_ele.tif")

Once the raster file is read, it is stored in the dem object as a SpatRaster.

Code
dem
class       : SpatRaster 
dimensions  : 720, 570, 1  (nrow, ncol, nlyr)
resolution  : 0.01666667, 0.01666667  (x, y)
extent      : 38.49167, 47.99167, -12.00833, -0.008325335  (xmin, xmax, ymin, ymax)
coord. ref. : lon/lat WGS 84 (EPSG:4326) 
source      : bathy_ele.tif 
name        : wioregio-7753 
min value   :         -5040 
max value   :          2264 

This object contains both the spatial extent of the raster and its associated values. The coord. ref. field shows lon/lat WGS 84, which is Geographic Coordinates. The extent appears to be in degree, with the latitude being a mix of positive and negative numbers. If you just want to know the CRS from a SpatRaster, you just call crs() like so:

Code
dem |>
  terra::crs()
[1] "GEOGCRS[\"WGS 84\",\n    ENSEMBLE[\"World Geodetic System 1984 ensemble\",\n        MEMBER[\"World Geodetic System 1984 (Transit)\"],\n        MEMBER[\"World Geodetic System 1984 (G730)\"],\n        MEMBER[\"World Geodetic System 1984 (G873)\"],\n        MEMBER[\"World Geodetic System 1984 (G1150)\"],\n        MEMBER[\"World Geodetic System 1984 (G1674)\"],\n        MEMBER[\"World Geodetic System 1984 (G1762)\"],\n        MEMBER[\"World Geodetic System 1984 (G2139)\"],\n        ELLIPSOID[\"WGS 84\",6378137,298.257223563,\n            LENGTHUNIT[\"metre\",1]],\n        ENSEMBLEACCURACY[2.0]],\n    PRIMEM[\"Greenwich\",0,\n        ANGLEUNIT[\"degree\",0.0174532925199433]],\n    CS[ellipsoidal,2],\n        AXIS[\"geodetic latitude (Lat)\",north,\n            ORDER[1],\n            ANGLEUNIT[\"degree\",0.0174532925199433]],\n        AXIS[\"geodetic longitude (Lon)\",east,\n            ORDER[2],\n            ANGLEUNIT[\"degree\",0.0174532925199433]],\n    USAGE[\n        SCOPE[\"Horizontal component of 3D system.\"],\n        AREA[\"World.\"],\n        BBOX[-90,-180,90,180]],\n    ID[\"EPSG\",4326]]"

Although the information is a bit disorganized, it does mention the presence of key details such as the datum and and the used World Geodetic System 1984. For instance, we can visualize the DEM using the plot() function from the terra package:

Code
# Visualize the DEM
plot(dem)

11.2 Glimpse of a raster

Code
dem %>% terra::res()
[1] 0.01666667 0.01666667

With a cell size of 0.01666667 degrees, the equivalent grid size is approximately 1.83km. This information is crucial as it provides insight into the spatial resolution of the raster, which is estimated to be around 1.8km.

Code
dem %>% terra::ext()
SpatExtent : 38.491669165, 47.991671065, -12.008327735, -0.0083253350000021 (xmin, xmax, ymin, ymax)

Similarly, observing the geographical extent of the dem file, we can determine that it ranges from approximately 38.49 degrees East to 47.99 degrees East in longitude, and from 12 degrees South to around 0 degrees North in latitude.

Code
dem %>% terra::nrow();
[1] 720
Code
dem %>% terra::ncol();
[1] 570
Code
dem %>% terra::ncell()
[1] 410400

In summary, this raster file contains digital elevation and bathymetry data of the East Africa area. It has a spatial resolution of approximately 1.8km, covering a geographical extent from approximately 38.49 degrees East to 47.99 degrees East in longitude and from 12 degrees South to around 0 degrees North in latitude. The file consists of 720 rows and 570 columns, resulting in a total of 410,400 pixels.

11.3 Cropping

Cropping a raster file to the area of interest is essential for several reasons. Firstly, it helps to reduce the size of the dataset, making it more manageable and efficient to work with, particularly when dealing with large raster files. By focusing only on the area of interest, we can eliminate unnecessary data, thereby improving processing speed and reducing memory usage.

Additionally, cropping allows us to extract specific regions or features that are relevant to our analysis, enabling a more targeted and precise examination of the data. This can enhance the accuracy and reliability of subsequent analyses, as well as facilitate clearer visualization of the specific area under investigation. Ultimately, cropping a raster file to the area of interest streamlines the workflow, optimizes computational resources, and facilitates a more detailed analysis of the desired geographic region.

To crop a raster using the terra package in R, we need first to define the extent for cropping, which determine the extent of the area you want to crop. terra package has a ext function that define the cropping extent by specifying the minimum and maximum values for the x and y coordinates.

For example, we want to crop the data for the Pemba Channel and hence we can define the geographical cropping extent of the area as;

Code
pemba.channel = terra::ext(39.0, 40.0, -5.8, -4.2)
pemba.channel
SpatExtent : 39, 40, -5.8, -4.2 (xmin, xmax, ymin, ymax)
Important

Keep your eye on the the ext() function, as it need to follow the order xmin, xmax, ymin, ymax as opposed to xmin, ymin, xmax, ymax as you do for st_crop().

Then we can crop the file using crop() function.

Code
pemba.dem = dem %>% 
  terra::crop(pemba.channel) 

pemba.dem
class       : SpatRaster 
dimensions  : 96, 60, 1  (nrow, ncol, nlyr)
resolution  : 0.01666667, 0.01666667  (x, y)
extent      : 38.99167, 39.99167, -5.808326, -4.208326  (xmin, xmax, ymin, ymax)
coord. ref. : lon/lat WGS 84 (EPSG:4326) 
source(s)   : memory
name        : wioregio-7753 
min value   :         -1286 
max value   :           413 

Notice that the cropped raster for the Pemba Channel has a spatial resolution of approximately 1.8km, which is similar to the origin file but covering a geographical extent from approximately 38.99 degrees East to 39.99 degrees East in longitude and from 5.8 degrees South to around 4.2 degrees South in latitude. The file consists of 96 rows and 60 columns, resulting in a total of 5,760 pixels. The values of raster ranges from 413 to around -1286 meters.

Code
pemba.dem %>% 
  terra::plot()

11.4 Classifying rasters

In the terra package, the classify() function allows to assign divide continuous values into discrete or categories of different groups of raster cells based on specified criteria.

To perform raster classification using terra, you typically need a raster object and a classification scheme. The classification scheme defines the rules or conditions to determine how the values in the raster will be categorized. This can be achieved by providing a custom function or a set of thresholds.

We will divide our ocean bathymetry into two groups, all cells with less than or equal to 200 meters are shallow and those cells above 200 as deep

Code
cut.points  = c(-1300, -200,0)
Code
 depth.class = pemba.dem %>% 
  terra::classify(cut.points)

depth.class
class       : SpatRaster 
dimensions  : 96, 60, 1  (nrow, ncol, nlyr)
resolution  : 0.01666667, 0.01666667  (x, y)
extent      : 38.99167, 39.99167, -5.808326, -4.208326  (xmin, xmax, ymin, ymax)
coord. ref. : lon/lat WGS 84 (EPSG:4326) 
source(s)   : memory
categories  : wioregio-7753 
name        : wioregio-7753 
min value   :  (-1300–-200] 
max value   :      (-200–0] 
Code
depth.class %>% 
  terra::plot()

11.5 Aggregating

Adjusting the grid size of raster data, whether by increasing or decreasing it, serves several purposes. Increasing the grid size, or decreasing the resolution, is useful when fine details are not crucial or when working with large datasets, as it reduces computational burden and memory usage. On the other hand, decreasing the grid size, or increasing the resolution, allows for a more precise representation of spatial phenomena, which is advantageous for accurate analyses such as environmental modeling.

Grid size adjustments also aid in data compatibility, harmonizing multiple datasets with different resolutions, and can enhance visualization by simplifying large-scale patterns. Additionally, modifying the grid size can optimize processing efficiency, trading off between detail and computational performance.

Code
pemba.dem.low = pemba.dem %>% 
  terra::aggregate(fact = 5, fun = mean)

The aggregate() function reduces the resolution of the raster by aggregating cells into larger groups. In this case, the fact parameter is set to 5, indicating that each new cell in the aggregated raster will represent a 5x5 grid of the original cells. The fun parameter is set to “mean”, meaning that the values of the cells within each group will be averaged to produce the value of the aggregated cell. This obviously results in some data loss, but that can be acceptable, depending on the purpose of your analysis. Note that you can pass just about any function to fun =, like min(), max() or even your own function.

Code
pemba.dem.low
class       : SpatRaster 
dimensions  : 20, 12, 1  (nrow, ncol, nlyr)
resolution  : 0.08333335, 0.08333335  (x, y)
extent      : 38.99167, 39.99167, -5.874993, -4.208326  (xmin, xmax, ymin, ymax)
coord. ref. : lon/lat WGS 84 (EPSG:4326) 
source(s)   : memory
name        : wioregio-7753 
min value   :      -1202.76 
max value   :        258.20 

The resulting raster, assigned to the object pemba.dem.low, has a lower resolution compared to the original pemba.dem raster, as cells are combined and averaged.

11.6 Resampling

While the aggregate() function in the terra package is used to increase the grid size and decrease the resolution of a raster, the resample() function is used to modify the grid size and change the resolution of the expected output. By specifying the target resolution or grid size, you can increase or decrease the resolution of the output raster.

To understand the concept of resampling, I am going to demonstrate using the MUR SST product, which has a spatial resolution of approximately 1 kilometer (km). It offers high-resolution global coverage, providing detailed information about sea surface temperature patterns at a fine scale.

Let’s read the file into session

Code
sst = terra::rast("data/pemba_mur.nc")
sst
class       : SpatRaster 
dimensions  : 201, 301, 1  (nrow, ncol, nlyr)
resolution  : 0.01, 0.01  (x, y)
extent      : 37.995, 41.005, -6.005, -3.995  (xmin, xmax, ymin, ymax)
coord. ref. : lon/lat WGS 84 
source      : pemba_mur.nc 
varname     : analysed_sst (Analysed Sea Surface Temperature) 
name        : analysed_sst 
unit        :     degree_C 
time        : 2023-06-14 09:00:00 UTC 

Upon observation, it becomes apparent that the sea surface temperature (SST) dataset has a resolution of 0.01 degree, which translates to approximately 1.1 kilometers. This resolution is notably higher compared to the 1.8-kilometer resolution of the digital elevation model (DEM).

Code
pemba.dem.high = pemba.dem %>% 
  terra::resample(sst)

pemba.dem.high
class       : SpatRaster 
dimensions  : 201, 301, 1  (nrow, ncol, nlyr)
resolution  : 0.01, 0.01  (x, y)
extent      : 37.995, 41.005, -6.005, -3.995  (xmin, xmax, ymin, ymax)
coord. ref. : lon/lat WGS 84 (EPSG:4326) 
source(s)   : memory
name        : wioregio-7753 
min value   :    -1284.7975 
max value   :      389.0256 

The resampled pemba.dem.high now has a resolution of 0.01 degree, which translates to approximately 1.1 kilometers, the same value to that of sea surface temperature. We can confirm the resolutions using a res function.

Code
pemba.dem.low %>% terra::res()*110;
[1] 9.166669 9.166669
Code
pemba.dem %>% terra::res()*110;
[1] 1.833334 1.833334
Code
pemba.dem.high %>% terra::res()*110
[1] 1.1 1.1
Code
sst %>% terra::res()*110
[1] 1.1 1.1

Similarly, using the resample() function, it is possible to modify the grid size and adjust the resolution of a raster dataset. In this context, we want to decrease the SST data resolution to align it with the DEM.

Code
sst.low = sst %>% 
  resample(pemba.dem)

sst.low
class       : SpatRaster 
dimensions  : 96, 60, 1  (nrow, ncol, nlyr)
resolution  : 0.01666667, 0.01666667  (x, y)
extent      : 38.99167, 39.99167, -5.808326, -4.208326  (xmin, xmax, ymin, ymax)
coord. ref. : lon/lat WGS 84 
source(s)   : memory
name        : analysed_sst 
min value   :     -7.76800 
max value   :     27.97364 
time        : 2023-06-14 09:00:00 UTC 

This process ensures that both datasets share a consistent grid size, enabling accurate analysis and comparison between the SST and DEM datasets at a matching resolution.

let’s check whether the extents is the same for temperature and dem

Code
pemba.dem %>% terra::ext();
SpatExtent : 38.991669265, 39.991669465, -5.808326495, -4.208326175 (xmin, xmax, ymin, ymax)
Code
sst.low %>% terra::ext()
SpatExtent : 38.991669265, 39.991669465, -5.808326495, -4.208326175 (xmin, xmax, ymin, ymax)

We can generate visual representations of the temperature, elevation, and bathymetry variations in the Pemba Channel by plotting the corresponding raster datasets.

Code
par(mfrow = c(1,2))

pemba.dem %>% 
  terra::plot()

sst.low%>% 
  terra::plot()

11.7 Stacking raster

In terra, you can stack multiple rasters into a single seamless raster object using the c() function, which combines SpatRaster objects as long as they have the same pixel size, extent, and coordinate reference system (CRS) . This is useful when working with multiple rasters that represent different variables or time steps, as it simplifies the reading of raster data by using a single object to represent multiple rasters.

Once we are sure that our raster have similar geographical extents and spatial resolution, we can stack them together using c function in R. This function combines several raster objects into a single stack or brick, enabling simultaneous analysis and manipulation of the stacked layers.

Raster stacking allows for convenient access and processing of multiple layers within a single object, facilitating operations such as extracting values, conducting calculations, or visualizing the combined information. The stacked raster is a useful tool for analyzing and exploring the relationships and variations among different raster datasets in a unified manner.

Code
pemba.rast = c(sst.low, pemba.dem)
pemba.rast
class       : SpatRaster 
dimensions  : 96, 60, 2  (nrow, ncol, nlyr)
resolution  : 0.01666667, 0.01666667  (x, y)
extent      : 38.99167, 39.99167, -5.808326, -4.208326  (xmin, xmax, ymin, ymax)
coord. ref. : lon/lat WGS 84 
source(s)   : memory
names       : analysed_sst, wioregio-7753 
min values  :     -7.76800,         -1286 
max values  :     27.97364,           413 

11.8 Basic Plotting

With the dataset size reduced dataset and stacked the file, we can now explore the visualization capabilities offered by the base plotting function. This function, built into R, provides a wide range of options for creating plots and graphs from raster dataset.

Code
pemba.rast %>% 
  plot(
    main = c("Sea Surface Temperature", "Elevation & Bathymetry"),
    xlab = "X-axis",         # Label for the x-axis
    ylab = "Y-axis",         # Label for the y-axis
     )

11.9 Raster Manipulation

The packages “terra” allow for easy manipulation of raster data in R. With these packages, rasters can be treated as variables in mathematical equations, allowing for exploration of data loss by calculating the difference between original and disaggregated DEMS.

Code
ggplot() +
  geom_spatraster(data = sst.low)

FIGURE 11.1. Sea surface temperature

Here we stumble! Why? because this area is close to the equator and hardly find sea surface temperature below 25 degree. But Figure 11.1 indicate a range of temperature from -7 to 28 oC. The color ramp clearly show as the data has the land with darkblue and the ocean with light blue colors, instead of the gradient colors. We should not be fooled by the colors but lets dig the numbers. Lets first check the summary of the raster.

Code
sst.low %>% summary()
  analysed_sst   
 Min.   :-7.768  
 1st Qu.:27.155  
 Median :27.561  
 Mean   :20.190  
 3rd Qu.:27.711  
 Max.   :27.974  

We notice that from the first quantile through the maximum value are less than one degree celcius, but the minimum values is far low. Then we spot this as outlier. Let’s us make a histogram of the sst from the raster

Code
sst.low %>% 
  terra::as.data.frame() %>% 
  ggplot(aes(x = analysed_sst)) +
  geom_histogram()

Code
sst.low = sst.low %>% 
  tidyterra::rename(sst = 1) %>% 
  tidyterra::filter(sst > 0)

sst.low
class       : SpatRaster 
dimensions  : 96, 60, 1  (nrow, ncol, nlyr)
resolution  : 0.01666667, 0.01666667  (x, y)
extent      : 38.99167, 39.99167, -5.808326, -4.208326  (xmin, xmax, ymin, ymax)
coord. ref. : lon/lat WGS 84 
source(s)   : memory
name        :      sst 
min value   : 26.69426 
max value   : 27.97364 

Now the raster file has correct temperature range between 26 and 28 degree celcius. we can make a plot to see the spatial distribution of this temperature in the channel

Code
pemba.rast = c(sst.low, pemba.dem)
Code
pemba.rast %>% 
  plot(
    main = c("Sea Surface Temperature", "Elevation & Bathymetry"),
    xlab = "X-axis",         # Label for the x-axis
    ylab = "Y-axis",         # Label for the y-axis
    col = hcl.colors(palette = "Spectral", n = 20)
     )

We can use mutate together with if_else function to classify raster based on a threshold value. For instance, we know from literature that artisanal fisheries operated within shallow water of less than 200 meters. Hence, we need to demarcate this area for fisheries management plans. Instead of using mutate, which add raster to existing raster to form stacked raster object, transmute create a raster with only computed values.

Code
pemba.depth.class = pemba.rast %>% 
  tidyterra::rename(bathy = 2) %>% 
  tidyterra::transmute(
    bath.class = if_else(bathy > -200, "Shallow", "Deep")
    )
pemba.depth.class
class       : SpatRaster 
dimensions  : 96, 60, 1  (nrow, ncol, nlyr)
resolution  : 0.01666667, 0.01666667  (x, y)
extent      : 38.99167, 39.99167, -5.808326, -4.208326  (xmin, xmax, ymin, ymax)
coord. ref. : lon/lat WGS 84 
source(s)   : memory
categories  : label 
name        : bath.class 
min value   :       Deep 
max value   :    Shallow 
Code
pemba.depth.class %>% 
  plot(
    # main = c("Sea Surface Temperature", "Elevation & Bathymetry"),
    xlab = "X-axis",         # Label for the x-axis
    ylab = "Y-axis",         # Label for the y-axis
    col = c("red", "green")
     )

Code
pemba.depth.class %>% 
  terra::expanse()
  layer        area
1     1 19620711224

To visualize data in R, you can use the ggplot2 package, which provides a flexible and powerful system for creating graphics[1][2]. The ggplot2 package uses a grammar of graphics that allows you to build complex plots by combining simple components[1]. However, if you prefer to use the base plotting function in R, you can do so by using the plot() function in terra[3]. The plot() function creates a map of the values of a SpatRaster or SpatVector object, which can be customized using the available arguments[3]. Overall, both ggplot2 and plot() are useful tools for visualizing data in R, and the choice of which one to use depends on personal preference and the specific needs of the analysis.

Code
ggplot() +
  # ggspatial::annotation_map_tile(type = "osm", zoom = 8, progress = "none")+
  geom_spatraster(data = sst.low, alpha = 1) +
  ggspatial::annotation_scale()

11.10 Point Extraction

Code
chl = list.files("data/satellite data/Chl-a/", pattern = ".nc", full.names = TRUE)
sst = list.files("data/satellite data/SST/", pattern = ".nc", full.names = TRUE)


for (i in 1:12){

label = paste0("data/satellite data/processed/","chl_",month.abb[i] %>% str_to_lower(), ".tif")
label2 = paste0("data/satellite data/processed/","sst_",month.abb[i] %>% str_to_lower(), ".tif")

chl[i] %>% 
  terra::rast() %>% 
  tidyterra::select(chl = 2) %>% 
  # tidyterra::filter(chl < 10) %>%
  # terra::crop(pemba.dem)  %>%
  terra::writeRaster(filename = label)

labe2 = paste0("data/satellite data/processed/","sst_",month.abb[i] %>% str_to_lower(), ".tif")

sst[i] %>% 
  terra::rast() %>% 
  tidyterra::select(sst = 1) %>% 
  # tidyterra::filter(chl < 10) %>%
  # terra::crop(pemba.dem)  %>%
  terra::writeRaster(filename = label2)

  
}
Code
sst.list = list.files(path = "data/satellite data/processed/", pattern = "sst", include.dirs = TRUE, full.names = TRUE) 

sst.stack = sst.list %>% 
  terra::rast() 

sst.stack = sst.stack %>% 
  tidyterra::select(
    jan = 5,  feb = 4, mar = 8, apr = 1, may = 9, jun = 7, jul = 6, aug = 2, sep = 12, oct = 11, nov = 10, dec = 3
  )
Code
pemba.sst.stack = sst.stack %>% 
  terra::crop(pemba.dem)
Code
pemba.sst.stack %>% 
  terra::plot(
    col = hcl.colors(palette = "RdBu", n = 12, rev = TRUE)
    )

Code
chl.list = list.files(path = "data/satellite data/processed/", pattern = "chl", include.dirs = TRUE, full.names = TRUE) 

chl.stack = chl.list %>% 
  terra::rast() 

chl.stack = chl.stack %>% 
  tidyterra::select(
    jan = 5,  feb = 4, mar = 8, apr = 1, may = 9, jun = 7, jul = 6, aug = 2, sep = 12, oct = 11, nov = 10, dec = 3
  )
Code
pemba.chl.stack = chl.stack %>% 
  terra::crop(pemba.dem)
Code
pemba.chl.stack %>% 
  terra::hist()

Code
pemba.chl.stack %>% 
  terra::plot(
    col = hcl.colors(palette = "RdBu", n = 12, rev = TRUE)
    )

Code
vikatio = pemba.chl.stack %>% 
  terra::values() %>% 
  quantile( c(.05,.95), na.rm = TRUE) %>% 
  as.vector()
Code
ggplot() +
  geom_spatraster(data = pemba.chl.stack)+
  facet_wrap(~lyr, nrow = 2)+
  scale_fill_gradientn(colours = hcl.colors(n = 12, palette = "RdBu", rev = TRUE), na.value = NA, limits = vikatio)

Code
set.seed(1254)

random.locations = pemba.dem %>% 
  terra::as.polygons() %>% 
  sf::st_as_sf() %>% 
  sf::st_sample(size = 50) %>% 
  sf::st_as_sf() %>% 
  dplyr::mutate(id = 1:n())

random.locations.coords = random.locations %>% 
  st_coordinates() %>% 
  as_tibble() %>% 
  select(lon = 1, lat = 2)
Code
ggplot() +
  ggspatial::annotation_map_tile(type = "osm", zoom = 8) +
  ggspatial::layer_spatial(data = random.locations)

11.10.1 Temperature monthly

Code
pemba.sst.locations = pemba.sst.stack %>% 
  terra::extract(random.locations)
Code
random.locations.coords %>% 
  bind_cols(
    pemba.sst.locations
  ) %>% 
  gt::gt()%>% 
  gt::opt_interactive(
    use_search = TRUE,
    # use_filters = TRUE,
    use_resizers = TRUE,
    use_highlight = TRUE,
    use_compact_mode = TRUE,
    use_text_wrapping = FALSE,
    use_page_size_select = TRUE
  ) %>%
  gt::fmt_number(decimals = 3) |>
  gt::fmt_integer(ID) |>
  gt::cols_label_with(
    fn = ~ janitor::make_clean_names(., case = "all_caps")
  ) |>
  gt::data_color(
    columns = jan:mar,
    palette = "Reds"
  ) |>
  gt::data_color(
    columns = may:sep,
    palette = "Blues"
  ) |>
  gt::data_color(
    columns = nov:dec,
    palette = "Reds"
  )|>
  gt::data_color(
    columns = c(apr, oct),
    palette = "Greens"
  )|>
  gt::tab_style(
    style = cell_fill(color = "gray95"),
    locations = cells_body(columns = c(lon, lat))
  ) |>
  gt::tab_style(
    locations = cells_body(columns = ID),
    style = cell_text(weight = "bold")
  ) 

?(caption)

Code
sst.extracts = random.locations.coords %>% 
  bind_cols(pemba.sst.locations)


sst.extracts %>% 
  pivot_longer(cols = jan:dec, names_to = "months", values_to = "data") %>% 
  mutate(months = str_to_title(months), months = forcats::fct_inorder(months)) %>% 
  ggplot(aes(x = months, y = data))+
  geom_boxplot()

11.10.2 Chlorophyll monthly

Code
pemba.chl.locations = pemba.chl.stack %>% 
  terra::extract(random.locations)
Code
random.locations.coords %>% 
  bind_cols(
    pemba.chl.locations
  ) %>% 
  gt::gt()%>% 
  gt::opt_interactive(
    use_search = TRUE,
    # use_filters = TRUE,
    use_resizers = TRUE,
    use_highlight = TRUE,
    use_compact_mode = TRUE,
    use_text_wrapping = FALSE,
    use_page_size_select = TRUE
  ) %>%
  gt::fmt_number(decimals = 3) |>
  gt::fmt_integer(ID) |>
  gt::cols_label_with(
    fn = ~ janitor::make_clean_names(., case = "all_caps")
  ) |>
  gt::data_color(
    columns = jan:mar,
    palette = "Reds"
  ) |>
  gt::data_color(
    columns = may:sep,
    palette = "Blues"
  ) |>
  gt::data_color(
    columns = nov:dec,
    palette = "Reds"
  )|>
  gt::data_color(
    columns = c(apr, oct),
    palette = "Greens"
  )|>
  gt::tab_style(
    style = cell_fill(color = "gray95"),
    locations = cells_body(columns = c(lon, lat))
  ) |>
  gt::tab_style(
    locations = cells_body(columns = ID),
    style = cell_text(weight = "bold")
  ) 

?(caption)

Code
chl.extracts = random.locations.coords %>% 
  bind_cols(pemba.chl.locations)


chl.extracts %>% 
  pivot_longer(cols = jan:dec, names_to = "months", values_to = "data") %>% 
  mutate(months = str_to_title(months), months = forcats::fct_inorder(months)) %>% 
  dplyr::filter(data < 1) %>% 
  ggplot(aes(x = months, y = data))+
  geom_boxplot()+
  scale_y_continuous(trans = scales::log10_trans())

11.11 Raster conversion

you can derive contour lines as spatVector from bathymetry or elevation raster with as.contour() function

Code
depth.contour = pemba.dem %>% 
  terra::as.contour(level = seq(-1200,0,200))

depth.contour
 class       : SpatVector 
 geometry    : lines 
 dimensions  : 7, 1  (geometries, attributes)
 extent      : 39, 39.98334, -5.799993, -4.21666  (xmin, xmax, ymin, ymax)
 coord. ref. : lon/lat WGS 84 (EPSG:4326) 
 names       : level
 type        : <num>
 values      : -1200
               -1000
                -800
Code
depth.contour %>% 
  terra::plot()

We can also

Code
depth.classes = pemba.dem %>% 
  terra::classify(c(-1300,-800,-500,-200,0)) %>% 
  terra::as.polygons()
Code
depth.classes %>% 
  terra::plot()