## ----include = FALSE---------------------------------------------------------- knitr::opts_chunk$set(collapse = TRUE, comment = "#>", fig.width = 7, fig.height = 5) ## ----------------------------------------------------------------------------- library(ggplot2) library(dplyr) library(ggcircular) ## ----------------------------------------------------------------------------- boundary_angles <- tibble( theta = c(0.05, 0.10, 2 * pi - 0.10, 2 * pi - 0.05) ) boundary_angles |> summarise( arithmetic_mean = mean(theta), circular_mean = mean_direction(theta), Rbar = mean_resultant_length(theta) ) ## ----------------------------------------------------------------------------- glimpse(wind_directions) glimpse(animal_steps) glimpse(hourly_activity) glimpse(axial_orientations) ## ----------------------------------------------------------------------------- wind_directions |> count(season, station) ## ----------------------------------------------------------------------------- directional <- c(0, pi) axial <- c(0, pi) tibble( case = c("directional", "axial"), Rbar = c( mean_resultant_length(directional), mean_resultant_length(axial, axial = TRUE) ), mean = c( mean_direction(directional), mean_direction(axial, axial = TRUE) ) ) ## ----------------------------------------------------------------------------- tibble( degrees = c(0, 90, 180, 270), radians = deg_to_rad(degrees), hours = rad_to_hour(radians), compass = rad_to_compass(radians) ) ## ----------------------------------------------------------------------------- ggplot(wind_directions, aes(x = direction)) + geom_rose(bins = 16) + scale_x_circular_degrees() + coord_circular() + theme_circular() ## ----------------------------------------------------------------------------- ggplot(wind_directions, aes(x = direction)) + geom_rose( aes(fill = after_stat(proportion)), bins = 16, normalize = "proportion" ) + scale_x_circular_degrees() + coord_circular() + theme_rose() ## ----------------------------------------------------------------------------- ggplot(wind_directions, aes(x = direction, fill = season)) + geom_rose(bins = 16, alpha = 0.75) + facet_wrap(~ season) + scale_x_circular_degrees() + coord_circular() + theme_circular() ## ----------------------------------------------------------------------------- ggplot(wind_directions, aes(x = direction)) + geom_rose(aes(y = after_stat(density)), bins = 24, alpha = 0.35) + geom_circular_density(linewidth = 1) + scale_x_circular_degrees() + coord_circular() + theme_circular() ## ----------------------------------------------------------------------------- ggplot(wind_directions, aes(x = direction)) + geom_circular_density(bw = 0.25, linewidth = 1) + geom_circular_density(bw = 0.75, linetype = 2) + scale_x_circular_degrees() + coord_circular() + theme_circular() ## ----------------------------------------------------------------------------- wind_directions |> group_by(season) |> circular_summary(direction) ## ----------------------------------------------------------------------------- ggplot(wind_directions, aes(x = direction, colour = season)) + geom_circular_density(linewidth = 1) + geom_mean_direction(length = "resultant") + scale_x_circular_degrees() + coord_circular() + theme_circular() ## ----------------------------------------------------------------------------- circular_mean_ci(wind_directions$direction, method = "large_sample") rayleigh_test(wind_directions$direction) ## ----------------------------------------------------------------------------- ggplot(wind_directions, aes(x = direction)) + geom_rose(bins = 16, alpha = 0.8) + stat_circular_test(test = "rayleigh", y = 1.1, size = 3) + scale_x_circular_degrees() + coord_circular() + theme_circular() ## ----------------------------------------------------------------------------- ggplot(wind_directions, aes(x = direction)) + geom_rose(bins = 16, aes(fill = after_stat(count))) + geom_mean_direction() + scale_x_circular_compass() + coord_circular(zero = "north", direction = "clockwise") + theme_compass() ## ----------------------------------------------------------------------------- axial_orientations |> group_by(group) |> circular_summary(orientation, axial = TRUE) ## ----------------------------------------------------------------------------- ggplot(axial_orientations, aes(x = orientation, fill = group)) + geom_rose(bins = 18, axial = TRUE, alpha = 0.7) + geom_mean_direction(axial = TRUE) + scale_x_circular_degrees(limits = c(0, pi)) + coord_circular() + theme_circular() ## ----------------------------------------------------------------------------- animal_steps |> group_by(state) |> summarise( mean_step = mean(step_length, na.rm = TRUE), median_step = median(step_length, na.rm = TRUE), .groups = "drop" ) ## ----------------------------------------------------------------------------- ggplot(animal_steps, aes(x = x, y = y, group = id, colour = id)) + geom_path(alpha = 0.7) + coord_equal() + theme_minimal() ## ----------------------------------------------------------------------------- plot_state_angles(animal_steps, angle = turn_angle, state = state, type = "rose") ## ----------------------------------------------------------------------------- plot_state_angles(animal_steps, angle = turn_angle, state = state, type = "density") ## ----------------------------------------------------------------------------- fit_mix <- fit_vonmises_mixture( wind_directions$direction, k = 2, nstart = 3, seed = 2026, max_iter = 200 ) tidy_circular(fit_mix) glance_circular(fit_mix) ## ----------------------------------------------------------------------------- ggplot(wind_directions, aes(x = direction)) + geom_rose(aes(y = after_stat(density)), bins = 24, alpha = 0.35) + stat_vonmises_mixture(fit = fit_mix, linewidth = 1) + scale_x_circular_degrees() + coord_circular() + theme_circular() ## ----------------------------------------------------------------------------- fit <- structure( list( y = wind_directions$direction[1:50], mui = normalize_angle(wind_directions$direction[1:50] + rnorm(50, 0, 0.15)), term_labels = c("intercept", "speed") ), class = "angular" ) tidy_circular(fit) glance_circular(fit) circular_model_diagnostics(fit) ## ----------------------------------------------------------------------------- autoplot(fit, type = "residuals_density") ## ----------------------------------------------------------------------------- if (requireNamespace("posterior", quietly = TRUE)) { set.seed(1) draws <- posterior::draws_df( theta = rnorm(400, mean = pi / 3, sd = 0.25), phi = rnorm(400, mean = pi, sd = 0.35) ) circular_draws <- as_circular_draws(draws, variables = c("theta", "phi")) summarise_circular_draws(circular_draws) } ## ----------------------------------------------------------------------------- if (requireNamespace("posterior", quietly = TRUE)) { autoplot_circular_draws(circular_draws) }