MyNixOS website logo
Description

Asymmetric Smoothed-Association Matrices via GAM Fits.

Render a pairwise, asymmetric smoothed-association matrix of continuous variables. Each cell shows the fitted spline from an 'mgcv' generalised additive model, with the upper triangle displaying 'gam(x_j ~ s(x_i))' and the lower triangle 'gam(x_i ~ s(x_j))'. Unlike Pearson's correlation matrix, the visualisation is intentionally asymmetric, revealing heteroscedasticity, leverage, and directional non-linearity that a single scalar correlation hides. An asymmetry index and a 24-category shape taxonomy quantify the directional difference and qualitative form of each fitted smooth.

janusplot janusplot logo

R-CMD-check test-coverage pkgdown Lifecycle:experimental

Asymmetric, GAM-based smoothed-association matrices for continuous variables. Each off-diagonal cell shows a directional mgcv::gam(y ~ s(x)) fit, so the upper and lower triangles tell different stories whenever the relationship is genuinely asymmetric — precisely where a scalar Pearson correlation loses information.

Two novelties, paired with the asymmetry story:

  1. Asymmetry indexA = |EDF_yx − EDF_xy| / (EDF_yx + EDF_xy) ∈ [0, 1] — a single-number summary of the directional disparity per pair.
  2. 24-category shape taxonomy — each fitted smooth is classified into one of 24 named shapes (linear_up, skewed_peak, bimodal, bi_wave, rippled_monotone, …) via a (T, I) dispatch on turning-point and inflection counts, with monotonicity/convexity indices for disambiguation. The taxonomy rolls up through three broader tiers: archetype (7), monotonic (3), linear (2) — grounded in shape-constrained regression (Pya & Wood 2015), dose-response pharmacology (Calabrese 2008), and Morse critical- point classification (Milnor 1963).

Install

# development version from GitHub (fast; no vignettes)
pak::pak("max578/janusplot")

# or, with vignettes built locally (recommended — enables
# browseVignettes("janusplot") and vignette("janusplot")):
# install.packages("remotes")
remotes::install_github(
  "max578/janusplot",
  build_vignettes = TRUE,
  dependencies    = TRUE
)

Note: neither pak::pak() nor devtools::install_github() / remotes::install_github() build vignettes by default when installing from a source repository. The build_vignettes = TRUE flag above is required for browseVignettes() to find them. The CRAN release ships prebuilt vignettes and needs no extra flag.

Quick start

library(janusplot)

# Palmer penguins — four continuous traits
d <- na.omit(palmerpenguins::penguins[,
       c("bill_length_mm", "bill_depth_mm",
         "flipper_length_mm", "body_mass_g")])
janusplot(d)

Default encoding:

  • Cell colour — Pearson correlation on a diverging RdBu palette symmetric around zero (override via colour_by = "spearman" / "kendall" / "edf" / "deviance_gap" / "none").
  • Bottom-leftA = ... (asymmetry index) stacked over EDF = ....
  • Top-right — significance glyph for the smooth’s F-test (· * ** ***).
  • Below the matrix — a standing reference legend illustrating all 24 shape categories as canonical thumbnail splines, labelled <name> (<code>).

Opt into a per-cell shape marker via annotations:

# Two-letter shape code, top-left (ASCII — safe on any font / PDF):
janusplot(d, annotations = c("edf", "A", "code"))

# Unicode shape glyph, bottom-right:
janusplot(d, annotations = c("edf", "A", "shape"),
          glyph_style = "unicode")

Shape taxonomy — what gets classified

Archetype (7)CategoriesExample
monotone_linearlinear_uplinear_downy = x
monotone_curvedconvex_upconcave_upconvex_downconcave_downs_shaperippled_monotonetanh, sqrt, exp(−x)
unimodalu_shapeinverted_uskewed_peakbroad_peakrippled_peak(x−.5)², x·exp(−3x), plateau
wavewavewarped_waverippled_wavecomplex_wavesin(2πx) family
multimodalbimodalbimodal_ripplebi_wavebi_wave_rippletwo-peak mix, sin(4πx)
chaoticcomplex≥ 5 extrema / inflections
degenerateflatindeterminateconstant / fit failure

Full table (with 2-letter codes + monotonic / linear rollups + glyph + gloss) via janusplot_shape_hierarchy().

Sensitivity study — built-in

The classifier’s recovery behaviour is characterised across a full factorial of sample sizes × noise levels × ground-truth shapes:

# Precomputed 2160-fit demo sweep — zero wait
data("shape_sensitivity_demo")
janusplot_shape_sensitivity_plot(shape_sensitivity_demo, "recovery_curves")
janusplot_shape_sensitivity_plot(shape_sensitivity_demo, "confusion_archetype")

# Run your own — full grid in parallel
future::plan(future::multisession, workers = 4L)
res <- janusplot_shape_sensitivity(parallel = TRUE)

Four diagnostic plots ("confusion_fine" / "confusion_archetype" / "accuracy_grid" / "recovery_curves") + summary aggregations at fine and archetype levels. Design, pre-registered hypotheses, and full walk-through in the shape-recognition-sensitivity vignette.

Key features

  • Real GAM fits via mgcv — EDF, F-test p-values, confidence envelopes, random effects via s(g, bs = "re").
  • Asymmetric matrix — upper / lower triangles carry the two directional regressions.
  • Three correlation flavours computed per pair — Pearson (default), Spearman, Kendall — surfaced in janusplot_data() output.
  • adjust = formula — propagate covariates and random effects into every cell’s smooth.
  • janusplot_data() — per-pair raw fits, correlations, EDFs, p-values, shape metrics + hierarchy columns, without the plot.
  • janusplot(..., with_data = TRUE) — plot + tidy data frame in one call.
  • Parallel dispatch via future.apply for large matrices and sensitivity sweeps.
  • Deterministic — seed 2026L pins the shipped demo + vignette figures; user sweeps accept seed =.

Why asymmetric?

A Pearson correlation discards both the shape of an association and the direction information that a non-linear data-generating process leaves in its residuals. Under the additive-noise causal discovery setting (Hoyer et al. 2009; Peters et al. 2014) the forward regression y ~ s(x) and its inverse x ~ s(y) are generically asymmetric when the underlying DGP is non-linear, and that asymmetry identifies the causal direction under mild conditions. janusplot surfaces this asymmetry as a visual pre-discovery diagnostic — not a causal inference procedure. See the vignette and the accompanying paper for scope and explicit non-claims.

Documentation

  • Reference + articles (pkgdown site)
  • vignette("janusplot") — quickstart + feature tour
  • vignette("shape-recognition-sensitivity") — design, hypotheses, every diagnostic plot
  • Paper: Beyond Pearson: Visualising Asymmetric Non-linear Associations with Generalised Additive Models (Moldovan, in preparation; target venue R Journal).

Status

R CMD check --as-cran clean (0 errors, 0 warnings, 3 cosmetic NOTEs — new submission / local env); 190 test expectations; 88.5 % coverage.

Citation

citation("janusplot")
Metadata

Version

0.1.0

License

Unknown

Platforms (80)

    Darwin
    FreeBSD
    Genode
    GHCJS
    Linux
    MMIXware
    NetBSD
    none
    OpenBSD
    Redox
    Solaris
    uefi
    WASI
    Windows
Show all
  • aarch64-darwin
  • aarch64-freebsd
  • aarch64-genode
  • aarch64-linux
  • aarch64-netbsd
  • aarch64-none
  • aarch64-uefi
  • aarch64-windows
  • aarch64_be-none
  • arc-linux
  • arm-none
  • armv5tel-linux
  • armv6l-linux
  • armv6l-netbsd
  • armv6l-none
  • armv7a-linux
  • armv7a-netbsd
  • armv7l-linux
  • armv7l-netbsd
  • avr-none
  • i686-cygwin
  • i686-freebsd
  • i686-genode
  • i686-linux
  • i686-netbsd
  • i686-none
  • i686-openbsd
  • i686-windows
  • javascript-ghcjs
  • loongarch64-linux
  • m68k-linux
  • m68k-netbsd
  • m68k-none
  • microblaze-linux
  • microblaze-none
  • microblazeel-linux
  • microblazeel-none
  • mips-linux
  • mips-none
  • mips64-linux
  • mips64-none
  • mips64el-linux
  • mipsel-linux
  • mipsel-netbsd
  • mmix-mmixware
  • msp430-none
  • or1k-none
  • powerpc-linux
  • powerpc-netbsd
  • powerpc-none
  • powerpc64-linux
  • powerpc64le-linux
  • powerpcle-none
  • riscv32-linux
  • riscv32-netbsd
  • riscv32-none
  • riscv64-linux
  • riscv64-netbsd
  • riscv64-none
  • rx-none
  • s390-linux
  • s390-none
  • s390x-linux
  • s390x-none
  • sh4-linux
  • vc4-none
  • wasm32-wasi
  • wasm64-wasi
  • x86_64-cygwin
  • x86_64-darwin
  • x86_64-freebsd
  • x86_64-genode
  • x86_64-linux
  • x86_64-netbsd
  • x86_64-none
  • x86_64-openbsd
  • x86_64-redox
  • x86_64-solaris
  • x86_64-uefi
  • x86_64-windows