How to create a min-max lineplot by month

前端 未结 1 1582
梦毁少年i
梦毁少年i 2021-01-19 18:20

I have retail beef ad counts time series data, and I intend to make stacked line chart aim to show On a three-week average basis, quantity of average ads that grocers posted

相关标签:
1条回答
  • 2021-01-19 19:03
    • Also see How to create a min-max plot by month with fill_between?
    • See in-line comments for details
    import pandas as pd
    import matplotlib.pyplot as plt
    import seaborn as sns
    import calendar
    
    #################################################################
    # setup from question
    url = 'https://gist.githubusercontent.com/adamFlyn/96e68902d8f71ad62a4d3cda135507ad/raw/4761264cbd55c81cf003a4219fea6a24740d7ce9/df.csv'
    df = pd.read_csv(url, parse_dates=['date'])
    df.drop(columns=['Unnamed: 0'], inplace=True)
    df_grp = df.groupby(['date', 'retail_item']).agg({'number_of_ads': 'sum'})
    df_grp["percentage"] = df_grp.groupby(level=0).apply(lambda x:100 * x / float(x.sum()))
    df_grp = df_grp.reset_index(level=[0,1])
    #################################################################
    
    # create a month map from long to abbreviated calendar names
    month_map = dict(zip(calendar.month_name[1:], calendar.month_abbr[1:]))
    
    # update the month column name
    df_grp['month'] = df_grp.date.dt.month_name().map(month_map)
    
    # set month as categorical so they are plotted in the correct order
    df_grp.month = pd.Categorical(df_grp.month, categories=month_map.values(), ordered=True)
    
    # use groupby to aggregate min mean and max
    dfmm = df_grp.groupby(['retail_item', 'month'])['percentage'].agg([max, min, 'mean']).stack().reset_index(level=[2]).rename(columns={'level_2': 'mm', 0: 'vals'}).reset_index()
    
    # create a palette map for line colors
    cmap = {'min': 'k', 'max': 'k', 'mean': 'b'}
    
    # iterate through each retail item and plot the corresponding data
    for g, d in dfmm.groupby('retail_item'):
        plt.figure(figsize=(7, 4))
        sns.lineplot(x='month', y='vals', hue='mm', data=d, palette=cmap)
    
        # select only min or max data for fill_between
        y1 = d[d.mm == 'max']
        y2 = d[d.mm == 'min']
        plt.fill_between(x=y1.month, y1=y1.vals, y2=y2.vals, color='gainsboro')
        
        # add lines for specific years
        for year in [2016, 2018, 2020]:
            data = df_grp[(df_grp.date.dt.year == year) & (df_grp.retail_item == g)]
            sns.lineplot(x='month', y='percentage', ci=None, data=data, label=year)
        
        plt.ylim(0, 100)
        plt.margins(0, 0)
        plt.legend(bbox_to_anchor=(1., 1), loc='upper left')
        
        plt.ylabel('Percentage of Ads')
        plt.title(g)
        plt.show()
    

    0 讨论(0)
提交回复
热议问题