pythonmatplotlibtime-seriesweekend

How to highlight weekends in plots


For a simple time series:

import pandas as pd
df = pd.DataFrame({'dt':['2020-01-01', '2020-01-02', '2020-01-04', '2020-01-05', '2020-01-06'], 'foo':[1,2, 4,5,6]})
df['dt'] = pd.to_datetime(df.dt)
df['dt_label']= df['dt'].dt.strftime('%Y-%m-%d %a')
df = df.set_index('dt')
#display(df)
df['foo'].plot()
x =plt.xticks(ticks=df.reset_index().dt.values, labels=df.dt_label, rotation=90, horizontalalignment='right')

How can I highlight the x-axis labels for weekends?

edit

Pandas Plots: Separate color for weekends, pretty printing times on x axis

suggests:

def highlight_weekends(ax, timeseries):
    d = timeseries.dt
    ranges = timeseries[d.dayofweek >= 5].groupby(d.year * 100 + d.weekofyear).agg(['min', 'max'])
    for i, tmin, tmax in ranges.itertuples():
        ax.axvspan(tmin, tmax, facecolor='orange', edgecolor='none', alpha=0.1)

but applying it with

highlight_weekends(ax, df.reset_index().dt)

will not change the plot


Solution

  • I've extended your sample data a little so we can can make sure that we can highlight more than a single weekend instance.

    In this solution I create a column 'weekend', which is a column of bools indicating whether the corresponding date was at a weekend.

    We then loop over these values and make a call to ax.axvspan

    import pandas as pd
    import matplotlib.pyplot as plt
    
    # Add a couple of extra dates to sample data
    df = pd.DataFrame({'dt': ['2020-01-01',
                              '2020-01-02',
                              '2020-01-04',
                              '2020-01-05',
                              '2020-01-06',
                              '2020-01-07',
                              '2020-01-09',
                              '2020-01-10',
                              '2020-01-11',
                              '2020-01-12']})
    # Fill in corresponding observations
    df['foo'] = range(df.shape[0])
    
    df['dt'] = pd.to_datetime(df.dt)
    
    df['dt_label']= df['dt'].dt.strftime('%Y-%m-%d %a')
    
    df = df.set_index('dt')
    
    ax = df['foo'].plot()
    plt.xticks(ticks=df.reset_index().dt.values, 
               labels=df.dt_label,
               rotation=90,
               horizontalalignment='right')
    
    # Create an extra column which highlights whether or not a date occurs at the weekend
    df['weekend'] = df['dt_label'].apply(lambda x: x.endswith(('Sat', 'Sun')))
    
    # Loop over weekend pairs (Saturdays and Sundays), and highlight
    for i in range(df['weekend'].sum() // 2):
        ax.axvspan(df[df['weekend']].index[2*i],
                   df[df['weekend']].index[2*i+1],
                   alpha=0.5)
    

    enter image description here