pythonpandasmatplotlibpandas-datareader

Shading between two lines


I want to use axvspan() function to visualize a DataFrame that I obtained using Pandas DataReader.But when I use the the following codes, I saw an error and there is no shading in subplots. What should I do? Thank you.

import matplotlib.pyplot as plt
import pandas_datareader.data as pdr
import pandas as pd
import datetime
start = datetime.datetime (2000,1,1)
end = datetime.datetime (2021,5,1)
df  = pdr.DataReader(['WFRBSB50215', 'WFRBST01134','WFRBST01122', 'WFRBSN09139', 'WFRBSB50189', 'WFRBST01110','WFRBSB50191'],'fred',start, end)
df.columns = ['Share of Total Net Worth Held by the Bottom 50% (1st to 50th Wealth Percentiles)',
              'Share of Total Net Worth Held by the Top 1% (99th to 100th Wealth Percentiles)', 
              'Share of Corporate Equities and Mutual Fund Shares Helb By Top1%(99th to 100th Wealth Percentiles)', 
              'Share of Financial Assets Held by the 90th to 99th Wealth Percentiles',
              'Share of Total Assets Held by the Bottom 50% (1st to 50th Wealth Percentiles)',
              'Share of Real Estate Held by the Top 1% (99th to 100th Wealth Percentiles)',
              'Share of Real Estate Held by the Bottom %50(1st to 50th Wealth Percentiles)'
              ]
ax = df.plot(subplots=True, layout=(7,1), figsize=(15,15), linewidth=3.5, colormap="summer")
ax.axvspan('2007-1-12', '2009-6-1', color='c', alpha=0.5)
ax.axvspan('2019-12-1', '2020-2-1',color= 'orange', alpha=0.5)
plt.xlabel('Date')
ax[0,].set_title('Share of Total Net Worth Held by the Bottom 50%')
ax[0,].set_ylabel('Percent of Aggregate')
ax[1,].set_title('Share of Total Net Worth Held by the Top 1%')
ax[1,].set_ylabel('Percent of Aggregate')
ax[2,].set_title('Share of Corporate Equities and Mutual Fund Shares Helb By Top 1%')
ax[2,].set_ylabel('Percent of Aggregate')
ax[3,].set_title('Share of Financial Assets Held by the 90th to 99th Wealth Percentiles')
ax[3,].set_ylabel('Percent of Aggregate')
ax[4,].set_title('Share of Total Assets Held by the Bottom 50% ')
ax[4,].set_ylabel('Percent of Aggregate')
ax[5,].set_title('Share of Real Estate Held by the Top 1%')
ax[5,].set_ylabel('Percent of Aggregate')
ax[6,].set_title('Share of Real Estate Held by the Bottom %50')
ax[6,].set_ylabel('Percent of Aggregate')
plt.tight_layout()
plt.style.use('seaborn-white')
plt.show()

Solution

  • Try looping over all Subplots and adding axvspan to the specific AxesSubplot instead:

    axes = df.plot(subplots=True, layout=(7, 1), figsize=(15, 15), linewidth=3.5,
                   colormap="summer", ylabel='Percent of Aggregate', xlabel='Date')
    
    for (ax,), col in zip(axes, df.columns):
        ax.axvspan('2007-1-12', '2009-6-1', color='c', alpha=0.5)
        ax.axvspan('2019-12-1', '2020-2-1', color='orange', alpha=0.5)
        ax.set_title(col)
    
    plt.tight_layout()
    plt.style.use('seaborn-white')
    plt.show()
    

    Some slight code reduction using the ylabel and xlabel kwargs of plot and also setting subplot titles from df.columns instead of manually.

    plot


    Adding legend for axvspan. The simplest approach is to add a label to each axvspan and make the legend at the end of each iteration:

    axes = df.plot(subplots=True, layout=(7, 1), figsize=(15, 15), linewidth=3.5,
                   colormap="summer", ylabel='Percent of Aggregate', xlabel='Date',
                   legend=False)
    
    for (ax,), col in zip(axes, df.columns):
        ax.axvspan('2007-1-12', '2009-6-1', color='c', alpha=0.5,
                   label='2008 Crisis')
        ax.axvspan('2019-12-1', '2020-2-1', color='orange', alpha=0.5,
                   label='Pandemic')
        ax.set_title(col)
        ax.legend()
    
    plt.style.use('seaborn-white')
    plt.tight_layout()
    plt.show()
    

    plot 2 with axvspan legend on all subplots


    Alternatively a single legend can be made for just the Crises:

    fig, axes = plt.subplots(nrows=7, figsize=(15, 15))
    df.plot(subplots=True, ax=axes, linewidth=3.5,
            colormap="summer", ylabel='Percent of Aggregate', xlabel='Date')
    
    for ax, col in zip(axes, df.columns):
        ax.axvspan('2007-1-12', '2009-6-1', color='c', alpha=0.5,
                   label='2008 Crisis')
        ax.axvspan('2019-12-1', '2020-2-1', color='orange', alpha=0.5,
                   label='Pandemic')
        ax.set_title(col)
    
    handles, labels = axes[-1].get_legend_handles_labels()
    
    fig.legend(handles[-2:], labels[-2:], title='Crises',
               loc='lower left', ncol=2)
    
    plt.style.use('seaborn-white')
    plt.tight_layout()
    plt.show()
    

    plot 3 single legend for Crises

    ^ Single legend is here in the lower left.