| Title: | Interactive 3D Surface Plots for Multi-Factor Interaction Visualization |
|---|---|
| Description: | Visualize interactions between multiple experimental factors using interactive 3D surface plots powered by 'plotly'. Instead of examining combinatorial pairwise interaction plots, map factor combinations to response surfaces and use surface crossings as geometric indicators of interaction effects. Supports continuous, categorical, and mixed factor designs with automatic binning for continuous conditioning variables. |
| Authors: | Chris Brantner [aut, cre] |
| Maintainer: | Chris Brantner <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.1.0 |
| Built: | 2026-05-26 06:35:59 UTC |
| Source: | https://github.com/cjbrant/ixsurface |
Used when a continuous variable appears in facet_by to produce a
manageable number of surfaces.
bin_continuous(x, n_bins = 3, method = c("quantile", "equal", "pretty"))bin_continuous(x, n_bins = 3, method = c("quantile", "equal", "pretty"))
x |
Numeric vector to bin. |
n_bins |
Integer. Number of bins (default 3). |
method |
Character. One of |
A factor with descriptive level labels.
x = rnorm(100, mean = 50, sd = 15) bin_continuous(x, n_bins = 3, method = "quantile") bin_continuous(x, n_bins = 4, method = "equal")x = rnorm(100, mean = 50, sd = 15) bin_continuous(x, n_bins = 3, method = "quantile") bin_continuous(x, n_bins = 4, method = "equal")
Identifies where predicted response surfaces cross for different levels of conditioning factors. Returns a data frame of approximate crossing locations.
find_crossings( model, x, y, facet_by, n = 50, n_bins = 3, bin_method = "quantile", tolerance = NULL )find_crossings( model, x, y, facet_by, n = 50, n_bins = 3, bin_method = "quantile", tolerance = NULL )
model |
A fitted model object. |
x |
Character. First focal variable. |
y |
Character. Second focal variable. |
facet_by |
Character vector. Conditioning variable(s). |
n |
Integer. Grid resolution (default 50). |
n_bins |
Integer. Bins for continuous facet_by (default 3). |
bin_method |
Character. Binning method. |
tolerance |
Numeric or NULL. Crossing detection tolerance. |
A data.frame with columns:
x-coordinate of crossing
y-coordinate of crossing
predicted response at crossing (average of both surfaces)
which surface pair crosses
dat = sim_factorial(design = "mixed", seed = 42) fit = lm(y ~ temp * pressure * catalyst, data = dat) crossings = find_crossings(fit, "temp", "pressure", "catalyst") head(crossings)dat = sim_factorial(design = "mixed", seed = 42) fit = lm(y ~ temp * pressure * catalyst, data = dat) crossings = find_crossings(fit, "temp", "pressure", "catalyst") head(crossings)
Generates an interactive plotly surface plot from a fitted model. Two focal
variables are mapped to the x and y aesthetics, with the predicted response
on z. Additional conditioning factors (facet_by) generate separate
surfaces — where surfaces cross indicates interaction effects.
interaction_surface( model, x, y, facet_by = NULL, n = 50, n_bins = 3, bin_method = "quantile", alpha = 0.6, show_points = FALSE, show_crossings = TRUE, show_contour = FALSE, contour_z = NULL, labs = NULL, title = NULL, theme = "default", ... )interaction_surface( model, x, y, facet_by = NULL, n = 50, n_bins = 3, bin_method = "quantile", alpha = 0.6, show_points = FALSE, show_crossings = TRUE, show_contour = FALSE, contour_z = NULL, labs = NULL, title = NULL, theme = "default", ... )
model |
A fitted model object with a |
x |
Character. Variable name mapped to the x-axis. |
y |
Character. Variable name mapped to the y-axis. |
facet_by |
Character vector or NULL. Variable(s) whose levels generate separate surfaces. Continuous variables are automatically binned. |
n |
Integer. Grid resolution per continuous axis (default 50).
Analogous to |
n_bins |
Integer. Number of bins for continuous |
bin_method |
Character. Binning method for continuous |
alpha |
Numeric in |
show_points |
Logical. If TRUE, overlays the observed data points,
color-coded by |
show_crossings |
Logical. If TRUE (default), marks regions where surfaces cross with red markers. |
show_contour |
Logical. If FALSE (default), no contour projection. If TRUE, projects crossing curves onto the x-y floor of the plot as a 2D summary of interaction regions. |
contour_z |
Numeric or NULL. The z-value at which to draw the contour projection. If NULL, uses the minimum z in the plot. |
labs |
Named list for axis labels, e.g.,
|
title |
Character or NULL. Plot title. |
theme |
Character. Color theme: "default", "viridis", or "grey". |
... |
Additional arguments (reserved for future use). |
Geometric interpretation:
Parallel surfaces no interaction between facet_by
and the focal variables
Crossing surfaces interaction present
Twisted/warped surfaces higher-order or nonlinear interaction
For categorical focal variables, the surface is constructed over an integer grid with axis tick labels showing level names.
Non-focal, non-facet_by variables are held at their median
(continuous) or mode (categorical).
For GLM family models, predictions are returned on the response scale via
predict(..., type = "response").
A plotly htmlwidget object.
dat = sim_factorial(design = "mixed", seed = 42) fit = lm(y ~ temp * pressure * catalyst, data = dat) interaction_surface(fit, x = "temp", y = "pressure", facet_by = "catalyst") # with GLM dat$success = rbinom(nrow(dat), 1, plogis(scale(dat$y))) gfit = glm(success ~ temp * pressure * catalyst, data = dat, family = binomial) interaction_surface(gfit, x = "temp", y = "pressure", facet_by = "catalyst")dat = sim_factorial(design = "mixed", seed = 42) fit = lm(y ~ temp * pressure * catalyst, data = dat) interaction_surface(fit, x = "temp", y = "pressure", facet_by = "catalyst") # with GLM dat$success = rbinom(nrow(dat), 1, plogis(scale(dat$y))) gfit = glm(success ~ temp * pressure * catalyst, data = dat, family = binomial) interaction_surface(gfit, x = "temp", y = "pressure", facet_by = "catalyst")
For a model with multiple factors, generates interaction surface plots for
every pair of focal variables, using remaining variables as conditioning
factors (facet_by). Useful for exploratory analysis.
interaction_surface_grid( model, factors = NULL, facet_max = 2, n = 30, n_bins = 3, alpha = 0.6, ... )interaction_surface_grid( model, factors = NULL, facet_max = 2, n = 30, n_bins = 3, alpha = 0.6, ... )
model |
A fitted model object. |
factors |
Character vector or NULL. Variables to consider. If NULL, uses all predictors. |
facet_max |
Integer. Maximum number of |
n |
Integer. Grid resolution (default 30, lower for speed). |
n_bins |
Integer. Bins for continuous facet_by variables. |
alpha |
Numeric. Surface opacity. |
... |
Passed to |
A named list of plotly objects. Names use pattern "x__y".
dat = sim_factorial(design = "mixed", seed = 42) fit = lm(y ~ temp * pressure * catalyst, data = dat) plots = interaction_surface_grid(fit) plots$temp__pressuredat = sim_factorial(design = "mixed", seed = 42) fit = lm(y ~ temp * pressure * catalyst, data = dat) plots = interaction_surface_grid(fit) plots$temp__pressure
For continuous variables, generates a regular sequence across the observed
range. For categorical/factor variables, uses all observed levels. Continuous
facet_by variables are binned, and predictions use bin midpoints.
make_prediction_grid( model, x, y, facet_by = NULL, n = 50, n_bins = 3, bin_method = "quantile" )make_prediction_grid( model, x, y, facet_by = NULL, n = 50, n_bins = 3, bin_method = "quantile" )
model |
A fitted model object. |
x |
Character. First focal variable (mapped to x-axis). |
y |
Character. Second focal variable (mapped to y-axis). |
facet_by |
Character vector or NULL. Conditioning variable(s) whose levels generate separate surfaces. |
n |
Integer. Grid density for continuous axes. |
n_bins |
Integer. Number of bins for continuous |
bin_method |
Character. Binning method: "quantile", "equal", or "pretty". |
A list with components:
data.frame suitable for predict()
named list of bin info for continuous facet_by variables
dat = sim_factorial(design = "mixed", seed = 42) fit = lm(y ~ temp * pressure * catalyst, data = dat) result = make_prediction_grid(fit, x = "temp", y = "pressure", facet_by = "catalyst", n = 10) str(result$grid)dat = sim_factorial(design = "mixed", seed = 42) fit = lm(y ~ temp * pressure * catalyst, data = dat) result = make_prediction_grid(fit, x = "temp", y = "pressure", facet_by = "catalyst", n = 10) str(result$grid)
Visualizes only the crossing points between interaction surfaces as an interactive 3D scatter plot, color-coded by surface pair. This isolates where interaction effects are strongest, without the surfaces themselves.
plot_crossings( model, x, y, facet_by, n = 50, n_bins = 3, bin_method = "quantile", tolerance = NULL, labs = NULL, title = NULL, marker_size = 3, marker_opacity = 0.7 )plot_crossings( model, x, y, facet_by, n = 50, n_bins = 3, bin_method = "quantile", tolerance = NULL, labs = NULL, title = NULL, marker_size = 3, marker_opacity = 0.7 )
model |
A fitted model object. |
x |
Character. First focal variable. |
y |
Character. Second focal variable. |
facet_by |
Character vector. Conditioning variable(s). |
n |
Integer. Grid resolution (default 50). |
n_bins |
Integer. Bins for continuous facet_by (default 3). |
bin_method |
Character. Binning method. |
tolerance |
Numeric or NULL. Crossing detection tolerance. |
labs |
Named list for axis labels, e.g.,
|
title |
Character or NULL. Plot title. |
marker_size |
Numeric. Marker size (default 3). |
marker_opacity |
Numeric in |
A plotly htmlwidget object. If no crossings are found,
returns an empty plot with a "No crossings detected" annotation.
dat = sim_factorial(design = "mixed", seed = 42) fit = lm(y ~ temp * pressure * catalyst, data = dat) plot_crossings(fit, "temp", "pressure", "catalyst") # with custom labels plot_crossings(fit, "temp", "pressure", "catalyst", labs = list(x = "Temp (C)", y = "Press (psi)", z = "Yield"))dat = sim_factorial(design = "mixed", seed = 42) fit = lm(y ~ temp * pressure * catalyst, data = dat) plot_crossings(fit, "temp", "pressure", "catalyst") # with custom labels plot_crossings(fit, "temp", "pressure", "catalyst", labs = list(x = "Temp (C)", y = "Press (psi)", z = "Yield"))
Generates synthetic data from a factorial design with known interaction
structure. Useful for demonstrating and testing interaction_surface.
sim_factorial( n = 200, design = c("mixed", "continuous", "categorical"), noise = 0.5, seed = NULL )sim_factorial( n = 200, design = c("mixed", "continuous", "categorical"), noise = 0.5, seed = NULL )
n |
Integer. Total number of observations (default 200). |
design |
Character. One of:
|
noise |
Numeric. Standard deviation of Gaussian noise (default 0.5). |
seed |
Integer or NULL. Random seed for reproducibility. |
The data generating process includes main effects for all factors, two-way
interactions between the first two factors, and a three-way interaction
(weaker) involving all factors. This makes it straightforward to verify that
interaction_surface correctly detects the embedded structure.
A data.frame with factor columns and a response column y.
dat = sim_factorial(design = "mixed", seed = 42) head(dat)dat = sim_factorial(design = "mixed", seed = 42) head(dat)