---
title: "Getting Started with ixsurface"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Getting Started with ixsurface}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  eval = FALSE
)
library(ixsurface)
```

## Overview

`ixsurface` generates interactive 3D surface plots from fitted models to visualize
multi-factor interactions. Where surfaces cross, the effect of one factor depends
on the level of another — the geometric signature of an interaction.

**Geometric interpretation:**

- **Parallel surfaces** = no interaction between the conditioning factor and focal variables
- **Crossing surfaces** = interaction present
- **Twisted/warped surfaces** = higher-order or nonlinear interaction

## Simulating Data

`sim_factorial()` generates synthetic factorial data with known interaction
structure. Three designs are available:

```{r sim}
library(ixsurface)

# Mixed: 2 continuous + 1 categorical factor
dat = sim_factorial(n = 300, design = "mixed", seed = 42)
str(dat)

# Continuous: 3 continuous factors
dat_cont = sim_factorial(n = 300, design = "continuous", seed = 42)

# Categorical: 3 categorical factors
dat_cat = sim_factorial(n = 300, design = "categorical", seed = 42)
```

All designs include main effects, two-way interactions, and a weaker three-way
interaction, making it straightforward to verify that surfaces cross where expected.

## Main Function: interaction_surface

The primary function takes a fitted model and maps two focal variables to the
x and y axes, with predicted response on z. The `facet_by` argument generates
a separate surface for each level of a conditioning variable.

```{r surface-basic}
fit = lm(y ~ temp * pressure * catalyst, data = dat)

# One surface per catalyst level
interaction_surface(fit, x = "temp", y = "pressure", facet_by = "catalyst")
```

*This produces an interactive plotly widget with three colored surfaces. Rotate,
zoom, and hover to inspect predicted values.*

### Full Feature Example

Enable observed data overlay, crossing markers, and contour projection:

```{r surface-full}
interaction_surface(
  fit, x = "temp", y = "pressure", facet_by = "catalyst",
  show_points = TRUE, show_crossings = TRUE, show_contour = TRUE,
  alpha = 0.5,
  labs = list(x = "Temperature (C)", y = "Pressure (psi)", z = "Yield"),
  title = "Mixed Design: temp x pressure | catalyst"
)
```

*Three surfaces appear with red crossing markers where they intersect. Red circles
on the floor plane show the contour projection. Colored scatter points are observed
data, matched to their nearest surface.*

### Single Surface

Omitting `facet_by` produces a single response surface. Non-focal variables are
held at their median (continuous) or mode (categorical):

```{r surface-single}
interaction_surface(fit, x = "temp", y = "pressure",
                    show_points = TRUE, alpha = 0.7)
```

## GLM Support

For `glm` models, predictions are automatically on the response scale via
`predict(..., type = "response")`. For logistic regression, surfaces represent
probabilities bounded to [0, 1]:

```{r glm}
dat$success = rbinom(nrow(dat), 1, plogis((dat$y - 50) / 5))
gfit = glm(success ~ temp * pressure * catalyst, data = dat, family = binomial)

interaction_surface(gfit, x = "temp", y = "pressure", facet_by = "catalyst",
                    labs = list(z = "P(success)"))
```

## Continuous Conditioning Variables

When a continuous variable is used as `facet_by`, it is automatically binned.
Control this with `n_bins` and `bin_method`:
```{r continuous-facet}
fit_cont = lm(y ~ temp * pressure * speed, data = dat_cont)

interaction_surface(fit_cont, x = "temp", y = "pressure", facet_by = "speed",
                    n_bins = 4, bin_method = "quantile",
                    show_crossings = TRUE)
```

## Crossing Detection: find_crossings

`find_crossings()` returns a data frame of approximate crossing locations without
generating a plot. Useful for programmatic analysis:

```{r find-crossings}
cx = find_crossings(fit, "temp", "pressure", "catalyst")
head(cx)
#>         cx       cy       cz               pair_label
#> 1  150.000 10.81633 44.66789 catalyst=A vs catalyst=B
#> 2  152.041 10.81633 44.67123 catalyst=A vs catalyst=B
#> ...

table(cx$pair_label)
```

The returned data frame has columns `cx`, `cy`, `cz` (coordinates) and
`pair_label` (which surface pair crosses).

## Crossings-Only Visualization: plot_crossings

`plot_crossings()` renders just the crossing points as a 3D scatter, stripping
away the surfaces to focus on where interaction effects are strongest:

```{r plot-crossings}
plot_crossings(fit, "temp", "pressure", "catalyst",
               labs = list(x = "Temp (C)", y = "Press (psi)", z = "Yield"),
               marker_size = 4, marker_opacity = 0.8)
```

*Points are color-coded by surface pair.*

## Pairwise Grid: interaction_surface_grid

For exploratory analysis, `interaction_surface_grid()` generates all C(k, 2)
pairwise plots. Remaining variables become conditioning factors:

```{r grid}
plots = interaction_surface_grid(fit, n = 20)
names(plots)
#> [1] "temp__pressure"    "temp__catalyst"    "pressure__catalyst"

# View individual plots
plots$temp__pressure
```

## Metadata Access

Every `interaction_surface()` plot carries an `ixsurface_meta` attribute for
downstream use:

```{r metadata}
p = interaction_surface(fit, x = "temp", y = "pressure",
                        facet_by = "catalyst", n = 20)
meta = attr(p, "ixsurface_meta")
meta$n_surfaces
#> [1] 3
meta$surface_labels
#> [1] "catalyst=A" "catalyst=B" "catalyst=C"
```

The metadata includes `z_matrices` (one matrix per surface), `x_vals`, `y_vals`,
and `binned_by` information for continuous conditioning variables.
