Skip to content

[plotting] Migrate plotting from matplotlib/xarray to tidydraws + plotnine (#988)#990

Draft
drbenvincent wants to merge 60 commits into
mainfrom
migrate-plotting-tidydraws-plotnine
Draft

[plotting] Migrate plotting from matplotlib/xarray to tidydraws + plotnine (#988)#990
drbenvincent wants to merge 60 commits into
mainfrom
migrate-plotting-tidydraws-plotnine

Conversation

@drbenvincent

@drbenvincent drbenvincent commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

Summary

Migrates CausalPy experiment plotting from imperative matplotlib/ArviZ composition to a declarative tidydraws + plotnine stack (#988).

The public contract remains stable: experiment plot() methods return (matplotlib.figure.Figure, matplotlib.axes.Axes | numpy.ndarray). Internally, Bayesian plot builders return PlotSpec, which contains a declarative ggplot and an optional narrow post-draw matplotlib overlay.

Architecture

model output
    ↓
prediction_draws / dataarray_draws       # canonical long-form posterior draws
    ↓
summarize_draws / spaghetti_draws         # reusable posterior transformations
    ↓
posterior_kind_layers                     # ribbon / histogram / spaghetti geoms
    ↓
PlotSpec                                  # declarative plot + compatibility overlay
    ↓
BaseExperiment._finalize_plot             # stable public (Figure, Axes) return

ITS, Synthetic Control, Synthetic DiD, and Piecewise ITS additionally share a semantic CausalPanelDatabuild_causal_panel_plot() path for their common three-panel outcome/effect/cumulative-effect view.

Plotnine is imported consistently through the p9 namespace. Matplotlib overlays remain only for compatibility behavior that is awkward to express declaratively, including date-axis formatting, custom legends required by legend_kwargs, and selected post-draw axis adjustments.

What changed

  • Added plotnine>=0.15.7, tidydraws==0.4.3, and direct polars dependencies while retaining Python 3.11 support.
  • Migrated Bayesian ribbon, histogram, and spaghetti uncertainty views to shared tidy-draw transformations and Plotnine geoms.
  • Migrated RD, RK, DiD, PrePostNEGD, ITS, PiecewiseITS, Synthetic Control, Synthetic DiD, Staggered DiD, and PanelRegression plotting surfaces.
  • Replaced ArviZ plotting calls with explicit summaries and declarative layers; production experiment plotting no longer calls az.plot_*.
  • Preserved explicit keyword-only public plot signatures and stable matplotlib return values.
  • Added centralized validation for kind, ci_kind, and num_samples.
  • Ensured spaghetti paths are isolated by panel, series, chain, and draw identity.
  • Added dtype-aware DiD x-axis handling for numeric, boolean, categorical, and datetime inputs.
  • Preserved Patsy-based formula validation from current main across the affected experiments.
  • Restored PrePostNEGD legends/axis labels, corrected PanelRegression OLS coefficient orientation, and fixed Staggered DiD shared-y behavior for three or more cohorts.

Scope

  • In scope: migrated experiment plotting surfaces, including Bayesian kind ∈ {"ribbon", "histogram", "spaghetti"} views and PanelRegression/Staggered DiD auxiliary plots.
  • Out of scope: IPW-specific plots and the IV plot() stub (NotImplementedError).
  • Histogram heatmaps intentionally use Plotnine geom_bin_2d raw bin counts mapped to alpha for this pass.
  • Cosmetic parity and broader theming refinements are intentionally deferred.

Size

Against the current PR base:

  • Whole diff: +3,003 / −2,621, net +382 lines.
  • Production plotting source: net +397 lines.
  • Experiment modules including base.py: net −3 lines.
  • plot_utils.py: net +400 lines, containing the shared extraction, transformation, composition, and rendering helpers.
  • Tests: net −30 lines.

The remaining production increase is concentrated in the shared plotting layer rather than duplicated experiment implementations.

Test evidence

  • Full local suite: 1,213 passed, 5 skipped.
  • prek run --all-files.
  • make test-patch-cov: 97% total coverage, 96% patch coverage.
  • Public (Figure, Axes) contract coverage for every posterior kind.
  • Regression coverage for invalid options, boolean DiD time, multi-series spaghetti grouping, PrePost legends/labels, OLS coefficient orientation, and 3+ cohort Staggered DiD facets.
  • Semantic CausalPanelData coverage for ITS, Synthetic Control, and Synthetic DiD.
  • Remote CI for the latest commit is currently running.

drbenvincent and others added 5 commits July 9, 2026 12:11
First step of the plotting migration from imperative matplotlib/xarray to a
declarative tidydraws + plotnine stack. environment.yml is regenerated from
pyproject.toml by the pyproject2conda prek hook.

Co-authored-by: Cursor <cursoragent@cursor.com>
Replace the imperative matplotlib/xarray _bayesian_plot with a declarative
plotnine build for the ribbon and spaghetti kinds, returning a ggplot. The
xarray dimension guards (isel(treated_units=0), stack) are replaced by
tidydraws prediction_draws + point_interval, grouping on the running variable.

The histogram kind (a per-column-normalised 2D density heatmap with no plotnine
geom) keeps the legacy matplotlib code path via _bayesian_plot_mpl and returns
a (fig, ax) tuple. base._render_plot now passes a ggplot straight through while
retaining the legacy tuple path for not-yet-migrated experiments.

Tests updated for the new return type and to spy on td.point_interval for the
ci_prob wiring check.

Co-authored-by: Cursor <cursoragent@cursor.com>
Temporary visual-review assets for the plotnine migration PR. Removed in the
final cleanup commit before merge; referenced from PR comments via raw URLs.

Co-authored-by: Cursor <cursoragent@cursor.com>
Build a two-facet ggplot for kind="ribbon": top facet shows the pre/post
scatter plus control and treatment posterior predictive bands, bottom facet
shows the treatment effect posterior as a geom_density with a zero reference
line and credible-interval bounds, replacing az.plot_posterior. Posterior
extraction uses tidydraws prediction_draws + point_interval.

spaghetti and histogram kinds route to the retained matplotlib method and
return a (fig, ax) tuple. ci_prob wiring test now spies on td.point_interval.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Relabel scatter points to the same Control/Treatment series names as the
posterior bands so points, lines and bands share a single legend (the fill
guide is suppressed). Drop the oversized panel_spacing that left a large
vertical gap between the two facets.

Co-authored-by: Cursor <cursoragent@cursor.com>
…988)

The plotnine paths already covered the default ribbon (and RD spaghetti)
kinds; keeping full `_bayesian_plot_mpl` copies only grew the files.
Delete those fallbacks and raise for kinds that do not yet map cleanly.

Co-authored-by: Cursor <cursoragent@cursor.com>
@drbenvincent

Copy link
Copy Markdown
Collaborator Author

Cleanup after RD / PrePostNEGD migration

The earlier RD and PrePostNEGD commits added plotnine paths but left the full legacy matplotlib methods as _bayesian_plot_mpl, so those files only grew (Guardrail #2 anti-pattern).

This commit deletes both duplicate plotters (~218 net lines removed). Default ribbon (and RD spaghetti) stay on the single plotnine path. Unsupported kinds (histogram, and PrePost spaghetti) now raise ValueError pointing at #988 rather than carrying a second full implementation — we can revisit those later when there is a clean geom.

Next up: Guardrail #0 inventory for DifferenceInDifferences, then the component-wise migration from the issue’s worked example.

drbenvincent and others added 4 commits July 9, 2026 13:56
Build scatter plus control/treatment (and multi-period counterfactual)
ribbons as a shared plotnine ggplot, then .draw() and reuse the existing
continuous-x violin and causal-impact arrow snippets. Returns (fig, ax).

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Replace the imperative matplotlib/xarray _bayesian_plot with a declarative
plotnine build for ribbon and spaghetti, returning a ggplot. The kink
threshold is a geom_vline. kind='histogram' raises until a plotnine path
exists.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@drbenvincent

Copy link
Copy Markdown
Collaborator Author

Commit — RegressionKink (ribbon, default)

Full ggplot return (same shape as RD). Scatter + posterior ribbon/line + kink geom_vline. No matplotlib escape hatch; kind='histogram' raises until a plotnine path exists.

Before (matplotlib)

rkink before

After (plotnine)

rkink after

Review checklist

  • HDI band centred on the correct data ✓
  • Kink threshold at x=0.5 ✓
  • Colours: black data, orange posterior mean+band, red threshold ✓
  • Title (Bayesian R² + change-in-gradient CI) preserved ✓

Known cosmetic deltas (deferred to the final theming pass): legend moved to the right (plotnine default) and includes the threshold series; multi-line title left-aligned rather than centred.

Visual review approved.

drbenvincent and others added 10 commits July 9, 2026 14:21
Build the three-panel ITS layout as a faceted plotnine ggplot, then .draw()
and reuse treatment axvlines, singleton HDI markers, and date formatting.
Returns (fig, ax); kind other than ribbon raises.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Build the three-panel SC layout as a faceted plotnine ggplot, then .draw()
and reuse the treatment axvline, optional predictor lines, and date formatting.
Returns (fig, ax); kind other than ribbon raises.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…988)

Build the three-panel SDiD layout as a faceted plotnine ggplot, then .draw()
and reuse the treatment axvline and date formatting. Returns (fig, ax);
kind other than ribbon raises.

Co-authored-by: Cursor <cursoragent@cursor.com>
…mages (#988)

Co-authored-by: Cursor <cursoragent@cursor.com>
Build the three-panel PiecewiseITS layout as a faceted plotnine ggplot over
the full time series, then .draw() and reuse interruption axvlines plus
titles/legend. Returns (fig, ax); kind other than ribbon raises. OLS path
unchanged.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…#988)

Build the event-study view with geom_pointrange over cached ATT/HDI
bounds, then .draw() and set titles/legend. Returns (fig, [ax]).
plot_group_time and OLS paths unchanged.

Co-authored-by: Cursor <cursoragent@cursor.com>
)

Co-authored-by: Cursor <cursoragent@cursor.com>
@drbenvincent

Copy link
Copy Markdown
Collaborator Author

Commit — StaggeredDifferenceInDifferences event study (Bayesian plot())

Migrated the default event-study view only: plotnine geom_pointrange + pre-treatment geom_rect / hline / vline over cached att/att_lower/att_upper.draw() → titles + matplotlib legend. Still returns (fig, [ax]). No tidydraws (HDI fixed at fit time). plot_group_time and OLS paths left on matplotlib for a separate assessment.

Before (matplotlib)

staggered before

After (plotnine + matplotlib overlay)

staggered after

Review checklist

  • Placebo (grey squares) / ATT (blue circles) with HDI intervals ✓
  • Pre-treatment shade + treatment onset vline ✓
  • Zero reference hline ✓
  • plot_group_time unchanged this commit ✓

Visual review approved. Next: Guardrail #0 for Bayesian plot_group_time.

drbenvincent and others added 2 commits July 9, 2026 15:01
…988)

Build cohort ATT trajectories as a faceted (or overlay) plotnine ggplot
with ribbons/lines/points, then .draw() for titles, shared-y, vlines, and
legends. OLS helpers unchanged; unused Bayesian segment helper removed.

Co-authored-by: Cursor <cursoragent@cursor.com>
@drbenvincent

Copy link
Copy Markdown
Collaborator Author

Commit — StaggeredDifferenceInDifferences plot_group_time (Bayesian)

Migrated Bayesian cohort trajectories: plotnine ribbons/lines/points (facet default + overlay) over cached ATT/HDI → .draw() → titles, shared-y, treatment vlines, legends. Fill scale matched to grey/blue (was default cyan/red). OLS paths and shared matplotlib helpers left alone. Deleted unused _plot_bayesian_group_time_segment.

Before (matplotlib)

group_time before

After (plotnine + matplotlib overlay)

group_time after

Review checklist

  • Placebo (grey dashed) / ATT (blue solid) with matching ribbon fills ✓
  • Treatment onset vline ✓
  • Per-cohort titles + shared y ✓
  • OLS plot_group_time unchanged ✓

Visual review approved. Next: Guardrail #0 for PanelRegression (assess methods independently; low priority).

Replace az.plot_forest and OLS barh with geom_errorbarh/geom_col; thread hdi_prob via az.hdi for wiring tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
@drbenvincent

Copy link
Copy Markdown
Collaborator Author

SC + SDiD — spaghetti & histogram (Step 1–2)

Commit: 81c89376

Migrated SyntheticControl and SyntheticDifferenceInDifferences off the matplotlib fallback for kind="spaghetti" and kind="histogram", following the ITS pattern:

  • plotnine: facets, causal-impact ribbon, mean lines, observations, zero lines
  • spaghetti: sampled posterior draws via tidydraws + geom_line (alpha 0.1) + mean overlay
  • histogram: matplotlib pcolormesh overlay after .draw() (same fix as ITS — avoids geom_tile 1-unit height artifact)

Review images (migration_review/):

  • sc_spaghetti_step1_after.png, sdid_spaghetti_step1_after.png
  • sc_histogram_step2_after.png, sdid_histogram_step2_after.png

Still on matplotlib fallback: DiD, PiecewiseITS, PrePostNEGD (spaghetti/histogram); RD/RKink (histogram only).

Next: DiD / PiecewiseITS / PrePostNEGD spaghetti + histogram.

…PostNEGD (#988)

Follow the ITS/SC pattern: plotnine layout with tidydraws draw samples for spaghetti and matplotlib pcolormesh overlays for histogram density. PrePostNEGD keeps ggplot return for ribbon only.

Co-authored-by: Cursor <cursoragent@cursor.com>
@drbenvincent

Copy link
Copy Markdown
Collaborator Author

DiD + PiecewiseITS + PrePostNEGD — spaghetti & histogram

Commit: dedf7468

All three experiments now support kind="spaghetti" and kind="histogram" on the plotnine path (same ITS/SC pattern):

Experiment Layout Spaghetti Histogram
DiD single panel sampled draws per group + mean lines pcolormesh overlay per trajectory (shared y-bins)
PiecewiseITS 3-panel facets draws on fitted/counterfactual/effect/cumulative pcolormesh per panel (top: shared bins for fitted + CF)
PrePostNEGD 2-panel facets top facet only; bottom effect density unchanged top facet pcolormesh; ribbon still returns ggplot

Review images (migration_review/):

  • did_spaghetti_step1_after.png, did_histogram_step2_after.png
  • piecewise_its_spaghetti_step1_after.png, piecewise_its_histogram_step2_after.png
  • prepostnegd_spaghetti_step1_after.png, prepostnegd_histogram_step2_after.png

Remaining matplotlib fallback: RD/RKink histogram only.

Next: RD/RK histogram plotnine path, then Step 3 cleanup (_bayesian_plot_matplotlib removal).

#988)

geom_line(group="_draw_id") merged control and treatment posterior samples that share chain/draw ids at the same pretest x, producing vertical comb artifacts. Use per-series _line_id and sort by draw then pre.

Co-authored-by: Cursor <cursoragent@cursor.com>
@drbenvincent

Copy link
Copy Markdown
Collaborator Author

PrePostNEGD spaghetti fix — visual gate passed

Commit: 28fedf1c

Bug: geom_line(group="_draw_id") connected control and treatment posterior draws that share the same chain/draw id at each pretest x → vertical comb artifacts.

Fix: per-series _line_id + group="_line_id"; sort by [_draw_id, pre].

Review image: migration_review/prepostnegd_spaghetti_step1_after.png (approved)

Remaining: RD/RKink histogram plotnine path, then Step 3 cleanup.

Use the plotnine scatter/line/vline base with matplotlib pcolormesh density overlay after .draw(), matching ITS and DiD. Completes kind parity for all Bayesian time-series-style experiment plots.

Co-authored-by: Cursor <cursoragent@cursor.com>
@drbenvincent

Copy link
Copy Markdown
Collaborator Author

RD + RKink — histogram (final kind slice)

Commit: (see latest on branch)

Last matplotlib fallback removed: RegressionDiscontinuity and RegressionKink kind="histogram" now use plotnine points/lines/vlines + matplotlib pcolormesh overlay (same pattern as ITS).

Review images (migration_review/):

  • rd_histogram_step2_after.png
  • rkink_histogram_step2_after.png

Compare to existing baselines: rd_histogram_step0_baseline.png (in .scratch/plot_validation/ from Step 0).

All experiments now have plotnine paths for ribbon/spaghetti/histogram (where applicable). Next: Step 3 cleanup — remove _bayesian_plot_matplotlib, dedup helpers.

@drbenvincent

Copy link
Copy Markdown
Collaborator Author

RD + RKink histogram — visual gate passed

Commit: 65c4741c

Plotnine scatter/line/vline base + matplotlib pcolormesh overlay approved for both experiments.

Review images: migration_review/rd_histogram_step2_after.png, migration_review/rkink_histogram_step2_after.png

Migration slice complete: all Bayesian experiments with kind now on plotnine paths (ribbon/spaghetti/histogram). Ready for Step 3 cleanup (_bayesian_plot_matplotlib removal, helper dedup).

Drop unused matplotlib Bayesian plot implementations now that all kind
variants use plotnine (histogram keeps a matplotlib pcolormesh overlay).

Co-authored-by: Cursor <cursoragent@cursor.com>
@drbenvincent

Copy link
Copy Markdown
Collaborator Author

Step 3 complete — dead matplotlib Bayesian paths removed

Removed _bayesian_plot_matplotlib from all 8 experiments that had plotnine parity (~1,390 lines). Unused plot_xY / _PlotXYStyle imports cleaned up.

Still intentional:

  • plot_xY + _plot_histogram remain in plot_utils (tests + histogram pcolormesh overlay)
  • kind="histogram" still returns (fig, ax) after plotnine layout + matplotlib density overlay
  • plot() dual return handling in base.py updated to document that

Checks: prek on changed files; test_plot_utils, test_public_plot_signatures, test_piecewise_its (139 passed).

Migration slice for Bayesian kind plots is done. Optional follow-ups: dedupe _sample_draw_lines, notebook CI / tidydraws items if still open on this PR.

drbenvincent and others added 7 commits July 9, 2026 22:00
…988)

Extract sample_draw_lines, prediction/da summaries, posterior_kind_layers,
and plot_posterior_histogram into plot_utils; refactor experiments to use
them instead of copy-pasted inner functions. Remove plot_xY, ribbon/spaghetti
matplotlib paths, and histogram_tile_df. Mark tidydraws pip-only for CI.

Co-authored-by: Cursor <cursoragent@cursor.com>
Visual gate is complete; review PNGs remain in PR comments and git history.

Co-authored-by: Cursor <cursoragent@cursor.com>
Unify experiment plots behind BaseExperiment rendering with a stable (Figure, Axes) contract, shared tidydraws/plotnine primitives, and declarative geom_tile posterior histograms using proportion normalization instead of matplotlib pcolormesh overlays.

Co-authored-by: Cursor <cursoragent@cursor.com>
Derive summaries, paths, and histograms from one tidy posterior table and remove duplicate legacy plotting paths.

Co-authored-by: Cursor <cursoragent@cursor.com>
Separate tidy plot-data preparation from plotnine composition and keep only the compatibility legend bridge.

Co-authored-by: Cursor <cursoragent@cursor.com>
Separate tidy posterior preparation from declarative plot composition and remove the unused histogram-layer abstraction.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
drbenvincent and others added 4 commits July 14, 2026 12:36
Merge origin/main and preserve Patsy validation while completing the
tidydraws/plotnine migration: causal-panel semantic contract for ITS/SC/SDiD/PiecewiseITS, shared posterior validation, discrete-x DiD scales, PlotSpec-only Bayesian internals, and stable public (Figure, Axes) returns.

Upstream blocker tracked at drbenvincent/tidydraws#35

Co-authored-by: Cursor <cursoragent@cursor.com>
Consolidate posterior transformations and use explicit causal-panel data to reduce duplicated plotting code while preserving public plot contracts.

Co-authored-by: Cursor <cursoragent@cursor.com>
Remove branch-specific agent guidance so plotting changes do not alter repository-wide Cursor behavior.

Co-authored-by: Cursor <cursoragent@cursor.com>
Use the 0.4.3 release with bare ArviZ metadata so CausalPy retains its existing ArviZ constraint across supported Python versions.

Co-authored-by: Cursor <cursoragent@cursor.com>
@codecov

codecov Bot commented Jul 14, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.96157% with 66 lines in your changes missing coverage. Please review.
✅ Project coverage is 95.42%. Comparing base (13af0ef) to head (23eb421).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
causalpy/plot_utils.py 90.61% 16 Missing and 4 partials ⚠️
causalpy/experiments/staggered_did.py 80.55% 8 Missing and 6 partials ⚠️
causalpy/experiments/base.py 79.31% 6 Missing and 6 partials ⚠️
causalpy/experiments/diff_in_diff.py 89.65% 4 Missing and 2 partials ⚠️
causalpy/experiments/panel_regression.py 96.38% 1 Missing and 2 partials ⚠️
causalpy/tests/test_input_validation.py 85.00% 1 Missing and 2 partials ⚠️
causalpy/experiments/regression_kink.py 95.12% 1 Missing and 1 partial ⚠️
causalpy/tests/test_plot_show_parameter.py 96.36% 1 Missing and 1 partial ⚠️
causalpy/tests/test_posterior_plot_contracts.py 98.40% 1 Missing and 1 partial ⚠️
causalpy/experiments/interrupted_time_series.py 95.45% 0 Missing and 1 partial ⚠️
... and 1 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #990      +/-   ##
==========================================
- Coverage   95.51%   95.42%   -0.10%     
==========================================
  Files          98       99       +1     
  Lines       15868    16080     +212     
  Branches      931      979      +48     
==========================================
+ Hits        15157    15345     +188     
- Misses        504      524      +20     
- Partials      207      211       +4     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

drbenvincent and others added 6 commits July 14, 2026 16:53
Restore plot semantics and compatibility behavior across panel, pre/post, and staggered DiD views, with focused regression coverage.

Co-authored-by: Cursor <cursoragent@cursor.com>
Use a consistent Plotnine namespace to reduce import noise, while removing unused plot metadata and avoiding mutation through a frozen result bundle.

Co-authored-by: Cursor <cursoragent@cursor.com>
Keep Plotnine as the single legend owner while preserving Matplotlib compatibility for figure display, legend options, and layout.

Co-authored-by: Cursor <cursoragent@cursor.com>
Render the first causal panel at the top and keep the PrePost legend inside its data panel for clearer notebook plots.

Co-authored-by: Cursor <cursoragent@cursor.com>
Assert the Plotnine figure-level legend used by the declarative singleton-period plot instead of expecting an Axes legend.

Co-authored-by: Cursor <cursoragent@cursor.com>
Commit only notebooks with complete, error-free Papermill executions so the refreshed plots are ready for review.

Co-authored-by: Cursor <cursoragent@cursor.com>
@drbenvincent

Copy link
Copy Markdown
Collaborator Author

Notebook rendering checkpoint

Commit 23eb4218 contains the 28 documentation notebooks whose final Papermill executions completed successfully with no exception. The notebook output changes remain separate from the plotting code commits.

Not rerendered or not complete yet:

  • interrupted-time-series-causalpy-vs-causalimpact.ipynb — skipped because it requires the optional causalimpact package.
  • interrupted-time-series-placebo-in-time-analysis.ipynb — very slow; the Papermill run did not complete.
  • inverse-propensity-latent.ipynb — slow model fit; the run was stopped before completion.
  • synthetic-difference-in-differences-pymc.ipynb — slow model fit; the full run was stopped before completion.
  • instrumental-variables-pymc.ipynb and instrumental-variables-weak-instruments.ipynb — excluded from this rendering batch because of their JAX/NumPyro environment requirement.

These notebooks should be rerendered on a faster machine when their dependencies and runtime allow it.

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