---
title: "Prepare Forest Data with Helper Functions"
output:
  rmarkdown::html_vignette:
    highlight: pygments
vignette: >
  %\VignetteIndexEntry{Prepare Forest Data with Helper Functions}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  fig.width = 8,
  fig.height = 4.5
)
```

```{r setup}
library(ggforestplotR)
library(ggplot2)
```

This short article covers the `forest_data` interchange object and the helper
functions that prepare it before a plot is drawn.

## Use `as_forest_data()` to standardize a coefficient table

`as_forest_data()` converts your column names into the internal structure used
by `ggforestplotR`. The result is a `forest_data` data-frame subclass containing
the columns expected by `ggforestplot()`, `add_forest_table()`, and
`add_split_table()`.

```{r as-forest-data}
raw_coefs <- data.frame(
  variable = c("Age", "BMI", "Treatment"),
  beta = c(0.10, -0.08, 0.34),
  lower = c(0.02, -0.16, 0.12),
  upper = c(0.18, 0.00, 0.56),
  display = c("Age", "BMI", "Treatment"),
  section = c("Clinical", "Clinical", "Treatment"),
  sample_size = c(120, 115, 98),
  p_value = c(0.04, 0.15, 0.001)
)

forest_ready <- as_forest_data(
  data = raw_coefs,
  term = "variable",
  estimate = "beta",
  conf.low = "lower",
  conf.high = "upper",
  label = "display",
  grouping = "section",
  n = "sample_size",
  p.value = "p_value",
  estimate_scale = "identity",
  effect_label = "Beta",
  conf.level = 0.95
)
```

Use `forest_metadata()` to inspect the semantic and provenance contract. The
complete fitted model and a duplicate copy of the source data are not retained.

```{r inspect-forest-metadata}
forest_metadata(forest_ready)[c(
  "estimate_scale", "axis_transform", "effect_label", "conf_level",
  "reference_value", "source_model", "source_package", "source_columns"
)]
```

Once the data are standardized, you can pass them straight into `ggforestplot()`.

```{r helper-to-plot}
ggforestplot(forest_ready)
```

## Use `as_forest_data()` for model objects

If `broom` is available, the model-specific `as_forest_data()` method pulls
coefficient estimates and confidence limits from a fitted model. The method
also assigns model semantics such as `Beta`, `OR`, or `HR`.

```{r tidy-model}
fit <- lm(mpg ~ wt + hp + qsec, data = mtcars)

model_ready <- as_forest_data(fit)
```

The returned object can be passed directly into `ggforestplot()`.

```{r helper-to-plot-model}
ggforestplot(model_ready)
```

`tidy_forest_model()` remains available as a compatibility wrapper and returns
the same `forest_data` object.

## Derive subgroup effects from an interaction model

For a fitted model with one continuous-by-factor interaction,
`subgroup = "auto"` identifies the factor from model metadata and estimates the
focal variable's average slope within each observed factor level.

```{r model-subgroup-effects}
interaction_fit <- lm(wt ~ hp + mpg * factor(cyl) + qsec, data = mtcars)

subgroup_ready <- tidy_forest_model(
  interaction_fit,
  subgroup = "auto",
  focal = "mpg"
)

as.data.frame(subgroup_ready)[, c(
  "term", "subgroup", "estimate", "conf.low", "conf.high", "p.value"
)]

ggforestplot(subgroup_ready, striped_rows = TRUE) +
  add_forest_table(columns = c("term", "estimate", "p"))
```

These rows are average `mpg` slopes within the `cyl` levels. They come from
`marginaleffects::avg_slopes()` using the original model and its covariance
matrix. No subgroup-specific models are refitted. The focal main effect, factor
main-effect coefficients, and raw interaction coefficients are replaced by the
derived block; unrelated coefficients remain standalone in formula order.

The same interaction can be selected explicitly:

```{r explicit-model-subgroup-effects}
tidy_forest_model(
  interaction_fit,
  subgroup = "cyl",
  focal = "mpg"
)
```

Automatic selection currently requires exactly one unambiguous
continuous-by-factor interaction. Factor-by-factor effects require explicit
predictor names and use `marginaleffects::avg_comparisons()`. Continuous
subgroups, transformed focal terms, multiple selected interactions, and
three-way interactions are rejected. Logistic and Cox effects are calculated
on their model scale and shown as odds ratios and hazard ratios by default, not
as marginal probabilities or survival probabilities.

The canonical `p.value` combines two compatible display roles: ordinary
covariates retain their coefficient p-values, while every derived subgroup
block receives an omnibus Wald test of the selected interaction. The display
layer moves that interaction p-value to the subgroup header and leaves the
individual levels blank, so one table column can present both kinds of tests.

Use `p_method = "level"` when the subgroup-specific slope or comparison tests
are the quantities that should appear beside the individual estimates:

```{r model-subgroup-level-p-values}
level_p_ready <- tidy_forest_model(
  interaction_fit,
  subgroup = "auto",
  focal = "mpg",
  p_method = "level"
)

ggforestplot(level_p_ready, striped_rows = TRUE) +
  add_forest_table(columns = c("term", "estimate", "p"))
```

Both methods use the same canonical `p.value` column. `"overall"` changes the
test and places it on the subgroup header; `"level"` retains the tests returned
for the derived effects and places them on the subgroup rows.
