Reporting¶
The reporting module provides HTML report generation for MMM results with interactive Plotly visualizations.
Report Generator¶
Main report generator for MMM reports.
Assembles sections, applies styling, and produces portable HTML output.
- class mmm_framework.reporting.generator.MMMReportGenerator(model=None, data=None, config=None, panel=None, results=None, sensitivity=None, llm=None, allocation=None, pacing=None, triangulation=None, spec_curve=None, cfo=None)[source]¶
Bases:
objectGenerate portable HTML reports from Bayesian MMM results.
Parameters¶
- modelAny, optional
Fitted MMM model (BayesianMMM, NestedMMM, MultivariateMMM, etc.)
- dataMMMDataBundle, optional
Pre-extracted data bundle (alternative to model)
- configReportConfig, optional
Report configuration
- panelAny, optional
Panel dataset used for fitting
- resultsAny, optional
Model fit results
- sensitivitydict, optional
Sensitivity analysis results
Examples¶
>>> from mmm_framework import BayesianMMM >>> from mmm_reporting import MMMReportGenerator, ReportConfig >>> >>> # Fit model >>> mmm = BayesianMMM(panel, model_config, trend_config) >>> results = mmm.fit() >>> >>> # Generate report >>> report = MMMReportGenerator( ... model=mmm, ... config=ReportConfig( ... title="Q4 2025 Marketing Analysis", ... client="Acme Corp", ... analysis_period="Jan 2023 - Dec 2025", ... ) ... ) >>> report.to_html("mmm_report.html")
- __init__(model=None, data=None, config=None, panel=None, results=None, sensitivity=None, llm=None, allocation=None, pacing=None, triangulation=None, spec_curve=None, cfo=None)[source]¶
- add_section(section_type, section_config=None, position=None)[source]¶
Add a section to the report.
- Return type:
Parameters¶
- section_typestr
Type of section from SECTION_REGISTRY
- section_configSectionConfig, optional
Configuration for the section
- positionint, optional
Position to insert (None = append)
Returns¶
- MMMReportGenerator
Self for chaining
- remove_section(section_id)[source]¶
Remove a section by ID.
- Return type:
Parameters¶
- section_idstr
Section ID to remove
Returns¶
- MMMReportGenerator
Self for chaining
- class mmm_framework.reporting.generator.ReportBuilder[source]¶
Bases:
objectFluent builder for creating customized reports.
Examples¶
>>> report = ( ... ReportBuilder() ... .with_model(mmm) ... .with_title("Q4 Analysis") ... .with_client("Acme Corp") ... .enable_all_sections() ... .disable_section("diagnostics") ... .with_credible_interval(0.9) ... .build() ... )
- with_llm(llm)[source]¶
Attach a LangChain chat model used to enrich CMO/planner narrative in the Augur readout (best-effort; templated fallback otherwise).
- Return type:
- with_insights(insights)[source]¶
Pre-supply CMO/planner narrative slots (skips insight generation).
- Return type:
- augur_readout()[source]¶
Configure the editorial “Media Performance Readout” (Augur) shell.
Sets the Augur palette + cream/ink shell, a numbered sticky contents nav, a confidentiality notice and channel-name formatting. The Augur section set (headline → reallocation → deep dives → posterior-predictive fit & checks → tests → next steps) is selected by
shell == "augur".- Return type:
- with_allocation(plan)[source]¶
Attach a budget-allocation plan (a default reallocation from
planning.default_reallocation(), or a saved Planner plan).The plan is exposed on the report bundle as
allocation_resultsand turns the allocation section ON (classic and Augur). A falsy/empty plan is ignored, so the section stays off. The plan dict shape is the one theplan_budgetop /AllocationSectionconsume.- Return type:
- with_channel_colors(channel_colors)[source]¶
Set per-channel chart colors (a ChannelColors instance).
- Return type:
- with_credible_interval(prob)[source]¶
Set default credible interval (e.g., 0.8 for 80% CI).
- Return type:
- enable_section(section_name, **kwargs)[source]¶
Enable a section with optional configuration.
- Return type:
- client_report()[source]¶
Configure a clean, client-ready report.
Includes: Executive Summary, Channel Performance, Decomposition, Saturation & Carryover, and a simplified Methodology note. Excludes: Diagnostics (trace plots / prior-posterior) and Sensitivity.
Also enables sticky side-nav, confidentiality notice, and automatic channel-name formatting (underscores → spaces, title-case).
- Return type:
Configuration¶
Configuration classes for MMM report generation.
Provides immutable, validated configuration for report customization.
- class mmm_framework.reporting.config.ColorPalette(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)[source]¶
Bases:
EnumPre-defined color palettes for reports.
- SAGE = 'sage'¶
- CORPORATE = 'corporate'¶
- WARM = 'warm'¶
- MONOCHROME = 'monochrome'¶
- AUGUR = 'augur'¶
- class mmm_framework.reporting.config.ColorScheme(primary='#8fa86a', primary_dark='#6d8a4a', accent='#6a8fa8', accent_dark='#4a6d8a', warning='#d4a86a', danger='#c97067', success='#6abf8a', text='#2d3a2d', text_muted='#5a6b5a', background='#fafbf9', background_alt='#f0f2ed', surface='#ffffff', border='#d4ddd4', font_sans='Source Sans 3, sans-serif')[source]¶
Bases:
objectColor scheme for report styling.
- __init__(primary='#8fa86a', primary_dark='#6d8a4a', accent='#6a8fa8', accent_dark='#4a6d8a', warning='#d4a86a', danger='#c97067', success='#6abf8a', text='#2d3a2d', text_muted='#5a6b5a', background='#fafbf9', background_alt='#f0f2ed', surface='#ffffff', border='#d4ddd4', font_sans='Source Sans 3, sans-serif')¶
- class mmm_framework.reporting.config.ChannelColors(colors=<factory>)[source]¶
Bases:
objectColor mapping for media channels.
- with_channel(channel, color)[source]¶
Return new ChannelColors with added/updated channel color.
- Return type:
- __init__(colors=<factory>)¶
- class mmm_framework.reporting.config.SectionConfig(enabled=True, title=None, subtitle=None, show_uncertainty=True, credible_interval=0.8, chart_height=400, chart_width=None, custom_notes=None)[source]¶
Bases:
objectConfiguration for individual report sections.
- __init__(enabled=True, title=None, subtitle=None, show_uncertainty=True, credible_interval=0.8, chart_height=400, chart_width=None, custom_notes=None)¶
- class mmm_framework.reporting.config.ReportConfig(title='Marketing Mix Model Report', subtitle=None, client=None, analysis_period=None, generated_date=None, model_version=None, framework_version=None, color_scheme=<factory>, channel_colors=<factory>, font_family_serif="'DM Serif Display', serif", font_family_sans="'Inter', -apple-system, BlinkMacSystemFont, sans-serif", font_family_mono="'JetBrains Mono', monospace", shell='default', cmo_insights=<factory>, default_credible_interval=0.8, currency_symbol='$', currency_format=', .0f', percentage_format='.1%', decimal_format='.2f', large_number_format='short', executive_summary=<factory>, model_fit=<factory>, posterior_predictive=<factory>, estimands=<factory>, channel_roi=<factory>, decomposition=<factory>, saturation=<factory>, sensitivity=<factory>, pacing=<factory>, long_term=<factory>, triangulation=<factory>, spec_curve=<factory>, cfo=<factory>, causal_assumptions=<factory>, methodology=<factory>, diagnostics=<factory>, geographic=<factory>, mediators=<factory>, cannibalization=<factory>, factor_analysis=<factory>, headline=<factory>, marginal_returns=<factory>, reallocation=<factory>, flighting=<factory>, deep_dives=<factory>, carryover=<factory>, ppc_timeseries=<factory>, recommended_tests=<factory>, evidence_guide=<factory>, next_steps=<factory>, allocation=<factory>, include_plotly_js=True, plotly_cdn_version='2.27.0', include_print_styles=True, minify_html=False, uncertainty_callout=True, methodology_note=True, long_term_multiplier=None, show_nav=False, confidential=False, format_channel_names=False)[source]¶
Bases:
objectComplete configuration for report generation.
-
color_scheme:
ColorScheme¶
-
channel_colors:
ChannelColors¶
-
executive_summary:
SectionConfig¶
-
model_fit:
SectionConfig¶
-
posterior_predictive:
SectionConfig¶
-
estimands:
SectionConfig¶
-
channel_roi:
SectionConfig¶
-
decomposition:
SectionConfig¶
-
saturation:
SectionConfig¶
-
sensitivity:
SectionConfig¶
-
pacing:
SectionConfig¶
-
long_term:
SectionConfig¶
-
triangulation:
SectionConfig¶
-
spec_curve:
SectionConfig¶
-
cfo:
SectionConfig¶
-
causal_assumptions:
SectionConfig¶
-
methodology:
SectionConfig¶
-
diagnostics:
SectionConfig¶
-
geographic:
SectionConfig¶
-
mediators:
SectionConfig¶
-
cannibalization:
SectionConfig¶
-
factor_analysis:
SectionConfig¶
-
headline:
SectionConfig¶
-
marginal_returns:
SectionConfig¶
-
reallocation:
SectionConfig¶
-
flighting:
SectionConfig¶
-
deep_dives:
SectionConfig¶
-
carryover:
SectionConfig¶
-
ppc_timeseries:
SectionConfig¶
-
recommended_tests:
SectionConfig¶
-
evidence_guide:
SectionConfig¶
-
next_steps:
SectionConfig¶
-
allocation:
SectionConfig¶
- classmethod minimal(title='MMM Report', client=None)[source]¶
Create minimal report with only essential sections.
- Return type:
- classmethod full(title='Marketing Mix Model Report', client=None)[source]¶
Create comprehensive report with all sections.
- Return type:
- classmethod presentation(title='MMM Results', client=None)[source]¶
Create presentation-focused report optimized for stakeholders.
- Return type:
- classmethod augur_readout(title='Media Performance Readout', client=None, *, cmo_insights=None)[source]¶
Create the editorial “Media Performance Readout” (Augur) report.
A narrative, evidence-coded client deliverable: masthead + numbered contents nav, a headline with a KPI strip and recommendations, a channel scorecard with Scale/Test/Hold/Reduce tiers, ROI-with-uncertainty, marginal-vs-average return, saturation, reallocation, per-channel deep dives, carryover, a posterior-predictive fit-over-time + checks section, and recommended tests / next steps. CMO/planner narrative is filled by
reporting.insights.build_report_insights(templated fallback + optional LLM enrichment).- Return type:
- __init__(title='Marketing Mix Model Report', subtitle=None, client=None, analysis_period=None, generated_date=None, model_version=None, framework_version=None, color_scheme=<factory>, channel_colors=<factory>, font_family_serif="'DM Serif Display', serif", font_family_sans="'Inter', -apple-system, BlinkMacSystemFont, sans-serif", font_family_mono="'JetBrains Mono', monospace", shell='default', cmo_insights=<factory>, default_credible_interval=0.8, currency_symbol='$', currency_format=', .0f', percentage_format='.1%', decimal_format='.2f', large_number_format='short', executive_summary=<factory>, model_fit=<factory>, posterior_predictive=<factory>, estimands=<factory>, channel_roi=<factory>, decomposition=<factory>, saturation=<factory>, sensitivity=<factory>, pacing=<factory>, long_term=<factory>, triangulation=<factory>, spec_curve=<factory>, cfo=<factory>, causal_assumptions=<factory>, methodology=<factory>, diagnostics=<factory>, geographic=<factory>, mediators=<factory>, cannibalization=<factory>, factor_analysis=<factory>, headline=<factory>, marginal_returns=<factory>, reallocation=<factory>, flighting=<factory>, deep_dives=<factory>, carryover=<factory>, ppc_timeseries=<factory>, recommended_tests=<factory>, evidence_guide=<factory>, next_steps=<factory>, allocation=<factory>, include_plotly_js=True, plotly_cdn_version='2.27.0', include_print_styles=True, minify_html=False, uncertainty_callout=True, methodology_note=True, long_term_multiplier=None, show_nav=False, confidential=False, format_channel_names=False)¶
-
color_scheme:
- class mmm_framework.reporting.config.ChartConfig(height=400, width=None, margin=<factory>, show_legend=True, legend_position='top', animation=True, responsive=True, show_credible_intervals=True, ci_alpha=0.2, ci_level=0.8, x_title=None, y_title=None, x_tickformat=None, y_tickformat=None)[source]¶
Bases:
objectConfiguration for individual charts.
- __init__(height=400, width=None, margin=<factory>, show_legend=True, legend_position='top', animation=True, responsive=True, show_credible_intervals=True, ci_alpha=0.2, ci_level=0.8, x_title=None, y_title=None, x_tickformat=None, y_tickformat=None)¶
Sections¶
Report section renderers for MMM reports.
Each section is a modular component that can be enabled/disabled and customized independently.
- class mmm_framework.reporting.sections.Section(data, config, section_config=None)[source]¶
Bases:
objectBase class for report sections.
- property interval_noun: str¶
"credible interval"/"confidence interval".Every section that names its interval reads this instead of writing “credible” literally. A bootstrap percentile interval describes the sampling variability of an estimator; the probability statement a credible interval licenses is simply false for it.
- class mmm_framework.reporting.sections.ExecutiveSummarySection(data, config, section_config=None)[source]¶
Bases:
SectionExecutive summary with key metrics and uncertainty callouts.
- class mmm_framework.reporting.sections.ModelFitSection(data, config, section_config=None)[source]¶
Bases:
SectionModel fit visualization with actual vs predicted.
UPDATED: Now includes geo-level dropdown selector when geo data is available. The default view shows aggregated (total) model fit, with option to drill down to individual geographies.
- class mmm_framework.reporting.sections.ChannelROISection(data, config, section_config=None)[source]¶
Bases:
SectionChannel ROI analysis with forest plot.
- class mmm_framework.reporting.sections.DecompositionSection(data, config, section_config=None)[source]¶
Bases:
SectionRevenue decomposition showing contribution of each component.
UPDATED: Now includes geo-level dropdown selector when geo data is available. Features both stacked area (time series) and waterfall (total contribution) views, each with independent geo selectors.
- class mmm_framework.reporting.sections.SaturationSection(data, config, section_config=None)[source]¶
Bases:
SectionSaturation and adstock analysis.
- class mmm_framework.reporting.sections.SensitivitySection(data, config, section_config=None)[source]¶
Bases:
SectionSensitivity analysis results.
- class mmm_framework.reporting.sections.PacingSection(data, config, section_config=None)[source]¶
Bases:
SectionIn-flight pacing — planned vs actual delivery (issue #107).
Closes the loop between the recommended plan and live delivery: planned vs actual spend by channel, divergence flags, and the expected effect on the outcome. Data-gated on
bundle.pacing.
- class mmm_framework.reporting.sections.LongTermSection(data, config, section_config=None)[source]¶
Bases:
SectionShort-term vs long-term / brand effect (issue #106).
A weekly MMM measures activation + within-window carryover; it does NOT measure true long-term brand equity. This section surfaces the estimable immediate-vs-carryover split, states the long-term caveat plainly (so the report can’t be read as having measured brand), optionally shows an assumption-driven long-term-multiplier scenario, and lists the data needed to measure long-term properly. Data-gated on
bundle.long_term.
- class mmm_framework.reporting.sections.TriangulationSection(data, config, section_config=None)[source]¶
Bases:
SectionTriangulation panel — MMM × experiment × platform (issue #104).
Puts each channel’s effect from the MMM, from experiments, and from platform-reported attribution side by side, with a reconciled recommendation and plain-language notes on any disagreement. Convergent evidence across independent methods is the most persuasive thing to show a skeptical CFO; divergence, shown honestly, is where the real conversation happens. Data-gated on
bundle.triangulation.
- class mmm_framework.reporting.sections.SpecCurveSection(data, config, section_config=None)[source]¶
Bases:
SectionSpec-curve / model-averaging robustness (issue #103).
Renders how each channel’s ROI moves across a pre-registered set of defensible specs, plus the model-averaged (BMA) estimate — so robustness across specs is itself a reported result and fragility can’t hide behind one hand-picked number. Data-gated on
bundle.spec_curve.The BMA weighting is labelled explicitly, because averaging a causal estimand with predictive weights is a category error the payload’s
weighting_caveatspells out. Seemmm_framework.validation.spec_curve.
- class mmm_framework.reporting.sections.MethodologySection(data, config, section_config=None)[source]¶
Bases:
SectionModel methodology documentation.
- class mmm_framework.reporting.sections.CFOSection(data, config, section_config=None)[source]¶
Bases:
SectionCFO one-pager — marketing’s P&L contribution + spend-cut risk (issue #108).
Rolls the model up into the two numbers a budget owner carries into a board room: marketing’s total incremental contribution vs the base (non-marketing) outcome, with a credible interval, and a spend-cut sensitivity (“cut marketing X% → this much revenue/profit at risk”). Data-gated on
bundle.cfo.
- class mmm_framework.reporting.sections.CausalAssumptionsSection(data, config, section_config=None)[source]¶
Bases:
SectionCausal assumptions, identification strategy and sensitivity to unobserved confounding.
Always renders the no-unobserved-confounding / SUTVA caveat (the honest framing a causal-branded tool owes its readers). When the data bundle carries
causal_assumptions(identification strategy, assumed confounders, and the robustness-value table frommmm_framework.validation), those details are rendered too.
- class mmm_framework.reporting.sections.DiagnosticsSection(data, config, section_config=None)[source]¶
Bases:
SectionMCMC diagnostics and convergence checks.
Gated OFF for a frequentist fit, with a stated reason. Left on, the extractor supplies
NoneR-hat/ESS and the table below renders them as “N/A” — which is correct but reads as a broken table rather than as a property of the estimator. Worse, before_merge_fit_provenancelearned the paradigm, the recomputed ESS of a bootstrap trace was ≈``n_boot`` and the row rendered “✅ Pass”.
- class mmm_framework.reporting.sections.GeographicSection(data, config, section_config=None)[source]¶
Bases:
SectionGeographic performance breakdown for multi-geo models.
- class mmm_framework.reporting.sections.MediatorSection(data, config, section_config=None)[source]¶
Bases:
SectionMediator pathway analysis for nested models.
- class mmm_framework.reporting.sections.CannibalizationSection(data, config, section_config=None)[source]¶
Bases:
SectionCross-product cannibalization effects analysis.
- class mmm_framework.reporting.sections.FactorAnalysisSection(data, config, section_config=None)[source]¶
Bases:
SectionLatent-structure section for a non-MMM model — a CFA’s loadings, an LCA’s class profiles, etc. Renders a summary table + the model’s declared estimands as cards, with family-specific headings supplied by the bundle (
latent_section_title/latent_table_title/latent_estimands_title). Empty unless the bundle carriesfactor_loadingsorcfa_fit_indices.
- class mmm_framework.reporting.sections.EstimandsSection(data, config, section_config=None)[source]¶
Bases:
SectionDeclared / default estimand results with credible intervals.
Renders the model’s pre-specified causal quantities (e.g. contribution ROI, marginal ROAS, incremental contribution per channel) as a single table of point estimate + credible interval. Data-driven: empty unless the bundle carries
estimands(populated by the extractor for MMM models).
- class mmm_framework.reporting.sections.PosteriorPredictiveSection(data, config, section_config=None)[source]¶
Bases:
SectionPosterior-predictive goodness-of-fit checks for MMM models.
Default-on for MMM models: shows whether the fitted model can reproduce the data it was trained on, via observed-vs-predicted, a density overlay of replicated datasets, predictive-interval calibration, and residual structure. Data-driven: empty unless the bundle carries
posterior_predictive.
- class mmm_framework.reporting.sections.AllocationSection(data, config, section_config=None)[source]¶
Bases:
SectionBudget-allocation plan: recommended per-channel (and per-geo) spend plus an optional forward flighting calendar.
Data-driven and default-off: renders only when the bundle carries
allocation_results(a plan computed by theplan_budgetop), so a normal model report that has no plan attached silently omits the section.
Data Extractors¶
Data extractors for MMM report generation.
Provides adapters to extract report data from various MMM model types: - BayesianMMM (core framework) - NestedMMM, MultivariateMMM, CombinedMMM (extensions) - PyMC-Marketing MMM class
Each extractor converts model-specific data structures into a unified MMMDataBundle that the report generator can consume.
This subpackage organizes extractors by domain: - bundle: MMMDataBundle data container - base: DataExtractor ABC and protocols - mixins: Shared extraction utilities (aggregation, geo-level) - bayesian: BayesianMMMExtractor for core framework - extended: ExtendedMMMExtractor for extension models - pymc_marketing: PyMCMarketingExtractor for compatibility
- class mmm_framework.reporting.extractors.MMMDataBundle(dates=None, geo_names=None, actual_by_geo=None, predicted_by_geo=None, fit_statistics_by_geo=None, actual=None, predicted=None, fit_statistics=None, total_revenue=None, marketing_attributed_revenue=None, blended_roi=None, marketing_contribution_pct=None, channel_roi=None, channel_spend=None, channel_contribution=None, channel_evidence=None, component_totals=None, component_time_series=None, saturation_curves=None, adstock_curves=None, current_spend=None, sensitivity_results=None, pacing=None, long_term=None, triangulation=None, spec_curve=None, cfo=None, causal_assumptions=None, model_specification=None, model_kind='mmm', inference_family='bayesian', estimator=None, interval_kind=None, interval_semantics=None, frequentist_caveats=None, factor_loadings=None, cfa_fit_indices=None, latent_section_title=None, latent_table_title=None, latent_estimands_title=None, estimands=None, allocation_results=None, posterior_predictive=None, diagnostics=None, trace_data=None, trace_parameters=None, prior_samples=None, posterior_samples=None, channel_names=None, pooled_channels=None, time_varying_betas=None, reach_frequency=None, mediator_effects=None, cross_effects=None, outcome_correlations=None, geo_performance=None, geo_roi=None, geo_contribution=None, mediator_names=None, mediator_pathways=None, mediator_time_series=None, total_indirect_effect=None, product_names=None, cannibalization_matrix=None, net_product_effects=None, component_time_series_by_geo=None, component_totals_by_geo=None, actual_by_product=None, predicted_by_product=None, fit_statistics_by_product=None, component_time_series_by_product=None, component_totals_by_product=None)[source]¶
Bases:
objectUnified data container for MMM report generation.
All fields are optional - sections will gracefully skip if data is missing.
Attributes¶
- datesarray-like, optional
Time index for the model.
- actualndarray, optional
Observed KPI values (aggregated to period level).
- predicteddict, optional
Predictions with “mean”, “lower”, “upper” keys.
- fit_statisticsdict, optional
Model fit metrics like “r2”, “rmse”, “mae”, “mape”.
- channel_nameslist[str], optional
Names of media channels.
- channel_roidict, optional
Channel-level ROI with uncertainty.
- channel_spenddict, optional
Total spend per channel.
- channel_contributiondict, optional
Channel contribution with uncertainty.
- component_totalsdict, optional
Total contribution per component.
- component_time_seriesdict, optional
Time series per component.
- saturation_curvesdict, optional
Saturation curve data per channel.
- adstock_curvesdict, optional
Adstock decay weights per channel.
- current_spenddict, optional
Current spend level per channel.
- diagnosticsdict, optional
MCMC diagnostics like divergences, rhat, ess.
- trace_datadict, optional
MCMC trace samples for diagnostic plots.
- trace_parameterslist[str], optional
Parameter names for trace plots.
- prior_samplesdict, optional
Prior samples for comparison.
- posterior_samplesdict, optional
Posterior samples for comparison.
- model_specificationdict, optional
Model configuration details.
- geo_nameslist[str], optional
Geography names for hierarchical models.
- geo_performancedict, optional
Geo-level performance metrics.
- geo_roidict, optional
Geo-level ROI by channel.
- geo_contributiondict, optional
Geo-level contribution by component.
- actual_by_geodict, optional
Observed values per geo.
- predicted_by_geodict, optional
Predictions per geo with uncertainty.
- fit_statistics_by_geodict, optional
Fit statistics per geo.
- component_time_series_by_geodict, optional
Component time series per geo.
- component_totals_by_geodict, optional
Component totals per geo.
- product_nameslist[str], optional
Product names for multi-product models.
- actual_by_productdict, optional
Observed values per product.
- predicted_by_productdict, optional
Predictions per product with uncertainty.
- fit_statistics_by_productdict, optional
Fit statistics per product.
- component_time_series_by_productdict, optional
Component time series per product.
- component_totals_by_productdict, optional
Component totals per product.
- mediator_nameslist[str], optional
Mediator names for nested models.
- mediator_pathwaysdict, optional
Effect pathways through mediators.
- mediator_time_seriesdict, optional
Mediator values over time.
- mediator_effectsdict, optional
Mediator effect estimates.
- total_indirect_effectdict, optional
Total indirect effect with uncertainty.
- cannibalization_matrixdict, optional
Cross-product cannibalization effects.
- cross_effectsdict, optional
Cross-outcome effects.
- outcome_correlationsndarray, optional
Correlation matrix between outcomes.
- net_product_effectsdict, optional
Net effects per product after cannibalization.
- total_revenuefloat, optional
Total observed revenue/KPI.
- marketing_attributed_revenuedict, optional
Revenue attributed to marketing.
- blended_roidict, optional
Overall blended ROI with uncertainty.
- marketing_contribution_pctdict, optional
Marketing contribution as percentage.
- sensitivity_resultsdict, optional
Sensitivity analysis results.
-
dates:
ndarray|DatetimeIndex|list|None= None¶
- property has_posterior_predictive: bool¶
Check if posterior-predictive goodness-of-fit data is available.
- __init__(dates=None, geo_names=None, actual_by_geo=None, predicted_by_geo=None, fit_statistics_by_geo=None, actual=None, predicted=None, fit_statistics=None, total_revenue=None, marketing_attributed_revenue=None, blended_roi=None, marketing_contribution_pct=None, channel_roi=None, channel_spend=None, channel_contribution=None, channel_evidence=None, component_totals=None, component_time_series=None, saturation_curves=None, adstock_curves=None, current_spend=None, sensitivity_results=None, pacing=None, long_term=None, triangulation=None, spec_curve=None, cfo=None, causal_assumptions=None, model_specification=None, model_kind='mmm', inference_family='bayesian', estimator=None, interval_kind=None, interval_semantics=None, frequentist_caveats=None, factor_loadings=None, cfa_fit_indices=None, latent_section_title=None, latent_table_title=None, latent_estimands_title=None, estimands=None, allocation_results=None, posterior_predictive=None, diagnostics=None, trace_data=None, trace_parameters=None, prior_samples=None, posterior_samples=None, channel_names=None, pooled_channels=None, time_varying_betas=None, reach_frequency=None, mediator_effects=None, cross_effects=None, outcome_correlations=None, geo_performance=None, geo_roi=None, geo_contribution=None, mediator_names=None, mediator_pathways=None, mediator_time_series=None, total_indirect_effect=None, product_names=None, cannibalization_matrix=None, net_product_effects=None, component_time_series_by_geo=None, component_totals_by_geo=None, actual_by_product=None, predicted_by_product=None, fit_statistics_by_product=None, component_time_series_by_product=None, component_totals_by_product=None)¶
- class mmm_framework.reporting.extractors.HasTrace(*args, **kwargs)[source]¶
Bases:
ProtocolProtocol for objects with an ArviZ InferenceData trace.
- __init__(*args, **kwargs)¶
- class mmm_framework.reporting.extractors.HasModel(*args, **kwargs)[source]¶
Bases:
ProtocolProtocol for objects with a PyMC model.
- __init__(*args, **kwargs)¶
- class mmm_framework.reporting.extractors.DataExtractor[source]¶
Bases:
ABCBase class for model data extractors.
All concrete extractors should inherit from this class and implement the extract() method. Shared utilities for HDI computation, diagnostics extraction, and fit statistics are provided.
Attributes¶
- ci_probfloat
Credible interval probability (default 0.8).
Examples¶
>>> class MyExtractor(DataExtractor): ... def __init__(self, model, ci_prob=0.8): ... self.model = model ... self._ci_prob = ci_prob ... ... @property ... def ci_prob(self): ... return self._ci_prob ... ... def extract(self): ... bundle = MMMDataBundle() ... # ... extract data ... return bundle
- stamp_inference_family(bundle, diagnostics)[source]¶
Copy the estimation paradigm onto the bundle for section gating.
Kept separate from
_merge_fit_provenance()(which owns the diagnostics dict) because sections read the bundle, not the dict, and a section that has to reach intobundle.diagnosticsto learn what vocabulary to use is a section that will forget to.- Return type:
- class mmm_framework.reporting.extractors.AggregationMixin[source]¶
Bases:
objectMixin providing data aggregation utilities for extractors.
Provides methods for aggregating data by period, geography, and product while properly propagating uncertainty through sample aggregation.
- class mmm_framework.reporting.extractors.GeoExtractionMixin[source]¶
Bases:
objectMixin providing geo-level extraction methods.
Requires the class to have panel, mmm, and ci_prob attributes.
- class mmm_framework.reporting.extractors.ProductExtractionMixin[source]¶
Bases:
objectMixin providing product-level extraction methods.
Requires the class to have panel, mmm, and ci_prob attributes.
- class mmm_framework.reporting.extractors.BayesianMMMExtractor(mmm, panel=None, results=None, ci_prob=0.8)[source]¶
Bases:
DataExtractor,AggregationMixin,GeoExtractionMixin,ProductExtractionMixin,EstimandPPCMixinExtract data from mmm-framework’s BayesianMMM class.
Inherits shared utilities from DataExtractor and AggregationMixin for HDI computation, fit statistics, and data aggregation.
Parameters¶
- mmmBayesianMMM
Fitted BayesianMMM instance
- panelPanelDataset
Panel data used for fitting
- resultsMMMResults, optional
Fit results if available
- ci_probfloat
Credible interval probability (default 0.8)
- class mmm_framework.reporting.extractors.ExtendedMMMExtractor(model, panel=None, results=None, ci_prob=0.8)[source]¶
Bases:
DataExtractor,EstimandPPCMixinExtract data from mmm-framework’s extended MMM models.
Inherits shared utilities from DataExtractor for HDI computation, fit statistics, and MCMC diagnostics.
Supports NestedMMM (mediation pathways), MultivariateMMM (per-outcome fit, decomposition, and cross-effects), and CombinedMMM (both).
Parameters¶
- modelAny
Extended MMM model instance (NestedMMM, MultivariateMMM, or CombinedMMM)
- panelAny, optional
Accepted for interface parity with BayesianMMMExtractor (the extension models carry their own data arrays).
- resultsAny, optional
Fit results, if available.
- ci_probfloat
Credible interval probability (default 0.8)
- class mmm_framework.reporting.extractors.FactorAnalysisExtractor(model, ci_prob=0.94, **_)[source]¶
Bases:
DataExtractorExtract a latent-structure summary + estimands from a non-MMM garden model into an
MMMDataBundle(family-agnostic: CFA, LCA, …).
- class mmm_framework.reporting.extractors.PyMCMarketingExtractor(mmm, ci_prob=0.8)[source]¶
Bases:
DataExtractorExtract data from pymc-marketing’s MMM class.
Inherits shared utilities from DataExtractor for HDI computation, fit statistics, and MCMC diagnostics.
Provides compatibility with the standard pymc-marketing MMM.
Parameters¶
- mmmAny
PyMC-Marketing MMM instance
- ci_probfloat
Credible interval probability (default 0.8)
- mmm_framework.reporting.extractors.create_extractor(model, **kwargs)[source]¶
Factory function to create appropriate extractor for model type.
- Parameters:
model (
Any) – MMM model instance.**kwargs – Additional arguments passed to extractor.
- Return type:
- Returns:
Appropriate extractor for the model type.
Charts¶
Decomposition Charts¶
Decomposition chart functions for MMM reporting.
Contains waterfall, stacked area, and time series decomposition charts.
- mmm_framework.reporting.charts.decomposition.create_decomposition_chart(dates, components, config, chart_config=None, div_id='decompositionChart', chart_type='stacked_area')[source]¶
Create time series decomposition visualization.
- Return type:
Parameters¶
- datesarray-like
Time index
- componentsdict
Mapping of component name to time series values
- configReportConfig
Report configuration
- chart_configChartConfig, optional
Chart-specific configuration
- div_idstr
HTML div ID
- chart_typestr
Either “stacked_area” or “stacked_bar”
Returns¶
- str
HTML string with embedded Plotly chart
- mmm_framework.reporting.charts.decomposition.create_stacked_area_chart(dates, components, config, chart_config=None, div_id='stackedAreaChart')[source]¶
Convenience wrapper for stacked area decomposition chart.
- Return type:
- mmm_framework.reporting.charts.decomposition.create_waterfall_chart(categories, values, config, chart_config=None, div_id='waterfallChart', total_label='Total')[source]¶
Create waterfall chart for revenue decomposition.
- Return type:
Parameters¶
- categorieslist[str]
Component names (e.g., [“Baseline”, “TV”, “Search”, …])
- valuesndarray
Contribution values for each component
- configReportConfig
Report configuration
- chart_configChartConfig, optional
Chart-specific configuration
- div_idstr
HTML div ID
- total_labelstr
Label for the total bar
Returns¶
- str
HTML string with embedded Plotly chart
- mmm_framework.reporting.charts.decomposition.create_stacked_area_chart_with_geo_selector(dates, components_agg, components_by_geo=None, geo_names=None, config=None, chart_config=None, div_id='decompositionStackedArea')[source]¶
Create stacked area decomposition chart with geo selector dropdown.
- Return type:
Parameters¶
- datesarray-like
Time index for x-axis
- components_aggdict
Aggregated component time series: {component_name: ndarray}
- components_by_geodict, optional
Per-geo components: {geo_name: {component_name: ndarray}}
- geo_nameslist, optional
List of geography names
- configReportConfig
Report configuration
- chart_configChartConfig, optional
Chart-specific configuration
- div_idstr
HTML div ID for the chart
Returns¶
- str
HTML string with embedded Plotly chart and dropdown
- mmm_framework.reporting.charts.decomposition.create_waterfall_chart_with_geo_selector(component_totals_agg, component_totals_by_geo=None, geo_names=None, config=None, chart_config=None, div_id='decompositionWaterfall')[source]¶
Create waterfall chart for contribution breakdown with geo selector.
- Return type:
Parameters¶
- component_totals_aggdict
Aggregated component totals: {component_name: total_contribution}
- component_totals_by_geodict, optional
Per-geo totals: {geo_name: {component_name: total}}
- geo_nameslist, optional
List of geography names
- configReportConfig
Report configuration
- chart_configChartConfig, optional
Chart-specific configuration
- div_idstr
HTML div ID
Returns¶
- str
HTML string with embedded Plotly waterfall chart
Diagnostic Charts¶
Diagnostic chart functions for MMM reporting.
Contains saturation curves, adstock decay, prior/posterior comparison, trace plots, and sensitivity analysis charts.
- mmm_framework.reporting.charts.diagnostic.create_saturation_curves(channels, spend_ranges, response_curves, current_spend, config, chart_config=None, div_id='saturationCharts', ci_bands=None)[source]¶
Create saturation curve visualizations for each channel.
- Return type:
Parameters¶
- channelslist[str]
Channel names
- spend_rangesdict
Mapping of channel to spend value array for x-axis
- response_curvesdict
Mapping of channel to response curve values
- current_spenddict
Mapping of channel to current spend level
- configReportConfig
Report configuration
- chart_configChartConfig, optional
Chart-specific configuration
- div_idstr
HTML div ID
- ci_bandsdict, optional
Mapping of channel to (lower, upper) CI arrays
Returns¶
- str
HTML string with embedded Plotly charts in a grid
- mmm_framework.reporting.charts.diagnostic.create_adstock_chart(channels, lag_weights, config, chart_config=None, div_id='adstockChart')[source]¶
Create adstock/carryover decay visualization.
- Return type:
Parameters¶
- channelslist[str]
Channel names
- lag_weightsdict
Mapping of channel to decay weight arrays
- configReportConfig
Report configuration
- chart_configChartConfig, optional
Chart-specific configuration
- div_idstr
HTML div ID
Returns¶
- str
HTML string with embedded Plotly chart
- mmm_framework.reporting.charts.diagnostic.create_prior_posterior_chart(parameter_names, prior_samples, posterior_samples, config, chart_config=None, div_id='priorPosteriorChart')[source]¶
Create prior vs posterior comparison visualization.
- Return type:
Parameters¶
- parameter_nameslist[str]
Names of parameters to plot
- prior_samplesdict
Mapping of parameter name to prior samples
- posterior_samplesdict
Mapping of parameter name to posterior samples
- configReportConfig
Report configuration
- chart_configChartConfig, optional
Chart-specific configuration
- div_idstr
HTML div ID
Returns¶
- str
HTML string with embedded Plotly charts
- mmm_framework.reporting.charts.diagnostic.create_trace_plot(parameter_names, traces_data, config, chart_config=None, div_id='tracePlot', n_chains=4)[source]¶
Create MCMC trace plots for diagnostics.
- Return type:
Parameters¶
- parameter_nameslist[str]
Parameters to visualize
- traces_datadict
Mapping of parameter name to samples array (chains x draws)
- configReportConfig
Report configuration
- chart_configChartConfig, optional
Chart-specific configuration
- div_idstr
HTML div ID
- n_chainsint
Number of MCMC chains
Returns¶
- str
HTML string with embedded Plotly charts
- mmm_framework.reporting.charts.diagnostic.create_sensitivity_chart(scenarios, base_values, alternative_values, config, chart_config=None, div_id='sensitivityChart')[source]¶
Create sensitivity analysis comparison chart.
- Return type:
Parameters¶
- scenarioslist[str]
Names of sensitivity scenarios
- base_valuesndarray
Values from base model specification
- alternative_valuesdict
Mapping of scenario name to alternative values
- configReportConfig
Report configuration
- chart_configChartConfig, optional
Chart-specific configuration
- div_idstr
HTML div ID
Returns¶
- str
HTML string with embedded Plotly chart
Fit Charts¶
Model fit chart functions for MMM reporting.
Contains actual vs predicted visualizations with geo/product selectors.
- mmm_framework.reporting.charts.fit.create_model_fit_chart(dates, actual, predicted_mean, predicted_lower, predicted_upper, config, chart_config=None, div_id='modelFitChart')[source]¶
Create model fit visualization showing actual vs predicted with uncertainty.
- Return type:
Parameters¶
- datesarray-like
Time index for observations
- actualndarray
Observed KPI values
- predicted_meanndarray
Posterior mean predictions
- predicted_lowerndarray
Lower bound of credible interval
- predicted_upperndarray
Upper bound of credible interval
- configReportConfig
Report configuration
- chart_configChartConfig, optional
Chart-specific configuration
- div_idstr
HTML div ID for the chart
Returns¶
- str
HTML string with embedded Plotly chart
- mmm_framework.reporting.charts.fit.create_model_fit_chart_with_geo_selector(dates, actual_agg, predicted_agg, actual_by_geo=None, predicted_by_geo=None, geo_names=None, config=None, chart_config=None, div_id='modelFitChart')[source]¶
Create model fit visualization with geo selector dropdown.
- Return type:
Parameters¶
- datesarray-like
Time index for x-axis
- actual_aggndarray
Aggregated observed values (sum over all geos)
- predicted_aggdict
Aggregated predictions with keys “mean”, “lower”, “upper”
- actual_by_geodict, optional
Per-geo observed values: {geo_name: ndarray}
- predicted_by_geodict, optional
Per-geo predictions: {geo_name: {“mean”, “lower”, “upper”}}
- geo_nameslist, optional
List of geography names
- configReportConfig
Report configuration
- chart_configChartConfig, optional
Chart-specific configuration
- div_idstr
HTML div ID for the chart
Returns¶
- str
HTML string with embedded Plotly chart and dropdown
- mmm_framework.reporting.charts.fit.create_model_fit_chart_with_dimension_filter(dates, actual_agg, predicted_agg, actual_by_geo=None, predicted_by_geo=None, actual_by_product=None, predicted_by_product=None, geo_names=None, product_names=None, config=None, chart_config=None, div_id='modelFitChartFiltered')[source]¶
Create model fit visualization with multi-select dimension filters.
Supports filtering by geography and/or product with checkbox-based UI. Default view shows aggregated data; users can select multiple specific geos/products to compare.
- Return type:
Parameters¶
- datesarray-like
Time index for x-axis
- actual_aggndarray
Aggregated observed values (sum over all dimensions)
- predicted_aggdict
Aggregated predictions with keys “mean”, “lower”, “upper”
- actual_by_geodict, optional
Per-geo observed values: {geo_name: ndarray}
- predicted_by_geodict, optional
Per-geo predictions: {geo_name: {“mean”, “lower”, “upper”}}
- actual_by_productdict, optional
Per-product observed values: {product_name: ndarray}
- predicted_by_productdict, optional
Per-product predictions: {product_name: {“mean”, “lower”, “upper”}}
- geo_nameslist, optional
List of geography names
- product_nameslist, optional
List of product names
- configReportConfig
Report configuration
- chart_configChartConfig, optional
Chart-specific configuration
- div_idstr
HTML div ID for the chart
Returns¶
- str
HTML string with embedded Plotly chart and multi-select filters
- mmm_framework.reporting.charts.fit.create_fit_statistics_with_geo_selector(fit_stats_agg, fit_stats_by_geo=None, geo_names=None, config=None, div_id='fitStatsTable')[source]¶
Create fit statistics display with geo selector.
This uses JavaScript to show/hide table rows based on selection.
- Return type:
Parameters¶
- fit_stats_aggdict
Aggregated fit statistics: {“r2”, “rmse”, “mape”}
- fit_stats_by_geodict, optional
Per-geo stats: {geo_name: {“r2”, “rmse”, “mape”}}
- geo_nameslist, optional
Geography names
- configReportConfig
Report configuration
- div_idstr
HTML div ID
Returns¶
- str
HTML string with statistics table and selector
ROI Charts¶
ROI chart functions for MMM reporting.
Contains ROI forest plots and channel performance visualizations.
- mmm_framework.reporting.charts.roi.create_roi_forest_plot(channels, roi_mean, roi_lower, roi_upper, config, chart_config=None, div_id='roiForestPlot', reference_line=1.0)[source]¶
Create forest plot showing channel ROI with credible intervals.
- Return type:
Parameters¶
- channelslist[str]
Channel names
- roi_meanndarray
Posterior mean ROI for each channel
- roi_lowerndarray
Lower bound of credible interval
- roi_upperndarray
Upper bound of credible interval
- configReportConfig
Report configuration
- chart_configChartConfig, optional
Chart-specific configuration
- div_idstr
HTML div ID
- reference_linefloat
Value for vertical reference line (default 1.0 for break-even)
Returns¶
- str
HTML string with embedded Plotly chart
Helpers¶
ROI Helpers¶
ROI computation functions for MMM reporting.
Functions for computing ROI with uncertainty quantification from fitted models.
- mmm_framework.reporting.helpers.roi.compute_roi_with_uncertainty(model, spend_data=None, hdi_prob=0.94, n_samples=None)[source]¶
Compute ROI with full uncertainty quantification.
Computes average ROI (contribution / spend) for each channel with credible intervals derived from the posterior distribution.
- Return type:
Parameters¶
- modelBayesianMMM or ExtendedMMM
Fitted MMM model with trace
- spend_datadict or pd.Series, optional
Channel spend totals. If None, extracts from model’s panel data.
- hdi_probfloat
Probability mass for HDI (default 0.94)
- n_samplesint, optional
Number of posterior samples to use. If None, uses all.
Returns¶
- pd.DataFrame
DataFrame with ROI metrics per channel including: - spend: Total channel spend - contribution_mean/lower/upper: Revenue contribution with HDI - roi_mean/lower/upper: ROI with HDI - prob_positive: P(ROI > 0) - prob_profitable: P(ROI > 1)
Examples¶
>>> roi_df = compute_roi_with_uncertainty(mmm) >>> print(roi_df[['channel', 'roi_mean', 'roi_hdi_low', 'roi_hdi_high', 'prob_profitable']])
- mmm_framework.reporting.helpers.roi.compute_marginal_roi(model, channel, spend_level=None, delta=0.01, hdi_prob=0.94)[source]¶
Compute marginal ROI at a given spend level.
Marginal ROI is the derivative of the response curve with respect to spend, measuring the incremental return from the next dollar invested.
Parameters¶
- modelBayesianMMM
Fitted model
- channelstr
Channel name
- spend_levelfloat, optional
Spend level to evaluate. If None, uses current average spend.
- deltafloat
Relative change for numerical differentiation
- hdi_probfloat
HDI probability
Returns¶
- dict
Marginal ROI statistics including mean, HDI, and comparison to average ROI
Decomposition Helpers¶
Component decomposition functions for MMM reporting.
Functions for computing model component decomposition with uncertainty.
- mmm_framework.reporting.helpers.decomposition.compute_component_decomposition(model, include_time_series=True, hdi_prob=0.94)[source]¶
Compute full component decomposition of model predictions.
Breaks down total outcome into contributions from: - Baseline/intercept - Trend - Seasonality - Media channels (individually) - Control variables - Geographic/product effects (if applicable)
- Return type:
list[DecompositionResult]
Parameters¶
- modelBayesianMMM
Fitted model
- include_time_seriesbool
Whether to include time series arrays
- hdi_probfloat
HDI probability
Returns¶
- list[DecompositionResult]
Decomposition results by component
Examples¶
>>> decomp = compute_component_decomposition(mmm) >>> df = pd.DataFrame([d.to_dict() for d in decomp]) >>> print(df[['component', 'total_contribution', 'pct_of_total']])
- mmm_framework.reporting.helpers.decomposition.compute_decomposition_waterfall(decomp, start_label='Starting Value', end_label='Total Outcome')[source]¶
Format decomposition for waterfall chart visualization.
- Return type:
Parameters¶
- decomplist[DecompositionResult]
Decomposition results
- start_labelstr
Label for starting point
- end_labelstr
Label for ending total
Returns¶
- pd.DataFrame
DataFrame formatted for waterfall chart
Summary Helpers¶
Summary report generation functions for MMM reporting.
Functions for generating comprehensive model summaries with diagnostics.
- mmm_framework.reporting.helpers.summary.generate_model_summary(model, hdi_prob=0.94)[source]¶
Generate comprehensive model summary for reporting.
Aggregates key metrics into a single dictionary suitable for report generation or dashboard display.
Parameters¶
- modelBayesianMMM or ExtendedMMM
Fitted model
- hdi_probfloat
HDI probability
Returns¶
- dict
Summary containing: - model_info: Basic model metadata - diagnostics: MCMC convergence diagnostics - roi_summary: ROI by channel - decomposition: Component contributions - saturation_summary: Saturation levels - adstock_summary: Carryover effects