Skip to content

plot_rolling_statistics

yohou.plotting.exploration.plot_rolling_statistics(df, *, columns=None, window_size=7, statistics='mean', show_original=True, groups=None, facet_by='member', facet_n_cols=2, color_palette=None, show_legend=True, title=None, x_label=None, y_label=None, width=None, height=None, connect_gaps=False, resampler=None, line_width=2.0, line_opacity=0.3, smooth_width=2.5, smooth_opacity=0.8)

Plot rolling window statistics (mean, std, min, max, median, quantiles).

Parameters

Name Type Description Default
df DataFrame

Input DataFrame with 'time' column and numeric columns to plot.

required
columns str | list[str] | None

Column(s) to compute statistics for. If None, uses all numeric columns except 'time'.

None
window_size int | dict[str, int]

Size of the rolling window. When a dict is provided, keys are column names and values are per-column window sizes.

7
statistics str | list[str]

Statistic(s) to compute. Options: "mean", "std", "min", "max", "median", "q25" (25th percentile), "q75" (75th percentile), "sum".

"mean"
show_original bool

Whether to show the original series alongside the statistics.

True
groups list[str] | None

Panel group prefixes to plot.

None
facet_by Literal['group', 'member'] | None

Faceting axis for panel data. "group" creates one subplot per group, "member" one per member. None disables faceting. Ignored for non-panel data.

"member"
facet_n_cols int

Number of columns in facet grid.

2
color_palette list[str] | None

Custom color palette. If None, uses yohou palette.

None
show_legend bool

Whether to show the legend.

True
title str | None

Plot title.

None
x_label str | None

X-axis label.

None
y_label str | None

Y-axis label.

None
width int | None

Plot width in pixels.

None
height int | None

Plot height in pixels.

None
connect_gaps bool

Whether to connect gaps in the data with lines.

False
resampler bool | Literal['widget'] | None

Enable plotly-resampler for large datasets. True or "widget" creates a FigureWidgetResampler; False or None uses a plain go.Figure.

None
line_width float

Width of the original series line in pixels.

2.0
line_opacity float

Opacity of the original series line.

0.3
smooth_width float

Width of the rolling statistic lines in pixels.

2.5
smooth_opacity float

Opacity of the rolling statistic lines.

0.8

Returns

Type Description
Figure

Plotly figure object.

Examples

>>> import polars as pl
>>> from yohou.plotting import plot_rolling_statistics
>>> # Create sample data
>>> df = pl.DataFrame({
...     "time": pl.date_range(pl.date(2020, 1, 1), pl.date(2020, 12, 31), "1mo", eager=True),
...     "y": [100, 120, 115, 130, 140, 135, 150, 160, 155, 170, 180, 175],
... })
>>> # Simple rolling mean
>>> fig = plot_rolling_statistics(df, window_size=3, statistics="mean")
>>> len(fig.data)
2
>>> # Rolling mean without original
>>> fig = plot_rolling_statistics(df, window_size=3, statistics="mean", show_original=False)
>>> len(fig.data)
1

See Also

plot_time_series : Plot basic time series.

Source Code

Show/Hide source
def plot_rolling_statistics(
    df: pl.DataFrame,
    *,
    columns: str | list[str] | None = None,
    window_size: int | dict[str, int] = 7,
    statistics: str | list[str] = "mean",
    show_original: bool = True,
    groups: list[str] | None = None,
    facet_by: Literal["group", "member"] | None = "member",
    facet_n_cols: int = 2,
    color_palette: list[str] | None = None,
    show_legend: bool = True,
    title: str | None = None,
    x_label: str | None = None,
    y_label: str | None = None,
    width: int | None = None,
    height: int | None = None,
    connect_gaps: bool = False,
    resampler: bool | Literal["widget"] | None = None,
    line_width: float = 2.0,
    line_opacity: float = 0.3,
    smooth_width: float = 2.5,
    smooth_opacity: float = 0.8,
) -> go.Figure:
    """
    Plot rolling window statistics (mean, std, min, max, median, quantiles).

    Parameters
    ----------
    df : pl.DataFrame
        Input DataFrame with 'time' column and numeric columns to plot.
    columns : str | list[str] | None, default=None
        Column(s) to compute statistics for. If None, uses all numeric columns except 'time'.
    window_size : int | dict[str, int], default=7
        Size of the rolling window. When a dict is provided, keys are column names
        and values are per-column window sizes.
    statistics : str | list[str], default="mean"
        Statistic(s) to compute. Options: "mean", "std", "min", "max", "median",
        "q25" (25th percentile), "q75" (75th percentile), "sum".
    show_original : bool, default=True
        Whether to show the original series alongside the statistics.
    groups : list[str] | None, default=None
        Panel group prefixes to plot.
    facet_by : Literal["group", "member"] | None, default="member"
        Faceting axis for panel data.  ``"group"`` creates one subplot per
        group, ``"member"`` one per member.  ``None`` disables faceting.
        Ignored for non-panel data.
    facet_n_cols : int, default=2
        Number of columns in facet grid.
    color_palette : list[str] | None, default=None
        Custom color palette. If None, uses yohou palette.
    show_legend : bool, default=True
        Whether to show the legend.
    title : str | None, default=None
        Plot title.
    x_label : str | None, default=None
        X-axis label.
    y_label : str | None, default=None
        Y-axis label.
    width : int | None, default=None
        Plot width in pixels.
    height : int | None, default=None
        Plot height in pixels.
    connect_gaps : bool, default=False
        Whether to connect gaps in the data with lines.
    resampler : bool | Literal["widget"] | None, default=None
        Enable plotly-resampler for large datasets.  ``True`` or
        ``"widget"`` creates a ``FigureWidgetResampler``; ``False`` or
        ``None`` uses a plain ``go.Figure``.
    line_width : float, default=2.0
        Width of the original series line in pixels.
    line_opacity : float, default=0.3
        Opacity of the original series line.
    smooth_width : float, default=2.5
        Width of the rolling statistic lines in pixels.
    smooth_opacity : float, default=0.8
        Opacity of the rolling statistic lines.

    Returns
    -------
    go.Figure
        Plotly figure object.

    Examples
    --------
    >>> import polars as pl
    >>> from yohou.plotting import plot_rolling_statistics

    >>> # Create sample data
    >>> df = pl.DataFrame({
    ...     "time": pl.date_range(pl.date(2020, 1, 1), pl.date(2020, 12, 31), "1mo", eager=True),
    ...     "y": [100, 120, 115, 130, 140, 135, 150, 160, 155, 170, 180, 175],
    ... })

    >>> # Simple rolling mean
    >>> fig = plot_rolling_statistics(df, window_size=3, statistics="mean")
    >>> len(fig.data)
    2

    >>> # Rolling mean without original
    >>> fig = plot_rolling_statistics(df, window_size=3, statistics="mean", show_original=False)
    >>> len(fig.data)
    1

    See Also
    --------
    [`plot_time_series`][yohou.plotting.plot_time_series] : Plot basic time series.
    """
    # Validate inputs
    validate_plotting_data(df, min_rows=2)
    validate_plotting_params(width=width, height=height)

    if groups is None and columns is None and _auto_detect_panel(df):
        groups = []

    if groups is not None:
        _color_mgr = PanelColorManager(color_palette)
        legend_tracker = LegendTracker(show_legend=show_legend)

        def _render_rolling(ctx: RenderContext) -> None:
            """Render rolling window statistics traces for a single column."""
            base = [c for c in ctx.sub_df.columns if c != "time"][0]
            _stats = [statistics] if isinstance(statistics, str) else list(statistics)
            ws = window_size.get(base, 7) if isinstance(window_size, dict) else window_size
            member_color = _color_mgr.get_color(ctx.display_name)
            if show_original:
                ctx.fig.add_trace(
                    go.Scatter(
                        x=ctx.sub_df["time"],
                        y=ctx.sub_df[base],
                        mode="lines",
                        name=ctx.display_name,
                        legendgroup=ctx.display_name,
                        line={"color": member_color, "width": line_width},
                        opacity=line_opacity,
                        showlegend=False,
                        connectgaps=connect_gaps,
                    ),
                    row=ctx.row,
                    col=ctx.col,
                )
            t = RollingStatisticsTransformer(window_size=ws, statistics=_stats)
            t.fit(ctx.sub_df)
            df_s = t.transform(ctx.sub_df)
            for si, stat in enumerate(_stats):
                scol = f"{base}_{stat}"
                legend_kw = grouped_legend_kwargs(
                    ctx.display_name,
                    stat,
                    legend_tracker,
                    is_first_in_group=si == 0,
                )
                ctx.fig.add_trace(
                    go.Scatter(
                        x=df_s["time"],
                        y=df_s[scol],
                        mode="lines",
                        line={
                            "color": member_color,
                            "width": smooth_width,
                            "dash": LINE_DASH_SEQUENCE[si % len(LINE_DASH_SEQUENCE)],
                        },
                        opacity=smooth_opacity,
                        connectgaps=connect_gaps,
                        **legend_kw,
                    ),
                    row=ctx.row,
                    col=ctx.col,
                )

        effective_facet_by = facet_by or "member"
        fig = facet_figure(
            df,
            _render_rolling,
            groups=groups,
            columns=columns,
            facet_by=effective_facet_by,
            facet_n_cols=facet_n_cols,
            title=title or "Rolling Statistics",
            x_label=x_label or "Time",
            y_label=y_label,
            width=width,
            height=height,
            resampler=resampler,
        )
        fig.update_layout(showlegend=show_legend)
        return fig

    # Non-panel case: column-mode facet_figure
    plot_columns = validate_plotting_data(df, columns=columns, exclude=["time"])
    if isinstance(statistics, str):
        statistics = [statistics]
    _colors = resolve_color_palette(color_palette, len(plot_columns))
    _col_colors = dict(zip(plot_columns, _colors, strict=False))

    def _render_rolling(ctx: RenderContext) -> None:
        """Render rolling statistics into a column-faceted subplot."""
        base = ctx.display_name
        col_color = _col_colors[base]
        if show_original:
            ctx.fig.add_trace(
                go.Scatter(
                    x=ctx.sub_df["time"],
                    y=ctx.sub_df[base],
                    mode="lines",
                    name=base,
                    line={"color": col_color, "width": line_width},
                    opacity=0.3,
                    hovertemplate=f"<b>{base}</b><br>%{{x}}<br>%{{y:.2f}}<extra></extra>",
                    connectgaps=connect_gaps,
                ),
                row=ctx.row,
                col=ctx.col,
            )
        ws = window_size.get(base, 7) if isinstance(window_size, dict) else window_size
        transformer = RollingStatisticsTransformer(window_size=ws, statistics=statistics)
        transformer.fit(ctx.sub_df)
        df_stats = transformer.transform(ctx.sub_df)
        for s_idx, stat in enumerate(statistics):
            stat_col = f"{base}_{stat}"
            s_dash = LINE_DASH_SEQUENCE[s_idx % len(LINE_DASH_SEQUENCE)] if len(statistics) > 1 else "solid"
            ctx.fig.add_trace(
                go.Scatter(
                    x=df_stats["time"],
                    y=df_stats[stat_col],
                    mode="lines",
                    name=stat,
                    line={"color": col_color, "width": smooth_width, "dash": s_dash},
                    opacity=smooth_opacity,
                    hovertemplate=f"<b>{stat}</b><br>%{{x}}<br>%{{y:.2f}}<extra></extra>",
                    connectgaps=connect_gaps,
                ),
                row=ctx.row,
                col=ctx.col,
            )

    fig = facet_figure(
        df,
        _render_rolling,
        columns=plot_columns,
        facet_n_cols=facet_n_cols,
        title=title or "Rolling Statistics",
        x_label=x_label or "Time",
        y_label=y_label,
        width=width,
        height=height,
        resampler=resampler,
    )
    fig.update_layout(showlegend=show_legend)

    return fig

Tutorials

The following example notebooks use this component:

  • How to Apply Window Transformations


    Data-Features

    Feature engineering with LagTransformer, RollingStatisticsTransformer, SlidingWindowFunctionTransformer, and ExponentialMovingAverage on time series data.

    View · Open in marimo

  • Exploratory Visualization


    Visualization

    Exploratory time series visualisation with raw series plots, rolling statistics overlays, seasonal overlays, subseries diagnostics, distribution boxplots, missing data pattern auditing, outlier detection, and resampling comparison.

    View · Open in marimo