
Rotoehu - Merge Bathymetry with DEM data
Source:vignettes/rotoehu-merge-bathy-dem.Rmd
rotoehu-merge-bathy-dem.RmdLake bathymetry data is useful for a range of applications, including habitat mapping, water quality monitoring, and hydrodynamic modelling. However, lakes sit within a landscape, and it is often useful to know how the bathymetry data relates to the surrounding topography. This is particularly important for hydrodynamic modelling of lakes with large fluctuations in water level, or for flood risk assessments in the surrounding area.
This vignette demonstrates how to merge bathymetry data with a
Digital Elevation Model (DEM) raster using the
merge_bathy_dem() function.
Load the data
We will use the bathytools package to merge bathymetry data with a
DEM raster. The package includes example data for Lake Rotoehu, New
Zealand. The bathymetry data is stored as a a contour shapefile
accessible via the Limnotrack ltapi package.
Whereas the DEM data is stored as a raster in a TIF file. The DEM raster
was prepared from LiDAR data provided by Land Information New Zealand and
aggregated to 32m. The original 1m data can be downloaded here.
We will also use a shapefile of the lake shoreline and a shapefile of the lake catchment. These are both sourced from the LERNZmp database. The LERNZmp database was developed as part of the LERNZmp project. Read more about the LERNZmp project here or visit the Shiny platform here.
library(bathytools)
library(tmap) # Used for plotting spatial data
# Lake Rotoehu lake id is 40188
shoreline <- ltapi::lt_fetch(
"lernzmp_lakes",
filter = ltapi::lt_filter(lernzmp_id == "LID40188")
)
# Get lake catchment
catchment <- ltapi::lt_fetch(
"lernzmp_catchments",
filter = ltapi::lt_filter(lernzmp_id == "LID40188")
)
# The catchment shapefile is in WGS84 (EPSG:4326) but the data is in NZTM2000
# (EPSG:2193). We will set the CRS of the catchment to NZTM2000.
sf::st_crs(catchment) <- 2193
#> Warning: st_crs<- : replacing crs does not reproject data; use st_transform for
#> thatThe example lake we will be looking at is Lake Rotoehu in the Bay of Plenty Region on the North Island of Aotearoa New Zealand.
The tmap package is used
to plot spatial data. The tmap_mode("view") function is
used to display the map in the viewer pane in RStudio. The
tmap_options(basemaps = "Esri.WorldImagery") function is
used to set the basemap to a satellite image. It is similar to the
ggplot2 package, but is specifically designed for spatial
data. Here we plot the lake shoreline in light blue and the lake
catchment in pink.
tmap_mode("view")
#> ℹ tmap modes "plot" - "view"
#> ℹ toggle with `tmap::ttm()`
tmap_options(basemap.server = "Esri.WorldImagery")
tm_shape(shoreline) +
tm_borders(col = "#8DA0CB", lwd = 2) +
tm_shape(catchment) +
tm_borders(col = "#E78AC3", lwd = 2) The depth data is stored as contours and is available on the same
LERNZmp database. The depth contours are stored as a shapefile and can
be accessed using the ltapi package. The depth contours are
in meters and are negative values. We will convert the depth contours to
positive values for plotting.
# Get lake depth contours
contours <- ltapi::lt_fetch(
"lake_contours",
filter = ltapi::lt_filter(lernzmp_id == "LID40188")
) |>
dplyr::mutate(depth = depth_m)
dem_raster <- terra::rast(system.file("extdata/dem_32m.tif",
package = "bathytools"))
tm_shape(dem_raster) +
tm_raster(col_alpha = 0.5, col.scale = tm_scale_continuous(values = "-brewer.yl_gn_bu")) +
tm_shape(shoreline) +
tm_borders(col = "#FC8D62", lwd = 2) +
tm_shape(catchment) +
tm_borders(col = "#A6D854", lwd = 2) Generate the bathymetry raster
The first step is to generate a bathymetry raster from the shoreline
and depth data. The rasterise_bathy() function is used to
generate the bathymetry raster. The function takes the shoreline, depth
data, and the coordinate reference system (CRS) as inputs. The function
returns a SpatRaster object representing the bathymetry
raster.
bathy_raster <- rasterise_bathy(shoreline = shoreline,
contours = contours,
crs = 2193,
res = 8)
#> No islands found.
#> ℹ Generating depth points for interpolation
#> Warning in st_cast.sf(p[!sf::st_is_empty(p$geometry), ], "POINT"): repeating
#> attributes for all sub-geometries for which they may not be constant
#> Warning in st_cast.sf(p[!sf::st_is_empty(p$geometry), ], "POINT"): repeating
#> attributes for all sub-geometries for which they may not be constant
#> Warning in st_cast.sf(p[!sf::st_is_empty(p$geometry), ], "POINT"): repeating
#> attributes for all sub-geometries for which they may not be constant
#> Warning in st_cast.sf(p[!sf::st_is_empty(p$geometry), ], "POINT"): repeating
#> attributes for all sub-geometries for which they may not be constant
#> Warning in st_cast.sf(p[!sf::st_is_empty(p$geometry), ], "POINT"): repeating
#> attributes for all sub-geometries for which they may not be constant
#> Warning in st_cast.sf(p[!sf::st_is_empty(p$geometry), ], "POINT"): repeating
#> attributes for all sub-geometries for which they may not be constant
#> Warning: large number of points for interpolation (95645)
#> ✔ Generating depth points for interpolation [6.2s]
#>
#> ℹ Interpolating depth points to raster
#> ℹ Adjusting depths >= 0 to -0.4m
#> ℹ Interpolating depth points to raster
#> ✔ Interpolating depth points to raster [870ms]
tm_shape(dem_raster) +
tm_raster(col_alpha = 0.5,
col.scale = tm_scale_continuous(values = "-brewer.yl_gn_bu")) +
tm_shape(bathy_raster) +
tm_raster(col.scale = tm_scale_continuous(values = "-viridis", ticks = seq(-90, 0, by = 10))) +
tm_shape(shoreline) +
tm_borders(col = "#FC8D62", lwd = 2) +
tm_shape(catchment) +
tm_borders(col = "#A6D854", lwd = 2) Merge the bathymetry with the DEM
The next step is to merge the bathymetry raster with the DEM raster.
The merge_bathy_dem() function is used to merge the
bathymetry raster with the DEM raster. The function takes the shoreline,
bathymetry raster, DEM raster, and catchment shapefile as inputs. The
function returns a SpatRaster object representing the
merged bathymetry and DEM data.
If the resolution of the bathymetry raster is different from the DEM raster, the bathymetry raster will be resampled to match the resolution of the DEM raster.
dem_bath <- merge_bathy_dem(shoreline = shoreline, bathy_raster = bathy_raster,
dem_raster = dem_raster, catchment = catchment)
#> Resolutions differ. Resampling bathy_raster to DEM resolution.
#> Lake surface elevation from DEM: 294.25 m
dem_bath
#> class : SpatRaster
#> size : 338, 208, 1 (nrow, ncol, nlyr)
#> resolution : 32, 32 (x, y)
#> extent : 1906176, 1912832, 5778576, 5789392 (xmin, xmax, ymin, ymax)
#> coord. ref. : NZGD2000 / New Zealand Transverse Mercator 2000 (EPSG:2193)
#> source(s) : memory
#> varname : dem_32m
#> name : elevation
#> min value : 281.262914
#> max value : 644.796875Spatial plot of the merged raster
Here we plot the merged raster with the lake and catchment boundaries.
tm_shape(dem_bath) +
tm_raster(col_alpha = 0.5,
col.scale = tm_scale_continuous(values = "-brewer.yl_gn_bu")) +
tm_shape(shoreline) +
tm_borders(col = "#FC8D62", lwd = 2) +
tm_shape(catchment) +
tm_borders(col = "#A6D854", lwd = 2) The colours in this plot do not clearly distinguish between the
bathymetry and DEM data. We will add a break at the surface elevation of
the lake to better distinguish between the two datasets. We can extract
the water surface elevation from the DEM data using the
get_lake_surface_elevation() function.
lake_elev <- get_lake_surface_elevation(dem_raster = dem_raster,
shoreline = shoreline)
#> Lake surface elevation from DEM: 294.25 mWe can now plot the merged raster with the lake surface elevation as the break in the colour palette.
tm_dem_bath(dem_bath = dem_bath, lake_elev = lake_elev)Hypsograph of the merged raster
A hypsograph is a plot of the area of a lake at different depths. The
bathy_to_hypso() function can be used to generate a
hypsograph from the bathymetry raster. The function takes the bathymetry
raster as input and returns a data frame with the depth and area at each
depth.
hyps <- bathy_to_hypso(bathy_raster = bathy_raster)
head(hyps)
#> elev depth area
#> 1 0.0 0.0 8089024
#> 2 -0.2 -0.2 7810453
#> 3 -0.4 -0.4 7531883
#> 4 -0.6 -0.6 7253312
#> 5 -0.8 -0.8 7157888
#> 6 -1.0 -1.0 7065600The hypsograph can be plotted to show the area of the lake at different depths.
library(ggplot2)
ggplot(hyps, aes(x = area, y = depth)) +
geom_line() +
geom_point() +
labs(x = "Area (m^2)", y = "Depth (m)") +
theme_bw()
Extended hypsograph of the merged raster
When merging bathymetry with DEM data, it is often useful to extend
the hypsograph to include the area of the lake at different elevations
above the lake surface. This can be done by specifying an additional
elevation to extend the lake surface. The dem_to_hypso()
function can take an additional argument ext_elev to
specify this elevation. It also requires the merged raster and the lake
surface elevation as inputs, the lake shoreline polygon, and the lake
elevation.
Here we will extend the hypsograph by 3 meters above the lake surface elevation. This will allow us to see the area of the lake at different elevations above the lake surface.
lake_depth <- get_lake_depth(bathy_raster = bathy_raster)
ext_hyps <- dem_to_hypsograph(shoreline = shoreline, dem_bath = dem_bath,
lake_elev = lake_elev, lake_depth = lake_depth,
ext_elev = 3)
head(ext_hyps)
#> elev depth area
#> 1 297.25 3.0 9153536
#> 2 297.05 2.8 9097216
#> 3 296.85 2.6 9032704
#> 4 296.65 2.4 8966144
#> 5 296.45 2.2 8894464
#> 6 296.25 2.0 8838144The extended hypsograph can be plotted to show the area of the lake at different depths or elevations. Here we will plot the area of the lake at different elevations above the lake surface.
ggplot(ext_hyps, aes(x = area, y = elev)) +
geom_hline(yintercept = lake_elev, linetype = "dashed", color = "red") +
geom_line() +
geom_point() +
labs(x = "Area (m^2)", y = "Elevation (m.a.s.l)") +
theme_bw()
3-D plot of the merged raster
The plot_raster_3d() function can be used to create a
3-D plot of the merged raster. The function takes the merged raster and
the shoreline as inputs. The fact argument controls the
aggregation factor for the raster. A higher factor will result in a
smoother plot, but will take longer to render.
p1 <- plot_raster_3d(x = dem_bath, shoreline = shoreline, split_lake = TRUE)
p1Saving the merged raster
The merged raster can be saved to a file using the
terra::writeRaster() function. The function takes the
raster object and the file path as inputs.
It is important to note that SpatRaster can not be saved
as “.rds” files. They can also be quite large, so it is recommended to
save the raster in a compressed format, such as GeoTIFF.
terra::writeRaster(dem_bath, "dem_bath.tif", overwrite = TRUE)