You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Child of #1155 (1.1 declarative plotting migration). Depends on child A (shared draw-and-finalize seam).
Workflow
Branch from pymc6_and_pymcmarketing1_migration and open the PR against pymc6_and_pymcmarketing1_migration. Not main. See the parent issue for why.
Problem
plot_posterior_over_x is the single largest piece of shared plotting behaviour and it is entirely imperative matplotlib. It owns kind (ribbon / histogram / spaghetti), ci_kind (hdi / eti), ci_prob, and num_samples, and every experiment forwards those keywords straight to it. Until posterior rendering has a declarative path, every experiment migration is stuck migrating only the base geometry — which is exactly what happened in #1135.
Experiments also still carry the xarray dimension guards the migration is supposed to delete. RD alone does self.pred.isel(chain=0, draw=0, treated_units=0) and self.pred.isel(treated_units=0) inside _plot.
Scope
1. Tidy draw extraction. One helper that turns the canonical prediction container into long-form draws with named columns (chain, draw, series, x, value), so no experiment writes isel / az.extract / .stack(sample=("chain","draw")) in a plot method again. It must key on data properties (has_posterior_draws), not backend identity — the migration branch has a single backend-agnostic _plot and there is no _bayesian_plot / _ols_plot split to branch on any more.
Decide here whether that helper is tidydraws or hand-rolled. tidydraws was pinned in #1135 and removed again in #1137 because nothing imported it. It requires Python ≥ 3.12 while the project still supports 3.11 — #990 hit this as an sdist CI failure and never resolved it. Settle the support question before adding the dependency. If it comes back, it comes back as a range pin (tidydraws>=x.y), never an exact pin.
2. Declarative posterior layers. Layer builders for each kind that return plotnine geoms where a faithful geom exists, and fall back to a narrow post-.draw() matplotlib overlay where one does not:
ribbon → geom_ribbon + geom_line, honouring ci_kind (HDI vs equal-tailed).
spaghetti → geom_line over sampled draws. Group on a per-series line id, not the draw id — geom_line(group="_draw_id") connects control and treatment draws that share a chain/draw id at the same x and produces vertical comb artifacts ([plotting] Migrate plotting from matplotlib/xarray to tidydraws + plotnine (#988) #990 hit this in PrePostNEGD). Sort by [draw_id, x].
histogram → keep the matplotlib pcolormesh overlay. geom_tile does not work: plotnine defaults to a tile height of 1 data unit, so on a y-scale of roughly 20–130 the density renders as thin horizontal dashes ([plotting] Migrate plotting from matplotlib/xarray to tidydraws + plotnine (#988) #990 tried it and reverted). Bring across the shared-binning fixes too — one combined histogram across pre/post panels, and shared y edges when several series share an x — otherwise each panel bins on its own range and the scales disagree.
3. Centralised validation for kind, ci_kind, and num_samples, so an invalid value raises the same error from every experiment.
Files likely touched
causalpy/plot_utils.py
pyproject.toml / environment.yml (only if tidydraws returns; environment.yml is regenerated by the prek hook, never hand-edited)
New tests
Acceptance criteria
A layer builder exists for each kind, usable from any experiment without that experiment touching xarray dims.
Tidy draw extraction covers multi-series and multi-chain cases; a regression test asserts spaghetti paths are isolated by panel, series, chain, and draw.
Histogram binning is shared across panels/series that share an axis; a test pins the shared-edges behaviour.
Invalid kind / ci_kind / num_samples raise from one place, with a test.
ci_prob / hdi_prob wiring tests still pass.
The Python 3.11 vs tidydraws ≥ 3.12 question has an explicit written answer in the PR.
prek run --all-files passes; make test-patch-cov passes.
Out of scope
Deleting plot_posterior_over_x — it stays until every consumer is migrated (child G).
Migrating any experiment to use the new layers (children C–F).
Child of #1155 (1.1 declarative plotting migration). Depends on child A (shared draw-and-finalize seam).
Workflow
Branch from
pymc6_and_pymcmarketing1_migrationand open the PR againstpymc6_and_pymcmarketing1_migration. Notmain. See the parent issue for why.Problem
plot_posterior_over_xis the single largest piece of shared plotting behaviour and it is entirely imperative matplotlib. It ownskind(ribbon/histogram/spaghetti),ci_kind(hdi/eti),ci_prob, andnum_samples, and every experiment forwards those keywords straight to it. Until posterior rendering has a declarative path, every experiment migration is stuck migrating only the base geometry — which is exactly what happened in #1135.Experiments also still carry the xarray dimension guards the migration is supposed to delete. RD alone does
self.pred.isel(chain=0, draw=0, treated_units=0)andself.pred.isel(treated_units=0)inside_plot.Scope
1. Tidy draw extraction. One helper that turns the canonical prediction container into long-form draws with named columns (chain, draw, series, x, value), so no experiment writes
isel/az.extract/.stack(sample=("chain","draw"))in a plot method again. It must key on data properties (has_posterior_draws), not backend identity — the migration branch has a single backend-agnostic_plotand there is no_bayesian_plot/_ols_plotsplit to branch on any more.Decide here whether that helper is
tidydrawsor hand-rolled.tidydrawswas pinned in #1135 and removed again in #1137 because nothing imported it. It requires Python ≥ 3.12 while the project still supports 3.11 — #990 hit this as an sdist CI failure and never resolved it. Settle the support question before adding the dependency. If it comes back, it comes back as a range pin (tidydraws>=x.y), never an exact pin.2. Declarative posterior layers. Layer builders for each
kindthat return plotnine geoms where a faithful geom exists, and fall back to a narrow post-.draw()matplotlib overlay where one does not:ribbon→geom_ribbon+geom_line, honouringci_kind(HDI vs equal-tailed).spaghetti→geom_lineover sampled draws. Group on a per-series line id, not the draw id —geom_line(group="_draw_id")connects control and treatment draws that share a chain/draw id at the same x and produces vertical comb artifacts ([plotting] Migrate plotting from matplotlib/xarray to tidydraws + plotnine (#988) #990 hit this in PrePostNEGD). Sort by[draw_id, x].histogram→ keep the matplotlibpcolormeshoverlay.geom_tiledoes not work: plotnine defaults to a tile height of 1 data unit, so on a y-scale of roughly 20–130 the density renders as thin horizontal dashes ([plotting] Migrate plotting from matplotlib/xarray to tidydraws + plotnine (#988) #990 tried it and reverted). Bring across the shared-binning fixes too — one combined histogram across pre/post panels, and shared y edges when several series share an x — otherwise each panel bins on its own range and the scales disagree.3. Centralised validation for
kind,ci_kind, andnum_samples, so an invalid value raises the same error from every experiment.Files likely touched
causalpy/plot_utils.pypyproject.toml/environment.yml(only if tidydraws returns;environment.ymlis regenerated by the prek hook, never hand-edited)Acceptance criteria
kind, usable from any experiment without that experiment touching xarray dims.kind/ci_kind/num_samplesraise from one place, with a test.ci_prob/hdi_probwiring tests still pass.tidydraws≥ 3.12 question has an explicit written answer in the PR.prek run --all-filespasses;make test-patch-covpasses.Out of scope
plot_posterior_over_x— it stays until every consumer is migrated (child G).