| Title: | Interactive 3D Surface Plots for Multi-Factor Interaction Visualization |
| Version: | 0.1.0 |
| 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. |
| License: | MIT + file LICENSE |
| Encoding: | UTF-8 |
| RoxygenNote: | 7.3.3 |
| URL: | https://github.com/cjbrant/ixsurface |
| BugReports: | https://github.com/cjbrant/ixsurface/issues |
| Imports: | plotly (≥ 4.10.0), stats, utils, grDevices |
| Suggests: | testthat (≥ 3.0.0), knitr, rmarkdown |
| Config/testthat/edition: | 3 |
| VignetteBuilder: | knitr |
| NeedsCompilation: | no |
| Packaged: | 2026-03-21 19:06:11 UTC; christopherbrantner |
| Author: | Chris Brantner [aut, cre] |
| Maintainer: | Chris Brantner <cjbrantn@gmail.com> |
| Repository: | CRAN |
| Date/Publication: | 2026-03-26 09:30:22 UTC |
ixsurface: 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.
Author(s)
Maintainer: Chris Brantner cjbrantn@gmail.com
See Also
Useful links:
Assign observations to the nearest surface group
Description
For color-coding observed data by facet_by level. Handles both categorical and binned continuous facet_by variables.
Usage
assign_obs_to_surface(obs, by_vars, by_combos, binned_by)
Arguments
obs |
Data frame of observations. |
by_vars |
Character vector of facet_by variable names. |
by_combos |
Data frame of surface-level combinations. |
binned_by |
Named list of bin info. |
Value
Integer vector of surface indices (1-indexed).
Bin a continuous variable into discrete levels
Description
Used when a continuous variable appears in facet_by to produce a
manageable number of surfaces.
Usage
bin_continuous(x, n_bins = 3, method = c("quantile", "equal", "pretty"))
Arguments
x |
Numeric vector to bin. |
n_bins |
Integer. Number of bins (default 3). |
method |
Character. One of |
Value
A factor with descriptive level labels.
Examples
x = rnorm(100, mean = 50, sd = 15)
bin_continuous(x, n_bins = 3, method = "quantile")
bin_continuous(x, n_bins = 4, method = "equal")
Compute approximate surface crossing points
Description
For each pair of surfaces, finds grid cells where the z-difference changes sign, indicating the surfaces cross in that region.
Usage
compute_crossings(
z_matrices,
x_vals,
y_vals,
by_combos,
by_vars,
binned_by = list(),
tolerance = NULL
)
Arguments
z_matrices |
List of z matrices (one per surface). |
x_vals |
Numeric vector of x grid values. |
y_vals |
Numeric vector of y grid values. |
by_combos |
Data frame of facet_by combinations. |
by_vars |
Character vector of facet_by variable names. |
binned_by |
Named list of bin info for continuous by-variables. |
tolerance |
Numeric or NULL. Adaptive if NULL (2 percent of z-range). |
Value
A data.frame with columns cx, cy, cz, pair_label.
Detect whether a variable in a model is continuous or categorical
Description
Detect whether a variable in a model is continuous or categorical
Usage
detect_factor_type(model, varname)
Arguments
model |
A fitted model object. |
varname |
Character string naming the variable. |
Value
Character: "continuous" or "categorical".
Find Crossing Regions Between Interaction Surfaces
Description
Identifies where predicted response surfaces cross for different levels of conditioning factors. Returns a data frame of approximate crossing locations.
Usage
find_crossings(
model,
x,
y,
facet_by,
n = 50,
n_bins = 3,
bin_method = "quantile",
tolerance = NULL
)
Arguments
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. |
Value
A data.frame with columns:
- cx
x-coordinate of crossing
- cy
y-coordinate of crossing
- cz
predicted response at crossing (average of both surfaces)
- pair_label
which surface pair crosses
Examples
dat = sim_factorial(design = "mixed", seed = 42)
fit = lm(y ~ temp * pressure * catalyst, data = dat)
crossings = find_crossings(fit, "temp", "pressure", "catalyst")
head(crossings)
Interactive 3D Surface Plot for Multi-Factor Interactions
Description
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.
Usage
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",
...
)
Arguments
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). |
Details
Geometric interpretation:
Parallel surfaces
\tono interaction betweenfacet_byand the focal variablesCrossing surfaces
\tointeraction presentTwisted/warped surfaces
\tohigher-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").
Value
A plotly htmlwidget object.
Examples
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")
Generate All Pairwise Interaction Surface Plots
Description
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.
Usage
interaction_surface_grid(
model,
factors = NULL,
facet_max = 2,
n = 30,
n_bins = 3,
alpha = 0.6,
...
)
Arguments
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 |
Value
A named list of plotly objects. Names use pattern "x__y".
Examples
dat = sim_factorial(design = "mixed", seed = 42)
fit = lm(y ~ temp * pressure * catalyst, data = dat)
plots = interaction_surface_grid(fit)
plots$temp__pressure
Lighten a hex color
Description
Lighten a hex color
Usage
lighten_color(hex_color, amount = 0.3)
Arguments
hex_color |
Character hex color. |
amount |
Numeric in |
Value
Character hex color.
Generate a label for a facet_by combination
Description
Generate a label for a facet_by combination
Usage
make_by_label(row, by_vars, binned_by = list())
Arguments
row |
A single-row data.frame. |
by_vars |
Character vector of by-variable names. |
binned_by |
Named list of bin info for continuous by-variables. |
Value
A character label.
Build a prediction grid over two focal variables
Description
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.
Usage
make_prediction_grid(
model,
x,
y,
facet_by = NULL,
n = 50,
n_bins = 3,
bin_method = "quantile"
)
Arguments
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". |
Value
A list with components:
- grid
data.frame suitable for
predict()- binned_by
named list of bin info for continuous facet_by variables
Examples
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)
Plot Crossing Regions as a Standalone 3D Scatter
Description
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.
Usage
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
)
Arguments
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 |
Value
A plotly htmlwidget object. If no crossings are found,
returns an empty plot with a "No crossings detected" annotation.
Examples
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"))
Safe prediction wrapper with GLM/GAM support
Description
Dispatches predict() with type = "response" for GLMs and GAMs
to return predictions on the response scale (e.g., probabilities for logistic
regression). Falls back to plain predict() for lm and others.
Usage
safe_predict(model, newdata)
Arguments
model |
A fitted model object. |
newdata |
A data.frame for prediction. |
Value
Numeric vector of predictions.
Simulate a Multi-Factor Experimental Dataset
Description
Generates synthetic data from a factorial design with known interaction
structure. Useful for demonstrating and testing interaction_surface.
Usage
sim_factorial(
n = 200,
design = c("mixed", "continuous", "categorical"),
noise = 0.5,
seed = NULL
)
Arguments
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. |
Details
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.
Value
A data.frame with factor columns and a response column y.
Examples
dat = sim_factorial(design = "mixed", seed = 42)
head(dat)
Get a qualitative color palette for surfaces
Description
Get a qualitative color palette for surfaces
Usage
surface_palette(n)
Arguments
n |
Number of colors needed. |
Value
Character vector of hex colors.