mgplot.fill_between_plot

Plot a filled region between two bounds.

  1"""Plot a filled region between two bounds."""
  2
  3from typing import Final, NotRequired, Unpack
  4
  5from matplotlib.axes import Axes
  6from pandas import DataFrame
  7
  8from mgplot.axis_utils import map_periodindex, set_labels
  9from mgplot.keyword_checking import BaseKwargs, report_kwargs, validate_kwargs
 10from mgplot.settings import get_setting
 11from mgplot.utilities import check_clean_timeseries, constrain_data, get_axes
 12
 13# --- constants
 14ME: Final[str] = "fill_between_plot"
 15REQUIRED_COLUMNS: Final[int] = 2
 16DEFAULT_COLOR: Final[str] = "steelblue"
 17DEFAULT_ALPHA: Final[float] = 0.3
 18
 19
 20class FillBetweenKwargs(BaseKwargs):
 21    """Keyword arguments for the fill_between_plot function."""
 22
 23    ax: NotRequired[Axes | None]
 24    color: NotRequired[str]
 25    alpha: NotRequired[float]
 26    label: NotRequired[str | None]
 27    linewidth: NotRequired[float]
 28    edgecolor: NotRequired[str | None]
 29    plot_from: NotRequired[int | None]
 30    max_ticks: NotRequired[int]
 31
 32
 33def fill_between_plot(data: DataFrame, **kwargs: Unpack[FillBetweenKwargs]) -> Axes:
 34    """Plot a filled region between lower and upper bounds.
 35
 36    Args:
 37        data: DataFrame - A two-column DataFrame with PeriodIndex.
 38              The first column is the lower bound, the second is the upper bound.
 39        kwargs: FillBetweenKwargs - keyword arguments for the plot.
 40
 41    Returns:
 42        Axes - matplotlib Axes object.
 43
 44    Raises:
 45        TypeError: If data is not a DataFrame.
 46        ValueError: If data does not have exactly two columns.
 47
 48    """
 49    # --- validate inputs
 50    report_kwargs(caller=ME, **kwargs)
 51    validate_kwargs(schema=FillBetweenKwargs, caller=ME, **kwargs)
 52
 53    if not isinstance(data, DataFrame):
 54        raise TypeError(f"data must be a DataFrame for {ME}()")
 55
 56    if len(data.columns) != REQUIRED_COLUMNS:
 57        raise ValueError(f"data must have exactly two columns for {ME}(), got {len(data.columns)}")
 58
 59    # --- check and constrain data
 60    data = check_clean_timeseries(data, ME)
 61    data, kwargs_d = constrain_data(data, **kwargs)
 62
 63    # --- handle PeriodIndex conversion
 64    saved_pi = map_periodindex(data)
 65    if saved_pi is not None:
 66        data = saved_pi[0]
 67
 68    # --- get axes
 69    axes, kwargs_d = get_axes(**kwargs_d)
 70
 71    if data.empty or data.isna().all().all():
 72        print(f"Warning: No data to plot in {ME}().")
 73        return axes
 74
 75    # --- extract bounds
 76    lower = data.iloc[:, 0]
 77    upper = data.iloc[:, 1]
 78
 79    # --- extract plot arguments
 80    color = kwargs_d.get("color", DEFAULT_COLOR)
 81    alpha = kwargs_d.get("alpha", DEFAULT_ALPHA)
 82    label = kwargs_d.get("label", None)
 83    linewidth = kwargs_d.get("linewidth", 0)
 84    edgecolor = kwargs_d.get("edgecolor", None)
 85
 86    # --- plot
 87    axes.fill_between(
 88        data.index,
 89        lower,
 90        upper,
 91        color=color,
 92        alpha=alpha,
 93        label=label,
 94        linewidth=linewidth,
 95        edgecolor=edgecolor,
 96    )
 97
 98    # --- set axis labels
 99    if saved_pi is not None:
100        set_labels(axes, saved_pi[1], kwargs_d.get("max_ticks", get_setting("max_ticks")))
101
102    return axes
ME: Final[str] = 'fill_between_plot'
REQUIRED_COLUMNS: Final[int] = 2
DEFAULT_COLOR: Final[str] = 'steelblue'
DEFAULT_ALPHA: Final[float] = 0.3
class FillBetweenKwargs(mgplot.keyword_checking.BaseKwargs):
21class FillBetweenKwargs(BaseKwargs):
22    """Keyword arguments for the fill_between_plot function."""
23
24    ax: NotRequired[Axes | None]
25    color: NotRequired[str]
26    alpha: NotRequired[float]
27    label: NotRequired[str | None]
28    linewidth: NotRequired[float]
29    edgecolor: NotRequired[str | None]
30    plot_from: NotRequired[int | None]
31    max_ticks: NotRequired[int]

Keyword arguments for the fill_between_plot function.

ax: NotRequired[matplotlib.axes._axes.Axes | None]
color: NotRequired[str]
alpha: NotRequired[float]
label: NotRequired[str | None]
linewidth: NotRequired[float]
edgecolor: NotRequired[str | None]
plot_from: NotRequired[int | None]
max_ticks: NotRequired[int]
def fill_between_plot( data: pandas.core.frame.DataFrame, **kwargs: Unpack[FillBetweenKwargs]) -> matplotlib.axes._axes.Axes:
 34def fill_between_plot(data: DataFrame, **kwargs: Unpack[FillBetweenKwargs]) -> Axes:
 35    """Plot a filled region between lower and upper bounds.
 36
 37    Args:
 38        data: DataFrame - A two-column DataFrame with PeriodIndex.
 39              The first column is the lower bound, the second is the upper bound.
 40        kwargs: FillBetweenKwargs - keyword arguments for the plot.
 41
 42    Returns:
 43        Axes - matplotlib Axes object.
 44
 45    Raises:
 46        TypeError: If data is not a DataFrame.
 47        ValueError: If data does not have exactly two columns.
 48
 49    """
 50    # --- validate inputs
 51    report_kwargs(caller=ME, **kwargs)
 52    validate_kwargs(schema=FillBetweenKwargs, caller=ME, **kwargs)
 53
 54    if not isinstance(data, DataFrame):
 55        raise TypeError(f"data must be a DataFrame for {ME}()")
 56
 57    if len(data.columns) != REQUIRED_COLUMNS:
 58        raise ValueError(f"data must have exactly two columns for {ME}(), got {len(data.columns)}")
 59
 60    # --- check and constrain data
 61    data = check_clean_timeseries(data, ME)
 62    data, kwargs_d = constrain_data(data, **kwargs)
 63
 64    # --- handle PeriodIndex conversion
 65    saved_pi = map_periodindex(data)
 66    if saved_pi is not None:
 67        data = saved_pi[0]
 68
 69    # --- get axes
 70    axes, kwargs_d = get_axes(**kwargs_d)
 71
 72    if data.empty or data.isna().all().all():
 73        print(f"Warning: No data to plot in {ME}().")
 74        return axes
 75
 76    # --- extract bounds
 77    lower = data.iloc[:, 0]
 78    upper = data.iloc[:, 1]
 79
 80    # --- extract plot arguments
 81    color = kwargs_d.get("color", DEFAULT_COLOR)
 82    alpha = kwargs_d.get("alpha", DEFAULT_ALPHA)
 83    label = kwargs_d.get("label", None)
 84    linewidth = kwargs_d.get("linewidth", 0)
 85    edgecolor = kwargs_d.get("edgecolor", None)
 86
 87    # --- plot
 88    axes.fill_between(
 89        data.index,
 90        lower,
 91        upper,
 92        color=color,
 93        alpha=alpha,
 94        label=label,
 95        linewidth=linewidth,
 96        edgecolor=edgecolor,
 97    )
 98
 99    # --- set axis labels
100    if saved_pi is not None:
101        set_labels(axes, saved_pi[1], kwargs_d.get("max_ticks", get_setting("max_ticks")))
102
103    return axes

Plot a filled region between lower and upper bounds.

Args: data: DataFrame - A two-column DataFrame with PeriodIndex. The first column is the lower bound, the second is the upper bound. kwargs: FillBetweenKwargs - keyword arguments for the plot.

Returns: Axes - matplotlib Axes object.

Raises: TypeError: If data is not a DataFrame. ValueError: If data does not have exactly two columns.