knitr::opts_chunk$set( collapse = TRUE, comment = "#>", fig.width = 8, fig.height = 8, warning = FALSE, message = FALSE )
This vignette showcases the functions used to derive the roughness and anisotropy exponents from a rotated landscape.
First, we perform all the steps from this vignette.
library("statisticalRoughness") library("rayshader") library("raster") rstr <- raster(file.path(system.file("extdata/rasters/", package = "statisticalRoughness"), "submarine_canyon.tif")) # raster_resolution <- 10 raster_resolution <- 50 # rstr <- raster::aggregate(rstr, fact = 9) # 90 m to match Pastor-Satorras # raster_resolution <- 90 FT2D <- rstr %>% detrend_dem() %>% raster::as.matrix() %>% fft2D(dx = raster_resolution, dy = raster_resolution, Hann = TRUE) nbin <- 20 binned_power_spectrum <- bin(log10(FT2D$radial_frequency_vector), log10(FT2D$spectral_power_vector), nbin) binned_power_spectrum <- na.omit(binned_power_spectrum) normalized_spectral_power_matrix <- get_normalized_spectral_power_matrix(binned_power_spectrum, FT2D) filtered_spectral_power_matrix <- filter_spectral_power_matrix(normalized_spectral_power_matrix, FT2D, quantile_prob = c(0.9999)) ang_fourier <- get_fourier_angle(filtered_spectral_power_matrix, FT2D) ang_fourier <- 0 rotated_raster <- rotate_raster(rstr, ang_fourier)
On the figure below, the horizontal line is the middle row, the leftmost vertical line is the first third column and the rightmost vertical line is the middle column.
ind_x <- nrow(rotated_raster) %/% 2 ind_y <- ncol(rotated_raster) %/% 3 .rotated_raster <- rotated_raster .rotated_raster[ind_x, ] <- NA .rotated_raster[, ind_y] <- NA .rotated_raster[, ind_x] <- NA matrix_for_rayshader(.rotated_raster) %>% sphere_shade(texture = "imhof4") %>% add_shadow(ray_shade(matrix_for_rayshader(.rotated_raster), sunaltitude = 20), max_darken = 0.3) %>% add_shadow(ambient_shade(matrix_for_rayshader(.rotated_raster)), 0) %>% plot_map()
The height-height correlation function (HHCF) is defined as:
[C(r) = \left\langle \sqrt{[h(x+r,t)-h(x,t)]^2} \right\rangle]
with $h$ the elevation, $x$ the spatial coordinate, $t$ the time coordinate, $r$ a spatial increment and where brackets indicate averaging.
With this definition, we can now calculate the HHCF for the rotated_raster
in the row-wise (margin = 1
) and column-wise directions (margin = 2
) using get_hhcf()
.
hhcf_x <- get_hhcf_(rotated_raster, raster_resolution, margin = 1) hhcf_y <- get_hhcf_(rotated_raster, raster_resolution, margin = 2)
The HHCF scales with increasing $r$ as:
[ C(r) \sim r^\alpha ]
with $\alpha$ the roughness exponent.
We now use get_alpha()
to derive the roughness exponents $\alpha_x$ and $\alpha_y$ in each direction.
The option do_plot = TRUE
provides a graphical display of the step-wise binned regression process and identification of the cross-over lengthscale.
As the regression is a piecewise regression, for each direction, two slopes are returned, for example: $\alpha_{1,x}$ and $\alpha_{2,x}$.
get_alpha_(hhcf_x$hhcf[ind_x, ], raster_resolution, hhcf_x$autocorr_len[ind_x], do_plot = TRUE)
get_alpha_(hhcf_y$hhcf[ind_y, ], raster_resolution, hhcf_y$autocorr_len[ind_y], do_plot = TRUE)
get_alpha()
includes a number of safeguard and the function will return NA
.
Here is an example the roughly follow a ridgeline, the middle column, with no statistically consistent scaling.
get_alpha_(hhcf_y$hhcf[ind_x, ], raster_resolution, hhcf_y$autocorr_len[ind_x], do_plot = TRUE)
Provided a list of HHCF from get_hhcf()
, the function get_all_alpha()
computes all step-wise regressions.
alpha_x <- get_all_alpha_(hhcf_x, raster_resolution) alpha_y <- get_all_alpha_(hhcf_y, raster_resolution)
alphas <- rbind( alpha_x %>% stats::na.omit() %>% dplyr::mutate(direction = 'x'), alpha_y %>% stats::na.omit() %>% dplyr::mutate(direction = 'y') ) %>% reshape2::melt(measure.vars = c("alpha1", "alpha2")) p <- ggplot2::ggplot(alphas, ggplot2::aes(x = .data$value, group = .data$direction, color = .data$direction)) + ggplot2::geom_density(n = 512) + ggplot2::facet_grid(.data$variable ~ .) + ggpubr::theme_pubr() p
The resulting data.frames
can easily be summarized with summarise_alpha()
.
For example:
alpha_x %>% summarise_alpha() alpha_y %>% summarise_alpha()
x_stats <- alpha_x %>% summarise_alpha() y_stats <- alpha_y %>% summarise_alpha()
In a more human-readable format, we can summarize the entire landscape on rotated_raster
by:
| | row-wise direction, $x$ | column-wise direction, $y$ |
|:-----------|:-------------------------------------------------------------------------------:|:-------------------------------------------------------------------------------:|
| $\alpha_1$ | r x_stats$alpha1_mean %>% signif(2)
$\pm$ r x_stats$alpha1_sd %>% signif(2)
| r y_stats$alpha1_mean %>% signif(2)
$\pm$ r y_stats$alpha1_sd %>% signif(2)
|
| $\alpha_2$ | r x_stats$alpha2_mean %>% signif(2)
$\pm$ r x_stats$alpha2_sd %>% signif(2)
| r y_stats$alpha2_mean %>% signif(2)
$\pm$ r y_stats$alpha2_sd %>% signif(2)
|
These numbers mean that the topography is mainly correlated in a positive way below r mean(c(x_stats$change_point_mean, y_stats$change_point_mean)) %>% signif(3)
meters and more correlated in the $x$-direction than in the $y$-direction as $\alpha_{1,x} > \alpha_{1,y} > 0.5$.
Above r mean(c(x_stats$change_point_mean, y_stats$change_point_mean)) %>% signif(3)
meters, the topography is negatively correlated and more so in the y-direction than in the $x$-direction $\alpha_{2,y} < \alpha_{2,x} < 0.5$.
These results also mean that the $x$-direction corresponds to the down-slope direction, $\mathbf{e}\parallel$, while the $y$-direction corresponds to the across-slope direction, $\mathbf{e}\perp$.
Further, the dominant slope in the $x$-direction results in increased smoothing and higher values of roughness exponents.
This is what we could have expected from a visual inspection of the landscape.
The anisotropy exponent is the ratio between the down-slope and across-slope roughness exponents:
[ \zeta = \frac{\alpha_\perp}{\alpha_\parallel}]
Because of the increased smoothing due to gravity in the down-slope direction, $\alpha_\perp \geq \alpha_\parallel$ and $\zeta \geq 1$. From the central values of $\alpha_{1,x}$ and $\alpha_{1,y}$, the value of the anisotropy exponent $\zeta_1$ can be derived as:
[ \zeta_1 = \frac{\max{\alpha_{1,x}, \alpha_{1,x}}}{\min{\alpha_{1,x}, \alpha_{1,x}}}]
This estimate of $\zeta$ is handled by an internal function which includes a check for the spread of the distribution of $\alpha$.
If the distribution is not constrained enough, NA
values are returned.
For the current landscape:
| | anisotropy exponent, $\zeta$ |
|:----------|:--------------------------------------------------------------------------------------------------------------------:|
| $\zeta_1$ | r get_zeta_(x_stats$alpha1_mean, y_stats$alpha1_mean, x_stats$alpha1_IQR, y_stats$alpha1_IQR, TRUE) %>% signifNA()
|
| $\zeta_2$ | r get_zeta_(x_stats$alpha2_mean, y_stats$alpha2_mean, x_stats$alpha2_IQR, y_stats$alpha2_IQR, TRUE) %>% signifNA()
|
get_zeta(rstr, raster_resolution, full = TRUE) %>% dplyr::mutate_all(signifNA)
get_zeta(rstr,raster_resolution) %>% dplyr::mutate_all(signifNA)
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.