MMMPlotSuite v2 Migration Guide#
PyMC-Marketing is moving from the monolithic MMMPlotSuite to a namespace-based plotting API backed by arviz-plots. The new API uses PlotCollection for subplot layout, dimension-aware faceting, and multi-backend rendering. The legacy suite will be removed in pymc-marketing 2.0.0.
This guide covers how to opt in to the new API and what has changed.
Opting In#
Set plot_suite = "new" on an existing instance to switch to the new API. Until set to "new", accessing mmm.plot emits a FutureWarning.
from pymc_marketing.mmm import MMM, TimeSliceCrossValidator
mmm = MMM(...)
mmm.plot_suite = "new"
cv = TimeSliceCrossValidator(
n_init=100,
forecast_horizon=12,
date_column="date",
)
cv.plot_suite = "new"
Common Arguments#
All methods share a consistent parameter set. These are explained once here; subsequent sections refer to them by name.
Argument |
Type |
Default |
Description |
|---|---|---|---|
|
|
|
Override the model’s fitted data for a single call. When |
|
|
|
Credible interval width. Replaces |
|
|
|
Subset coordinates, e.g. |
|
|
|
Shorthand for |
|
|
|
Rendering backend: |
|
|
|
Return a |
|
— |
— |
Forwarded to |
|
|
|
Per-visual-element kwargs e.g. |
fig, axes = mmm.plot.diagnostics.posterior_predictive(
hdi_prob=0.89,
dims={"channel": ["tv"]},
figsize=(10, 4),
line_kwargs={"color": "blue"},
hdi_kwargs={"alpha": 0.3},
)
Non-Matplotlib Backends (not fully supported)#
Any method that accepts backend can render with Plotly or Bokeh instead of Matplotlib. When using a non-matplotlib backend you must pass return_as_pc=True, which returns a PlotCollection instead of a (Figure, axes) tuple.
Note: Non-matplotlib backend support has not been fully tested and is likely to contain issues. Use at your own risk.
waterfall() in the decomposition namespace does not accept backend or return_as_pc — it always returns a matplotlib (Figure, axes) tuple.
# Plotly backend — requires return_as_pc=True
pc = mmm.plot.diagnostics.posterior_predictive(
backend="plotly",
return_as_pc=True,
)
pc.show()
mmm.plot.diagnostics#
Method names#
Legacy |
New |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
Argument changes#
Old |
New |
Notes |
|---|---|---|
|
|
Single level per call |
|
|
Also accepts a single string |
— |
|
New on |
— |
|
New on |
— |
|
New on |
— |
|
New on |
fig, axes = mmm.plot.diagnostics.posterior_predictive()
fig, axes = mmm.plot.diagnostics.posterior(var_names=["alpha", "beta"])
fig, axes = mmm.plot.diagnostics.residuals_distribution(quantiles=[0.025, 0.5, 0.975])
mmm.plot.decomposition#
Method names#
Legacy |
New |
|---|---|
|
|
|
|
|
|
Argument changes#
Old |
New |
Notes |
|---|---|---|
|
|
Single level per call |
|
|
Default flipped to True |
— |
|
New on |
waterfall() does not accept backend or return_as_pc — it always returns (Figure, NDArray[Axes]).
fig, axes = mmm.plot.decomposition.contributions_over_time(
include=["channels", "baseline"]
)
fig, axes = mmm.plot.decomposition.waterfall()
fig, axes = mmm.plot.decomposition.channel_share_hdi(hdi_prob=0.89)
mmm.plot.sensitivity#
Method names#
Legacy |
New |
|---|---|
|
|
|
|
|
|
Argument changes#
Old |
New |
Notes |
|---|---|---|
|
|
Single level per call |
— |
|
New — controls x-axis scale |
— |
|
New — scale spend axis by cost-per-unit |
— |
|
New — aggregate over dimensions before plotting |
fig, axes = mmm.plot.sensitivity.analysis()
fig, axes = mmm.plot.sensitivity.analysis(x_sweep_axis="absolute", hdi_prob=0.89)
mmm.plot.transformation#
Method names#
Legacy |
New |
|---|---|
|
|
|
|
Argument changes#
Old |
New |
Notes |
|---|---|---|
|
|
Default flipped to True |
|
|
Single level; pass |
— |
|
New on both methods |
— |
|
New on |
— |
|
New on |
— |
|
New on |
— |
|
New on |
— |
|
Now required positional arg on |
fig, axes = mmm.plot.transformation.saturation_scatterplot()
fig, axes = mmm.plot.transformation.saturation_curves(
curves=saturation_curve_data,
n_samples=20,
)
Budget Plots#
Budget plots have moved from mmm.plot to optimizer.plot. BudgetPlots is stateless — all data is passed per-call via samples.
Argument changes#
Old |
New |
Notes |
|---|---|---|
|
|
Single level per call |
— |
|
Required arg — output of |
from pymc_marketing.mmm import MMM, BudgetOptimizerWrapper
mmm = MMM(...)
mmm.plot_suite = "new"
optimizer = BudgetOptimizerWrapper(
model=mmm, start_date="2024-01-01", end_date="2024-12-31"
)
samples = optimizer.allocate_budget(...)
fig, axes = optimizer.plot.allocation_roas(samples=samples)
fig, axes = optimizer.plot.contribution_over_time(samples=samples)
Cross-Validation Plots#
CV plots use MMMCVPlotSuite when cv.plot_suite = "new".
Argument changes#
Old |
New |
Notes |
|---|---|---|
|
|
Single level per call |
— |
|
New on |
cv = TimeSliceCrossValidator(n_init=100, forecast_horizon=12, date_column="date")
cv.plot_suite = "new"
cv_idata = cv.run(X, y, mmm=mmm)
fig, axes = cv.plot.predictions(cv_idata)
fig, axes = cv.plot.param_stability(cv_idata, var_names=["alpha"])
fig, axes = cv.plot.crps(cv_idata)
Removal Timeline#
The legacy MMMPlotSuite (the default when mmm.plot_suite is not set) will be removed in pymc-marketing 2.0.0. Until then, accessing mmm.plot without opting in emits a FutureWarning.
To suppress it: set mmm.plot_suite = "new".