Search code examples
pythonpandasmatplotlibrolling-average

Plotting rolling average on top of a stacked bar chart in pandas


I am trying to plot how many daily events of each category happened, together with a 7 days rolling average of the total. Concretely my data has the shape:

date_range = pd.date_range(start='2023-01-01', periods=10)
data = {
    'Category A': np.random.randint(1, 10, 10),
    'Category B': np.random.randint(1, 10, 10),
}
df = pd.DataFrame(data, index=date_range)

adding the rolling average:

df['total'] = df.sum(axis=1)
df['rolling'] = df['total'].rolling(window=7).mean()

Then I thought I could simply do

ax = df[['Category A', 'Category B']].plot(kind='bar', stacked=True)
df['rolling'].plot(kind='line', ax=ax)

However, I can only see the second plot. Is there a way to add one on top of each other, without overwriting the first? alpha does not seem to help here.


Solution

  • The x-data for your barplot and line plot don't align. The bar plot has a categorical x-axis, and the bars are at positions 0, 1, 2, .... A quick way to see this is with get_xticks():

    ax = df[['Category A', 'Category B']].plot(kind='bar', stacked=True)
    ax.get_xticks()
    

    returns

    array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
    

    while

    df['rolling'].plot(kind='line', ax=ax)
    ax.get_xticks()
    

    returns

    array([19358, 19367], dtype=int64)
    

    The easy fix is to specify the x-values manually to align with the barplot:

    ax.plot(range(len(df)), df['rolling'])