Skip to content

Time Plot

Timeline plots of a value column resampled and aggregated by period from raw transactional data.

Aggregation happens here (line.plot does not aggregate), over the configured transaction-date column (column.transaction_date). Use this module for an actual datetime x-axis; use plots.line for relative or sequential x-values.

plot(df, value_col, period='D', agg_func='sum', group_col=None, title=None, eyebrow=None, subtitle=None, x_label=None, y_label=None, legend_title=None, ax=None, source_text=None, move_legend_outside=False, legend_style=None, **kwargs)

Plot value_col over time, aggregated by period.

df must contain the configured transaction-date column (column.transaction_date) as a datetime column. value_col is aggregated here with agg_func per period; line.plot does not aggregate. With group_col the result is one line per group value with a legend; without it, a single line with no legend.

Parameters:

Name Type Description Default
df DataFrame

The dataframe to plot.

required
value_col str

The column to plot.

required
period str | BaseOffset

The period to group the data by (e.g., "D", "W", "M", "Q", "Y", or a pandas BaseOffset).

'D'
agg_func str

The aggregation function to apply to value_col.

'sum'
group_col str

The column to group the data by.

None
title str

The title of the plot.

None
eyebrow str

Small uppercase label rendered above the title.

None
subtitle str

Supporting copy rendered below the title.

None
x_label str

X-axis label; omitted means no label.

None
y_label str

Y-axis label; omitted means no label.

None
legend_title str

The title of the legend.

None
ax Axes

The matplotlib axes object to plot on.

None
source_text str

The source text to add to the plot.

None
move_legend_outside bool

Whether to move the legend outside the plot.

False
legend_style Literal['box', 'end_of_line']

How series are labelled. "box" (default when None) renders the standard legend; "end_of_line" suppresses the legend and places a colored series label at the right end of each line; it is a no-op without group_col. With group_col and "end_of_line", move_legend_outside and legend_title are ignored and a UserWarning is emitted if either is supplied.

None
**kwargs Any

Additional keyword arguments for pandas' plot function. linewidth defaults to 3 and color to the primary color, or the palette with group_col.

{}

Returns:

Name Type Description
SubplotBase SubplotBase

The matplotlib axes object.

Raises:

Type Description
ValueError

If legend_style is not one of None, "box", or "end_of_line".

Source code in openretailscience/plots/time.py
def plot(
    df: pd.DataFrame,
    value_col: str,
    period: str | BaseOffset = "D",
    agg_func: str = "sum",
    group_col: str | None = None,
    title: str | None = None,
    eyebrow: str | None = None,
    subtitle: str | None = None,
    x_label: str | None = None,
    y_label: str | None = None,
    legend_title: str | None = None,
    ax: Axes | None = None,
    source_text: str | None = None,
    move_legend_outside: bool = False,
    legend_style: Literal["box", "end_of_line"] | None = None,
    **kwargs: Any,  # noqa: ANN401
) -> SubplotBase:
    """Plot ``value_col`` over time, aggregated by ``period``.

    ``df`` must contain the configured transaction-date column (``column.transaction_date``) as a
    datetime column. ``value_col`` is aggregated here with ``agg_func`` per ``period``; ``line.plot``
    does not aggregate. With ``group_col`` the result is one line per group value with a legend;
    without it, a single line with no legend.

    Args:
        df (pd.DataFrame): The dataframe to plot.
        value_col (str): The column to plot.
        period (str | BaseOffset): The period to group the data by (e.g., "D", "W", "M", "Q", "Y",
            or a pandas ``BaseOffset``).
        agg_func (str, optional): The aggregation function to apply to ``value_col``.
        group_col (str, optional): The column to group the data by.
        title (str, optional): The title of the plot.
        eyebrow (str, optional): Small uppercase label rendered above the title.
        subtitle (str, optional): Supporting copy rendered below the title.
        x_label (str, optional): X-axis label; omitted means no label.
        y_label (str, optional): Y-axis label; omitted means no label.
        legend_title (str, optional): The title of the legend.
        ax (Axes, optional): The matplotlib axes object to plot on.
        source_text (str, optional): The source text to add to the plot.
        move_legend_outside (bool, optional): Whether to move the legend outside the plot.
        legend_style (Literal["box", "end_of_line"], optional): How series are labelled. ``"box"``
            (default when None) renders the standard legend; ``"end_of_line"`` suppresses the
            legend and places a colored series label at the right end of each line; it is a no-op
            without ``group_col``. With ``group_col`` and ``"end_of_line"``, ``move_legend_outside``
            and ``legend_title`` are ignored and a UserWarning is emitted if either is supplied.
        **kwargs: Additional keyword arguments for pandas' ``plot`` function. ``linewidth`` defaults
            to 3 and ``color`` to the primary color, or the palette with ``group_col``.

    Returns:
        SubplotBase: The matplotlib axes object.

    Raises:
        ValueError: If legend_style is not one of ``None``, ``"box"``, or ``"end_of_line"``.
    """
    if legend_style not in (None, "box", "end_of_line"):
        msg = f"legend_style must be one of (None, 'box', 'end_of_line'); got {legend_style!r}"
        raise ValueError(msg)

    periods = df[get_option("column.transaction_date")].dt.to_period(period).rename("transaction_period")

    if group_col is None:
        default_colors = get_named_color("primary")
        df = df.groupby(periods)[value_col].agg(agg_func)
        show_legend = False
    else:
        df = (
            df.groupby([group_col, periods])[value_col]
            .agg(agg_func)
            .reset_index()
            .pivot(index="transaction_period", columns=group_col, values=value_col)
        )
        default_colors = get_plot_colors(df.shape[1])
        show_legend = True

    linewidth = kwargs.pop("linewidth", 3)
    color = kwargs.pop("color", default_colors)
    ax = df.plot(
        linewidth=linewidth,
        color=color,
        legend=show_legend,
        ax=ax,
        **kwargs,
    )

    return standard_graph_styles(
        ax,
        title=title,
        eyebrow=eyebrow,
        subtitle=subtitle,
        x_label=x_label,
        y_label=y_label,
        legend_title=legend_title,
        move_legend_outside=move_legend_outside,
        show_legend=show_legend,
        legend_style=legend_style,
        source_text=source_text,
        grid_axis="y",
        x_margin=0,
    )