| Title: | Analyzing the Orientation of Maximum Horizontal Stress |
|---|---|
| Description: | Models the direction of the maximum horizontal stress using relative plate motion parameters. Statistical algorithms to evaluate the modeling results compared with the observed data. Provides plots to visualize the results. Methods described in Stephan et al. (2023) <doi:10.1038/s41598-023-42433-2> and Wdowinski (1998) <doi:10.1016/S0079-1946(98)00091-3>. |
| Authors: | Tobias Stephan [aut, cre] (ORCID: <https://orcid.org/0000-0002-9290-014X>) |
| Maintainer: | Tobias Stephan <[email protected]> |
| License: | GPL (>= 3) |
| Version: | 0.4.9.9001 |
| Built: | 2026-09-23 18:06:04 UTC |
| Source: | https://github.com/tobiste/tectonicr |
Calculates the absolute angular velocity of plate motion
abs_vel(w, alpha, r = earth_radius())abs_vel(w, alpha, r = earth_radius())
w |
Angular velocity or rate or angle of rotation |
alpha |
Angular distance to Euler pole or small circle around Euler pole |
r |
Radius. Default is WGS84 Earth's radius (6371.009 km) |
numeric (unit of velocity: km/Myr)
abs_vel(0.21, 0) abs_vel(0.21, 45) abs_vel(0.21, 90)abs_vel(0.21, 0) abs_vel(0.21, 45) abs_vel(0.21, 90)
Calculates the angle between two vectors
angle_vectors(x, y)angle_vectors(x, y)
x, y
|
Vectors in Cartesian coordinates. Can be vectors of three numbers or a matrix of 3 columns (x, y, z) |
numeric. angle in degrees
u <- c(1, -2, 3) v <- c(-2, 1, 1) angle_vectors(u, v) # 96.26395u <- c(1, -2, 3) v <- c(-2, 1, 1) angle_vectors(u, v) # 96.26395
Helper functions to transform between angles in degrees and radians.
rad2deg(rad) deg2rad(deg)rad2deg(rad) deg2rad(deg)
rad |
(array of) angles in radians. |
deg |
(array of) angles in degrees. |
numeric. angle in degrees or radians.
deg2rad(seq(-90, 90, 15)) rad2deg(seq(-pi / 2, pi / 2, length = 13))deg2rad(seq(-90, 90, 15)) rad2deg(seq(-pi / 2, pi / 2, length = 13))
Performs Angular Randomisation Test for homogeneity on two samples of circular data after Ruxton et al. (2023). P-values are estimated using permutation.
ar_test(x, y, n_perm = 1000L, axial = FALSE, alpha = NULL)ar_test(x, y, n_perm = 1000L, axial = FALSE, alpha = NULL)
x, y
|
numeric vectors. Angles in degrees |
n_perm |
integer. Number of permutations |
axial |
logical. Whether the data are axial, i.e. |
alpha |
(optional) numeric. Significance level of the test (values between 0 and 1). |
Null Hypothesis (): The two circular samples share an identical underlying
probability distribution.
Alternative Hypothesis (): The two samples come from different distributions.
Small p-value (, e.g., <0.05): Reject the null hypothesis.
This indicates strong evidence that the two samples come from different
circular distributions (differing in central tendency/mean direction or shape).
Large p-value (): Fail to reject the null hypothesis;
there is insufficient evidence to claim the two circular samples differ.
list containing the test statistic, the p-value, the significance value alpha and a logical decision whether to reject the null hypothesis or not.
Concentration Differences: The test can suffer from markedly lower statistical power if the underlying unimodal distributions differ by concentration (dispersion/spread) rather than location—especially with small, uneven sample sizes where the smaller sample comes from the more concentrated distribution.
Axial/Multimodal Data: ART performs poorly and loses power when applied to axially symmetric or symmetrically multimodal distributions.
Ruxton, G.D., Malkemper, E.P. & Landler, L. Evaluating the power of a recent method for comparing two circular distributions: an alternative to the Watson U2 test. Sci Rep 13, 10007 (2023). https://doi.org/10.1038/s41598-023-36960-1
Other Tests:
kuiper_test(),
norm_chisq(),
rayleigh-test,
watson_test(),
watson_two_sample,
watson_wheeler_test_perm(),
weighted-rayleigh-test
set.seed(20250411) x1 <- c(35, 45, 50, 55, 60, 70, 85, 95, 105, 120) x2 <- c(75, 80, 90, 100, 110, 130, 135, 140, 150, 160, 165) ar_test(x1, x2) # San Andreas Fault Data: data(san_andreas) data("nuvel1") PoR <- subset(nuvel1, nuvel1$plate.rot == "na") sa.por <- PoR_shmax(san_andreas, PoR, "right") ar_test(sa.por$azi.PoR, rvm(100, 135, 10), axial = TRUE, alpha = 0.05)set.seed(20250411) x1 <- c(35, 45, 50, 55, 60, 70, 85, 95, 105, 120) x2 <- c(75, 80, 90, 100, 110, 130, 135, 140, 150, 160, 165) ar_test(x1, x2) # San Andreas Fault Data: data(san_andreas) data("nuvel1") PoR <- subset(nuvel1, nuvel1$plate.rot == "na") sa.por <- PoR_shmax(san_andreas, PoR, "right") ar_test(sa.por$azi.PoR, rvm(100, 135, 10), axial = TRUE, alpha = 0.05)
Show direction axes in a map
axes( x, y, angle, radius = 0.5, arrow.code = 1, arrow.length = 0, add = FALSE, ... )axes( x, y, angle, radius = 0.5, arrow.code = 1, arrow.length = 0, add = FALSE, ... )
x, y
|
coordinates of points |
angle |
Azimuth in degrees |
radius |
length of axis |
arrow.code |
integer. Kind of arrow head. The default is |
arrow.length |
numeric Length of the edges of the arrow head (in
inches). (Ignored if |
add |
logical. add to existing plot? |
... |
optional arguments passed to |
No return value, called for side effects
data("san_andreas") axes(san_andreas$lon, san_andreas$lat, san_andreas$azi, add = FALSE)data("san_andreas") axes(san_andreas$lon, san_andreas$lat, san_andreas$azi, add = FALSE)
The circular mean difference is based on the sample circular distance
circular_mean_difference(x, w = NULL, axial = TRUE, na.rm = TRUE) circular_mean_difference_alt(x, w = NULL, axial = TRUE, na.rm = TRUE)circular_mean_difference(x, w = NULL, axial = TRUE, na.rm = TRUE) circular_mean_difference_alt(x, w = NULL, axial = TRUE, na.rm = TRUE)
x |
numeric vector. Values in degrees, for which the mean, median or standard deviation are required. |
w |
(optional) Weights. A vector of positive numbers, of the same length as
|
axial |
logical. Whether the data are axial, i.e. pi-periodical
( |
na.rm |
logical value indicating whether |
numeric
Mardia, K.V., and Jupp, P.E (1999). Directional Statistics, Wiley Series in Probability and Statistics. John Wiley & Sons, Inc., Hoboken, NJ, USA. doi:10.1002/9780470316979
data("san_andreas") circular_mean_difference(san_andreas$azi) circular_mean_difference(san_andreas$azi, weighting(san_andreas$unc)) circular_mean_difference_alt(san_andreas$azi) circular_mean_difference_alt(san_andreas$azi, weighting(san_andreas$unc))data("san_andreas") circular_mean_difference(san_andreas$azi) circular_mean_difference(san_andreas$azi, weighting(san_andreas$unc)) circular_mean_difference_alt(san_andreas$azi) circular_mean_difference_alt(san_andreas$azi, weighting(san_andreas$unc))
Calculate the (weighted median) and standard deviation of orientation data.
circular_mean(x, w = NULL, axial = TRUE, na.rm = TRUE) circular_var(x, w = NULL, axial = TRUE, na.rm = TRUE) circular_sd(x, w = NULL, axial = TRUE, na.rm = TRUE) circular_median(x, w = NULL, axial = TRUE, na.rm = TRUE) circular_quantiles(x, w = NULL, axial = TRUE, na.rm = TRUE) circular_IQR(x, w = NULL, axial = TRUE, na.rm = TRUE)circular_mean(x, w = NULL, axial = TRUE, na.rm = TRUE) circular_var(x, w = NULL, axial = TRUE, na.rm = TRUE) circular_sd(x, w = NULL, axial = TRUE, na.rm = TRUE) circular_median(x, w = NULL, axial = TRUE, na.rm = TRUE) circular_quantiles(x, w = NULL, axial = TRUE, na.rm = TRUE) circular_IQR(x, w = NULL, axial = TRUE, na.rm = TRUE)
x |
numeric vector. Values in degrees, for which the mean, median or standard deviation are required. |
w |
(optional) Weights. A vector of positive numbers, of the same length as
|
axial |
logical. Whether the data are axial, i.e. pi-periodical
( |
na.rm |
logical value indicating whether |
numeric vector
Weighting may be the reciprocal of the data uncertainties.
Weightings have no effect on quasi-quantiles if
length(x) %% 4 == 0.
Mardia, K.V. (1972). Statistics of Directional Data: Probability and Mathematical Statistics. London: Academic Press.
Mardia, K.V., and Jupp, P.E (1999). Directional Statistics, Wiley Series in Probability and Statistics. John Wiley & Sons, Inc., Hoboken, NJ, USA. doi:10.1002/9780470316979
N.I. Fisher (1993) Statistical Analysis of Circular Data, Cambridge University Press.
Ziegler, M. O.; Heidbach O. (2019). Manual of the Matlab Script Stress2Grid v1.1. WSM Technical Report 19-02, GFZ German Research Centre for Geosciences. doi:10.2312/wsm.2019.002
Heidbach, O., Tingay, M., Barth, A., Reinecker, J., Kurfess, D., & Mueller, B. (2010). Global crustal stress pattern based on the World Stress Map database release 2008. Tectonophysics 482, 3<U+2013>15, doi:10.1016/j.tecto.2009.07.023
set.seed(1) x <- rvm(10, 0, 100) %% 180 unc <- stats::runif(length(x), 0, 10) w <- weighting(unc) circular_mean(x, w) circular_var(x, w) circular_sd(x, w) circular_median(x, w) circular_quantiles(x, w) circular_IQR(x, w) data("san_andreas") w2 <- weighting(san_andreas$unc) circular_mean(san_andreas$azi) circular_mean(san_andreas$azi, w2) circular_median(san_andreas$azi) circular_median(san_andreas$azi, w2) circular_quantiles(san_andreas$azi) circular_quantiles(san_andreas$azi, w2) circular_var(san_andreas$azi) circular_var(san_andreas$azi, w2) data("nuvel1") PoR <- subset(nuvel1, nuvel1$plate.rot == "na") sa.por <- PoR_shmax(san_andreas, PoR, "right") circular_mean(sa.por$azi.PoR, w2) circular_median(sa.por$azi.PoR, w2) circular_var(sa.por$azi.PoR, w2) circular_quantiles(sa.por$azi.PoR, w2)set.seed(1) x <- rvm(10, 0, 100) %% 180 unc <- stats::runif(length(x), 0, 10) w <- weighting(unc) circular_mean(x, w) circular_var(x, w) circular_sd(x, w) circular_median(x, w) circular_quantiles(x, w) circular_IQR(x, w) data("san_andreas") w2 <- weighting(san_andreas$unc) circular_mean(san_andreas$azi) circular_mean(san_andreas$azi, w2) circular_median(san_andreas$azi) circular_median(san_andreas$azi, w2) circular_quantiles(san_andreas$azi) circular_quantiles(san_andreas$azi, w2) circular_var(san_andreas$azi) circular_var(san_andreas$azi, w2) data("nuvel1") PoR <- subset(nuvel1, nuvel1$plate.rot == "na") sa.por <- PoR_shmax(san_andreas, PoR, "right") circular_mean(sa.por$azi.PoR, w2) circular_median(sa.por$azi.PoR, w2) circular_var(sa.por$azi.PoR, w2) circular_quantiles(sa.por$azi.PoR, w2)
Kernel density estimates for circular data from a given kernel (von Mises, wrapped Cauchy, and wrapped Normal distribution and bandwidth
circular_density( x, z = NULL, bw = NULL, weights = NULL, na.rm = TRUE, from = 0, to = 360, n = 512L, axial = TRUE, kappa = NULL, rho = NULL, sd = NULL, c = NULL, kernel = c("vonmises", "wrappedcauchy", "wrappednormal", "wrappedlevy"), adjust = 1, subdensity = FALSE )circular_density( x, z = NULL, bw = NULL, weights = NULL, na.rm = TRUE, from = 0, to = 360, n = 512L, axial = TRUE, kappa = NULL, rho = NULL, sd = NULL, c = NULL, kernel = c("vonmises", "wrappedcauchy", "wrappednormal", "wrappedlevy"), adjust = 1, subdensity = FALSE )
x |
numeric. A vector of angles (in degrees) from which the estimate is to be computed. |
z |
numeric. Angles where the density is estimated. If |
bw, kappa, rho, sd, c
|
numeric. Smoothing bandwidth expressed as the concentration
parameter |
weights |
numeric. A vector of observation weights, of the same length as |
na.rm |
logical; if |
from, to
|
the left and right-most points of the grid at which the
density is to be estimated; the defaults are |
n |
integer. Number of equally spaced angles at which the density is to be estimated. |
axial |
Logical. Whether data are uniaxial ( |
kernel |
character. The smoothing kernel to be used; one of |
adjust |
the bandwidth used is actually |
subdensity |
logical. If |
Object of class "density"
stats::density(), dvm(), dwcauchy(), dwnorm(), and plot_density()
w <- weighting(san_andreas$unc) # von Mises kernel density circular_density(san_andreas$azi, kappa = 100) circular_density(san_andreas$azi, weights = w, kappa = 100) # wrapped Cauchy kernel density circular_density(san_andreas$azi, rho = 0.9, kernel = "wrappedcauchy") # wrapped Normal kernel density circular_density(san_andreas$azi, sd = 5, kernel = "wrappednormal")w <- weighting(san_andreas$unc) # von Mises kernel density circular_density(san_andreas$azi, kappa = 100) circular_density(san_andreas$azi, weights = w, kappa = 100) # wrapped Cauchy kernel density circular_density(san_andreas$azi, rho = 0.9, kernel = "wrappedcauchy") # wrapped Normal kernel density circular_density(san_andreas$azi, sd = 5, kernel = "wrappednormal")
Calculates bootstrapped estimates of the circular dispersion, its standard error and its confidence interval.
circular_dispersion_boot( x, y = NULL, w = NULL, w.y = NULL, R = 1000, conf.level = 0.95, ... )circular_dispersion_boot( x, y = NULL, w = NULL, w.y = NULL, R = 1000, conf.level = 0.95, ... )
x, y
|
vectors of numeric values in degrees. |
w, w.y
|
(optional) Weights. A vector of positive numbers and of the same
length as |
R |
positive integer. The number of bootstrap replicates (1000 by default). |
conf.level |
Level of confidence: |
... |
optional arguments passed to |
list containing:
MLEthe maximum likelihood estimate of the circular dispersion
sdestandard error of MLE
CIlower and upper limit of the confidence interval of MLE
data("nuvel1") PoR <- subset(nuvel1, nuvel1$plate.rot == "na") sa.por <- PoR_shmax(san_andreas, PoR, "right") circular_dispersion(sa.por$azi.PoR, y = 135, w = weighting(san_andreas$unc)) circular_dispersion_boot(sa.por$azi.PoR, y = 135, w = weighting(san_andreas$unc), R = 1000)data("nuvel1") PoR <- subset(nuvel1, nuvel1$plate.rot == "na") sa.por <- PoR_shmax(san_andreas, PoR, "right") circular_dispersion(sa.por$azi.PoR, y = 135, w = weighting(san_andreas$unc)) circular_dispersion_boot(sa.por$azi.PoR, y = 135, w = weighting(san_andreas$unc), R = 1000)
MLE angle (maximum density) using a circular distribution kernel with specified concentration
circular_mode(x, ...)circular_mode(x, ...)
x |
numeric. A vector of angles (in degrees) from which the estimate is to be computed. |
... |
parameters passed to |
numeric
N.I. Fisher (1993) Statistical Analysis of Circular Data, Cambridge University Press.
set.seed(20250411) x <- rvm(10, 0, 100) # Mode of von Mises kernel density (the default) circular_mode(x) # Mode of wrapped Cauchy kernel density circular_mode(x, kernel = "wrappedcauchy")set.seed(20250411) x <- rvm(10, 0, 100) # Mode of von Mises kernel density (the default) circular_mode(x) # Mode of wrapped Cauchy kernel density circular_mode(x, kernel = "wrappedcauchy")
Polar diagram where angles increase clockwise.
circular_plot( main = NULL, sub = NULL, labels = TRUE, at = c(grid.lines, grid.lines + 180), cborder = TRUE, radius = 1, scale = 1.1, grid = FALSE, grid.lines = seq(0, 135, 45), grid.circles = seq(0.2, radius, 0.2), origin.text = "N", ... )circular_plot( main = NULL, sub = NULL, labels = TRUE, at = c(grid.lines, grid.lines + 180), cborder = TRUE, radius = 1, scale = 1.1, grid = FALSE, grid.lines = seq(0, 135, 45), grid.circles = seq(0.2, radius, 0.2), origin.text = "N", ... )
main |
a main title for the plot, see also |
sub |
a subtitle for the plot. |
labels |
Either a logical value indicating whether to plot labels next to the tick marks, or a vector of labels for the tick marks. |
at |
Optional vector of angles at which tick marks should be plotted.
Set |
cborder |
logical. Whether to plot the primitive of the circular plot ( |
radius |
numeric. The radius of the circular plot. |
scale |
numeric. Increases the radius of the border to have some in-plot clearance. |
grid |
logical. Whether to add a grid to the circular plot. Default is |
grid.lines, grid.circles
|
numeric. Adds a sequence of straight grid
lines and circles based on angles (in degrees) and radii, respectively. Ignored when
|
origin.text |
character. String to be drawn at the top margin of the plot
( |
... |
optional parameters passed to |
none
circular_plot(grid = TRUE)circular_plot(grid = TRUE)
Uniformly distributed orientations should yield a straight line through the origin. Systematic departures from linearity will indicate preferred orientation.
circular_qqplot( x, axial = TRUE, xlab = paste("i/(n+1)"), ylab = NULL, main = "Circular Quantile-Quantile Plot", add_line = TRUE, col = "#B63679FF", ... )circular_qqplot( x, axial = TRUE, xlab = paste("i/(n+1)"), ylab = NULL, main = "Circular Quantile-Quantile Plot", add_line = TRUE, col = "#B63679FF", ... )
x |
numeric. Angles in degrees |
axial |
Logical. Whether data are uniaxial ( |
xlab, ylab, main
|
plot labels. |
add_line |
logical. Whether to connect the points by straight lines? |
col |
color for the dots. |
... |
graphical parameters |
plot
Borradaile, G. J. (2003). Statistics of earth science data: their distribution in time, space, and orientation (Vol. 351, p. 329). Berlin: Springer.
Other circ-qqplot:
vm_qqplot()
set.seed(20250411) # von Mises distribution x_vm <- rvm(100, mean = 0, kappa = 2) circular_qqplot(x_vm, pch = 20) x_wcauchy <- rwcauchy(100, mean = 0, rho = 0.5) circular_qqplot(x_wcauchy, pch = 20) # circular uniform data x_cunif <- rcunif(100) circular_qqplot(x_cunif, pch = 20)set.seed(20250411) # von Mises distribution x_vm <- rvm(100, mean = 0, kappa = 2) circular_qqplot(x_vm, pch = 20) x_wcauchy <- rwcauchy(100, mean = 0, rho = 0.5) circular_qqplot(x_wcauchy, pch = 20) # circular uniform data x_cunif <- rcunif(100) circular_qqplot(x_cunif, pch = 20)
Length of the smallest arc which contains all the observations. The circular range is based on the sample circular distance.
circular_range(x, axial = TRUE, na.rm = TRUE)circular_range(x, axial = TRUE, na.rm = TRUE)
x |
numeric vector. Values in degrees, for which the mean, median or standard deviation are required. |
axial |
logical. Whether the data are axial, i.e. pi-periodical
( |
na.rm |
logical value indicating whether |
numeric. angle in degrees
Mardia, K.V., and Jupp, P.E (1999). Directional Statistics, Wiley Series in Probability and Statistics. John Wiley & Sons, Inc., Hoboken, NJ, USA. doi:10.1002/9780470316979
roulette <- c(43, 45, 52, 61, 75, 88, 88, 279, 357) circular_range(roulette, axial = FALSE) data("san_andreas") circular_range(san_andreas$azi)roulette <- c(43, 45, 52, 61, 75, 88, 88, 279, 357) circular_range(roulette, axial = FALSE) data("san_andreas") circular_range(san_andreas$azi)
Measure of the chance variation expected from sample to sample in estimates
of the mean direction (after Mardia 1972).
It is a parametric estimate of the the circular standard error of the mean direction
by the particular form of the standard error for the von Mises distribution.
The approximated standard error of the mean direction is computed by the mean
resultant length and the MLE concentration parameter .
circular_sd_error(x, w = NULL, axial = TRUE, na.rm = TRUE)circular_sd_error(x, w = NULL, axial = TRUE, na.rm = TRUE)
x |
numeric vector. Values in degrees, for which the mean, median or standard deviation are required. |
w |
(optional) Weights. A vector of positive numbers, of the same length as
|
axial |
logical. Whether the data are axial, i.e. pi-periodical
( |
na.rm |
logical value indicating whether |
numeric
Batschelet, E. (1971). Recent statistical methods for orientation data. "Animal Orientation, Symposium 1970 on Wallops Island". Amer. Inst. Biol. Sciences, Washington.
Mardia, K.V. (1972). Statistics of Directional Data: Probability and Mathematical Statistics. London: Academic Press.
N.I. Fisher (1993) Statistical Analysis of Circular Data, Cambridge University Press.
Davis (1986) Statistics and data analysis in geology. 2nd ed., John Wiley & Sons.
mean_resultant_length(), circular_mean()
# Example data from Davis (1986), pp. 316 finland_stria <- c( 23, 27, 53, 58, 64, 83, 85, 88, 93, 99, 100, 105, 113, 113, 114, 117, 121, 123, 125, 126, 126, 126, 127, 127, 128, 128, 129, 132, 132, 132, 134, 135, 137, 144, 145, 145, 146, 153, 155, 155, 155, 157, 163, 165, 171, 172, 179, 181, 186, 190, 212 ) circular_sd_error(finland_stria, axial = FALSE) data(san_andreas) data("nuvel1") PoR <- subset(nuvel1, nuvel1$plate.rot == "na") sa.por <- PoR_shmax(san_andreas, PoR, "right") circular_sd_error(sa.por$azi.PoR, w = weighting(san_andreas$unc))# Example data from Davis (1986), pp. 316 finland_stria <- c( 23, 27, 53, 58, 64, 83, 85, 88, 93, 99, 100, 105, 113, 113, 114, 117, 121, 123, 125, 126, 126, 126, 127, 127, 128, 128, 129, 132, 132, 132, 134, 135, 137, 144, 145, 145, 146, 153, 155, 155, 155, 157, 163, 165, 171, 172, 179, 181, 186, 190, 212 ) circular_sd_error(finland_stria, axial = FALSE) data(san_andreas) data("nuvel1") PoR <- subset(nuvel1, nuvel1$plate.rot == "na") sa.por <- PoR_shmax(san_andreas, PoR, "right") circular_sd_error(sa.por$azi.PoR, w = weighting(san_andreas$unc))
Circular mean, standard deviation, variance, quasi-quantiles, mode, 95% confidence angle, standardized skewness and kurtosis
circular_summary( x, w = NULL, axial = TRUE, mode = FALSE, kappa = NULL, fisher.CI = FALSE, conf.level = 0.95, na.rm = FALSE )circular_summary( x, w = NULL, axial = TRUE, mode = FALSE, kappa = NULL, fisher.CI = FALSE, conf.level = 0.95, na.rm = FALSE )
x |
numeric vector. Values in degrees, for which the mean, median or standard deviation are required. |
w |
(optional) Weights. A vector of positive numbers, of the same length as
|
axial |
logical. Whether the data are axial, i.e. pi-periodical
( |
mode |
logical. Whether the circular mode should be calculated or not. |
kappa |
numeric. von Mises distribution concentration parameter used
for the circular mode. Will be estimated using |
fisher.CI |
logical. Whether Fisher's or the default Mardia/Batchelet's confidence interval should be calculated. |
conf.level |
Level of confidence: |
na.rm |
logical value indicating whether |
named vector
circular_mean(), circular_sd(), circular_var(),
circular_quantiles(), confidence_angle(), second_central_moment(),
circular_mode()
data("nuvel1") PoR <- subset(nuvel1, nuvel1$plate.rot == "na") sa.por <- PoR_shmax(san_andreas, PoR, "right") circular_summary(sa.por$azi.PoR) circular_summary(sa.por$azi.PoR, w = weighting(san_andreas$unc))data("nuvel1") PoR <- subset(nuvel1, nuvel1$plate.rot == "na") sa.por <- PoR_shmax(san_andreas, PoR, "right") circular_summary(sa.por$azi.PoR) circular_summary(sa.por$azi.PoR, w = weighting(san_andreas$unc))
Filter smoothed stress field containing a range of search radii or kernel half widths to find shortest wavelength (R) with the least circular sd. or dispersion (or any statistic) for each coordinate, respectively.
compact_grid(x, type = c("stress", "dispersion")) compact_grid2(x, ..., FUN = min)compact_grid(x, type = c("stress", "dispersion")) compact_grid2(x, ..., FUN = min)
x |
output of |
type |
character. Type of the grid |
... |
|
FUN |
function is used to aggregate the data using the search radius
|
sf object
stress2grid(), PoR_stress2grid(), kernel_dispersion(),
stress2grid_stats(), dplyr::dplyr_tidy_select()
data("san_andreas") res <- stress2grid(san_andreas) compact_grid(res) |> head() ## Not run: res2 <- stress2grid_stats(san_andreas) compact_grid2(res2, var, FUN = min) ## End(Not run)data("san_andreas") res <- stress2grid(san_andreas) compact_grid(res) |> head() ## Not run: res2 <- stress2grid_stats(san_andreas) compact_grid2(res2, var, FUN = min) ## End(Not run)
Probabilistic limit on the location of the true or population mean direction, assuming that the estimation errors are normally distributed.
confidence_angle(x, conf.level = 0.95, w = NULL, axial = TRUE, na.rm = TRUE) confidence_interval(x, conf.level = 0.95, w = NULL, axial = TRUE, na.rm = TRUE)confidence_angle(x, conf.level = 0.95, w = NULL, axial = TRUE, na.rm = TRUE) confidence_interval(x, conf.level = 0.95, w = NULL, axial = TRUE, na.rm = TRUE)
x |
numeric vector. Values in degrees, for which the mean, median or standard deviation are required. |
conf.level |
Level of confidence: |
w |
(optional) Weights. A vector of positive numbers, of the same length as
|
axial |
logical. Whether the data are axial, i.e. pi-periodical
( |
na.rm |
logical value indicating whether |
The confidence angle gives the interval, i.e. plus and minus the confidence angle, around the mean direction of a particular sample, that contains the true mean direction under a given level of confidence.
Angle in degrees
Batschelet, E. (1971). Recent statistical methods for orientation data. "Animal Orientation, Symposium 1970 on Wallops Island". Amer. Inst. Biol. Sciences, Washington.
Mardia, K.V. (1972). Statistics of Directional Data: Probability and Mathematical Statistics. London: Academic Press. (p. 146)
Davis (1986) Statistics and data analysis in geology. 2nd ed., John Wiley & Sons.
Jammalamadaka, S. Rao and Sengupta, A. (2001). Topics in Circular Statistics, Sections 3.3.3 and 3.4.1, World Scientific Press, Singapore.
mean_resultant_length(), circular_sd_error()
# Example data from Davis (1986), pp. 316 finland_stria <- c( 23, 27, 53, 58, 64, 83, 85, 88, 93, 99, 100, 105, 113, 113, 114, 117, 121, 123, 125, 126, 126, 126, 127, 127, 128, 128, 129, 132, 132, 132, 134, 135, 137, 144, 145, 145, 146, 153, 155, 155, 155, 157, 163, 165, 171, 172, 179, 181, 186, 190, 212 ) confidence_angle(finland_stria, axial = FALSE) confidence_interval(finland_stria, axial = FALSE) data(san_andreas) data("nuvel1") PoR <- subset(nuvel1, nuvel1$plate.rot == "na") sa.por <- PoR_shmax(san_andreas, PoR, "right") confidence_angle(sa.por$azi.PoR, w = weighting(san_andreas$unc)) confidence_interval(sa.por$azi.PoR, w = weighting(san_andreas$unc))# Example data from Davis (1986), pp. 316 finland_stria <- c( 23, 27, 53, 58, 64, 83, 85, 88, 93, 99, 100, 105, 113, 113, 114, 117, 121, 123, 125, 126, 126, 126, 127, 127, 128, 128, 129, 132, 132, 132, 134, 135, 137, 144, 145, 145, 146, 153, 155, 155, 155, 157, 163, 165, 171, 172, 179, 181, 186, 190, 212 ) confidence_angle(finland_stria, axial = FALSE) confidence_interval(finland_stria, axial = FALSE) data(san_andreas) data("nuvel1") PoR <- subset(nuvel1, nuvel1$plate.rot == "na") sa.por <- PoR_shmax(san_andreas, PoR, "right") confidence_angle(sa.por$azi.PoR, w = weighting(san_andreas$unc)) confidence_interval(sa.por$azi.PoR, w = weighting(san_andreas$unc))
For large samples (n >=25) i performs are parametric estimate based on
sample_circular_dispersion(). For smaller size samples, it returns a
bootstrap estimate.
confidence_interval_fisher( x, conf.level = 0.95, w = NULL, axial = TRUE, na.rm = TRUE, boot = FALSE, R = 1000L, quiet = FALSE )confidence_interval_fisher( x, conf.level = 0.95, w = NULL, axial = TRUE, na.rm = TRUE, boot = FALSE, R = 1000L, quiet = FALSE )
x |
numeric vector. Values in degrees, for which the mean, median or standard deviation are required. |
conf.level |
Level of confidence: |
w |
(optional) Weights. A vector of positive numbers, of the same length as
|
axial |
logical. Whether the data are axial, i.e. pi-periodical
( |
na.rm |
logical value indicating whether |
boot |
logical. Force bootstrap estimation |
R |
positive integer. The number of bootstrap replicates (1000 by default). |
quiet |
logical. Prints the used estimation (parametric or bootstrap). |
list
N.I. Fisher (1993) Statistical Analysis of Circular Data, Cambridge University Press.
# Example data from Davis (1986), pp. 316 finland_stria <- c( 23, 27, 53, 58, 64, 83, 85, 88, 93, 99, 100, 105, 113, 113, 114, 117, 121, 123, 125, 126, 126, 126, 127, 127, 128, 128, 129, 132, 132, 132, 134, 135, 137, 144, 145, 145, 146, 153, 155, 155, 155, 157, 163, 165, 171, 172, 179, 181, 186, 190, 212 ) confidence_interval_fisher(finland_stria, axial = FALSE) confidence_interval_fisher(finland_stria, axial = FALSE, boot = TRUE) data(san_andreas) data("nuvel1") PoR <- subset(nuvel1, nuvel1$plate.rot == "na") sa.por <- PoR_shmax(san_andreas, PoR, "right") confidence_interval_fisher(sa.por$azi.PoR, w = weighting(san_andreas$unc)) confidence_interval_fisher(sa.por$azi.PoR, w = weighting(san_andreas$unc), boot = TRUE)# Example data from Davis (1986), pp. 316 finland_stria <- c( 23, 27, 53, 58, 64, 83, 85, 88, 93, 99, 100, 105, 113, 113, 114, 117, 121, 123, 125, 126, 126, 126, 127, 127, 128, 128, 129, 132, 132, 132, 134, 135, 137, 144, 145, 145, 146, 153, 155, 155, 155, 157, 163, 165, 171, 172, 179, 181, 186, 190, 212 ) confidence_interval_fisher(finland_stria, axial = FALSE) confidence_interval_fisher(finland_stria, axial = FALSE, boot = TRUE) data(san_andreas) data("nuvel1") PoR <- subset(nuvel1, nuvel1$plate.rot == "na") sa.por <- PoR_shmax(san_andreas, PoR, "right") confidence_interval_fisher(sa.por$azi.PoR, w = weighting(san_andreas$unc)) confidence_interval_fisher(sa.por$azi.PoR, w = weighting(san_andreas$unc), boot = TRUE)
Corrects the longitudes or latitudes to value between -180° and 180° or -90° and 90°
longitude_modulo(x) latitude_modulo(x)longitude_modulo(x) latitude_modulo(x)
x |
Longitude(s) or latitude(s) in degrees |
numeric
longitude_modulo(-361 + 5 * 360) # -1 latitude_modulo(-91 + 5 * 180) # 89longitude_modulo(-361 + 5 * 360) # -1 latitude_modulo(-91 + 5 * 180) # 89
Converts vector between Cartesian and geographical coordinate systems
cartesian_to_geographical(n) geographical_to_cartesian(p) geographical_to_spherical(p)cartesian_to_geographical(n) geographical_to_cartesian(p) geographical_to_spherical(p)
n |
Cartesian coordinates (x, y, z) as vector |
p |
Geographical coordinates (latitude, longitude) as vector |
Functions return a (2- or 3-dimensional) vector representing a point in the requested coordinate system.
cartesian_to_spherical() and spherical_to_cartesian() for
conversions to spherical coordinates
n <- c(1, -2, 3) cartesian_to_geographical(n) p <- c(50, 10) geographical_to_cartesian(p)n <- c(1, -2, 3) cartesian_to_geographical(n) p <- c(50, 10) geographical_to_cartesian(p)
Converts vector between Cartesian and spherical coordinate systems
cartesian_to_spherical(n) spherical_to_cartesian(p) spherical_to_geographical(p)cartesian_to_spherical(n) spherical_to_cartesian(p) spherical_to_geographical(p)
n |
Cartesian coordinates (x, y, z) as vector |
p |
Spherical coordinates (colatitude, azimuth) as two-column vector |
Functions return a (2- or 3-dimensional) vector representing a point in the requested coordinate system.
cartesian_to_geographical() and geographical_to_cartesian() for
conversions to geographical coordinates
n <- c(1, -2, 3) cartesian_to_spherical(n) # 36.699, -63.435 p <- c(50, 10) spherical_to_cartesian(p) # 0.75, 0.13, 0.64n <- c(1, -2, 3) cartesian_to_spherical(n) # 36.699, -63.435 p <- c(50, 10) spherical_to_cartesian(p) # 0.75, 0.13, 0.64
Compilation of global models for current plate motions, including NUVEL1 (DeMets et al. 1990), NNR-NUVEL1A (DeMets et al., 1990), NNR-MORVEL56 (Argus et al., 2011), REVEL (Sella et al., 2002), GSRM2.1 (Kreemer et al., 2014), HS2-NUVEL1 (Gripp and Gordon, 1990), HS3-NUVEL1A (Gripp and Gordon, 2002), P073 (Chase 1978), AM1-2 (Minster and Jordan, 1978), ITRF2020-PPM (Altamimi et al. 2023), and PB2002 (Bird, 2003)
data('cpm_models')data('cpm_models')
list containing objects of class data.frame
The rotating plate
The abbreviation of the plate's name
Coordinates of the Pole of Rotation
The amount of rotation (angle in 1 Myr)
The anchored plate, i.e. plate.rot moves relative
to plate.fix
Model for current global plate motion
Altamimi, Z., Métivier, L., Rebischung, P., Collilieux, X., Chanard, K., Barnéoud, J., 2023. ITRF2020 Plate Motion Model. Geophys. Res. Lett. 50, 1–7. doi:10.1029/2023GL106373
Argus, D.F., Gordon, R.G., 1991. No-net-rotation model of current plate velocities incorporating plate motion model NUVEL-1. Geophys. Res. Lett. 18, 2039–2042. doi: 10.1029/91GL01532
Argus, D. F., Gordon, R. G., & DeMets, C. (2011). Geologically current motion of 56 plates relative to the no-net-rotation reference frame. Geochemistry, Geophysics, Geosystems, 12(11). 10.1029/2011GC003751.
Chase, C.G. (1978). Plate kinematics: The Americas, East Africa, and the rest of the world. Earth Planet. Sci. Lett. 37, 355–368. doi: doi:10.1016/0012-821X(78)90051-1
Bird, P. (2003), An updated digital model of plate boundaries, Geochem. Geophys. Geosyst., 4, 1027, doi: 10.1029/2001GC000252, 3.
DeMets, C., Gordon, R. G., Argus, D. F., & Stein, S. (1990). Current plate motions. Geophysical Journal International, 101(2), 425-478. doi:10.1111/j.1365-246X.1990.tb06579.x.
Gripp, A. E., & Gordon, R. G. (2002). Young tracks of hotspots and current plate velocities. Geophysical Journal International, 150(2), 321<U+2013>361. doi:10.1046/j.1365-246X.2002.01627.x.
Kreemer, C., Blewitt, G., & Klein, E. C. (2014). A geodetic plate motion and Global Strain Rate Model. Geochemistry, Geophysics, Geosystems, 15(10), 3849<U+2013>3889. doi: 10.1002/2014GC005407.
Minster, J. and Jorda, T. (1978). Present-day plate motions. Journal of Geophysical Research, 83, doi:10.1029/jb083ib11p05331.
Sella, G. F., Dixon, T. H., & Mao, A. (2002). REVEL: A model for Recent plate velocities from space geodesy. Journal of Geophysical Research: Solid Earth, 107(B4). doi: 10.1029/2000jb000033.
data("cpm_models") head(cpm_models[[1]])data("cpm_models") head(cpm_models[[1]])
Density, probability distribution function, quantiles, and random generation for the circular uniform distribution.
rcunif(n, axial = FALSE) dcunif(theta, axial = FALSE, log = FALSE) pcunif(theta, axial = FALSE, lower.tail = TRUE, log.p = FALSE) qcunif(p, axial = FALSE, lower.tail = TRUE, log.p = FALSE)rcunif(n, axial = FALSE) dcunif(theta, axial = FALSE, log = FALSE) pcunif(theta, axial = FALSE, lower.tail = TRUE, log.p = FALSE) qcunif(p, axial = FALSE, lower.tail = TRUE, log.p = FALSE)
n |
number of observations. If |
axial |
logical. Whether the data are axial, i.e. |
theta |
numeric. Angular value in degrees |
log, log.p
|
logical; if TRUE, probabilities p are given as log(p). |
lower.tail |
logical; if TRUE (default), probabilities are
|
p |
numeric. Vector of probabilities with values in |
dcunif gives the density,
pcunif gives the probability of circular uniform distribution function,
rcunif generates random deviates (in degrees), and
qcunif provides quantiles (in degrees).
set.seed(1) x <- rcunif(5) dcunif(x) dcunif(x, axial = TRUE) pcunif(x) qcunif(c(.25, .5, .75))set.seed(1) x <- rcunif(5) dcunif(x) dcunif(x, axial = TRUE) pcunif(x) qcunif(c(.25, .5, .75))
Convenience function to add PoR coordinates and PoR azimuths to data
data2PoR(x, PoR)data2PoR(x, PoR)
x |
|
PoR |
|
sf object in PoR CRS with additional columns lon.PoR,
lat.PoR, and azi.PoR
por <- subset(nuvel1, nuvel1$plate.rot == "na") data2PoR(san_andreas, por)por <- subset(nuvel1, nuvel1$plate.rot == "na") data2PoR(san_andreas, por)
Normalizes the angle between two directions to the acute angle in between, i.e. angles between 0 and 90°
deviation_norm(x, y = NULL)deviation_norm(x, y = NULL)
x, y
|
Minuend and subtrahend. Both numeric vectors of angles in degrees.
If |
numeric vector, acute angles between two directions, i.e. values between 0 and 90°
Tobias Stephan
deviation_norm(175, 5) deviation_norm(c(175, 95, 0), c(5, 85, NA)) deviation_norm(c(-5, 85, 95, 175, 185, 265, 275, 355, 365))deviation_norm(175, 5) deviation_norm(c(175, 95, 0), c(5, 85, NA)) deviation_norm(c(-5, 85, 95, 175, 185, 265, 275, 355, 365))
Calculate the angular difference between the observed and modeled direction
of maximum horizontal stresses () along
great circles, small circles, and
loxodromes of the relative plate motion's Euler pole
deviation_shmax(prd, obs)deviation_shmax(prd, obs)
prd |
|
obs |
Numeric vector containing the observed azimuth of
|
Deviation is positive for counterclockwise deviation of observed azimuth wrt. predicted azimuth.
An object of class data.frame
Deviation of observed stress from modeled
following
great circles
Small circles
Clockwise loxodromes
Counter-clockwise loxodromes
Tobias Stephan
Stephan, T., Enkelmann, E., and Kroner, U. "Analyzing the horizontal orientation of the crustal stress adjacent to plate boundaries". Sci Rep 13. 15590 (2023). doi:10.1038/s41598-023-42433-2.
model_shmax() to calculate the theoretical direction of
.
data("nuvel1") # North America relative to Pacific plate: PoR <- subset(nuvel1, nuvel1$plate.rot == "na") # the point where we want to model the SHmax direction: point <- data.frame(lat = 45, lon = 20) prd <- model_shmax(point, PoR) deviation_shmax(prd, obs = 90)data("nuvel1") # North America relative to Pacific plate: PoR <- subset(nuvel1, nuvel1$plate.rot == "na") # the point where we want to model the SHmax direction: point <- data.frame(lat = 45, lon = 20) prd <- model_shmax(point, PoR) deviation_shmax(prd, obs = 90)
Circular distance between two angles and circular dispersion of angles about a specified angle.
circular_distance(x, y, axial = TRUE, na.rm = TRUE) circular_dispersion( x, y = NULL, w = NULL, w.y = NULL, axial = TRUE, na.rm = TRUE ) circular_sd2(x, y, w = NULL, axial = TRUE, na.rm = TRUE)circular_distance(x, y, axial = TRUE, na.rm = TRUE) circular_dispersion( x, y = NULL, w = NULL, w.y = NULL, axial = TRUE, na.rm = TRUE ) circular_sd2(x, y, w = NULL, axial = TRUE, na.rm = TRUE)
x, y
|
vectors of numeric values in degrees. |
axial |
logical. Whether the data are axial, i.e. pi-periodical
( |
na.rm |
logical value indicating whether |
w, w.y
|
(optional) Weights. A vector of positive numbers and of the same
length as |
Circular dispersion is a measure for the spread of data like the variance.
Dispersion measures the spread about a given angles, whereas
the variance measures the spread about the mean (Mardia and Jupp, 1999). When
y = NULL the dispersion is identical to the variance.
Circular standard deviation in circular_sd2() is the transformed dispersion
instead of the variance as for circular_sd().
circular_distance returns a numeric vector of positive numbers,
circular_dispersion and circular_sd2() return a positive number.
If y is NULL, than the circular variance is returned.
Mardia, K.V. (1972). Statistics of Directional Data: Probability and Mathematical Statistics. London: Academic Press.
Mardia, K.V., and Jupp, P.E (1999). Directional Statistics, Wiley Series in Probability and Statistics. John Wiley & Sons, Inc., Hoboken, NJ, USA. doi:10.1002/9780470316979
circular_mean(), circular_var().
a <- c(0, 2, 359, 6, 354) circular_distance(a, 10) # distance to single value b <- a + 90 circular_distance(a, b) # distance to multiple values data("nuvel1") PoR <- subset(nuvel1, nuvel1$plate.rot == "na") sa.por <- PoR_shmax(san_andreas, PoR, "right") circular_dispersion(sa.por$azi.PoR, y = 135) circular_dispersion(sa.por$azi.PoR, y = 135, w = weighting(san_andreas$unc)) circular_sd2(sa.por$azi.PoR, y = 135, w = weighting(san_andreas$unc))a <- c(0, 2, 359, 6, 354) circular_distance(a, 10) # distance to single value b <- a + 90 circular_distance(a, b) # distance to multiple values data("nuvel1") PoR <- subset(nuvel1, nuvel1$plate.rot == "na") sa.por <- PoR_shmax(san_andreas, PoR, "right") circular_dispersion(sa.por$azi.PoR, y = 135) circular_dispersion(sa.por$azi.PoR, y = 135, w = weighting(san_andreas$unc)) circular_sd2(sa.por$azi.PoR, y = 135, w = weighting(san_andreas$unc))
Returns the great circle distance between a location and all grid point in km
dist_greatcircle( lat1, lon1, lat2, lon2, r = earth_radius(), method = c("haversine", "orthodrome", "vincenty", "euclidean") )dist_greatcircle( lat1, lon1, lat2, lon2, r = earth_radius(), method = c("haversine", "orthodrome", "vincenty", "euclidean") )
lat1, lon1
|
numeric vector. coordinate of point(s) 1 (degrees). |
lat2, lon2
|
numeric vector. coordinates of point(s) 2 (degrees). |
r |
numeric. radius of the sphere (default = 6371.0087714 km, i.e. the radius of the Earth) |
method |
Character. Formula for calculating great circle distance, one of:
|
numeric vector with length equal to length(lat1) or length(lat2)
orthodrome(), haversine(), vincenty()
# Haversine: (4149.157, 2296.583) km dist_greatcircle(lat1 = 20, lon1 = 12, lat2 = c(50, 30), lon2 = c(40, 32)) # Orthodrome: (4149.157, 2296.583) km dist_greatcircle( lat1 = 20, lon1 = 12, lat2 = c(50, 30), lon2 = c(40, 32), method = "orthodrome" ) # Vincenty: (4149.157, 2296.583) km dist_greatcircle( lat1 = 20, lon1 = 12, lat2 = c(50, 30), lon2 = c(40, 32), method = "vincenty" ) # Euclidean (4076.220, 2284.169) km dist_greatcircle( lat1 = 20, lon1 = 12, lat2 = c(50, 30), lon2 = c(40, 32), method = "euclidean" )# Haversine: (4149.157, 2296.583) km dist_greatcircle(lat1 = 20, lon1 = 12, lat2 = c(50, 30), lon2 = c(40, 32)) # Orthodrome: (4149.157, 2296.583) km dist_greatcircle( lat1 = 20, lon1 = 12, lat2 = c(50, 30), lon2 = c(40, 32), method = "orthodrome" ) # Vincenty: (4149.157, 2296.583) km dist_greatcircle( lat1 = 20, lon1 = 12, lat2 = c(50, 30), lon2 = c(40, 32), method = "vincenty" ) # Euclidean (4076.220, 2284.169) km dist_greatcircle( lat1 = 20, lon1 = 12, lat2 = c(50, 30), lon2 = c(40, 32), method = "euclidean" )
Circular summary statistics over intervals of distances.
distance_binned_stats( azi, distance, n.breaks = 10, width.breaks = NULL, unc = NULL, prd = NULL, prd.error = NULL, kappa = 2, R = 1000, conf.level = 0.95, ... )distance_binned_stats( azi, distance, n.breaks = 10, width.breaks = NULL, unc = NULL, prd = NULL, prd.error = NULL, kappa = 2, R = 1000, conf.level = 0.95, ... )
azi |
numeric. Azimuth values in degrees. |
distance |
numeric. the independent variable along the values in |
n.breaks |
numeric. number (greater than or equal to 2) giving the
number of equal-sized intervals into which |
width.breaks |
numeric. The width of the intervals into which |
unc |
(optional) Uncertainties of |
prd |
(optional) numeric. A predicted orientation in degrees. |
prd.error |
(optional) numeric. The uncertainty of the predicted orientation in degrees. |
kappa |
numeric. Concentration parameter applied for the circular mode. |
R |
integer. Number of bootstrap iterates for estimating the error of the dispersion. |
conf.level |
The level of confidence for confidence interval and bootstrapped standard error of dispersion. |
... |
optional arguments passed to |
tibble containing the n values for aziin each bin, min/median/max
distance of the bin, and the summary statistics for azi.
If prd is specified, the normal Chi-squared statistic, dispersion and its
standard error are returned as well.
circular_summary(), circular_dispersion(), and circular_dispersion_boot()
data("plates") plate_boundary <- subset(plates, plates$pair == "na-pa") data("san_andreas") PoR <- subset(nuvel1, nuvel1$plate.rot == "na") san_andreas$distance <- distance_from_pb( x = san_andreas, PoR = PoR, pb = plate_boundary, tangential = TRUE ) dat <- san_andreas |> cbind(PoR_shmax(san_andreas, PoR, "right")) distance_binned_stats(dat$azi.PoR, distance = dat$distance, width.breaks = 1, unc = dat$unc, prd = 135 ) |> head()data("plates") plate_boundary <- subset(plates, plates$pair == "na-pa") data("san_andreas") PoR <- subset(nuvel1, nuvel1$plate.rot == "na") san_andreas$distance <- distance_from_pb( x = san_andreas, PoR = PoR, pb = plate_boundary, tangential = TRUE ) dat <- san_andreas |> cbind(PoR_shmax(san_andreas, PoR, "right")) distance_binned_stats(dat$azi.PoR, distance = dat$distance, width.breaks = 1, unc = dat$unc, prd = 135 ) |> head()
Absolute distance of data points from the nearest plate boundary
distance_from_pb(x, PoR, pb, tangential = FALSE, km = FALSE, ...)distance_from_pb(x, PoR, pb, tangential = FALSE, km = FALSE, ...)
x |
|
PoR |
Pole of Rotation. |
pb |
|
tangential |
Logical. Whether the plate boundary is a tangential
boundary ( |
km |
Logical. Whether the distance is expressed in kilometers
( |
... |
optional arguments passed to |
The distance to the plate boundary is the longitudinal or latitudinal difference between the data point and the plate boundary (along the closest latitude or longitude) for inward/outward or tangential plate boundaries, respectively.
Numeric vector of the great circle distances in units defined by km.
Stresses emanate from the plate boundary along great circles, small circles or loxodromes associated with the pole of rotation. Hence the emanation distance is not necessarily the shortest distance to the plate boundary, which is measured along a great circle unrelated to the pole of rotation. The differences are particularly notable when the plate boundary is kinked or for convergent and divergent plate boundaries.
Wdowinski, S. (1998). A theory of intraplate tectonics. Journal of Geophysical Research: Solid Earth, 103(3), 5037<U+2013>5059. http://dx.doi.org/10.1029/97JB03390
data("nuvel1") na_pa <- subset(nuvel1, nuvel1$plate.rot == "na") data("plates") plate_boundary <- subset(plates, plates$pair == "na-pa") data("san_andreas") res <- distance_from_pb( x = san_andreas, PoR = na_pa, pb = plate_boundary, tangential = TRUE ) head(res) res.km <- distance_from_pb( x = san_andreas, PoR = na_pa, pb = plate_boundary, tangential = TRUE, km = TRUE ) range(res.km)data("nuvel1") na_pa <- subset(nuvel1, nuvel1$plate.rot == "na") data("plates") plate_boundary <- subset(plates, plates$pair == "na-pa") data("san_andreas") res <- distance_from_pb( x = san_andreas, PoR = na_pa, pb = plate_boundary, tangential = TRUE ) head(res) res.km <- distance_from_pb( x = san_andreas, PoR = na_pa, pb = plate_boundary, tangential = TRUE, km = TRUE ) range(res.km)
IERS mean radius of Earth in km (based on WGS 84)
earth_radius()earth_radius()
numeric value
Transforms a sequence of rotations into a new reference system
equivalent_rotation(x, fixed, rot)equivalent_rotation(x, fixed, rot)
x |
Object of class
|
fixed |
plate that will be regarded as fixed. Has to be one out of
|
rot |
(optional) plate that will be regarded as rotating. Has to be one out of
|
sequence of plate rotations in new reference system. Same object
class as x
data(nuvel1) # load the NUVEL1 rotation parameters # all nuvel1 rotation equivalent to fixed Africa: equivalent_rotation(nuvel1, fixed = "af") # relative plate motion between Eurasia and India: equivalent_rotation(nuvel1, "eu", "in") # lat = 24.58, lon = 18.07, angle = 0.528data(nuvel1) # load the NUVEL1 rotation parameters # all nuvel1 rotation equivalent to fixed Africa: equivalent_rotation(nuvel1, fixed = "af") # relative plate motion between Eurasia and India: equivalent_rotation(nuvel1, "eu", "in") # lat = 24.58, lon = 18.07, angle = 0.528
Estimates the concentration parameter of a von Mises distribution, given a set of angular measurements.
est.kappa.MLE(x, w = NULL, bias = FALSE) est.kappa(x, w = NULL, p = 2)est.kappa.MLE(x, w = NULL, bias = FALSE) est.kappa(x, w = NULL, p = 2)
x |
numeric. Angles in degrees |
w |
numeric. Weightings |
bias |
logical parameter determining whether a bias correction is used
in the computation of the MLE. Default for bias is |
p |
integer. Number of parameters in the data space: 2 for circle (the default), 3 for a sphere. |
est.kappa.MLE() is the maximum likelihood estimate for MLE for .
est.kappa() uses an approximation based on the empirical equation:
where is the mean resultant length and is the
dimensionality of the data (2 for circular data).
numeric. Concentration of a von Mises distribution
set.seed(123) x <- rvm(100, 90, 10) w <- weighting(runif(100, 0, 10)) est.kappa(x, w) est.kappa.MLE(x, w)set.seed(123) x <- rvm(100, 90, 10) w <- weighting(runif(100, 0, 10)) est.kappa(x, w) est.kappa.MLE(x, w)
Creates an object of the orientation of the Euler pole axis
euler_pole(x, y, z = NA, geo = TRUE, angle = NA)euler_pole(x, y, z = NA, geo = TRUE, angle = NA)
x |
latitude or x coordinate of Euler pole axis |
y |
longitude or y |
z |
z coordinate |
geo |
logical, |
angle |
(optional) Angle of rotation in degrees (CCW rotation if angle is positive) |
An object of class "euler.pole" containing the Euler pole
axis in both geographical and Cartesian coordinates and the angle of rotation
in radians.
euler_pole(90, 0, angle = 45) euler_pole(0, 0, 1, geo = FALSE)euler_pole(90, 0, angle = 45) euler_pole(0, 0, 1, geo = FALSE)
geom_azimuth() visualizes axial-directional vector fields using a geom to
produce a new graphical layer, which allows aesthetic options.
This layer can be overlaid on a map to improve visualisation of mapped data.
The geom draws line segments (spokes) centered at (x, y) with a given
orientation (angle in degrees) and length (radius). By default the spoke
is centered using PositionCenterSpoke, so that the given coordinates mark
the middle of the line. The azimuths are given as angles in degrees increasing clockwise from North.
geom_azimuth( mapping = NULL, data = NULL, stat = "azimuth", center = TRUE, radius = NULL, na.rm = FALSE, show.legend = NA, inherit.aes = TRUE, ... )geom_azimuth( mapping = NULL, data = NULL, stat = "azimuth", center = TRUE, radius = NULL, na.rm = FALSE, show.legend = NA, inherit.aes = TRUE, ... )
mapping |
Set of aesthetic mappings created by |
data |
A data frame. If |
stat |
The statistical transformation to use on the data. Defaults to
|
center |
Logical; if |
radius |
Length of spoke |
na.rm |
If |
show.legend |
Logical. Should this layer be included in the legends? |
inherit.aes |
If |
... |
Other arguments passed on to |
A ggplot2 layer that adds axis-like spokes.
geom_azimuth() understands the following aesthetics (required aesthetics in bold):
x
y
angle (in degrees, transformed internally)
radius
colour
alpha
linewidth
linetype
ggplot2::geom_spoke(), geom_azimuthpoint()
set.seed(20250411) df <- data.frame( x = runif(5), y = runif(5), angle_deg = rvm(5, mean = 90, kappa = 10), radius = runif(5, 0.1, 2) ) if (require("ggplot2")) { ggplot(df, aes(x, y)) + geom_azimuth(aes(angle = angle_deg), radius = .1, linewidth = 1.2, colour = "blue") if (require("grid")) { ggplot(df, aes(x, y, radius = radius)) + geom_azimuth(aes(angle = angle_deg), center = FALSE, colour = "red", arrow = grid::arrow()) } }set.seed(20250411) df <- data.frame( x = runif(5), y = runif(5), angle_deg = rvm(5, mean = 90, kappa = 10), radius = runif(5, 0.1, 2) ) if (require("ggplot2")) { ggplot(df, aes(x, y)) + geom_azimuth(aes(angle = angle_deg), radius = .1, linewidth = 1.2, colour = "blue") if (require("grid")) { ggplot(df, aes(x, y, radius = radius)) + geom_azimuth(aes(angle = angle_deg), center = FALSE, colour = "red", arrow = grid::arrow()) } }
geom_azimuthpoint() draws line segments (spokes) like geom_azimuth(), but also
places a point (marker) at the spoke's center (x, y).
Aesthetic rules:
linewidth, linetype affect the spoke only
shape affects the point only
colour, alpha affect both spoke and point
size sets the size of the point only
geom_azimuthpoint( mapping = NULL, data = NULL, stat = "identity", center = TRUE, na.rm = FALSE, show.legend = NA, inherit.aes = TRUE, size = 2, ... )geom_azimuthpoint( mapping = NULL, data = NULL, stat = "identity", center = TRUE, na.rm = FALSE, show.legend = NA, inherit.aes = TRUE, size = 2, ... )
mapping |
Set of aesthetic mappings created by |
data |
A data frame. If |
stat |
The statistical transformation to use on the data. Defaults to
|
center |
Logical; if |
na.rm |
If |
show.legend |
Logical. Should this layer be included in the legends? |
inherit.aes |
If |
size |
Size of the point marker (default = 2). |
... |
Other arguments passed on to |
A list of ggplot2 layers (spokes + points).
geom_azimuthpoint() understands the following aesthetics (required aesthetics in bold):
x
y
angle (in degrees, transformed internally; spoke only)
radius (spoke only)
colour (shared)
alpha (shared)
linewidth (spoke only)
linetype (spoke only)
shape (point only)
size (point only, or via argument)
fill (point only, for shapes that accept fill)
geom_azimuth(), ggplot2::geom_spoke(), ggplot2::geom_point()
set.seed(20250411) df <- data.frame( x = runif(5), y = runif(5), angle_deg = rvm(5, mean = 90, kappa = 10), radius = runif(5, 0.1, 1), group = rep(1:2, length.out = 5) ) if (require("ggplot2")) { ggplot(data = df, aes(x, y, angle = angle_deg, radius = radius)) + geom_azimuthpoint(aes(colour = factor(group), shape = factor(group)), linewidth = 1.1, linetype = "dashed", size = 3, alpha = 0.8 ) }set.seed(20250411) df <- data.frame( x = runif(5), y = runif(5), angle_deg = rvm(5, mean = 90, kappa = 10), radius = runif(5, 0.1, 1), group = rep(1:2, length.out = 5) ) if (require("ggplot2")) { ggplot(data = df, aes(x, y, angle = angle_deg, radius = radius)) + geom_azimuthpoint(aes(colour = factor(group), shape = factor(group)), linewidth = 1.1, linetype = "dashed", size = 3, alpha = 0.8 ) }
Calculate initial bearing (or forward azimuth/direction) to go
from point a to point b following great circle arc on a
sphere.
get_azimuth(lat_a, lon_a, lat_b, lon_b)get_azimuth(lat_a, lon_a, lat_b, lon_b)
lat_a, lat_b
|
Numeric. Latitudes of a and b (in degrees). |
lon_a, lon_b
|
Numeric. Longitudes of a and b (in degrees). |
get_azimuth() is based on the spherical law of tangents.
This formula is for the initial bearing (sometimes referred to as
forward azimuth) which if followed in a straight line along a great circle
arc will lead from the start point a to the end point b.
where is the start point, ,
the end point ( is the difference in
longitude).
numeric. Azimuth in degrees
http://www.movable-type.co.uk/scripts/latlong.html
berlin <- c(52.517, 13.4) # Berlin tokyo <- c(35.7, 139.767) # Tokyo get_azimuth(berlin[1], berlin[2], tokyo[1], tokyo[2]) # 41.57361berlin <- c(52.517, 13.4) # Berlin tokyo <- c(35.7, 139.767) # Tokyo get_azimuth(berlin[1], berlin[2], tokyo[1], tokyo[2]) # 41.57361
Directions of 10 pidgeons, example data from Mardia and Jupp (1999), pp. 93
numeric vector of length 10
Mardia and Jupp (1999). Directional Statistics. John Wiley and Sons.
data("homing") homingdata("homing") homing
Download WSM2025 or WSM2016 database from the GFZ sever and applies optional filters.
If destdir is specified, the data can be reloaded in a later R session
using load_WSM() using the same arguments.
download_WSM( destdir = tempdir(), load = TRUE, version = c("2025", "2016"), ... ) load_WSM( file, quality = c("A", "B", "C", "D", "E", "X"), lat_range = c(-90, 90), lon_range = c(-180, 180), depth_range = c(-Inf, Inf), type = c("BO", "BOC", "BOT", "BS", "DIF", "FMA", "FMF", "FMS", "GFI", "GFM", "GFS", "GVA", "HF", "HFG", "HFM", "HFH", "HFP", "HFS", "OC", "PC", "SWB", "SWL", "SWS"), regime = c("N", "NS", "T", "TS", "S", NA) ) download_WSM2016(destdir = tempdir(), load = TRUE, ...) load_WSM2016( file, quality = c("A", "B", "C", "D", "E"), lat_range = c(-90, 90), lon_range = c(-180, 180), depth_range = c(-Inf, Inf), type = c("BO", "BOC", "BOT", "BS", "DIF", "FMA", "FMF", "FMS", "GFI", "GFM", "GFS", "GVA", "HF", "HFG", "HFM", "HFP", "OC", "PC", "SWB", "SWL", "SWS"), regime = c("N", "NS", "T", "TS", "S", NA) )download_WSM( destdir = tempdir(), load = TRUE, version = c("2025", "2016"), ... ) load_WSM( file, quality = c("A", "B", "C", "D", "E", "X"), lat_range = c(-90, 90), lon_range = c(-180, 180), depth_range = c(-Inf, Inf), type = c("BO", "BOC", "BOT", "BS", "DIF", "FMA", "FMF", "FMS", "GFI", "GFM", "GFS", "GVA", "HF", "HFG", "HFM", "HFH", "HFP", "HFS", "OC", "PC", "SWB", "SWL", "SWS"), regime = c("N", "NS", "T", "TS", "S", NA) ) download_WSM2016(destdir = tempdir(), load = TRUE, ...) load_WSM2016( file, quality = c("A", "B", "C", "D", "E"), lat_range = c(-90, 90), lon_range = c(-180, 180), depth_range = c(-Inf, Inf), type = c("BO", "BOC", "BOT", "BS", "DIF", "FMA", "FMF", "FMS", "GFI", "GFM", "GFS", "GVA", "HF", "HFG", "HFM", "HFP", "OC", "PC", "SWB", "SWL", "SWS"), regime = c("N", "NS", "T", "TS", "S", NA) )
destdir |
where to save files, defaults to |
load |
|
version |
character. Version of the World stress map database. Either
|
... |
(optional) arguments passed to |
file |
the name of the file which the data are to be read from. |
quality |
a character vectors containing the quality levels to be included. Includes all quality ranks (A-X) by default. |
lat_range, lon_range
|
two-element numeric vectors giving the range of latitudes and longitudes (in degrees). |
depth_range |
two-element numeric vectors giving the depth interval (in km) |
type |
a character vectors containing the methods of stress inversion to be included. Includes all methods by default. See WSM2016 manual for used acronyms. |
regime |
a character vectors containing the stress regimes to be
included. Acronyms: |
sf object of and the parsed numeric uncertainty (unc) based on
the reported standard deviation and the quality rank. If load=FALSE,
the path to the downloaded file is returned.
Because of R-compatibility and easy readability reasons, the downloaded
dataset is a modified version of the original, WSM server version:
All column names have been changed from uppercase (in the original dataset) to
lowercase characters.
Unknown azimuth values are represented by NA values instead of 999 in
the original.
Unknown regimes are represented by NA instead of "U" in the original.
https://datapub.gfz.de/download/10.5880.WSM.2025.001-Scbwez/WSM_Database_2025.csv
https://datapub.gfz-potsdam.de/download/10.5880.WSM.2016.001/wsm2016.csv
Heidbach, O., M. Rajabi, X. Cui, K. Fuchs, B. M<U+00FC>ller, J. Reinecker, K. Reiter, M. Tingay, F. Wenzel, F. Xie, M. O. Ziegler, M.-L. Zoback, and M. D. Zoback (2018): The World Stress Map database release 2016: Crustal stress pattern across scales. Tectonophysics, 744, 484-498, doi:10.1016/j.tecto.2018.07.007.
Heidbach, Oliver; Rajabi, Mojtaba; Di Giacomo, Domenico; Harris, James; Lammers, Steffi; Morawietz, Sophia; Pierdominici, Simona; Reiter, Karsten; von Specht, Sebastian; Storchak, Dmitry; Ziegler, Moritz O. (2025): World Stress Map Database Release 2025. GFZ Data Services. doi:10.5880/WSM.2025.001
## Not run: download_WSM( quality = c("A", "B", "C"), lat_range = c(51, 72), lon_range = c(-180, -130), depth_range = c(0, 10), type = "FMS" ) ## End(Not run)## Not run: download_WSM( quality = c("A", "B", "C"), lat_range = c(51, 72), lon_range = c(-180, -130), depth_range = c(0, 10), type = "FMS" ) ## End(Not run)
Check if object is euler.pole
is.euler(x)is.euler(x)
x |
Object of class
|
logical
A statistical test used to determine whether a set of angular or circular data points (such as times of day, compass directions, or degrees) are spread out evenly around a circle or if they cluster in some way.
kuiper_test(x, alpha = 0, axial = TRUE, quiet = FALSE)kuiper_test(x, alpha = 0, axial = TRUE, quiet = FALSE)
x |
numeric vector. Values in degrees |
alpha |
Significance level of the test. Valid levels are |
axial |
logical. Whether the data are axial, i.e. |
quiet |
logical. Prints the test's decision. |
The Null Hypothesis (): The data are distributed completely uniformly
(randomly and evenly) around the circle.
The Alternative Hypothesis (): The data are not uniform and
show a preference, clustering, or pattern somewhere on the circle.
The Test Statistic (V or ): It measures the
greatest positive and negative differences between your data's empirical
cumulative distribution and a theoretical uniform distribution.
High Test Statistic / Low p-value (, typically 0.05):
You reject the null hypothesis. This means your data are not uniform; they
have a significant preferred direction, grouping, or non-random pattern on the circle.
Low Test Statistic / High p-value (): You fail to
reject the null hypothesis. There is no strong evidence to say the data are
different from a flat, uniform distribution. The points appear random across the circle.
list containing the test statistic statistic and the significance
level p.value.
Kuiper's test statistic is a rotation-invariant Kolmogorov-type test statistic. The critical values of a modified Kuiper's test statistic are used according to the tabulation given in Stephens (1970).
Other Tests:
ar_test(),
norm_chisq(),
rayleigh-test,
watson_test(),
watson_two_sample,
watson_wheeler_test_perm(),
weighted-rayleigh-test
# Example data from Mardia and Jupp (1999), pp. 93 kuiper_test(homing, alpha = .05) # San Andreas Fault Data: data(san_andreas) data("nuvel1") PoR <- subset(nuvel1, nuvel1$plate.rot == "na") sa.por <- PoR_shmax(san_andreas, PoR, "right") kuiper_test(sa.por$azi.PoR, alpha = .05)# Example data from Mardia and Jupp (1999), pp. 93 kuiper_test(homing, alpha = .05) # San Andreas Fault Data: data(san_andreas) data("nuvel1") PoR <- subset(nuvel1, nuvel1$plate.rot == "na") sa.por <- PoR_shmax(san_andreas, PoR, "right") kuiper_test(sa.por$azi.PoR, alpha = .05)
Extract azimuths of line segments
line_azimuth(x, warn = TRUE) lines_azimuths(x)line_azimuth(x, warn = TRUE) lines_azimuths(x)
x |
sf object of type |
warn |
logical; if |
It is recommended to perform line_azimuth() on single line objects, i.e.
type "LINESTRING", instead of "MULTILINESTRING". This is because the azimuth
of the last point of a line will be calculated to the first point of the
next line otherwise. This will cause a warning message (if warn = TRUE).
For "MULTILINESTRING" objects, use lines_azimuths().
sf object of type "POINT" with the columns and entries of the first row of x
data("plates") # one line: subset(plates, pair == "af-eu") |> smoothr::densify() |> line_azimuth() |> head() # multiple lines: lines_azimuths(plates[1:5, ]) |> head()data("plates") # one line: subset(plates, pair == "af-eu") |> smoothr::densify() |> line_azimuth() |> head() # multiple lines: lines_azimuths(plates[1:5, ]) |> head()
Measure of spread around the circle. It should be noted that:
If , then the data is completely spread around the circle.
If , the data is completely concentrated on one point.
mean_resultant_length(x, w = NULL, na.rm = TRUE)mean_resultant_length(x, w = NULL, na.rm = TRUE)
x |
numeric vector. Values in degrees, for which the mean, median or standard deviation are required. |
w |
(optional) Weights. A vector of positive numbers, of the same length as
|
na.rm |
logical value indicating whether |
numeric.
Mardia, K.V. (1972). Statistics of Directional Data: Probability and Mathematical Statistics. London: Academic Press.
# Example data from Davis (1986), pp. 316 finland_stria <- c( 23, 27, 53, 58, 64, 83, 85, 88, 93, 99, 100, 105, 113, 113, 114, 117, 121, 123, 125, 126, 126, 126, 127, 127, 128, 128, 129, 132, 132, 132, 134, 135, 137, 144, 145, 145, 146, 153, 155, 155, 155, 157, 163, 165, 171, 172, 179, 181, 186, 190, 212 ) mean_resultant_length(finland_stria, w = NULL, na.rm = FALSE) # 0.800# Example data from Davis (1986), pp. 316 finland_stria <- c( 23, 27, 53, 58, 64, 83, 85, 88, 93, 99, 100, 105, 113, 113, 114, 117, 121, 123, 125, 126, 126, 126, 127, 127, 128, 128, 129, 132, 132, 132, 134, 135, 137, 144, 145, 145, 146, 153, 155, 155, 155, 157, 163, 165, 171, 172, 179, 181, 186, 190, 212 ) mean_resultant_length(finland_stria, w = NULL, na.rm = FALSE) # 0.800
Models the direction of maximum horizontal stress
along great circles, small circles, and
loxodromes at a given point or points according to the relative plate motion
in the geographical coordinate reference system.
model_shmax(df, euler)model_shmax(df, euler)
df |
|
euler |
|
following great circles is the
(initial) bearing between the given point and the pole of relative plate
motion. along small circles, clockwise, and
counter-clockwise loxodromes is 90°, +45°, and +135° (or -45°)
to this great circle bearing, respectively.
data.frame
Azimuth of modeled following
great circles
Small circles
Clockwise loxodromes
Counter-clockwise loxodromes
Tobias Stephan
Stephan, T., Enkelmann, E., and Kroner, U. "Analyzing the horizontal orientation of the crustal stress adjacent to plate boundaries". Sci Rep 13. 15590 (2023). doi:10.1038/s41598-023-42433-2.
deviation_shmax() to compute the deviation of the modeled direction
from the observed direction of .
PoR_shmax() to calculate the azimuth of
in the pole of rotation reference system.
data("nuvel1") # North America relative to Pacific plate: euler <- subset(nuvel1, nuvel1$plate.rot == "na") # the point where we mant to model the SHmax direction: point <- data.frame(lat = 45, lon = 20) model_shmax(point, euler)data("nuvel1") # North America relative to Pacific plate: euler <- subset(nuvel1, nuvel1$plate.rot == "na") # the point where we mant to model the SHmax direction: point <- data.frame(lat = 45, lon = 20) model_shmax(point, euler)
A quantitative comparison between the predicted and observed directions of
is obtained by the calculation of the average
azimuth and by a normalized test (Wdowsinki, 1998)
norm_chisq(obs, prd, unc)norm_chisq(obs, prd, unc)
obs |
Numeric vector containing the observed azimuth of
|
prd |
Numeric vector containing the modeled azimuths of
|
unc |
Uncertainty of observed |
The normalized test is
The value of the chi-squared test statistic is a number between 0 and 1
indicating the quality of the predicted
directions. Low values
() indicate good agreement,
high values () indicate a systematic misfit between predicted and
observed directions.
Numeric vector
Wdowinski, S., 1998, A theory of intraplate tectonics. Journal of Geophysical Research: Solid Earth, 103, 5037-5059, doi: 10.1029/97JB03390.
Other Tests:
ar_test(),
kuiper_test(),
rayleigh-test,
watson_test(),
watson_two_sample,
watson_wheeler_test_perm(),
weighted-rayleigh-test
data("nuvel1") PoR <- subset(nuvel1, nuvel1$plate.rot == "na") # North America relative to # Pacific plate data(san_andreas) point <- data.frame(lat = 45, lon = 20) prd <- model_shmax(point, PoR) norm_chisq(obs = c(50, 40, 42), prd = prd$sc, unc = c(10, NA, 5)) data(san_andreas) prd2 <- PoR_shmax(san_andreas, PoR, type = "right") norm_chisq(obs = prd2$azi.PoR, 135, unc = san_andreas$unc)data("nuvel1") PoR <- subset(nuvel1, nuvel1$plate.rot == "na") # North America relative to # Pacific plate data(san_andreas) point <- data.frame(lat = 45, lon = 20) prd <- model_shmax(point, PoR) norm_chisq(obs = c(50, 40, 42), prd = prd$sc, unc = c(10, NA, 5)) data(san_andreas) prd2 <- PoR_shmax(san_andreas, PoR, type = "right") norm_chisq(obs = prd2$azi.PoR, 135, unc = san_andreas$unc)
NNR-NUVEL-1 global model of current plate motions by DeMets et al. 1990
data('nuvel1')data('nuvel1')
An object of class data.frame
The rotating plate
The abbreviation of the plate's name
Coordinates of the Pole of Rotation
The amount of rotation (angle in 1 Myr)
The anchored plate, i.e. plate.rot moves relative
to plate.fix
Reference to underlying study
DeMets, C., Gordon, R. G., Argus, D. F., & Stein, S. (1990). Current plate motions. Geophysical Journal International, 101(2), 425-478. doi:10.1111/j.1365-246X.1990.tb06579.x.
data("nuvel1") head("nuvel1")data("nuvel1") head("nuvel1")
Global set of present plate boundaries on the Earth based on NUVEL-1 model by DeMets et al. 1990
data('nuvel1_plates')data('nuvel1_plates')
An object of class sf
DeMets, C., Gordon, R. G., Argus, D. F., & Stein, S. (1990). Current plate motions. Geophysical Journal International, 101(2), 425-478. doi:10.1111/j.1365-246X.1990.tb06579.x.
data("nuvel1_plates") head("nuvel1_plates")data("nuvel1_plates") head("nuvel1_plates")
Spectral decomposition of the 2D orientation tensor into two Eigenvectors and corresponding Eigenvalues provides provides a measure of location and a corresponding measure of dispersion, respectively.
ot_eigen2d(x, w = NULL, scale = FALSE) principal_direction(x, w = NULL) axial_strength(x, w = NULL) axial_dispersion(x, w = NULL)ot_eigen2d(x, w = NULL, scale = FALSE) principal_direction(x, w = NULL) axial_strength(x, w = NULL) axial_dispersion(x, w = NULL)
x |
numeric. Axial angular data (in degrees). |
w |
(optional) Weights. A vector of positive numbers, of the same length as
|
scale |
logical. Whether the Eigenvalues should be scaled so they sum up to 1. Only applicable when weighting are specified, otherwise the eigenvalues are always scaled. |
The Eigenvalues () can be
interpreted as the fractions of the variance explained by the
orientation of the associated Eigenvectors.
The two perpendicular Eigenvectors () are the "principal directions" with respect to the
highest and the lowest concentration of orientation data.
The strength of the orientation is the largest eigenvalue normalized
by the sum of the eigenvalues (scale=TRUE). Then is a
measure of dispersion of 2D orientation data with respect to .
ot_eigen2d returns a list of the Eigenvalues and the axial angles corresponding to the Eigenvectors.
principal_direction(), axial_strength() and axial_dispersion() are convenience functions
to return the orientation of the largest eigenvalue, the orientation strength, the axial dispersion respectively.
Eigenvalues and Eigenvectors of the orientation tensor (inertia tensor) are also called "principle moments of inertia" and "principle axes of inertia", respectively.
test <- rvm(100, mean = 0, k = 10) / 2 ot_eigen2d(test) data("nuvel1") PoR <- subset(nuvel1, nuvel1$plate.rot == "na") sa.por <- PoR_shmax(san_andreas, PoR, "right") sa_eig <- ot_eigen2d(sa.por$azi.PoR, w = weighting(san_andreas$unc), scale = TRUE) print(sa_eig) rose(sa.por$azi.PoR, muci = FALSE) rose_line(sa_eig$vectors, col = c("red", "green"), radius = sa_eig$values, lwd = 2 ) graphics::legend("topright", legend = round(sa_eig$values, 2), col = c("red", "green"), lty = 1 ) principal_direction(sa.por$azi.PoR) axial_strength(sa.por$azi.PoR) axial_dispersion(sa.por$azi.PoR)test <- rvm(100, mean = 0, k = 10) / 2 ot_eigen2d(test) data("nuvel1") PoR <- subset(nuvel1, nuvel1$plate.rot == "na") sa.por <- PoR_shmax(san_andreas, PoR, "right") sa_eig <- ot_eigen2d(sa.por$azi.PoR, w = weighting(san_andreas$unc), scale = TRUE) print(sa_eig) rose(sa.por$azi.PoR, muci = FALSE) rose_line(sa_eig$vectors, col = c("red", "green"), radius = sa_eig$values, lwd = 2 ) graphics::legend("topright", legend = round(sa_eig$values, 2), col = c("red", "green"), lty = 1 ) principal_direction(sa.por$azi.PoR) axial_strength(sa.por$azi.PoR) axial_dispersion(sa.por$azi.PoR)
2D orientation tensor characterizes distribution of axial angles using the Eigenvalue method (Watson 1966, Scheidegger 1965).
ortensor2d(x, w = NULL, norm = FALSE)ortensor2d(x, w = NULL, norm = FALSE)
x |
numeric. Axial angular data (in degrees). |
w |
(optional) Weights. A vector of positive numbers, of the same length as
|
norm |
logical. Whether the tensor should be normalized. |
The moment of inertia can be minimized by calculating the Cartesian coordinates of the orientation data, and calculating their covariance matrix. This yields
where is the Cartesian vector of the
orientations. Orientation tensor and the inertia tensor are
related by
where denotes the unit matrix, so that
2x2 matrix
Watson, G. S. (1966). The Statistics of Orientation Data. The Journal of Geology, 74(5), 786–797.
Scheidegger, A. E. (1964). The tectonic stress and tectonic motion direction in Europe and Western Asia as calculated from earthquake fault plane solutions. Bulletin of the Seismological Society of America, 54(5A), 1519–1528. doi:10.1785/BSSA05405A1519
Bachmann, F., Hielscher, R., Jupp, P. E., Pantleon, W., Schaeben, H., & Wegert, E. (2010). Inferential statistics of electron backscatter diffraction data from within individual crystalline grains. Journal of Applied Crystallography, 43(6), 1338–1355. https://doi.org/10.1107/S002188981003027X
test <- rvm(100, mean = 0, k = 10) ortensor2d(test)test <- rvm(100, mean = 0, k = 10) ortensor2d(test)
Assigns numeric values of the precision (sd.) of each measurement to the categorical quality ranking of the World Stress Map (A, B, C, D, E, X).
parse_wsm_quality(x) quantise_wsm_quality(x)parse_wsm_quality(x) quantise_wsm_quality(x)
x |
Either a string or a character/factor vector of WSM quality ranking |
"numeric". the standard deviation of stress azimuth
Heidbach, O., Barth, A., M<U+00FC>ller, B., Reinecker, J., Stephansson, O., Tingay, M., Zang, A. (2016). WSM quality ranking scheme, database description and analysis guidelines for stress indicator. World Stress Map Technical Report 16-01, GFZ German Research Centre for Geosciences. doi:10.2312/wsm.2016.001
parse_wsm_quality(c("A", "B", "C", "D", NA, "E", "X")) data("san_andreas") head(parse_wsm_quality(san_andreas$quality))parse_wsm_quality(c("A", "B", "C", "D", NA, "E", "X")) data("san_andreas") head(parse_wsm_quality(san_andreas$quality))
PB2002 global model of current plate motions by Bird 2003
data('pb2002')data('pb2002')
An object of class data.frame
The rotating plate
The abbreviation of the plate's name
Coordinates of the Pole of Rotation
The amount of rotation (angle in 1 Myr)
The anchored plate, i.e. plate.rot moves relative
to plate.fix
Reference to underlying study
Bird, P. (2003), An updated digital model of plate boundaries, Geochem. Geophys. Geosyst., 4, 1027, doi: 10.1029/2001GC000252, 3.
data("pb2002") head("pb2002")data("pb2002") head("pb2002")
Global set of present plate boundaries on the Earth based on PB2002 model by Bird (2003). Contains the plate boundary displacement types such as inward, outward, or tangentially displacement.
data('plates')data('plates')
An object of class sf
Bird, P. (2003), An updated digital model of plate boundaries, Geochem. Geophys. Geosyst., 4, 1027, doi: 10.1029/2001GC000252, 3.
data("plates") head("plates")data("plates") head("plates")
Plots multiples of a von Mises, wrapped Cauchy, and wrapped Normal density distribution in a circular plot
plot_density( x, bw = NULL, kernel = c("vonmises", "wrappedcauchy", "wrappednormal"), weights = NULL, axial = TRUE, n = 512L, norm.density = TRUE, kappa = NULL, rho = NULL, sd = NULL, c = NULL, fill = FALSE, scale = 0, shrink = 1, add = TRUE, main = NULL, labels = TRUE, at = seq(0, 360 - 45, 45), cborder = TRUE, grid = FALSE, ... )plot_density( x, bw = NULL, kernel = c("vonmises", "wrappedcauchy", "wrappednormal"), weights = NULL, axial = TRUE, n = 512L, norm.density = TRUE, kappa = NULL, rho = NULL, sd = NULL, c = NULL, fill = FALSE, scale = 0, shrink = 1, add = TRUE, main = NULL, labels = TRUE, at = seq(0, 360 - 45, 45), cborder = TRUE, grid = FALSE, ... )
x |
Either an object of class |
bw, kappa, rho, sd, c
|
numeric. Smoothing bandwidth expressed as the concentration
parameter |
kernel |
character. The smoothing kernel to be used; one of |
weights |
numeric. A vector of observation weights, of the same length as |
axial |
Logical. Whether data are uniaxial ( |
n |
integer. Number of equally spaced angles at which the density is to be estimated. |
norm.density |
logical. Normalize the density? |
fill |
logical. Whether to fill the density curve or draw just a line (the default) |
scale |
numeric. radius of plotted circle. Default is |
shrink |
numeric. parameter that controls the size of the plotted
function. Default is |
add |
logical. Add to existing plot? ( |
main |
a main title for the plot, see also |
labels |
Either a logical value indicating whether to plot labels next to the tick marks, or a vector of labels for the tick marks. |
at |
Optional vector of angles at which tick marks should be plotted.
Set |
cborder |
logical. Whether to plot the primitive of the circular plot ( |
grid |
logical. Whether a grid should be added. |
... |
Further graphical parameters may also be supplied as arguments. |
plot or calculated densities
Other circular-plot:
plot_points(),
rose(),
rose_geom,
rose_stats()
set.seed(20250411) # Filled von Mises kernel density curve inside the plot plot_density(san_andreas$azi, kappa = 100, fill = TRUE, col = "#51127C80", border = "#51127CFF", grid = TRUE, add = FALSE ) # Superimpose a wrapped Cauchy kernel distribution curve plot_density(san_andreas$azi, rho = 0.9, kernel = "wrappedcauchy", fill = FALSE, col = "#FB8861FF", add = TRUE ) # Superimpose a wrapped Normal kernel distribution curve plot_density(san_andreas$azi, sd = 2, kernel = "wrappednormal", fill = FALSE, col = "#E65164FF", add = TRUE ) # Superimpose a von Mises kernel density curve on a rose diagram: rose(san_andreas$azi, grid = TRUE) plot_density(san_andreas$azi, bw = 100, col = "#51127CFF", add = TRUE, lwd = 3 ) # Corona plot (density curve outside of a rose diagram plot): w <- weighting(san_andreas$unc) rose(san_andreas$azi, weights = w, dots = TRUE, stack = TRUE, dot_cex = 0.5, dot_pch = 21) plot_density(san_andreas$azi, weights = w, bw = 100, scale = 1.1, shrink = 3, xpd = NA, col = "#51127CFF" )set.seed(20250411) # Filled von Mises kernel density curve inside the plot plot_density(san_andreas$azi, kappa = 100, fill = TRUE, col = "#51127C80", border = "#51127CFF", grid = TRUE, add = FALSE ) # Superimpose a wrapped Cauchy kernel distribution curve plot_density(san_andreas$azi, rho = 0.9, kernel = "wrappedcauchy", fill = FALSE, col = "#FB8861FF", add = TRUE ) # Superimpose a wrapped Normal kernel distribution curve plot_density(san_andreas$azi, sd = 2, kernel = "wrappednormal", fill = FALSE, col = "#E65164FF", add = TRUE ) # Superimpose a von Mises kernel density curve on a rose diagram: rose(san_andreas$azi, grid = TRUE) plot_density(san_andreas$azi, bw = 100, col = "#51127CFF", add = TRUE, lwd = 3 ) # Corona plot (density curve outside of a rose diagram plot): w <- weighting(san_andreas$unc) rose(san_andreas$azi, weights = w, dots = TRUE, stack = TRUE, dot_cex = 0.5, dot_pch = 21) plot_density(san_andreas$azi, weights = w, bw = 100, scale = 1.1, shrink = 3, xpd = NA, col = "#51127CFF" )
Add points to a plot of circular data points on the current graphics device.
plot_points( x, axial = TRUE, stack = FALSE, binwidth = 1, cex = 1, sep = 0.025, jitter_factor = 0, ..., scale = 1.1, add = TRUE, main = NULL, labels = TRUE, at = seq(0, 360 - 45, 45), cborder = TRUE )plot_points( x, axial = TRUE, stack = FALSE, binwidth = 1, cex = 1, sep = 0.025, jitter_factor = 0, ..., scale = 1.1, add = TRUE, main = NULL, labels = TRUE, at = seq(0, 360 - 45, 45), cborder = TRUE )
x |
Data to be plotted. A numeric vector containing angles (in degrees). |
axial |
Logical. Whether data are uniaxial ( |
stack |
logical: if |
binwidth |
numeric. Bin width (in degrees) for the stacked dot plots.
ignored when |
cex |
character (or symbol) expansion: a numerical vector. This works as
a multiple of |
sep |
constant used to specify the distance between stacked points, if
|
jitter_factor |
numeric. Adds a small amount of random variation to the
location of each points along radius that is added to |
... |
Further graphical parameters may also be supplied as arguments. |
scale |
numeric. Scales radius of plotted dots Default is |
add |
logical. Add to existing plot? ( |
main |
a main title for the plot, see also |
labels |
Either a logical value indicating whether to plot labels next to the tick marks, or a vector of labels for the tick marks. |
at |
Optional vector of angles at which tick marks should be plotted.
Set |
cborder |
logical. Whether to plot the primitive of the circular plot ( |
A list with information on the plot
Other circular-plot:
plot_density(),
rose(),
rose_geom,
rose_stats()
set.seed(20250511) x <- rvm(100, mean = 90, k = 5) # plot poinit without jitter plot_points(x, add = FALSE) # with some jitter plot_points(x, jitter_factor = .2, add = FALSE) # stacked dots: plot_points(x, stack = TRUE, binwidth = 3, add = FALSE, xpd = TRUE)set.seed(20250511) x <- rvm(100, mean = 90, k = 5) # plot poinit without jitter plot_points(x, add = FALSE) # with some jitter plot_points(x, jitter_factor = .2, add = FALSE) # stacked dots: plot_points(x, stack = TRUE, binwidth = 3, add = FALSE, xpd = TRUE)
Transforms azimuths and models the direction of maximum
horizontal stress
in the Euler pole (Pole of Rotation)
coordinate reference system. When type of plate boundary is given, it also
gives the deviation from the theoretically predicted azimuth of
, the circular distance, and the normalized
statistics.
PoR_azimuth(x, PoR, axial = TRUE) PoR_shmax(x, PoR, type = c("none", "in", "out", "right", "left"), axial = TRUE)PoR_azimuth(x, PoR, axial = TRUE) PoR_shmax(x, PoR, type = c("none", "in", "out", "right", "left"), axial = TRUE)
x |
|
PoR |
|
axial |
logical. Whether the azimuth is axial (0-180°) or directional (0-360°). |
type |
Character. Type of plate boundary (optional). Can be
|
The theoretical azimuth of in the pole of
rotation reference system is
0 (or 180), 45, 90, 135° if the stress is sourced by an
outward, sinistral, inward, or dextral moving plate boundary, respectively.
directions of with respect to the four
plate boundary types.
PoR_azimuth returns numeric vector of the transformed azimuth in
degrees.
PoR_shmax returns either a numeric vector of the azimuths in the
transformed coordinate system (in degrees), or a "data.frame" with
azi.PoRthe transformed azimuths (in degrees),
prdthe predicted azimuths (in degrees),
devthe deviation between the transformed and the predicted azimuth in degrees (positive for counterclockwise deviation of observed azimuth wrt. predicted azimuth),
nchisqthe Norm test statistic, and
cdistthe angular distance between the transformed and the predicted azimuth.
Stephan, T., Enkelmann, E., and Kroner, U. "Analyzing the horizontal orientation of the crustal stress adjacent to plate boundaries". Sci Rep 13. 15590 (2023). doi:10.1038/s41598-023-42433-2.
model_shmax() to compute the theoretical direction of
in the geographical reference system.
deviation_shmax() to compute the deviation of the modeled direction
from the observed direction of .
norm_chisq() to calculate the normalized
statistics. circular_distance() to calculate the angular distance.
data("nuvel1") # North America relative to Pacific plate: PoR <- subset(nuvel1, nuvel1$plate.rot == "na") data("san_andreas") res <- PoR_shmax(san_andreas, PoR, type = "right") head(res)data("nuvel1") # North America relative to Pacific plate: PoR <- subset(nuvel1, nuvel1$plate.rot == "na") data("san_andreas") res <- PoR_shmax(san_andreas, PoR, type = "right") head(res)
Retrieve the PoR equivalent coordinates of an object
PoR_coordinates(x, PoR)PoR_coordinates(x, PoR)
x |
Can be either a |
PoR |
Pole of Rotation. |
PoR_coordinates() returns data.frame with the PoR coordinates
(lat.PoR, lon.PoR).
data("nuvel1") por <- subset(nuvel1, nuvel1$plate.rot == "na") # North America relative to Pacific plate data("san_andreas") # coordinates from sf object san_andreas.por_sf <- PoR_coordinates(san_andreas, por) head(san_andreas.por_sf) # coordinates from data.frame san_andreas.por_df <- PoR_coordinates(sf::st_drop_geometry(san_andreas), por) head(san_andreas.por_df)data("nuvel1") por <- subset(nuvel1, nuvel1$plate.rot == "na") # North America relative to Pacific plate data("san_andreas") # coordinates from sf object san_andreas.por_sf <- PoR_coordinates(san_andreas, por) head(san_andreas.por_sf) # coordinates from data.frame san_andreas.por_df <- PoR_coordinates(sf::st_drop_geometry(san_andreas), por) head(san_andreas.por_df)
Create the reference system transformed in Euler pole coordinate
PoR_crs(x)PoR_crs(x)
x |
|
The PoR coordinate reference system is oblique transformation of the geographical coordinate system with the Euler pole coordinates being the the translation factors.
Object of class crs
data("nuvel1") por <- subset(nuvel1, nuvel1$plate.rot == "na") # North America relative to Pacific plate PoR_crs(por)data("nuvel1") por <- subset(nuvel1, nuvel1$plate.rot == "na") # North America relative to Pacific plate PoR_crs(por)
Retrieve the (angular) great-circle distance between a point and the PoR (Euler pole).
PoR_distance(x, PoR, FUN = orthodrome)PoR_distance(x, PoR, FUN = orthodrome)
x |
Can be either a |
PoR |
Pole of Rotation. |
FUN |
function to calculate the great-circle distance.
|
numeric vector. Great-circle distance in degree
data("nuvel1") por <- subset(nuvel1, nuvel1$plate.rot == "na") # North America relative to Pacific plate data("san_andreas") # distance form sf object PoR_distance(san_andreas, por) |> head() # distance form data.frame PoR_distance(sf::st_drop_geometry(san_andreas), por) |> head() PoR_distance(sf::st_drop_geometry(san_andreas), por, FUN = orthodrome) |> head() PoR_distance(sf::st_drop_geometry(san_andreas), por, FUN = vincenty) |> head()data("nuvel1") por <- subset(nuvel1, nuvel1$plate.rot == "na") # North America relative to Pacific plate data("san_andreas") # distance form sf object PoR_distance(san_andreas, por) |> head() # distance form data.frame PoR_distance(sf::st_drop_geometry(san_andreas), por) |> head() PoR_distance(sf::st_drop_geometry(san_andreas), por, FUN = orthodrome) |> head() PoR_distance(sf::st_drop_geometry(san_andreas), por, FUN = vincenty) |> head()
Transforms the spatial data and azimuths into the PoR reference frame and shows them in a map
PoR_map( x, PoR, pb = NULL, type = c("none", "in", "out", "right", "left"), show.deviation = FALSE, ... )PoR_map( x, PoR, pb = NULL, type = c("none", "in", "out", "right", "left"), show.deviation = FALSE, ... )
x, pb
|
|
PoR |
Pole of Rotation. |
type |
Character. Type of plate boundary (optional). Can be
|
show.deviation |
logical.
Whether the data should be color-coded according to the deviation from the
prediction, or according to the stress regime? Is ignored if |
... |
optional arguments passed to |
plot
PoR_shmax(), axes(), tectonicr.colors()
data("nuvel1") na_pa <- subset(nuvel1, nuvel1$plate.rot == "na") data("plates") plate_boundary <- subset(plates, plates$pair == "na-pa") data("san_andreas") PoR_map(san_andreas, PoR = na_pa, pb = plate_boundary, type = "right", show.deviation = TRUE)data("nuvel1") na_pa <- subset(nuvel1, nuvel1$plate.rot == "na") data("plates") plate_boundary <- subset(plates, plates$pair == "na-pa") data("san_andreas") PoR_map(san_andreas, PoR = na_pa, pb = plate_boundary, type = "right", show.deviation = TRUE)
The data is transformed into the PoR system before the interpolation. The interpolation grid is returned in geographical coordinates and azimuths.
PoR_stress2grid( x, PoR, grid = NULL, PoR_grid = TRUE, lon_range = NULL, lat_range = NULL, gridsize = 2.5, remove_PoR = FALSE, ... ) PoR_stress2grid_stats( x, PoR, grid = NULL, PoR_grid = TRUE, lon_range = NULL, lat_range = NULL, gridsize = 2.5, remove_PoR = FALSE, ... )PoR_stress2grid( x, PoR, grid = NULL, PoR_grid = TRUE, lon_range = NULL, lat_range = NULL, gridsize = 2.5, remove_PoR = FALSE, ... ) PoR_stress2grid_stats( x, PoR, grid = NULL, PoR_grid = TRUE, lon_range = NULL, lat_range = NULL, gridsize = 2.5, remove_PoR = FALSE, ... )
x |
|
PoR |
Pole of Rotation. |
grid |
(optional) Point object of class |
PoR_grid |
logical. Whether the grid should be generated based on the
coordinate range in the PoR ( |
lon_range, lat_range
|
(optional) numeric vector specifying the minimum
and maximum longitudes and latitudes (are ignored if |
gridsize |
Numeric. Target spacing of the regular grid in decimal
degree. Default is |
remove_PoR |
logical. Whether PoR azimuths and coordinates will be removed from final output or not (the default.) |
... |
Arguments passed to |
Stress field and wavelength analysis in PoR system and back-transformed
sf object containing
longitude and latitude in geographical CRS (in degrees)
longitude and latitude in PoR CRS (in degrees).
Only if remove_PoR=TRUE
geographical mean in degree
PoR mean in degree. Only if remove_PoR=TRUE
Standard deviation of in degrees
Search radius in km
Mean distance of datapoints per search radius
Number of data points in search radius
data("san_andreas") data("nuvel1") PoR <- subset(nuvel1, nuvel1$plate.rot == "na") PoR_stress2grid(san_andreas, PoR) |> head() ## Not run: PoR_stress2grid_stats(san_andreas, PoR, mode = TRUE) |> head() ## End(Not run)data("san_andreas") data("nuvel1") PoR <- subset(nuvel1, nuvel1$plate.rot == "na") PoR_stress2grid(san_andreas, PoR) |> head() ## Not run: PoR_stress2grid_stats(san_andreas, PoR, mode = TRUE) |> head() ## End(Not run)
Transformation from spherical PoR to geographical coordinate system and vice versa
geographical_to_PoR(x, PoR) PoR_to_geographical(x, PoR)geographical_to_PoR(x, PoR) PoR_to_geographical(x, PoR)
x |
Can be either a |
PoR |
Pole of Rotation. |
object of same type of x with the transformed coordinates. If x
was a data.frame, transformed coordinates are named lat.PoR and lon.PoR for PoR CRS,
or lat and lon for geographical CRS).
data("nuvel1") por <- subset(nuvel1, nuvel1$plate.rot == "na") # North America relative to Pacific plate data("san_andreas") san_andreas.por <- geographical_to_PoR(san_andreas, por) head(san_andreas.por) head(PoR_to_geographical(san_andreas.por, por))data("nuvel1") por <- subset(nuvel1, nuvel1$plate.rot == "na") # North America relative to Pacific plate data("san_andreas") san_andreas.por <- geographical_to_PoR(san_andreas, por) head(san_andreas.por) head(PoR_to_geographical(san_andreas.por, por))
Conversion of PoR azimuths into geographical azimuths
PoR2Geo_azimuth(x, PoR, axial = TRUE)PoR2Geo_azimuth(x, PoR, axial = TRUE)
x |
|
PoR |
|
axial |
logical. Whether the azimuth is axial (0-180°) or directional (0-360°). |
numeric vector of transformed azimuths (in degrees)
Stephan, T., Enkelmann, E., and Kroner, U. "Analyzing the horizontal orientation of the crustal stress adjacent to plate boundaries". Sci Rep 13. 15590 (2023). doi:10.1038/s41598-023-42433-2.
data("nuvel1") # North America relative to Pacific plate: PoR <- subset(nuvel1, nuvel1$plate.rot == "na") data("san_andreas") san_andreas$azi.PoR <- PoR_shmax(san_andreas, PoR) # convert back to geo CRS PoR2Geo_azimuth(san_andreas, PoR) |> head()data("nuvel1") # North America relative to Pacific plate: PoR <- subset(nuvel1, nuvel1$plate.rot == "na") data("san_andreas") san_andreas$azi.PoR <- PoR_shmax(san_andreas, PoR) # convert back to geo CRS PoR2Geo_azimuth(san_andreas, PoR) |> head()
The maximum error in the model's predicted azimuth given the Pole of rotations uncertainty and distance of the data point to the pole.
prd_err(dist_PoR, sigma_PoR = 1)prd_err(dist_PoR, sigma_PoR = 1)
dist_PoR |
Distance to Euler pole (great circle distance, in degree) |
sigma_PoR |
uncertainty of the position of the Pole of rotation (in degree). |
numeric vector. The maximum error for azimuths prediction (in degree)
Ramsay, J.A. Folding and fracturing of rocks. McGraw-Hill, New York, 1967.
PoR_shmax() and model_shmax() for the model's prediction, and
orthodrome() for great circle distances.
prd_err(67, 1) # San Andreas example: data("nuvel1") por <- subset(nuvel1, nuvel1$plate.rot == "na") # North America relative to Pacific plate data("san_andreas") d <- PoR_distance(san_andreas, por) prd_err(d)prd_err(67, 1) # San Andreas example: data("nuvel1") por <- subset(nuvel1, nuvel1$plate.rot == "na") # North America relative to Pacific plate data("san_andreas") d <- PoR_distance(san_andreas, por) prd_err(d)
The fault's strike in the PoR CRS projected on the data point along the predicted stress trajectories.
projected_pb_strike(x, PoR, pb, tangential = FALSE, ...)projected_pb_strike(x, PoR, pb, tangential = FALSE, ...)
x, pb
|
|
PoR |
Pole of Rotation. |
tangential |
Logical. Whether the plate boundary is a tangential
boundary ( |
... |
optional arguments passed to |
Useful to calculate the beta angle, i.e. the angle
between direction (in PoR CRS!) and the fault's strike (in PoR CRS).
The beta angle is the same in geographical and PoR coordinates.
Numeric vector of the strike direction of the plate boundary (in degree)
The algorithm calculates the great circle bearing between line vertices. Since transform plate boundaries represent small circle lines in the PoR system, this great-circle azimuth is only a approximation of the true (small-circle) azimuth.
data("nuvel1") na_pa <- subset(nuvel1, nuvel1$plate.rot == "na") data("plates") plate_boundary <- subset(plates, plates$pair == "na-pa") data("san_andreas") res <- projected_pb_strike( x = san_andreas, PoR = na_pa, pb = plate_boundary, tangential = TRUE ) head(res) head(san_andreas$azi - res) # beta angledata("nuvel1") na_pa <- subset(nuvel1, nuvel1$plate.rot == "na") data("plates") plate_boundary <- subset(plates, plates$pair == "na-pa") data("san_andreas") res <- projected_pb_strike( x = san_andreas, PoR = na_pa, pb = plate_boundary, tangential = TRUE ) head(res) head(san_andreas$azi - res) # beta angle
Creates a set of plots including the azimuth as a function of the distance to the plate boundary, the Norm Chi-squared as a function of the distance to the plate boundary, the circular distance (and dispersion) a function of the distance to the plate boundary, a von-Mises QQ plot, and a rose diagram of the quality-weighted frequency distribution of the azimuths.
quick_plot(azi, distance, prd, unc = NULL, regime, width = 51)quick_plot(azi, distance, prd, unc = NULL, regime, width = 51)
azi |
numeric. Azimuth of |
distance |
numeric. Distance to plate boundary |
prd |
numeric. the predicted direction of |
unc |
numeric. Uncertainty of observed |
regime |
character vector. The stress regime (following the classification of the World Stress Map) |
width |
integer. window width (in number of observations) for moving
average of the azimuths, circular dispersion, and Norm Chi-square statistics.
If |
Plot 1 shows the transformed azimuths as a function of the distance to the plate boundary. The red line indicates the rolling circular mean, stippled red lines indicate the 95% confidence interval about the mean.
Plot 2 shows the normalized statistics as a
function of the distance to the plate boundary. The red line shows the
rolling statistic.
Plot 3 shows the circular distance of the transformed azimuths to the predicted azimuth, as a function of the distance to the plate boundary. The red line shows the rolling circular dispersion about the prediction.
Plot 4 give the rose diagram of the transformed azimuths.
four R base plots
PoR_shmax(), distance_from_pb(), circular_mean(),
circular_dispersion(), confidence_interval_fisher(), norm_chisq(),
weighted_rayleigh(), vm_qqplot()
data("nuvel1") na_pa <- subset(nuvel1, nuvel1$plate.rot == "na") data("plates") plate_boundary <- subset(plates, plates$pair == "na-pa") data("san_andreas") res <- PoR_shmax(san_andreas, na_pa, "right") d <- distance_from_pb(san_andreas, na_pa, plate_boundary, tangential = TRUE) quick_plot(res$azi.PoR, distance = d, prd = res$prd, unc = san_andreas$unc, regime = san_andreas$regime )data("nuvel1") na_pa <- subset(nuvel1, nuvel1$plate.rot == "na") data("plates") plate_boundary <- subset(plates, plates$pair == "na-pa") data("san_andreas") res <- PoR_shmax(san_andreas, na_pa, "right") d <- distance_from_pb(san_andreas, na_pa, plate_boundary, tangential = TRUE) quick_plot(res$azi.PoR, distance = d, prd = res$prd, unc = san_andreas$unc, regime = san_andreas$regime )
A test to determine whether a sample of circular or directional data is
evenly spread out or clustered around a single specific direction.
The test assesses the significance of the mean resultant length.
rayleight_test_perm() uses permutation to estimate p-values.
rayleigh_test(x, mu = NULL, axial = TRUE, alpha = 0.05, quiet = FALSE) rayleigh_test_perm(x, mu = NULL, axial = TRUE, n_perm = 1000L)rayleigh_test(x, mu = NULL, axial = TRUE, alpha = 0.05, quiet = FALSE) rayleigh_test_perm(x, mu = NULL, axial = TRUE, n_perm = 1000L)
x |
numeric vector. Values in degrees |
mu |
(optional) The specified or known mean direction (in degrees) in alternative hypothesis. |
axial |
logical. Whether the data are axial, i.e. |
alpha |
Significance level of the test. Valid levels are |
quiet |
logical. Prints the test's decision. |
n_perm |
integer. Number of permutations. |
Null Hypothesis : The population is distributed uniformly (randomly)
around the circle with no preferred direction.
Alternative Hypothesis : The population is not uniform and has a
unimodal (single-peaked) concentration in a preferred direction. When mu
is specified), angles are non-uniformly distributed around the specified direction.
Mean Resultant Length ( or R): A value between 0 and 1 that
measures how concentrated the data points are.
= 0: The data is completely spread out around the circle
= 1: All data points point in the exact same direction.
p-value The probability of seeing data this clustered purely by chance under the assumption of uniformity.
Small p-value (p < 0.05): Reject the null hypothesis. The length of the mean resultant differs significantly from zero, and the angles are not randomly distributed. You have strong evidence that the data points share a significant preferred or mean direction (unimodal clustering).
Large p-value (p 0.05): Fail to reject the null hypothesis. There is not
enough evidence to claim a preferred direction, meaning the data looks random or uniform around the circle.
a list with the components:
R or C
mean resultant length or the dispersion (if mu is
specified). Small values of R (large values of C) will reject
uniformity. Negative values of C indicate that vectors point in opposite
directions (also lead to rejection).
statistictest statistic
p.valuesignificance level of the test statistic
Although the Rayleigh test is consistent against (non-uniform)
von Mises alternatives, it is not consistent against alternatives with
p = 0 (in particular, distributions with antipodal symmetry, i.e. axial
data). Tests of non-uniformity which are consistent against all alternatives
include Kuiper's test (kuiper_test()) and Watson's test
(watson_test()).
The test assumes a unimodal alternative (one main peak).
If your data has two opposite clusters (bimodal or axial data, like a bi-directional line trend), the Rayleigh test can yield a high/non-significant p-value because the opposing vectors cancel each other out.
Fisher, N. I. (1993) Statistical Analysis of Circular Data, Cambridge University Press.
mean_resultant_length(), circular_mean()
Other Tests:
ar_test(),
kuiper_test(),
norm_chisq(),
watson_test(),
watson_two_sample,
watson_wheeler_test_perm(),
weighted-rayleigh-test
# Example data from Mardia and Jupp (1999), pp. 93 rayleigh_test(homing, axial = FALSE) # Do not reject null hypothesis. # R = 0.22; stat = 0.497, p = 0.62 rayleigh_test_perm(homing, axial = FALSE) # Example data from Davis (1986), pp. 316 rayleigh_test(striae, axial = FALSE) # reject null hypothesis rayleigh_test_perm(striae, axial = FALSE) # reject null hypothesis rayleigh_test(striae, mu = 105, axial = FALSE) # reject null hypothesis rayleigh_test_perm(striae, mu = 105, axial = FALSE) # reject null hypothesis # Example data from Mardia and Jupp (1999), pp. 99 atomic_weight <- c( rep(0, 12), rep(3.6, 1), rep(36, 6), rep(72, 1), rep(108, 2), rep(169.2, 1), rep(324, 1) ) rayleigh_test(atomic_weight, 0, axial = FALSE) # reject null hypothesis # San Andreas Fault Data: data(san_andreas) rayleigh_test(san_andreas$azi) # reject null hypothesis data("nuvel1") PoR <- subset(nuvel1, nuvel1$plate.rot == "na") sa.por <- PoR_shmax(san_andreas, PoR, "right") rayleigh_test(sa.por$azi.PoR, mu = 135) # reject null hypothesis rayleigh_test_perm(sa.por$azi.PoR, mu = 135, n_perm = 1e3) # reject null hypothesis# Example data from Mardia and Jupp (1999), pp. 93 rayleigh_test(homing, axial = FALSE) # Do not reject null hypothesis. # R = 0.22; stat = 0.497, p = 0.62 rayleigh_test_perm(homing, axial = FALSE) # Example data from Davis (1986), pp. 316 rayleigh_test(striae, axial = FALSE) # reject null hypothesis rayleigh_test_perm(striae, axial = FALSE) # reject null hypothesis rayleigh_test(striae, mu = 105, axial = FALSE) # reject null hypothesis rayleigh_test_perm(striae, mu = 105, axial = FALSE) # reject null hypothesis # Example data from Mardia and Jupp (1999), pp. 99 atomic_weight <- c( rep(0, 12), rep(3.6, 1), rep(36, 6), rep(72, 1), rep(108, 2), rep(169.2, 1), rep(324, 1) ) rayleigh_test(atomic_weight, 0, axial = FALSE) # reject null hypothesis # San Andreas Fault Data: data(san_andreas) rayleigh_test(san_andreas$azi) # reject null hypothesis data("nuvel1") PoR <- subset(nuvel1, nuvel1$plate.rot == "na") sa.por <- PoR_shmax(san_andreas, PoR, "right") rayleigh_test(sa.por$azi.PoR, mu = 135) # reject null hypothesis rayleigh_test_perm(sa.por$azi.PoR, mu = 135, n_perm = 1e3) # reject null hypothesis
Calculates the relative rotation between two rotations, i.e. the difference from rotation 1 to rotation 2.
relative_rotation(r1, r2)relative_rotation(r1, r2)
r1, r2
|
Objects of class |
list. Euler axes
(geographical coordinates) and Euler angles (in degrees)
Schaeben, H., Kroner, U. and Stephan, T. (2021). Euler Poles of Tectonic Plates. In B. S. Daza Sagar, Q. Cheng, J. McKinley and F. Agterberg (Eds.), Encyclopedia of Mathematical Geosciences. Encyclopedia of Earth Sciences Series (pp. 1–7). Springer Nature Switzerland AG 2021. doi: 10.1007/978-3-030-26050-7_435-1.
euler_pole() for class "euler.pole"
a <- euler_pole(90, 0, angle = 45) b <- euler_pole(0, 0, 1, geo = FALSE, angle = -15) relative_rotation(a, b) # axis: -90, -180; angle: 60 relative_rotation(b, a) # axis: 90, 0; angle: 60a <- euler_pole(90, 0, angle = 45) b <- euler_pole(0, 0, 1, geo = FALSE, angle = -15) relative_rotation(a, b) # axis: -90, -180; angle: 60 relative_rotation(b, a) # axis: 90, 0; angle: 60
A generic function for applying a function to rolling margins of an array.
roll_circstats( x, w = NULL, FUN, axial = TRUE, na.rm = TRUE, width = NULL, by.column = FALSE, partial = TRUE, fill = NA, ... )roll_circstats( x, w = NULL, FUN, axial = TRUE, na.rm = TRUE, width = NULL, by.column = FALSE, partial = TRUE, fill = NA, ... )
x |
numeric vector. Values in degrees, for which the mean, median or standard deviation are required. |
w |
(optional) Weights. A vector of positive numbers, of the same length as
|
FUN |
the function to be applied |
axial |
logical. Whether the data are axial, i.e. pi-periodical
( |
na.rm |
logical value indicating whether |
width |
integer specifying the window width (in numbers of observations)
which is aligned to the original sample according to the |
by.column |
logical. If |
partial |
logical or numeric. If |
fill |
a three-component vector or list (recycled otherwise) providing
filling values at the left/within/to the right of the data range. See the
fill argument of |
... |
optional arguments passed to |
numeric vector with the results of the rolling function.
If the rolling statistics are applied to values that are a function of distance it is recommended to sort the values first.
data("plates") plate_boundary <- subset(plates, plates$pair == "na-pa") data("san_andreas") PoR <- subset(nuvel1, nuvel1$plate.rot == "na") distance <- distance_from_pb( x = san_andreas, PoR = PoR, pb = plate_boundary, tangential = TRUE ) dat <- san_andreas[order(distance), ] roll_circstats(dat$azi, w = 1 / dat$unc, circular_mean, width = 51) |> head()data("plates") plate_boundary <- subset(plates, plates$pair == "na-pa") data("san_andreas") PoR <- subset(nuvel1, nuvel1$plate.rot == "na") distance <- distance_from_pb( x = san_andreas, PoR = PoR, pb = plate_boundary, tangential = TRUE ) dat <- san_andreas[order(distance), ] roll_circstats(dat$azi, w = 1 / dat$unc, circular_mean, width = 51) |> head()
A generic function for applying a function to rolling margins of an array.
roll_normchisq( obs, prd, unc = NULL, width = NULL, by.column = FALSE, partial = TRUE, fill = NA, ... ) roll_rayleigh( obs, prd, unc = NULL, width = NULL, by.column = FALSE, partial = TRUE, fill = NA, ... ) roll_dispersion( x, y, w = NULL, w.y = NULL, width = NULL, by.column = FALSE, partial = TRUE, fill = NA, ... ) roll_confidence( x, conf.level = 0.95, w = NULL, axial = TRUE, width = NULL, by.column = FALSE, partial = TRUE, fill = NA, ... ) roll_dispersion_CI( x, y, w = NULL, w.y = NULL, R, conf.level = 0.95, width = NULL, by.column = FALSE, partial = TRUE, fill = NA, ... ) roll_dispersion_sde( x, y, w = NULL, w.y = NULL, R, conf.level = 0.95, width = NULL, by.column = FALSE, partial = TRUE, fill = NA, ... )roll_normchisq( obs, prd, unc = NULL, width = NULL, by.column = FALSE, partial = TRUE, fill = NA, ... ) roll_rayleigh( obs, prd, unc = NULL, width = NULL, by.column = FALSE, partial = TRUE, fill = NA, ... ) roll_dispersion( x, y, w = NULL, w.y = NULL, width = NULL, by.column = FALSE, partial = TRUE, fill = NA, ... ) roll_confidence( x, conf.level = 0.95, w = NULL, axial = TRUE, width = NULL, by.column = FALSE, partial = TRUE, fill = NA, ... ) roll_dispersion_CI( x, y, w = NULL, w.y = NULL, R, conf.level = 0.95, width = NULL, by.column = FALSE, partial = TRUE, fill = NA, ... ) roll_dispersion_sde( x, y, w = NULL, w.y = NULL, R, conf.level = 0.95, width = NULL, by.column = FALSE, partial = TRUE, fill = NA, ... )
obs |
Numeric vector containing the observed azimuth of
|
prd |
Numeric vector containing the modeled azimuths of
|
unc |
Uncertainty of observed |
width |
integer specifying the window width (in numbers of observations)
which is aligned to the original sample according to the |
by.column |
logical. If |
partial |
logical or numeric. If |
fill |
a three-component vector or list (recycled otherwise) providing
filling values at the left/within/to the right of the data range. See the
fill argument of |
... |
optional arguments passed to |
x, y
|
numeric. Directions in degrees |
w, w.y
|
(optional) Weights of |
conf.level |
Level of confidence: |
axial |
logical. Whether the data are axial, i.e. pi-periodical
( |
R |
The number of bootstrap replicates. |
numeric vector with the test statistic of the rolling test.
roll_dispersion_CI returns a 2-column matrix with the lower and the upper
confidence limits
If the rolling functions are applied to values that are a function of distance it is recommended to sort the values first.
data("plates") plate_boundary <- subset(plates, plates$pair == "na-pa") data("san_andreas") PoR <- subset(nuvel1, nuvel1$plate.rot == "na") distance <- distance_from_pb( x = san_andreas, PoR = PoR, pb = plate_boundary, tangential = TRUE ) dat <- san_andreas[order(distance), ] dat.PoR <- PoR_shmax(san_andreas, PoR, "right") roll_normchisq(dat.PoR$azi.PoR, 135, dat$unc) |> head() roll_rayleigh(dat.PoR$azi.PoR, prd = 135, unc = dat$unc) |> head() roll_dispersion(dat.PoR$azi.PoR, y = 135, w = 1 / dat$unc) |> head() roll_confidence(dat.PoR$azi.PoR, w = 1 / dat$unc) |> head() roll_dispersion_CI(dat.PoR$azi.PoR, y = 135, w = 1 / dat$unc, R = 10) |> head()data("plates") plate_boundary <- subset(plates, plates$pair == "na-pa") data("san_andreas") PoR <- subset(nuvel1, nuvel1$plate.rot == "na") distance <- distance_from_pb( x = san_andreas, PoR = PoR, pb = plate_boundary, tangential = TRUE ) dat <- san_andreas[order(distance), ] dat.PoR <- PoR_shmax(san_andreas, PoR, "right") roll_normchisq(dat.PoR$azi.PoR, 135, dat$unc) |> head() roll_rayleigh(dat.PoR$azi.PoR, prd = 135, unc = dat$unc) |> head() roll_dispersion(dat.PoR$azi.PoR, y = 135, w = 1 / dat$unc) |> head() roll_confidence(dat.PoR$azi.PoR, w = 1 / dat$unc) |> head() roll_dispersion_CI(dat.PoR$azi.PoR, y = 135, w = 1 / dat$unc, R = 10) |> head()
Plots a rose diagram (rose of directions), the analogue of a histogram or density plot for angular data.
rose( x, weights = NULL, binwidth = NULL, bins = NULL, axial = TRUE, equal_area = TRUE, muci = TRUE, origin.text = "N", main = NULL, sub = NULL, at = seq(0, 360 - 45, 45), cborder = TRUE, labels = TRUE, col = "grey", dots = FALSE, dot_pch = 1, dot_cex = 1, dot_col = "slategrey", stack = FALSE, jitter_factor = 0, grid = FALSE, grid.lines = seq(0, 135, 45), grid.circles = seq(0.2, 1, 0.2), add = FALSE, rule = c("sturges", "rice"), ... )rose( x, weights = NULL, binwidth = NULL, bins = NULL, axial = TRUE, equal_area = TRUE, muci = TRUE, origin.text = "N", main = NULL, sub = NULL, at = seq(0, 360 - 45, 45), cborder = TRUE, labels = TRUE, col = "grey", dots = FALSE, dot_pch = 1, dot_cex = 1, dot_col = "slategrey", stack = FALSE, jitter_factor = 0, grid = FALSE, grid.lines = seq(0, 135, 45), grid.circles = seq(0.2, 1, 0.2), add = FALSE, rule = c("sturges", "rice"), ... )
x |
Data to be plotted. A numeric vector containing angles (in degrees). |
weights |
Optional vector of numeric weights associated with x. |
binwidth |
The width of the bins (in degrees). |
bins |
number of arcs to partition the circle width.
Overridden by |
axial |
Logical. Whether data are uniaxial ( |
equal_area |
Logical. Whether the radii of the bins are proportional to
the frequencies ( |
muci |
logical. Whether the mean and its 95% CI are added to the plot or not. |
origin.text |
character. String to be drawn at the top margin of the plot
( |
main, sub
|
Character string specifying the title and subtitle of the
plot. If |
at |
Optional vector of angles at which tick marks should be plotted.
Set |
cborder |
logical. Whether to plot the primitive of the circular plot ( |
labels |
Either a logical value indicating whether to plot labels next to the tick marks, or a vector of labels for the tick marks. |
col |
fill color of rose petals / fans |
dots |
logical. Whether a circular dot plot should be added
( |
dot_cex, dot_pch, dot_col
|
Plotting arguments for circular dot plot |
stack |
logical. Groups and stacks the dots if |
jitter_factor |
Add a small amount of noise to the angles' radius that
is added to |
grid |
logical. Whether to add a grid to the circular plot. Default is |
grid.lines, grid.circles
|
numeric. Adds a sequence of straight grid
lines and circles based on angles (in degrees) and radii, respectively. Ignored when
|
add |
logical. Add to existing plot? ( |
rule |
character. Rule to select optimal bin width, one of "sturges" (the default) or "rice". The optimal number according to Sturges' rule is |
... |
Additional graphical arguments passed to |
class of histogram that is a list of the calculated frequencies
parameters including the bin width.
Other circular-plot:
plot_density(),
plot_points(),
rose_geom,
rose_stats()
x <- rvm(100, mean = 90, k = 5) rose(x, axial = FALSE, border = TRUE, grid = TRUE) data("san_andreas") rose(san_andreas$azi, main = "equal area") rose(san_andreas$azi, equal_area = FALSE, main = "equal angle") # weighted frequencies: rose(san_andreas$azi, weights = 1 / san_andreas$unc, main = "weighted") # add dots: rose(san_andreas$azi, dots = TRUE, main = "dot plot", jitter = .2) # stack dots: rose(san_andreas$azi, dots = TRUE, stack = TRUE, dot_cex = 0.5, dot_pch = 21, main = "stacked dot plot" )x <- rvm(100, mean = 90, k = 5) rose(x, axial = FALSE, border = TRUE, grid = TRUE) data("san_andreas") rose(san_andreas$azi, main = "equal area") rose(san_andreas$azi, equal_area = FALSE, main = "equal angle") # weighted frequencies: rose(san_andreas$azi, weights = 1 / san_andreas$unc, main = "weighted") # add dots: rose(san_andreas$azi, dots = TRUE, main = "dot plot", jitter = .2) # stack dots: rose(san_andreas$azi, dots = TRUE, stack = TRUE, dot_cex = 0.5, dot_pch = 21, main = "stacked dot plot" )
Direction Lines and Fans in Circular Diagram
rose_line(x, radius = 1, axial = TRUE, add = TRUE, ...) rose_fan(x, d, radius = 1, axial = TRUE, add = TRUE, ...)rose_line(x, radius = 1, axial = TRUE, add = TRUE, ...) rose_fan(x, d, radius = 1, axial = TRUE, add = TRUE, ...)
x |
angles in degrees |
radius |
of the plotted circle |
axial |
Logical. Whether |
add |
logical. Add to existing plot? |
... |
optional arguments passed to |
d |
width of a fan (in degrees) |
No return value, called for side effects
Other circular-plot:
plot_density(),
plot_points(),
rose(),
rose_stats()
angles <- c(0, 10, 45) radius <- c(.7, 1, .2) lwd <- c(2, 1, .75) col <- c(1, 2, 3) rose_line(angles, radius = radius, axial = FALSE, add = FALSE, lwd = lwd, col = col)angles <- c(0, 10, 45) radius <- c(.7, 1, .2) lwd <- c(2, 1, .75) col <- c(1, 2, 3) rose_line(angles, radius = radius, axial = FALSE, add = FALSE, lwd = lwd, col = col)
Adds the average direction (and its spread) to an existing rose diagram.
rose_stats( x, weights = NULL, axial = TRUE, avg = c("mean", "median", "sample_median"), spread = c("CI", "fisher", "sd", "IQR", "mdev"), avg.col = "#B63679FF", avg.lty = 2, avg.lwd = 1.5, spread.col = ggplot2::alpha("#B63679FF", 0.2), spread.border = FALSE, spread.lty = NULL, spread.lwd = NULL, add = TRUE, ... )rose_stats( x, weights = NULL, axial = TRUE, avg = c("mean", "median", "sample_median"), spread = c("CI", "fisher", "sd", "IQR", "mdev"), avg.col = "#B63679FF", avg.lty = 2, avg.lwd = 1.5, spread.col = ggplot2::alpha("#B63679FF", 0.2), spread.border = FALSE, spread.lty = NULL, spread.lwd = NULL, add = TRUE, ... )
x |
Data to be plotted. A numeric vector containing angles (in degrees). |
weights |
Optional vector of numeric weights associated with x. |
axial |
Logical. Whether data are uniaxial ( |
avg |
character. The average estimate for x. Either the circular mean
( |
spread |
character. The measure of spread to be plotted as a fan.
Either Batchelet's 95% confidence interval by ( |
avg.col |
color for the average line |
avg.lty |
line type of the average line |
avg.lwd |
line width of the average line |
spread.col |
color of the spread fan |
spread.border |
logical. Whether to draw a border of the fan or not. |
spread.lty |
line type of the spread fan's border |
spread.lwd |
line width of the spread fan's border |
add |
logical. Add to existing plot? ( |
... |
optional arguments to |
plot or a two-element vector containing the calculated average and spread when assigned.
circular_mean(), circular_median(), circular_sample_median(),
confidence_interval(), confidence_interval_fisher(),
circular_sd(), circular_IQR(), circular_sample_median_deviation()
for statistical parameters.
Other circular-plot:
plot_density(),
plot_points(),
rose(),
rose_geom
data("san_andreas") rose(san_andreas$azi, weights = 1 / san_andreas$unc, muci = FALSE) rose_stats(san_andreas$azi, weights = 1 / san_andreas$unc, avg = "sample_median", spread = "mdev")data("san_andreas") rose(san_andreas$azi, weights = 1 / san_andreas$unc, muci = FALSE) rose_stats(san_andreas$azi, weights = 1 / san_andreas$unc, avg = "sample_median", spread = "mdev")
Alternative versions of variance, dispersion a distance (Mardia and Jupp, 1999; pp. 19-20). These alternative dispersion has a minimum at the sample median.
sample_circular_variance(x, w = NULL, axial = TRUE) sample_circular_distance(x, y, axial = TRUE, na.rm = TRUE) sample_circular_dispersion( x, y = NULL, w = NULL, w.y = NULL, axial = TRUE, na.rm = TRUE )sample_circular_variance(x, w = NULL, axial = TRUE) sample_circular_distance(x, y, axial = TRUE, na.rm = TRUE) sample_circular_dispersion( x, y = NULL, w = NULL, w.y = NULL, axial = TRUE, na.rm = TRUE )
x, y
|
vectors of numeric values in degrees. |
w, w.y
|
(optional) Weights. A vector of positive numbers and of the same
length as |
axial |
logical. Whether the data are axial, i.e. pi-periodical
( |
na.rm |
logical value indicating whether |
N.I. Fisher (1993) Statistical Analysis of Circular Data, Cambridge University Press.
Mardia, K.V., and Jupp, P.E (1999). Directional Statistics, Wiley Series in Probability and Statistics. John Wiley & Sons, Inc., Hoboken, NJ, USA. doi:10.1002/9780470316979
a <- c(0, 2, 359, 6, 354) sample_circular_distance(a, 10) # distance to single value b <- a + 90 sample_circular_distance(a, b) # distance to multiple values data("nuvel1") PoR <- subset(nuvel1, nuvel1$plate.rot == "na") sa.por <- PoR_shmax(san_andreas, PoR, "right") sample_circular_variance(sa.por$azi.PoR) sample_circular_dispersion(sa.por$azi.PoR, y = 135) sample_circular_dispersion(sa.por$azi.PoR, y = 135, w = weighting(san_andreas$unc))a <- c(0, 2, 359, 6, 354) sample_circular_distance(a, 10) # distance to single value b <- a + 90 sample_circular_distance(a, b) # distance to multiple values data("nuvel1") PoR <- subset(nuvel1, nuvel1$plate.rot == "na") sa.por <- PoR_shmax(san_andreas, PoR, "right") sample_circular_variance(sa.por$azi.PoR) sample_circular_dispersion(sa.por$azi.PoR, y = 135) sample_circular_dispersion(sa.por$azi.PoR, y = 135, w = weighting(san_andreas$unc))
Sample median direction for a vector of circular data
circular_sample_median(x, axial = TRUE, na.rm = TRUE) circular_sample_median_deviation(x, axial = TRUE, na.rm = TRUE)circular_sample_median(x, axial = TRUE, na.rm = TRUE) circular_sample_median_deviation(x, axial = TRUE, na.rm = TRUE)
x |
numeric vector. Values in degrees, for which the mean, median or standard deviation are required. |
axial |
logical. Whether the data are axial, i.e. pi-periodical
( |
na.rm |
logical value indicating whether |
numeric
N.I. Fisher (1993) Statistical Analysis of Circular Data, Cambridge University Press.
set.seed(1) x <- rvm(n = 100, mean = 0, kappa = 10) circular_sample_median(x) circular_sample_median_deviation(x) data("san_andreas") circular_sample_median(san_andreas$azi) circular_sample_median_deviation(san_andreas$azi)set.seed(1) x <- rvm(n = 100, mean = 0, kappa = 10) circular_sample_median(x) circular_sample_median_deviation(x) data("san_andreas") circular_sample_median(san_andreas$azi) circular_sample_median_deviation(san_andreas$azi)
Measures the skewness (a measure of the asymmetry of the probability distribution) and the kurtosis (measure of the "tailedness" of the probability distribution). Standardized versions are the skewness and kurtosis normalized by the mean resultant length (Mardia 1972).
second_central_moment(x, w = NULL, axial = TRUE, na.rm = FALSE)second_central_moment(x, w = NULL, axial = TRUE, na.rm = FALSE)
x |
numeric vector. Values in degrees, for which the mean, median or standard deviation are required. |
w |
(optional) Weights. A vector of positive numbers, of the same length as
|
axial |
logical. Whether the data are axial, i.e. pi-periodical
( |
na.rm |
logical value indicating whether |
Negative values of skewness indicate skewed data in counterclockwise direction.
Large kurtosis values indicate tailed, values close to 0 indicate packed
data.
list containing
skewnesssecond central sine momentum, i.e. the skewness
std_skewnessstandardized skewness
kurtosissecond central cosine momentum, i.e. the kurtosis
std_kurtosisstandardized kurtosis
data("nuvel1") PoR <- subset(nuvel1, nuvel1$plate.rot == "na") sa.por <- PoR_shmax(san_andreas, PoR, "right") second_central_moment(sa.por$azi.PoR) second_central_moment(sa.por$azi.PoR, w = weighting(san_andreas$unc))data("nuvel1") PoR <- subset(nuvel1, nuvel1$plate.rot == "na") sa.por <- PoR_shmax(san_andreas, PoR, "right") second_central_moment(sa.por$azi.PoR) second_central_moment(sa.por$azi.PoR, w = weighting(san_andreas$unc))
The shortest Great Circle distance between pairs of geometries
shortest_distance_to_line(x, line, ellipsoidal = FALSE)shortest_distance_to_line(x, line, ellipsoidal = FALSE)
x, line
|
objects of class |
ellipsoidal |
Logical. Whether the distance is calculated using
spherical distances ( |
numeric. Shortest distance in meters
plate_boundary <- subset(plates, plates$pair == "na-pa") shortest_distance_to_line(san_andreas, plate_boundary) |> head()plate_boundary <- subset(plates, plates$pair == "na-pa") shortest_distance_to_line(san_andreas, plate_boundary) |> head()
Returns the quadrant specific inverse of the tangent
atan2_spec(x, y) atan2d_spec(x, y)atan2_spec(x, y) atan2d_spec(x, y)
x, y
|
dividend and divisor that comprise the sum of sines and cosines, respectively. |
numeric.
Jammalamadaka, S. Rao, and Ambar Sengupta (2001). Topics in circular statistics. Vol. 5. world scientific.
Smallest angle between two points on the surface of a sphere, measured along the surface of the sphere
orthodrome(lat1, lon1, lat2, lon2) haversine(lat1, lon1, lat2, lon2) vincenty(lat1, lon1, lat2, lon2)orthodrome(lat1, lon1, lat2, lon2) haversine(lat1, lon1, lat2, lon2) vincenty(lat1, lon1, lat2, lon2)
lat1, lat2
|
numeric vector. latitudes of point 1 and 2 (in radians) |
lon1, lon2
|
numeric vector. longitudes of point 1 and 2 (in radians) |
"orthodrome"based on the spherical law of cosines
"haversine"uses haversine formula that is optimized for 64-bit floating-point numbers
"vincenty"uses Vincenty formula for an ellipsoid with equal major and minor axes
numeric. Angle in radians
Imboden, C. & Imboden, D. (1972). Formel fuer Orthodrome und Loxodrome bei der Berechnung von Richtung und Distanz zwischen Beringungs- und Wiederfundort. Die Vogelwarte 26, 336-346.
Sinnott, Roger W. (1984). Virtues of the Haversine. Sky and telescope 68(2), 158.
Vincenty, T. (1975). Direct and inverse solutions of geodesics on the ellipsoid with application of nested equations. Survey Review, 23(176), 88<U+2013>93. doi:10.1179/sre.1975.23.176.88.
http://www.movable-type.co.uk/scripts/latlong.html
http://www.edwilliams.org/avform147.htm
berlin <- c(52.52, 13.41) |> deg2rad() calgary <- c(51.04, -114.072) |> deg2rad() orthodrome(berlin[1], berlin[2], calgary[1], calgary[2]) # 1.176406 haversine(berlin[1], berlin[2], calgary[1], calgary[2]) # 1.176406 vincenty(berlin[1], berlin[2], calgary[1], calgary[2]) # 1.176406berlin <- c(52.52, 13.41) |> deg2rad() calgary <- c(51.04, -114.072) |> deg2rad() orthodrome(berlin[1], berlin[2], calgary[1], calgary[2]) # 1.176406 haversine(berlin[1], berlin[2], calgary[1], calgary[2]) # 1.176406 vincenty(berlin[1], berlin[2], calgary[1], calgary[2]) # 1.176406
Returns the converted azimuths, distances to the plate boundary, statistics of the model, and some plots.
stress_analysis( x, PoR, type = c("none", "in", "out", "right", "left"), pb, plot = TRUE, ... )stress_analysis( x, PoR, type = c("none", "in", "out", "right", "left"), pb, plot = TRUE, ... )
x |
|
PoR |
Pole of Rotation. |
type |
Character. Type of plate boundary (optional). Can be
|
pb |
(optional) |
plot |
(logical). Whether to produce a plot additional to output. |
... |
optional arguments to |
list containing the following values:
resultsdata.frame showing the the coordinate and azimuth conversions
(lat.PoR, lon.PoR, and azi.PoR), the predicted azimuths (prd),
deviation angle from predicted (dev), circular distance (cdist),
misfit to predicted stress direction (nchisq) and, if given, distance to tested
plate boundary (distance)
statsarray with circular (weighted) mean, circular standard deviation, circular variance, circular median, skewness, kurtosis, the 95% confidence angle, circular dispersion, and the normalized Chi-squared test statistic
testlist containing the test results of the (weighted) Rayleigh test against the uniform distribution about the predicted orientation.
PoR_shmax(), distance_from_pb(), norm_chisq(), quick_plot(), circular_summary()
data("nuvel1") na_pa <- subset(nuvel1, nuvel1$plate.rot == "na") data("plates") plate_boundary <- subset(plates, plates$pair == "na-pa") data("san_andreas") stress_analysis(san_andreas, na_pa, type = "right", plate_boundary, plot = TRUE)data("nuvel1") na_pa <- subset(nuvel1, nuvel1$plate.rot == "na") data("plates") plate_boundary <- subset(plates, plates$pair == "na-pa") data("san_andreas") stress_analysis(san_andreas, na_pa, type = "right", plate_boundary, plot = TRUE)
Color palette for stress regime
stress_colors()stress_colors()
function
stress_colors()stress_colors()
Subsets of the World Stress Map (WSM) compilation of information on the crustal present-day stress field (Version 1.1. 2019).
data('san_andreas') data('tibet') data('iceland')data('san_andreas') data('tibet') data('iceland')
A sf object / data.frame with 10 columns. Each row represents a
different in-situ stress measurement:
Measurement identifier
Latitude in degrees
Longitude in degrees
SHmax azimuth in degrees
Measurement standard deviation (in degrees)
Type of measurement
Depth in km
WSM quality rank
Stress regime
An object of class sf (inherits from data.frame) with 1126 rows and 10 columns.
An object of class sf (inherits from data.frame) with 1165 rows and 10 columns.
An object of class sf (inherits from data.frame) with 490 rows and 10 columns.
'san_andreas"contains 407 stress data adjacent to the San Andreas Fault to be tested against a tangentially displaced plate boundary.
"tibet"contains 947 stress data from the Himalaya and Tibetan plateau to be tested against an inward-moving displaced plate boundary.
'icelandcontains 201 stress data from Iceland to be tested against a outward-moving displaced plate boundary.
https://www.world-stress-map.org/
Heidbach, O., Barth, A., Müller, B., Reinecker, J., Stephansson, O., Tingay, M., & Zang, A. (2016). WSM quality ranking scheme, database description and analysis guidelines for stress indicator. WSM Technical Report; 16-01. GFZ German Research Centre for Geosciences. doi:10.2312/WSM.2016.001
download_WSM() for description of columns and stress regime
acronyms
data("san_andreas") head(san_andreas) data("tibet") head(tibet) data("iceland") head(iceland)data("san_andreas") head(san_andreas) data("tibet") head(tibet) data("iceland") head(iceland)
Construct lines that are
following small circles, great circles, or loxodromes of an Euler pole for
the relative plate motion.
eulerpole_paths(x, type = c("sc", "gc", "ld"), n = 10L, angle = 45, cw) eulerpole_smallcircles(x, n = 10L) eulerpole_greatcircles(x, n = 10L) eulerpole_loxodromes(x, n = 10L, angle = 45, cw)eulerpole_paths(x, type = c("sc", "gc", "ld"), n = 10L, angle = 45, cw) eulerpole_smallcircles(x, n = 10L) eulerpole_greatcircles(x, n = 10L) eulerpole_loxodromes(x, n = 10L, angle = 45, cw)
x |
Either an object of class |
type |
character. String specifying the type of curves to export. Either
|
n |
integer. Number of equally spaced curves; |
angle |
numeric. Direction of loxodromes; |
cw |
logical. Sense of loxodromes: |
Maximum horizontal stress can be aligned to three types of curves related to relative plate motion:
Lines that have a constant distance to the Euler pole.
If x contains angle, output additionally gives absolute
velocity on small circle (°/Myr -> km/Myr).
Paths of the shortest distance between the Euler pole and its antipodal position.
Lines of constant bearing, i.e. curves cutting small circles at a constant angle.
sf object
Tobias Stephan
data("nuvel1") por <- subset(nuvel1, nuvel1$plate.rot == "na") # North America relative to # Pacific plate eulerpole_smallcircles(por) eulerpole_greatcircles(por) eulerpole_loxodromes(x = por, angle = 45, n = 10, cw = FALSE) eulerpole_loxodromes(x = por, angle = 30, cw = TRUE) eulerpole_smallcircles(data.frame(lat = 30, lon = 10))data("nuvel1") por <- subset(nuvel1, nuvel1$plate.rot == "na") # North America relative to # Pacific plate eulerpole_smallcircles(por) eulerpole_greatcircles(por) eulerpole_loxodromes(x = por, angle = 45, n = 10, cw = FALSE) eulerpole_loxodromes(x = por, angle = 30, cw = TRUE) eulerpole_smallcircles(data.frame(lat = 30, lon = 10))
Stress field interpolation and wavelength analysis using a kernel (weighted) mean/median and standard deviation/IQR of stress data. Parameters can be adjusted to have inverse-distance-weighting (IDW) or nearest-neighbor interpolations (NN).
stress2grid( x, stat = c("mean", "median", "tensor"), grid = NULL, lon_range = NULL, lat_range = NULL, gridsize = 2, min_data = 3L, max_data = Inf, max_sd = Inf, threshold = deprecated(), min_dist_threshold = 200, arte_thres = deprecated(), method_weighting = FALSE, quality_weighting = TRUE, dist_weighting = c("inverse", "linear", "none"), idp = 1, qp = 1, mp = 1, dist_threshold = 0.1, R_range = seq(50, 1000, 50), axial = TRUE ) stress2grid_stats( x, grid = NULL, lon_range = NULL, lat_range = NULL, gridsize = 2, min_data = 4L, max_data = Inf, threshold = deprecated(), min_dist_threshold = 200, arte_thres = deprecated(), method_weighting = FALSE, quality_weighting = TRUE, dist_weighting = c("inverse", "linear", "none"), idp = 1, qp = 1, mp = 1, dist_threshold = 0.1, R_range = seq(50, 1000, 50), mode = FALSE, kappa = 10, axial = TRUE, ... )stress2grid( x, stat = c("mean", "median", "tensor"), grid = NULL, lon_range = NULL, lat_range = NULL, gridsize = 2, min_data = 3L, max_data = Inf, max_sd = Inf, threshold = deprecated(), min_dist_threshold = 200, arte_thres = deprecated(), method_weighting = FALSE, quality_weighting = TRUE, dist_weighting = c("inverse", "linear", "none"), idp = 1, qp = 1, mp = 1, dist_threshold = 0.1, R_range = seq(50, 1000, 50), axial = TRUE ) stress2grid_stats( x, grid = NULL, lon_range = NULL, lat_range = NULL, gridsize = 2, min_data = 4L, max_data = Inf, threshold = deprecated(), min_dist_threshold = 200, arte_thres = deprecated(), method_weighting = FALSE, quality_weighting = TRUE, dist_weighting = c("inverse", "linear", "none"), idp = 1, qp = 1, mp = 1, dist_threshold = 0.1, R_range = seq(50, 1000, 50), mode = FALSE, kappa = 10, axial = TRUE, ... )
x |
|
stat |
whether the direction of interpolated |
grid |
(optional) Point object of class |
lon_range, lat_range
|
(optional) numeric vector specifying the minimum
and maximum longitudes and latitudes (ignored if |
gridsize |
numeric. Target spacing of the regular grid in decimal
degree. Default is |
min_data |
integer. If the number of observations within distance
|
max_data |
integer. The number of nearest observations that should be
used for prediction, where "nearest" is defined in terms of the space of the
spatial locations. Default is |
max_sd |
numeric. Threshold for deviation of direction in degrees; if exceeds, missing values will be generated. |
threshold |
|
min_dist_threshold |
numeric. Distance threshold for smallest distance
of the prediction location to the next observation location.
Default is |
arte_thres |
|
method_weighting |
logical. If a method weighting should be applied:
Default is |
quality_weighting |
logical. If a quality weighting should be applied:
Default is |
dist_weighting |
Distance weighting method which should be used. One of
|
idp, qp, mp
|
numeric. The weighting power of inverse distance, quality
and method (the higher the value, the more weight).
Default is |
dist_threshold |
numeric. Distance weight to prevent overweight of data
nearby (0 to 1). Default is |
R_range |
numeric value or vector specifying the kernel half-width(s)
search radii,
i.e. the maximum distance from the prediction location to be used for
prediction (in km). Default is |
axial |
Logical. Whether angles in |
mode |
logical. Should the circular mode be included in the statistical summary (slow)? |
kappa |
numeric. von Mises distribution concentration parameter used
for the circular mode. Will be estimated using |
... |
(optional) arguments to |
stress2grid() is originally based on the MATLAB script
"stress2grid" by Ziegler and Heidbach (2019):
https://github.com/MorZieg/Stress2Grid.
The tectonicr version has been significantly modified to provide better
performance and more flexibility.
stress2grid_stats() is based on stress2grid() but calculates circular
summary statistics (see circular_summary()).
sf object containing
longitude and latitude in degrees
Circular mean od median SHmax in degree
Circular standard deviation or Quasi-IQR on the Circle of
in degrees
Search radius in km
Mean distance between grid point and datapoints per search radius
Number of data points in search radius
When stress2grid_stats(), azi and sd are replaced by the output of
circular_summary().
Although specialized for stress fields, this spatial interpolation
algorithm can be applied to type of data. Please adjust the axial argument
when applied to different, directional data sets.
Ziegler, M. and Heidbach, O. (2019). Matlab Script Stress2Grid v1.1. GFZ Data Services. doi:10.5880/wsm.2019.002
dist_greatcircle(), PoR_stress2grid(), compact_grid(),
circular_mean(), circular_median(), circular_sd(), circular_summary()
data("san_andreas") # Inverse Distance Weighting interpolation: stress2grid(san_andreas, stat = "median") |> head() stress2grid(san_andreas, stat = "tensor") |> head() # Nearest Neighbor interpolation: stress2grid(san_andreas, stat = "median", max_data = 5) |> head() ## Not run: stress2grid_stats(san_andreas, mode = TRUE) |> head() ## End(Not run)data("san_andreas") # Inverse Distance Weighting interpolation: stress2grid(san_andreas, stat = "median") |> head() stress2grid(san_andreas, stat = "tensor") |> head() # Nearest Neighbor interpolation: stress2grid(san_andreas, stat = "median", max_data = 5) |> head() ## Not run: stress2grid_stats(san_andreas, mode = TRUE) |> head() ## End(Not run)
Directions of 51 glacial striations, example data from Davis (1986), pp. 316
numeric vector of length 51
Davis, J.C. (1986) Statistics and Data Analysis in Geology. 2nd Edition, John Wiley & Sons, New York.
data("striae") striaedata("striae") striae
Calculates a direction at given coordinates,
sourced by multiple plate boundaries. This first-order approximation is the
circular mean of the superimposed theoretical directions, weighted by the
rotation rates of the underlying PoRs.
superimposed_shmax(df, PoRs, types, absolute = TRUE, PoR_weighting = NULL)superimposed_shmax(df, PoRs, types, absolute = TRUE, PoR_weighting = NULL)
df |
|
PoRs |
multirow |
types |
character vector with length equal to number of rows in |
absolute |
logical. Whether the resultant azimuth should be weighted using the absolute rotation at the points or the angular rotation of the PoRs. |
PoR_weighting |
(optional) numeric vector with length equal to number of rows in
|
two column vector. azi is the resultant azimuth in degrees /
geographical CRS), R is the resultant length.
superimposed_shmax_PB() for considering distances to plate boundaries
data(san_andreas) data(nuvel1) pors <- subset(nuvel1, plate.rot %in% c("eu", "na")) res <- superimposed_shmax(san_andreas, pors, types = c("in", "right"), PoR_weighting = c(2, 1)) head(res)data(san_andreas) data(nuvel1) pors <- subset(nuvel1, plate.rot %in% c("eu", "na")) res <- superimposed_shmax(san_andreas, pors, types = c("in", "right"), PoR_weighting = c(2, 1)) head(res)
Calculates a direction at given coordinates,
sourced by multiple plate boundaries. This first-order approximation is the
circular mean of the superimposed theoretical directions, weighted by the
rotation rates of the underlying PoRs, the inverse distance to the plate
boundaries, and the type of plate boundary.
superimposed_shmax_PB( x, pbs, model, rotation_weighting = TRUE, type_weights = c(divergent = 1, convergent = 3, transform_L = 2, transform_R = 2), idp = 1 )superimposed_shmax_PB( x, pbs, model, rotation_weighting = TRUE, type_weights = c(divergent = 1, convergent = 3, transform_L = 2, transform_R = 2), idp = 1 )
x |
grid. An object of |
pbs |
plate boundaries. |
model |
|
rotation_weighting |
logical. |
type_weights |
named vector. |
idp |
numeric. Weighting power of inverse distance. The higher the
number, the less impact far-distant boundaries have. When set to |
two-column matrix. azi is the resultant azimuth (in degrees), R
is the resultant length.
na_grid <- sf::st_make_grid(san_andreas, what = "centers", cellsize = 1) na_plate <- subset(plates, plateA == "na" | plateB == "na") cpm <- cpm_models[["NNR-MORVEL56"]] # make divergent to ridge-push: na_plate <- transform(na_plate, type = ifelse(na_plate$pair == "eu-na", "convergent", type)) res <- superimposed_shmax_PB(na_grid, na_plate, model = cpm, idp = 2) head(res)na_grid <- sf::st_make_grid(san_andreas, what = "centers", cellsize = 1) na_plate <- subset(plates, plateA == "na" | plateB == "na") cpm <- cpm_models[["NNR-MORVEL56"]] # make divergent to ridge-push: na_plate <- transform(na_plate, type = ifelse(na_plate$pair == "eu-na", "convergent", type)) res <- superimposed_shmax_PB(na_grid, na_plate, model = cpm, idp = 2) head(res)
assigns colors to continuous or categorical values for plotting
tectonicr.colors( x, n = 10, pal = NULL, categorical = FALSE, na.value = "grey", ... )tectonicr.colors( x, n = 10, pal = NULL, categorical = FALSE, na.value = "grey", ... )
x |
values for color assignment |
n |
integer. number of colors for continuous colors (i.e. 'categorical = FALSE“). |
pal |
either a named vector specifying the colors for categorical
values, or a color function. If |
categorical |
logical. |
na.value |
color for |
... |
optional arguments passed to palette function |
named color vector
val1 <- c("N", "S", "T", "T", NA) tectonicr.colors(val1, categorical = TRUE) tectonicr.colors(val1, pal = stress_colors(), categorical = TRUE) val2 <- runif(10) tectonicr.colors(val2, n = 5)val1 <- c("N", "S", "T", "T", NA) tectonicr.colors(val1, categorical = TRUE) tectonicr.colors(val1, pal = stress_colors(), categorical = TRUE) val2 <- runif(10) tectonicr.colors(val2, n = 5)
Vector or cross product
vcross(x, y)vcross(x, y)
x, y
|
numeric vectors of length 3 |
numeric vector of length 3
vcross(c(1, 2, 3), c(4, 5, 6))vcross(c(1, 2, 3), c(4, 5, 6))
Produces a Q-Q plot of the data against a specified von Mises distribution to graphically assess the goodness of fit of the model.
vm_qqplot( x, w = NULL, axial = TRUE, mean = NULL, kappa = NULL, xlab = "von Mises quantile function", ylab = "Empirical quantile function", main = "von Mises Q-Q Plot", col = "#B63679FF", add_line = TRUE, ... )vm_qqplot( x, w = NULL, axial = TRUE, mean = NULL, kappa = NULL, xlab = "von Mises quantile function", ylab = "Empirical quantile function", main = "von Mises Q-Q Plot", col = "#B63679FF", add_line = TRUE, ... )
x |
numeric. Angles in degrees |
w |
numeric. optional weightings for |
axial |
Logical. Whether data are uniaxial ( |
mean |
numeric. Circular mean of the von Mises distribution. If |
kappa |
numeric. Concentration parameter of the von Mises distribution.
If |
xlab, ylab, main
|
plot labels. |
col |
color for the dots. |
add_line |
logical. Whether to connect the points by straight lines? |
... |
graphical parameters |
plot
Other circ-qqplot:
circular_qqplot()
set.seed(20250411) # von Mises distribution x_vm <- rvm(100, mean = 0, kappa = 2) vm_qqplot(x_vm, pch = 20) x_wcauchy <- rwcauchy(100, mean = 0, rho = 0.5) vm_qqplot(x_wcauchy, pch = 20) # circular uniform data x_cunif <- rcunif(100) vm_qqplot(x_cunif, pch = 20)set.seed(20250411) # von Mises distribution x_vm <- rvm(100, mean = 0, kappa = 2) vm_qqplot(x_vm, pch = 20) x_wcauchy <- rwcauchy(100, mean = 0, rho = 0.5) vm_qqplot(x_wcauchy, pch = 20) # circular uniform data x_cunif <- rcunif(100) vm_qqplot(x_cunif, pch = 20)
Density, probability distribution function, quantiles, and random generation
for the circular normal distribution with mean and kappa .
rvm(n, mean, kappa) dvm(theta, mean, kappa, axial = FALSE, log = FALSE) pvm(theta, mean, kappa, from = NULL, tol = 1e-20) qvm(p, mean, kappa, from = NULL, tol = .Machine$double.eps^(0.6), ...)rvm(n, mean, kappa) dvm(theta, mean, kappa, axial = FALSE, log = FALSE) pvm(theta, mean, kappa, from = NULL, tol = 1e-20) qvm(p, mean, kappa, from = NULL, tol = .Machine$double.eps^(0.6), ...)
n |
number of observations. If |
mean |
numeric. The mean vector in degrees. |
kappa |
numeric. Concentration parameter in the range |
theta |
numeric. Angular value in degrees |
axial |
logical. Whether the data are axial, i.e. |
log |
logical. If |
from |
if |
tol |
numeric. The precision in evaluating the distribution function or the quantile. |
p |
numeric. Vector of probabilities with values in |
... |
parameters passed to |
dvm gives the density,
pvm gives the probability of the von Mises distribution function,
rvm generates random deviates (in degrees), and
qvm provides quantiles (in degrees).
set.seed(1) x <- rvm(5, mean = 90, kappa = 2) dvm(x, mean = 90, kappa = 2) dvm(x, mean = 90, kappa = 2, axial = TRUE) pvm(x, mean = 90, kappa = 2) qvm(c(.25, .5, .75), mean = 90, kappa = 2)set.seed(1) x <- rvm(5, mean = 90, kappa = 2) dvm(x, mean = 90, kappa = 2) dvm(x, mean = 90, kappa = 2, axial = TRUE) pvm(x, mean = 90, kappa = 2) qvm(c(.25, .5, .75), mean = 90, kappa = 2)
Test for Goodness-of-Fit against known DistributionA non-parametric statistical test used for circular data to determine whether a sample fits a specified theoretical distribution
watson_test( x, alpha = NULL, dist = c("uniform", "vonmises"), axial = TRUE, quiet = FALSE )watson_test( x, alpha = NULL, dist = c("uniform", "vonmises"), axial = TRUE, quiet = FALSE )
x |
numeric vector. Values in degrees |
alpha |
Significance level of the test. Valid levels are |
dist |
Distribution to test for. The default, |
axial |
logical. Whether the data are axial, i.e. |
quiet |
logical. Prints the test's decision. |
Null Hypothesis (): The circular sample comes from a specified
theoretical distribution (such as a uniform distribution or a specific von Mises distribution).
Alternative Hypothesis (): The circular sample does not follow the specified theoretical distribution.
To interpret the output of Watson's test, compare your
calculated test statistic to the critical value from
Watson's goodness-of-fit/homogeneity tables at your chosen significance level (, commonly set to 0.05),
or check the resulting p-value:
If (or p < ):
Reject the null hypothesis ().
Conclude that the data significantly deviates from the theoretical distribution.
If (or ):
Fail to reject the null hypothesis ().
There is not enough evidence to claim the data deviates from the expected model.
list containing the test statistic statistic, the significance
level p.value, the critical value critical.value, whether to reject the null hypothesis,
the significance level alpha, the tested distribution dist, and the number of data n
Watson's test statistic is a rotation-invariant Cramer - von Mises test. non-parametric, rank-based alternative to one-sample
Mardia and Jupp (1999). Directional Statistics. John Wiley and Sons.
Other Tests:
ar_test(),
kuiper_test(),
norm_chisq(),
rayleigh-test,
watson_two_sample,
watson_wheeler_test_perm(),
weighted-rayleigh-test
# Example data from Mardia and Jupp (1999), pp. 93 watson_test(homing, axial = FALSE, alpha = .05) # San Andreas Fault Data: data(san_andreas) data("nuvel1") PoR <- subset(nuvel1, nuvel1$plate.rot == "na") sa.por <- PoR_shmax(san_andreas, PoR, "right") watson_test(sa.por$azi.PoR, alpha = .05) watson_test(sa.por$azi.PoR, alpha = .05, dist = "vonmises") watson_test(sa.por$azi.PoR, alpha = .05, dist = "vonmises")# Example data from Mardia and Jupp (1999), pp. 93 watson_test(homing, axial = FALSE, alpha = .05) # San Andreas Fault Data: data(san_andreas) data("nuvel1") PoR <- subset(nuvel1, nuvel1$plate.rot == "na") sa.por <- PoR_shmax(san_andreas, PoR, "right") watson_test(sa.por$azi.PoR, alpha = .05) watson_test(sa.por$azi.PoR, alpha = .05, dist = "vonmises") watson_test(sa.por$azi.PoR, alpha = .05, dist = "vonmises")
Performs Watson's test for homogeneity on two samples of circular data.
watson_two_test_perm() uses permutation to estimate p-values.
watson_two_test(x, y, alpha = NULL, axial = TRUE, quiet = FALSE) watson_two_test_perm(x, y, axial = TRUE, n_perm = 1000L, alpha = NULL)watson_two_test(x, y, alpha = NULL, axial = TRUE, quiet = FALSE) watson_two_test_perm(x, y, axial = TRUE, n_perm = 1000L, alpha = NULL)
x, y
|
numeric vectors. Angles in degrees |
alpha |
Significance level of the test. Valid levels are |
axial |
logical. Whether the data are axial, i.e. |
quiet |
logical. Prints the test's decision. |
n_perm |
integer. Number of permutations |
A two-sample Watson's permutation test determines whether two
independent groups of circular data (angles or directions) come from the same
underlying distribution.
Null Hypothesis (): The two samples come from the same circular
distribution (the two groups of angles share a common distribution around the circle).
Alternative Hypothesis (): The two samples come from different
circular distributions (the groups are oriented or dispersed differently around the circle).
The Test Statistic () measures the distance between the cumulative distribution
functions of the two circular samples. A larger value means the
two sets of angles look more different from each other.
The P-Value represents the probability of getting a U² value as large as (or larger than) your observed value purely by chance, assuming the null hypothesis is true. It is calculated by shuffling the group labels across your data many times to build a reference permutation distribution.
Low p-value (, usually 0.05): Reject the null hypothesis. Conclude that
the two groups have significantly different circular distributions.
High p-value (): Fail to reject the null hypothesis. There is not
enough evidence to say the two groups are distributed differently around the circle.
list. Watson's two-sample test of homogeneity is performed, and the results are printed. If alpha is specified and non-zero, the test statistic is printed along with the critical value and decision. If alpha is omitted, the test statistic is printed and a range for the p-value of the test is given.
Critical values for the test statistic are obtained using the asymptotic distribution of the test statistic. It is recommended to use the obtained critical values and ranges for p-values only for combined sample sizes in excess of 17. Tables are available for smaller sample sizes and can be found in Mardia (1972) for instance.
Other Tests:
ar_test(),
kuiper_test(),
norm_chisq(),
rayleigh-test,
watson_test(),
watson_wheeler_test_perm(),
weighted-rayleigh-test
set.seed(20250411) x1 <- c(35, 45, 50, 55, 60, 70, 85, 95, 105, 120) x2 <- c(75, 80, 90, 100, 110, 130, 135, 140, 150, 160, 165) watson_two_test(x1, x2, axial = FALSE) watson_two_test_perm(x1, x2, axial = FALSE) data1 <- rvm(n=20, mean = 0, kappa=3) data2 <- rvm(n=20, mean = 90, kappa=2) watson_two_test(data1, data2, axial = FALSE) watson_two_test_perm(data1, data2, axial = FALSE) # San Andreas Fault Data: data(san_andreas) data("nuvel1") PoR <- subset(nuvel1, nuvel1$plate.rot == "na") sa.por <- PoR_shmax(san_andreas, PoR, "right") watson_two_test(sa.por$azi, 135, alpha = 0.05) watson_two_test_perm(sa.por$azi, rvm(100, 135, 10), alpha = 0.05)set.seed(20250411) x1 <- c(35, 45, 50, 55, 60, 70, 85, 95, 105, 120) x2 <- c(75, 80, 90, 100, 110, 130, 135, 140, 150, 160, 165) watson_two_test(x1, x2, axial = FALSE) watson_two_test_perm(x1, x2, axial = FALSE) data1 <- rvm(n=20, mean = 0, kappa=3) data2 <- rvm(n=20, mean = 90, kappa=2) watson_two_test(data1, data2, axial = FALSE) watson_two_test_perm(data1, data2, axial = FALSE) # San Andreas Fault Data: data(san_andreas) data("nuvel1") PoR <- subset(nuvel1, nuvel1$plate.rot == "na") sa.por <- PoR_shmax(san_andreas, PoR, "right") watson_two_test(sa.por$azi, 135, alpha = 0.05) watson_two_test_perm(sa.por$azi, rvm(100, 135, 10), alpha = 0.05)
A a non-parametric statistical test used to determine whether two or more independent samples of circular data (angles, directions, or periodic times) come from the same underlying population distribution. The difference between the samples can be in either the mean or the variance.
watson_wheeler_test_perm(x, y, axial = TRUE, n_perm = 1000L, alpha = NULL)watson_wheeler_test_perm(x, y, axial = TRUE, n_perm = 1000L, alpha = NULL)
x, y
|
numeric vectors. Angles in degrees |
axial |
logical. Whether the data are axial, i.e. |
n_perm |
integer. Number of permutations |
alpha |
Significance level of the test. Valid levels are |
Null Hypothesis () The samples come from identical populations (meaning
both the mean direction and the dispersion/variance are homogeneous across groups).
Alternative Hypothesis (): At least one sample comes from a different
population distribution, which can be due to a difference in the mean direction,
a difference in variance/concentration, or both.
Test Statistic (W): This value follows an approximate distribution.
Higher values of W indicate larger discrepancies between the angular distributions of your groups.
If the p-value is less than your significance level (commonly = 0.05),
you reject the null hypothesis.
This means you have strong evidence that the groups differ significantly in
their central direction or spread around the circle.
If the p-value is greater than 0.05, you fail to reject the null hypothesis, meaning there is no statistically significant evidence of difference among the groups.
list
Important Considerations & Limitations:
Sensitivity to both mean and variance: Because it detects differences in either mean or variance, a significant result does not automatically mean the mean angles are different; it could be driven entirely by differences in concentration (variance).
Sample size requirement: The chi-squared approximation requires each group to have a minimum sample size (typically at least 10 elements per group) to remain valid.
Other Tests:
ar_test(),
kuiper_test(),
norm_chisq(),
rayleigh-test,
watson_test(),
watson_two_sample,
weighted-rayleigh-test
set.seed(20250411) x1 <- c(35, 45, 50, 55, 60, 70, 85, 95, 105, 120) x2 <- c(75, 80, 90, 100, 110, 130, 135, 140, 150, 160, 165) watson_wheeler_test_perm(x1, x2, axial = FALSE) data1 <- rvm(n=20, mean = 0, kappa=3) data2 <- rvm(n=20, mean = 90, kappa=2) watson_wheeler_test_perm(data1, data2, axial = FALSE) # San Andreas Fault Data: data(san_andreas) data("nuvel1") PoR <- subset(nuvel1, nuvel1$plate.rot == "na") sa.por <- PoR_shmax(san_andreas, PoR, "right") watson_wheeler_test_perm(sa.por$azi.PoR, rvm(100, 135, 10))set.seed(20250411) x1 <- c(35, 45, 50, 55, 60, 70, 85, 95, 105, 120) x2 <- c(75, 80, 90, 100, 110, 130, 135, 140, 150, 160, 165) watson_wheeler_test_perm(x1, x2, axial = FALSE) data1 <- rvm(n=20, mean = 0, kappa=3) data2 <- rvm(n=20, mean = 90, kappa=2) watson_wheeler_test_perm(data1, data2, axial = FALSE) # San Andreas Fault Data: data(san_andreas) data("nuvel1") PoR <- subset(nuvel1, nuvel1$plate.rot == "na") sa.por <- PoR_shmax(san_andreas, PoR, "right") watson_wheeler_test_perm(sa.por$azi.PoR, rvm(100, 135, 10))
Density, probability distribution function, quantiles, and random generation
for the circular wrapped Cauchy distribution with mean and rho
rwcauchy(n, mean, rho) dwcauchy(theta, mean, rho, axial = FALSE, log = FALSE) pwcauchy( theta, mean, rho, axial = FALSE, from = NULL, lower.tail = TRUE, log.p = FALSE ) qwcauchy( p, mean, rho, axial = FALSE, from = NULL, lower.tail = TRUE, log.p = FALSE )rwcauchy(n, mean, rho) dwcauchy(theta, mean, rho, axial = FALSE, log = FALSE) pwcauchy( theta, mean, rho, axial = FALSE, from = NULL, lower.tail = TRUE, log.p = FALSE ) qwcauchy( p, mean, rho, axial = FALSE, from = NULL, lower.tail = TRUE, log.p = FALSE )
n |
number of observations. If |
mean |
numeric. The mean vector in degrees. |
rho |
numeric. Concentration parameter in the range (0, 1) |
theta |
numeric. Angular value in degrees |
axial |
logical. Whether the data are axial, i.e. |
log |
logical. If |
from |
if |
lower.tail |
logical; if TRUE (default), probabilities are
|
log.p |
logical. If |
p |
numeric. Vector of probabilities with values in |
dwcauchy gives the density,
pwcauchy gives the probability of the wrapped Cauchy distribution function,
rwcauchy generates random deviates (in degrees), and
qrwcauchy provides quantiles (in degrees).
set.seed(1) x <- rwcauchy(5, mean = 90, rho = exp(-1)) dwcauchy(x, mean = 90, rho = exp(-1)) dwcauchy(x, mean = 90, rho = exp(-1), axial = TRUE) pwcauchy(x, mean = 90, rho = exp(-1)) qwcauchy(c(.25, .5, .75), mean = 90, rho = exp(-1))set.seed(1) x <- rwcauchy(5, mean = 90, rho = exp(-1)) dwcauchy(x, mean = 90, rho = exp(-1)) dwcauchy(x, mean = 90, rho = exp(-1), axial = TRUE) pwcauchy(x, mean = 90, rho = exp(-1)) qwcauchy(c(.25, .5, .75), mean = 90, rho = exp(-1))
Weighted version of the Rayleigh test (or V0-test) for uniformity against a
distribution with a priori expected von Mises concentration.
weighted_rayleight_test_perm() uses permutation to estimate p-values.
weighted_rayleigh(x, mu = NULL, w = NULL, axial = TRUE, quiet = FALSE) weighted_rayleigh_perm(x, mu = NULL, w = NULL, axial = TRUE, n_perm = 1000L)weighted_rayleigh(x, mu = NULL, w = NULL, axial = TRUE, quiet = FALSE) weighted_rayleigh_perm(x, mu = NULL, w = NULL, axial = TRUE, n_perm = 1000L)
x |
numeric vector. Values in degrees |
mu |
(optional) The specified or known mean direction (in degrees) in alternative hypothesis. |
w |
numeric vector weights of length |
axial |
logical. Whether the data are axial, i.e. |
quiet |
logical. Prints the test's decision. |
n_perm |
integer. Number of permutations |
The Null hypothesis is uniformity (randomness). The alternative is a
distribution with a (specified) mean direction (mu).
If statistic >= p.value, the null hypothesis of randomness is rejected and
angles derive from a distribution with a (or the specified) mean direction.
a list with the components:
R or C
mean resultant length or the dispersion (if mu is
specified). Small values of R (large values of C) will reject
uniformity. Negative values of C indicate that vectors point in opposite
directions (also lead to rejection).
statisticTest statistic
p.valuesignificance level of the test statistic
Other Tests:
ar_test(),
kuiper_test(),
norm_chisq(),
rayleigh-test,
watson_test(),
watson_two_sample,
watson_wheeler_test_perm()
# Load data data("cpm_models") data(san_andreas) PoR <- equivalent_rotation(cpm_models[["NNR-MORVEL56"]], "na", "pa") sa.por <- PoR_shmax(san_andreas, PoR, "right") data("iceland") PoR.ice <- equivalent_rotation(cpm_models[["NNR-MORVEL56"]], "eu", "na") ice.por <- PoR_shmax(iceland, PoR.ice, "out") data("tibet") PoR.tib <- equivalent_rotation(cpm_models[["NNR-MORVEL56"]], "eu", "in") tibet.por <- PoR_shmax(tibet, PoR.tib, "in") # GOF test: weighted_rayleigh(tibet.por$azi.PoR, mu = 90, w = 1 / tibet$unc) weighted_rayleigh(ice.por$azi.PoR, mu = 0, w = 1 / iceland$unc) weighted_rayleigh(sa.por$azi.PoR, mu = 135, w = 1 / san_andreas$unc) weighted_rayleigh_perm(tibet.por$azi.PoR, mu = 90, w = 1 / tibet$unc) weighted_rayleigh_perm(ice.por$azi.PoR, mu = 0, w = 1 / iceland$unc) weighted_rayleigh_perm(sa.por$azi.PoR, mu = 135, w = 1 / san_andreas$unc)# Load data data("cpm_models") data(san_andreas) PoR <- equivalent_rotation(cpm_models[["NNR-MORVEL56"]], "na", "pa") sa.por <- PoR_shmax(san_andreas, PoR, "right") data("iceland") PoR.ice <- equivalent_rotation(cpm_models[["NNR-MORVEL56"]], "eu", "na") ice.por <- PoR_shmax(iceland, PoR.ice, "out") data("tibet") PoR.tib <- equivalent_rotation(cpm_models[["NNR-MORVEL56"]], "eu", "in") tibet.por <- PoR_shmax(tibet, PoR.tib, "in") # GOF test: weighted_rayleigh(tibet.por$azi.PoR, mu = 90, w = 1 / tibet$unc) weighted_rayleigh(ice.por$azi.PoR, mu = 0, w = 1 / iceland$unc) weighted_rayleigh(sa.por$azi.PoR, mu = 135, w = 1 / san_andreas$unc) weighted_rayleigh_perm(tibet.por$azi.PoR, mu = 90, w = 1 / tibet$unc) weighted_rayleigh_perm(ice.por$azi.PoR, mu = 0, w = 1 / iceland$unc) weighted_rayleigh_perm(sa.por$azi.PoR, mu = 135, w = 1 / san_andreas$unc)
Helper function to transform uncertainty angles into weighting factors
weighting( x, method = c("linear-inverse", "inverse", "cosine", "none"), max.err = 90, norm = TRUE )weighting( x, method = c("linear-inverse", "inverse", "cosine", "none"), max.err = 90, norm = TRUE )
x |
numeric. Uncertainty angle in degrees. |
method |
character. One of |
max.err |
numeric. The maximum expected error for x (90 by default). |
norm |
logical. Whether weights should be normalized so that the sum of the weights is 1. |
Linear inverse: , where is the maximum error expected for (e.g. ).
Inverse:
Cosine:
numeric
x <- seq(0, 90, 1) plot(x, weighting(x, "inverse"), col = 1, type = "l", xlab = "Uncertainty angle in degrees", ylab = "weight" ) lines(x, weighting(x, "cosine"), col = 2) lines(x, weighting(x, "linear-inverse"), col = 3) legend("topright", col = 1:3, lty = 1, legend = c("inverse", "cosine", "linear-inverse") )x <- seq(0, 90, 1) plot(x, weighting(x, "inverse"), col = 1, type = "l", xlab = "Uncertainty angle in degrees", ylab = "weight" ) lines(x, weighting(x, "cosine"), col = 2) lines(x, weighting(x, "linear-inverse"), col = 3) legend("topright", col = 1:3, lty = 1, legend = c("inverse", "cosine", "linear-inverse") )
Density, probability distribution function, quantiles, and random generation
for the circular normal distribution with mean and standard deviation .
rwnorm(n, mean = 0, sd = 1) dwnorm(theta, mean = 0, sd = 1, axial = FALSE, log = FALSE) pwnorm(theta, mean = 0, sd = 1, axial = FALSE, from = NULL, ...) qwnorm( p, mean = 0, sd = 1, axial = FALSE, from = NULL, tol = .Machine$double.eps^(0.6), ... )rwnorm(n, mean = 0, sd = 1) dwnorm(theta, mean = 0, sd = 1, axial = FALSE, log = FALSE) pwnorm(theta, mean = 0, sd = 1, axial = FALSE, from = NULL, ...) qwnorm( p, mean = 0, sd = 1, axial = FALSE, from = NULL, tol = .Machine$double.eps^(0.6), ... )
n |
number of observations. If |
mean |
numeric. The mean vector in degrees. |
sd |
numeric. standard deviation of the (unwrapped) normal distribution in degrees. |
theta |
numeric. Angular value in degrees |
axial |
logical. Whether the data are axial, i.e. |
log |
logical. If |
from |
if |
... |
optional parameters passed to underlying circular functions
|
p |
numeric. Vector of probabilities with values in |
tol |
numeric. The precision in evaluating the distribution function or the quantile. |
dwnorm gives the density,
pwnorm gives the probability of the wrapped normal distribution function,
rwnorm generates random deviates (in degrees), and
qwnorm provides quantiles (in degrees).
cunif, wnorm, wcauchy, and vonmises
set.seed(1) x <- rwnorm(5, mean = 90, sd = 5) dwnorm(x, mean = 90, sd = 5, axial = FALSE) dwnorm(x, mean = 90, sd = 5, axial = TRUE) pwnorm(x, mean = 90, sd = 5) qwnorm(c(.25, .5, .75), mean = 90, sd = 5)set.seed(1) x <- rwnorm(5, mean = 90, sd = 5) dwnorm(x, mean = 90, sd = 5, axial = FALSE) dwnorm(x, mean = 90, sd = 5, axial = TRUE) pwnorm(x, mean = 90, sd = 5) qwnorm(c(.25, .5, .75), mean = 90, sd = 5)