--- title: "Validation examples" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Validation examples} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set(collapse = TRUE, comment = "#>", fig.width = 7, fig.height = 5) ``` # Purpose This vignette gives reproducible validation examples for the main numerical components in `ggcircular`. The goal is not to provide a formal proof. The goal is to make core assumptions visible and testable. ```{r} library(ggplot2) library(dplyr) library(ggcircular) ``` # Boundary behavior Angles close to zero and `2 * pi` should have a mean close to zero. ```{r} boundary_angles <- c(0.02, 0.05, 2 * pi - 0.05, 2 * pi - 0.02) tibble( arithmetic_mean = mean(boundary_angles), circular_mean = mean_direction(boundary_angles), Rbar = mean_resultant_length(boundary_angles) ) ``` # Axial behavior Angles separated by `pi` cancel for directional data but agree for axial data. ```{r} theta <- c(0, pi) tibble( setting = c("directional", "axial"), mean = c(mean_direction(theta), mean_direction(theta, axial = TRUE)), Rbar = c(mean_resultant_length(theta), mean_resultant_length(theta, axial = TRUE)) ) ``` # Known mean direction The following simulation is concentrated around `pi / 3`. ```{r} set.seed(20260531) known_mean <- pi / 3 simulated_angles <- normalize_angle(rnorm(400, mean = known_mean, sd = 0.25)) circular_summary(tibble(theta = simulated_angles), theta) angular_distance(mean_direction(simulated_angles), known_mean) ``` ```{r} ggplot(tibble(theta = simulated_angles), aes(x = theta)) + geom_rose(aes(y = after_stat(density)), bins = 24, alpha = 0.4) + geom_circular_density(linewidth = 1) + geom_mean_direction() + stat_vonmises_fit(linewidth = 1, linetype = 2) + scale_x_circular_degrees() + coord_circular() + theme_circular() ``` # Von Mises mixture recovery A two-component mixture should recover two separated modes in this simple simulation. ```{r} set.seed(20260531) mixture_angles <- c( normalize_angle(rnorm(250, mean = pi / 4, sd = 0.20)), normalize_angle(rnorm(250, mean = 5 * pi / 4, sd = 0.25)) ) mixture_fit <- fit_vonmises_mixture(mixture_angles, k = 2, max_iter = 100) tidy_circular(mixture_fit) glance_circular(mixture_fit) ``` ```{r} ggplot(tibble(theta = mixture_angles), aes(x = theta)) + geom_rose(aes(y = after_stat(density)), bins = 32, alpha = 0.35) + stat_vonmises_mixture(fit = mixture_fit, linewidth = 1) + scale_x_circular_degrees() + coord_circular() + theme_circular() ``` # Optional comparison with circular When the optional `circular` package is installed, the mean direction can be compared against `circular::mean.circular()`. ```{r} if (requireNamespace("circular", quietly = TRUE)) { tibble( ggcircular = mean_direction(simulated_angles), circular = as.numeric(circular::mean.circular(circular::circular(simulated_angles))) ) } ``` # CRAN readiness checks The CRAN-oriented validation is intentionally separate from the statistical examples above. Before release, the package is checked with: ```{r, eval = FALSE} devtools::test() devtools::check(document = FALSE, args = "--as-cran", build_args = "--no-manual") devtools::check( document = FALSE, args = c("--as-cran", "--run-donttest"), build_args = "--no-manual" ) tools::checkRdaFiles("data") ``` The GitHub Actions workflow also includes a strict hard-dependency profile, a full-suggests profile and Linux R-devel. # Interpretation These examples are regression checks for expected behavior. They do not cover all inferential assumptions. In particular, small-sample inference, multimodal mixtures and model diagnostics should be interpreted with care.