Skip to content

feat(viz): per-facet shading for faceted regression-fit plots#9

Merged
ismayc merged 1 commit into
mainfrom
feat/per-facet-fit-shading
Jun 19, 2026
Merged

feat(viz): per-facet shading for faceted regression-fit plots#9
ismayc merged 1 commit into
mainfrom
feat/per-facet-fit-shading

Conversation

@ismayc

@ismayc ismayc commented Jun 19, 2026

Copy link
Copy Markdown
Member

Why

Two faceted multiple-regression inference plots in Chapter 10 showed the correct bootstrap/null distributions but without the shading overlayshade_p_value/shade_confidence_interval were scalar-only and couldn't shade per facet. This adds array/per-term shading so those figures shade like the R book, in both the plotly (default) and plotnine engines.

What

shade_p_value and shade_confidence_interval now accept per-term inputs:

  • p-value: an observed FitResult (term + estimate), a term-keyed frame (term + estimate/stat), or a dict
  • confidence interval: a per-term CI table (term, lower_ci, upper_ci)

Each facet of a visualize_fit() plot is then shaded from its own observed statistic / interval.

  • ShadeSpec carries an optional per_term mapping; InferPlot remembers the facet terms from visualize_fit() and dispatches to per-facet shading.
  • plotly: shades each subplot via add_vline/add_vrect with row/col (infinite tails clipped to that subplot's data range).
  • plotnine: term-keyed geom_rect/geom_vline layers (inherit_aes=False) land in the correct panel.
  • FitResult.visualize() and visualize_fit() gain shade_pvalue=/shade_ci= keyword args; + composition also works.

Usage:

obs  = specify(df, formula="y ~ a + b").fit()
null = specify(df, formula="y ~ a + b").hypothesize(null="independence").generate(reps=1000, type="permute").fit()
visualize_fit(null) + shade_p_value(obs_stat=obs, direction="two-sided")   # per-facet

Notes

  • Scalar shading on single-panel plots is unchanged.
  • Adding a per-term spec to a non-faceted plot raises a clear TypeError.
  • 100% coverage retained (169 tests), ruff clean.

🤖 Generated with Claude Code

shade_p_value / shade_confidence_interval now accept per-term values so each
facet of a visualize_fit() plot is shaded from its own observed statistic /
interval, in both engines:

- per-term obs_stat: an observed FitResult, a term-keyed frame (term + estimate
  or stat), or a dict -> {term: value}
- per-term endpoints: a term-keyed CI table (term, lower_ci, upper_ci)
- ShadeSpec carries an optional per_term mapping; InferPlot remembers the facet
  terms (from visualize_fit) and dispatches to per-facet shading
- plotly shades each subplot via add_vline/add_vrect with row/col (infinite
  tails clipped to that subplot's data range); plotnine adds term-keyed
  geom_rect/geom_vline layers (inherit_aes=False) that land in the right panel
- FitResult.visualize() and visualize_fit() gain shade_pvalue=/shade_ci= kwargs

Scalar shading on single-panel plots is unchanged. Adding a per-term spec to a
non-faceted plot raises a clear error. Fixes the two Chapter 10 faceted
multiple-regression inference figures that previously rendered without shading.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017CTL1QSTg1DmDUpqYuPEog
@ismayc ismayc merged commit 384f50e into main Jun 19, 2026
5 of 6 checks passed
@ismayc ismayc deleted the feat/per-facet-fit-shading branch June 19, 2026 00:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant