# Abacus Core Mixins: Plotting Scenario (`plotting_scenario.py`) This module provides the `ScenarioPlottingMixin` class, designed to be inherited by Marketing Mix Model (MMM) classes in Abacus. It offers methods for visualising the results of budget optimisation scenarios and plotting the direct response curves for marketing channels based on the fitted model. ::: abacus.core.mixins.plotting_scenario ## `ScenarioPlottingMixin` Class This mixin assumes the inheriting class provides attributes and methods like: - `X`: The original input DataFrame used for training. - `channel_columns`: List of channel names. - `compute_channel_contribution_original_scale()`: A method (likely from `ContributionMixin`) that returns channel contributions in the original target scale. - `_estimate_budget_contribution_fit()`: A method (likely from `OptimizationMixin`) to estimate contribution bounds for a given budget. ### Methods #### `plot_budget_scenarios` ```python def plot_budget_scenarios( self, *, base_data: Dict, method: str = "sigmoid", **kwargs: Any ) -> plt.Figure: ``` **(Experimental)** Plots side-by-side bar charts comparing budget allocation and resulting contribution across different scenarios. This visualisation helps compare the initial budget/contribution (`base_data`) with one or more alternative scenarios (`scenarios_data` passed via `kwargs`). For the contribution plot, it also shows estimated 90% credible intervals based on fitting a specified saturation curve (`method`) to the posterior contribution quantiles. **Parameters:** - `base_data` (`dict`, keyword-only): **Required.** A dictionary representing the baseline scenario. It must contain two keys: - `'budget'`: A dictionary mapping channel names to their budget values in this scenario. - `'contribution'`: A dictionary mapping channel names to their corresponding contribution values in this scenario. *(Both inner dictionaries can optionally include a 'total' key, which is ignored in the plot.)* - `method` (`str`, optional): The saturation function type (`"sigmoid"` or `"michaelis-menten"`) used to estimate the contribution bounds (passed to internal `_estimate_budget_contribution_fit`). Defaults to `"sigmoid"`. - `**kwargs`: Additional keyword arguments. Currently accepts: - `scenarios_data` (`List[Dict]`, optional): A list of dictionaries, each structured like `base_data`, representing alternative scenarios to plot alongside the base scenario. **Returns:** - `plt.Figure`: The matplotlib Figure object containing two subplots (one for budget, one for contribution). **Notes:** - This method is marked as experimental. - It relies on the `_estimate_budget_contribution_fit` method (likely inherited from `OptimizationMixin`) to calculate the contribution bounds shown in the second plot. - Helper function `ut.standardize_scenarios_dict_keys` is used internally to ensure input dictionaries have the expected keys. --- #### `plot_direct_contribution_curves` ```python def plot_direct_contribution_curves( self, show_fit: bool = False, xlim_max: Optional[Union[int, float]] = None, method: str = "sigmoid", channels: Optional[List[str]] = None, same_axes: bool = False, ) -> plt.Figure: ``` Plots the relationship between historical channel spend and the resulting mean posterior contribution (direct response curve). Optionally overlays a fitted saturation curve. This plot shows a scatter of actual spend points versus their corresponding mean contribution from the model fit. The term "direct" signifies that it plots immediate contribution against spend, without explicitly visualising the lagged effects captured by adstock transformations within the model. If `show_fit` is True, it estimates parameters for a chosen saturation function (`method`) based on this relationship and plots the resulting curve, along with its inflection point. **Parameters:** - `show_fit` (`bool`, optional): If `True`, estimates and plots a saturation curve fit (Sigmoid or Michaelis-Menten) over the scatter plot. Defaults to `False`. - `xlim_max` (`int | float`, optional): Sets the maximum limit for the x-axis (spend). If `None` (default), the limit is determined by the maximum observed spend for the channel(s) being plotted. - `method` (`str`, optional): The saturation function type (`"sigmoid"` or `"michaelis-menten"`) to use if `show_fit` is `True`. Defaults to `"sigmoid"`. - `channels` (`List[str]`, optional): A list of specific channel names to plot. If `None` (default), plots curves for all channels defined in `self.channel_columns`. - `same_axes` (`bool`, optional): If `True`, plots all selected channel curves on a single subplot. If `False` (default), creates a separate subplot for each channel. **Returns:** - `plt.Figure`: The matplotlib Figure object containing the plot(s). **Raises:** - `ValueError`: If any channel specified in `channels` is not found in `self.channel_columns`, or if `channels` contains duplicates. If `method` is invalid when `show_fit` is `True`. - `RuntimeError`: If the model hasn't been fitted with `X` data yet. --- *(Private helper methods `_plot_scenario` and `_plot_response_curve_fit` are used internally to handle the plotting logic for individual scenarios/bars and the fitted response curves, respectively.)*