Johnson-Neyman Analysis of Two- and Three-Way Interactions
Overview
Reports and plots the conditional effect of each variable involved in a multiplicative interaction across the range of its moderators, together with the region over which that effect is distinguishable from zero. Extends the classic framework of Johnson and Neyman (1936) and Johnson and Fay (1950) doi:10.1007/BF02288864 to three-way interactions and to Bayesian models. The single entry point JN() dispatches on the fitted object, with methods for lm()/glm() models, 'lme4' models, 'RSiena' and 'multiSiena' results, and matrices of posterior draws; support for further model classes is added by writing one jn_input() method. Results are classed objects with print(), summary() and plot() methods, and the figures carry data-density panels showing how much empirical support each part of the moderator range has. A detailed introduction can be found in Krause (2026) doi:10.48550/arXiv.2604.22051.
Bug fix
- The two-way standard errors were wrong. Following the delta method, the variance of the conditional effect is
Var(b_focal) + 2m Cov(b_focal, b_interaction) + m^2 Var(b_interaction), but the covariance term used wasCov(b_focal, b_other_main_effect)instead of the covariance with the interaction. Confidence bands,pvalues and therefore the regions of significance of every two-way frequentist analysis produced by version 1.0.x are affected, and results from those versions should be regenerated. Three-way analyses and all Bayesian analyses were computed correctly and are unchanged.
New interface
- New generic
JN(), which dispatches on the fitted object. It replacesJNK_freq()andJNK_bayes(), which split the package by inference paradigm rather than by input. Whether an analysis is frequentist or Bayesian now follows from the object handed in: models carrying point estimates and a covariance matrix are analysed with Wald tests, objects carrying draws as conditional posteriors.
Show all changes in 2.0.0Hide the rest of the changes in 2.0.0
- New generic
jn_input(), the extension point of the package, with methods forlm,glm,merMod,sienaFit,matrix,mcmc,mcmc.list,data.frame,sienaBayesFitandmultiSiena. Supporting a further model class means writing onejn_input()method returning eitherjn_wald()(point estimates and covariance) orjn_posterior()(draws); nothing else needs to change. This covers, for instance, models fitted by variational inference, where the variational parameters approximate the posterior. JN()returns a classed object withprint(),summary(),plot(),autoplot(),as.data.frame(),coef()andvcov()methods. Analyses producing one result per group return aJN_listcarrying the same methods. Figures are built on demand byplot()rather than stored in the result.JNK_freq()andJNK_bayes()are deprecated. They still work, delegate toJN(), and return the 1.0.x layout, but warn once per session. They will be removed in a future release.
New features
summary()reports the regions of significance directly: the stretches of the moderator over which each conditional effect is distinguishable from zero, with the share of observations falling inside each. For two-way Wald analyses the boundaries are solved for exactly, so their precision no longer depends onrange_size. Also available programmatically asjn_regions().plot()attaches data-density panels: a histogram of the observed moderator values below two-way plots, and marginal histograms along both axes of the heatmaps. A region of significance covering moderator values that were hardly observed is the standard failure mode of this technique, and the panels make it visible. Observed values are taken fromlm,glmandlme4models automatically, and can be supplied for any other input through thesupportargument. Turn the panels off withjn_style(show_density = FALSE).- New
jn_style()collects the colour and pattern settings that were previously repeated across both function signatures. plot()draws a figure for every variable involved in the interaction, since each takes its turn as the focal one: two figures for a two-way analysis, three for a three-way one. Passwhichfor a single figure. It draws and returns invisibly, so nothing is rendered twice.- New
jn_plots()returns every figure of an analysis at once without drawing them, andautoplot()returns a single one;jn_save()writes them to disk, replacing thesaveandfolderarguments. - Two-way Bayesian analyses can be drawn as a posterior mean with credible band against the moderator (
plot(x, type = "band")), directly comparable to the frequentist figure, in addition to the overlaid conditional densities. - For
sienaBayes()results, the level the draws were taken from is now recorded on the result and shown byprint(),summary()and the figures:Etawhen the parameters involved are shared across groups,Muwhen they vary and the hyper-parameter is used. Version 1.0.x labelled the figures this way; the information had been dropped. hyper_only = FALSEno longer produces group-level analyses when none of the parameters involved varies between groups. It now reports that and returns the population-level analysis alone, since the group analyses would have been identical copies.
Other changes
- The three-way extension is no longer called the Johnson-Neyman-Krause or JNK technique; it is referred to as JN3.
- The default
thresholdsfor Bayesian analyses are nowc(alpha/2, 1 - alpha/2), that isc(0.025, 0.975). The previous default ofc(0.49999999999999999, 0.5)marked essentially every cell significant.JNK_bayes()keeps the old default. control_fdris documented as what it is: the Benjamini-Hochberg step-up procedure controlling the false discovery rate across the moderator grid. Earlier documentation described it as Bonferroni-Holm.dplyr,tibble,tidyrandscalesare no longer dependencies.lme4moved from Imports to Suggests, since it is needed only for mixed-model input.patchworkwas added, for the density panels.- The package now has a test suite and a
Getting started with int3ractvignette.
From NEWS.md in the release
Install
Health
- OK13 OK2026-08-05
- NOTE12 OK, 1 NOTE2026-08-01
- OK7 OK2026-05-06
Documentation
- Help pages
- 15 (4 internal)includes a package overview page
- Examples that run
- 100%8 run in a plain check
- Exported functions with examples
- 56%
- Documented parameters
- 63%
- Return-value docs
- 89%
- Help pages citing references
- 7%
Downloads
Repository
- PRs merged (all time)
- 100%
- Median days to close, 50 most recently updated closed issues
- 124
- Median days to close, 50 most recently updated closed PRs
- 0
Forks over time
Releases over time
Issues over time
Commits over time
Commit identities over time
4 development-tooling and community-health practices detected across 3 families in the upstream repository
Checks run against github.com/rwkrause/int3ract on 2026-10-21.
GitHub Pages site
This repository shows signs of AI coding tools.
- Claude Codefirst seen 2026-04-10Named in .Rbuildignore: .claudeNamed in .gitignore: .claudePull request it wrote: opened by a project memberCommits: at least 4 crediting it in the message
- Claude Opus 54 commits · Sep 2026
Dependencies
Code & Tests
People & History
Pick two releases to compare their code metrics.
- 2.0.0Latest2026-09-01 · current release · diff ↗ ·
added 9 exports
JN, autoplot, jn_input, jn_plots, jn_posterior, jn_regions, jn_save, jn_style, jn_wald - 1.0.72026-05-05
- RR 4.6.0 released · 2026-04-24
Package metadata
- First published
- 2026-05-05
- Total releases
- 2 / 1 yrs
- License
- GPL (>= 3) OSI
- Minimum R
- ≥ 4.4.0
- Download size
- 135 KB
Cite
Cite this package
Run in R for the authors' entry:
citation("int3ract")The package provides a citation file, so citation() returns the authors' own entry.
It points to 10.48550/arxiv.2604.22051.
Cite the R Observatory
For a number measured here: a download total, a coverage figure, an archival date.
From data release v2026-10-24, which the citation names so these numbers can be found later. More on citing and the projects behind them.