Quick start: from vowel table to metrics and plots

Most analyses should start with a token-level table: one row per observation, one column for the category contrast, and one or more numeric acoustic features. phontrast() is the preferred entry point because it returns the main overlap and separation metrics side by side.

library(phontrast)

set.seed(2026)
vowels <- data.frame(
  speaker = rep(c("s01", "s02"), each = 60),
  vowel = rep(rep(c("ih", "eh"), each = 30), 2),
  f1 = c(
    rnorm(30, 500, 55), rnorm(30, 560, 60),
    rnorm(30, 510, 60), rnorm(30, 575, 65)
  ),
  f2 = c(
    rnorm(30, 1980, 150), rnorm(30, 1880, 155),
    rnorm(30, 1960, 160), rnorm(30, 1840, 165)
  )
)

The wide output is useful for analysis tables and joining to speaker metadata.

metrics_wide <- phontrast(
  data = vowels,
  features = c("f1", "f2"),
  category_col = "vowel",
  group_col = "speaker",
  output = "wide"
)

metrics_wide
#> # A tibble: 2 × 11
#>   scope group n_tokens pillai pillai_p_value bhatt_dist bhatt_affinity   jsd
#>   <chr> <chr>    <int>  <dbl>          <dbl>      <dbl>          <dbl> <dbl>
#> 1 group s01         60  0.316      0.0000198      0.276          0.758 0.288
#> 2 group s02         60  0.250      0.000278       0.166          0.847 0.164
#> # ℹ 3 more variables: js_distance <dbl>, mahalanobis_dist <dbl>,
#> #   percent_overlap <dbl>

The long output is easier to rank, filter, and plot. separation_value puts all metrics on a separation-oriented scale: larger values mean greater category separation, even for overlap metrics such as percent overlap and Bhattacharyya affinity.

metrics_long <- phontrast(
  data = vowels,
  features = c("f1", "f2"),
  category_col = "vowel",
  group_col = "speaker",
  output = "long"
)

metrics_long[, c("group", "metric", "estimate", "orientation", "separation_value")]
#> # A tibble: 14 × 5
#>    group metric                    estimate orientation separation_value
#>    <chr> <chr>                        <dbl> <chr>                  <dbl>
#>  1 s01   Pillai trace                 0.316 separation             0.316
#>  2 s02   Pillai trace                 0.250 separation             0.250
#>  3 s01   Bhattacharyya distance       0.276 separation             0.276
#>  4 s02   Bhattacharyya distance       0.166 separation             0.166
#>  5 s01   Bhattacharyya affinity       0.758 overlap                0.242
#>  6 s02   Bhattacharyya affinity       0.847 overlap                0.153
#>  7 s01   Jensen-Shannon divergence    0.288 separation             0.288
#>  8 s02   Jensen-Shannon divergence    0.164 separation             0.164
#>  9 s01   Jensen-Shannon distance      0.537 separation             0.537
#> 10 s02   Jensen-Shannon distance      0.406 separation             0.406
#> 11 s01   Mahalanobis distance         1.34  separation             1.34 
#> 12 s02   Mahalanobis distance         1.13  separation             1.13 
#> 13 s01   Percent overlap              0.425 overlap                0.575
#> 14 s02   Percent overlap              0.643 overlap                0.357

If ggplot2 is installed, the same objects can be visualized directly.

plot_category_space(
  data = vowels,
  features = c("f2", "f1"),
  category_col = "vowel",
  group_col = "speaker",
  reverse_x = TRUE,
  reverse_y = TRUE
)


plot_overlap_metrics(metrics_long)

For uncertainty intervals, use do_boot = TRUE. Bootstrapping recomputes every metric on every resample, so use a larger n_boot for final analyses than for interactive examples.

phontrast(
  data = vowels,
  features = c("f1", "f2"),
  category_col = "vowel",
  group_col = "speaker",
  do_boot = TRUE,
  n_boot = 1000,
  output = "long"
)