# Viz Module

> **User-facing** — Use `from bossanova import viz` or call plot methods
> directly on fitted models: `model.plot_params()`, `model.plot_resid()`

## Purpose

This module provides visualization functions for model exploration and
diagnostics. All functions follow the functional core pattern—they take
a model as input and return matplotlib Figure or Axes objects.

## Basic Usage

```python
from bossanova import model, viz
from bossanova.data import load_dataset

mtcars = load_dataset("mtcars")
m = model("mpg ~ wt + hp", mtcars).fit()

# Via viz module
viz.plot_params(m)
viz.plot_resid(m)

# Or via model methods (convenience wrappers)
m.plot_params()
m.plot_resid()
```

## Available Plots

| Function | Purpose |
|----------|---------|
| `plot_params` | Forest plot of parameter estimates |
| `plot_resid` | Residual diagnostic grid (4 panels) |
| `plot_predict` | Marginal predictions across predictor range |
| `plot_explore` | Marginal effects/means visualization |
| `plot_compare` | Multi-model coefficient comparison |
| `plot_dag` | Causal DAG visualization |
| `plot_lattice` | Model lattice (Hasse diagram) |
| `plot_cognition` | Combined DAG + lattice |

## Residual Diagnostics

`plot_resid()` produces a 2×2 grid:

```
┌─────────────────┬─────────────────┐
│ Residuals vs    │ Q-Q Plot        │
│ Fitted          │ (normality)     │
├─────────────────┼─────────────────┤
│ Scale-Location  │ Residuals vs    │
│ (homoscedast.)  │ Leverage        │
└─────────────────┴─────────────────┘
```

## Forest Plots

`plot_params()` shows coefficient estimates with confidence intervals:

```
            ─────●───── Intercept
      ─●─────           wt
          ──●──         hp
     ◄──────────────────────────────►
    -2    -1     0     1     2     3
```

## Styling

Plots use a consistent bossanova style. Customize via matplotlib:

```python
import matplotlib.pyplot as plt

fig, ax = plt.subplots()
viz.plot_params(m, ax=ax)
ax.set_title("My Custom Title")
plt.savefig("params.png")
```

## Key Exports

| Function | Purpose |
|----------|---------|
| `plot_params` | Forest plot of coefficients |
| `plot_resid` | Residual diagnostics |
| `plot_predict` | Prediction curves |
| `plot_explore` | Marginal effects plot |
| `plot_compare` | Multi-model comparison |

---

## Developer Guide: Adding New Plot Functions

### Standard Pattern

```python
def plot_something(
    model: BaseModel,
    *,
    # Filtering options
    include_intercept: bool = False,
    terms: list[str] | None = None,
    # FacetGrid options
    height: float = 3.0,
    aspect: float = 1.2,
    col_wrap: int = 4,
    palette: str | None = None,
) -> sns.FacetGrid:
    """One-line description.

    Returns:
        Seaborn FacetGrid for further customization.
    """
    import seaborn as sns

    # 1. Extract data (use _core helpers)
    df = extract_something(model, ...)

    # 2. Build FacetGrid kwargs
    facet_kwargs = build_facetgrid_kwargs(
        data=df,  # Polars DataFrame - seaborn handles conversion
        height=height,
        aspect=aspect,
        col_wrap=col_wrap,
        ...
    )

    # 3. Create and map
    g = sns.FacetGrid(**facet_kwargs)
    g.map_dataframe(_draw_panel, style=BOSSANOVA_STYLE, ...)

    # 4. Finalize
    finalize_facetgrid(g, title="...", xlabel="...", ylabel="...")
    return g
```

### Model Method Wrapper

Every `viz.plot_*` function gets a model method wrapper:

```python
# In bossanova/model/core.py
def plot_something(self, **kwargs):
    """Plot something. See bossanova.viz.plot_something for details."""
    from bossanova.internal.viz.something import plot_something
    return plot_something(self, **kwargs)
```
