【问题标题】:How to create a min-max lineplot by month如何按月创建最小-最大线图
【发布时间】:2021-01-11 23:45:55
【问题描述】:

我有零售牛肉广告计数时间序列数据,我打算制作堆叠折线图,旨在显示在三周的平均基础上,上周杂货店每家商店发布的平均广告数量。为此,我设法汇总用于绘图的数据并尝试制作我想要的折线图。主要动机基于context of the problem and desired plot。在我的尝试中,我无法获得非常好的折线图,因为它无法提供丰富的信息来理解。我想知道如何在matplotlib 中实现这个目标。谁能建议我从我目前的尝试中应该怎么做?有什么想法吗?

可重现的数据和当前的尝试

这是我在当前尝试中使用的minimal reproducible data:

import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import seaborn as sns
from datetime import timedelta, datetime

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])

for item in df_grp['retail_item'].unique():
    dd = df_grp[df_grp['retail_item'] == item].groupby(['date', 'percentage'])[['number_of_ads']].sum().reset_index(level=[0,1])
    dd['weakly_change'] = dd[['percentage']].rolling(7).mean()
    fig, ax = plt.subplots(figsize=(8, 6), dpi=144)
    sns.lineplot(dd.index, 'weakly_change', data=dd, ax=ax)
    ax.set_xlim(dd.index.min(), dd.index.max())
    ax.xaxis.set_major_formatter(mdates.DateFormatter('%b %Y'))
plt.gcf().autofmt_xdate()
plt.style.use('ggplot')
plt.xticks(rotation=90)
plt.show()

当前结果

但我无法获得预期的正确折线图,我想从this site 重现该图。这样做是否可行?有什么想法吗?

想要的情节

这是我想从 minimal reproducible data 制作的所需情节示例:

我不知道应该如何改变我当前的尝试来获得我想要的情节。任何人都可以知道在matplotlib 中执行此操作的任何可能方式吗?我还应该做什么?任何可能的帮助将不胜感激。谢谢

【问题讨论】:

    标签: python pandas matplotlib seaborn


    【解决方案1】:
    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()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-26
      • 2017-09-08
      • 1970-01-01
      • 1970-01-01
      • 2014-06-14
      • 1970-01-01
      相关资源
      最近更新 更多