如何在 matplotlib 中制作具有不同 y 轴的堆叠折线图?

时间:2021-05-07 15:54:43

标签: python pandas matplotlib seaborn

我想知道我应该如何制作在 matplotlib 中采用不同列的堆积折线图。关键是当我们进行聚合时,我需要在两个不同的列上进行数据聚合,我想我需要制作一个用于绘图的大数据框。我没有在 Pandas matplotlib 中找到更漂亮和方便的方法来做到这一点。任何人都可以建议可能的调整来做到这一点吗?有什么想法吗?

我的尝试

这是我需要做的第一个聚合:

import pandas as pd
import matplotlib.pyplot as plt

url = "https://gist.githubusercontent.com/adamFlyn/4657714653398e9269263a7c8ad4bb8a/raw/fa6709a0c41888503509e569ace63606d2e5c2ff/mydf.csv"
df = pd.read_csv(url, parse_dates=['date'])

df_re = df[df['retail_item'].str.contains("GROUND BEEF")]
df_rei = df_re.groupby(['date', 'retail_item']).agg({'number_of_ads': 'sum'})
df_rei = df_rei.reset_index(level=[0,1])
df_rei['week'] = pd.DatetimeIndex(df_rei['date']).week
df_rei['year'] = pd.DatetimeIndex(df_rei['date']).year
df_rei['week'] = df_rei['date'].dt.strftime('%W').astype('uint8')

df_ret_df1 = df_rei.groupby(['retail_item', 'week'])['number_of_ads'].agg([max, min, 'mean']).stack().reset_index(level=[2]).rename(columns={'level_2': 'mm', 0: 'vals'}).reset_index()

这是我需要做的第二个聚合,与第一个相似,除了我现在选择不同的列:

df_re['price_gap'] = df_re['high_price'] - df_re['low_price']
dff_rei1 = df_re.groupby(['date', 'retail_item']).agg({'price_gap': 'mean'})
dff_rei1 = dff_rei1.reset_index(level=[0,1])
dff_rei1['week'] = pd.DatetimeIndex(dff_rei1['date']).week
dff_rei1['year'] = pd.DatetimeIndex(dff_rei1['date']).year
dff_rei1['week'] = dff_rei1['date'].dt.strftime('%W').astype('uint8')

dff_ret_df2 = dff_rei1.groupby(['retail_item', 'week'])['price_gap'].agg([max, min, 'mean']).stack().reset_index(level=[2]).rename(columns={'level_2': 'mm', 0: 'vals'}).reset_index()

现在我正在努力如何将第一次、第二次聚合的输出组合到一个数据帧中以制作堆叠折线图。可以这样做吗?

目标

我想制作堆叠折线图,其中 y 轴采用不同的列,例如 y 轴应显示广告数量和价格范围,而 x 轴显示 52 周期间。这是我试图制作折线图的部分代码:

for g, d in df_ret_df1.groupby('retail_item'):
    fig, ax = plt.subplots(figsize=(7, 4), dpi=144)
    sns.lineplot(x='week', y='vals', hue='mm', data=d,alpha=.8)
    y1 = d[d.mm == 'max']
    y2 = d[d.mm == 'min']
    plt.fill_between(x=y1.week, y1=y1.vals, y2=y2.vals)
    
    for year in df['year'].unique():
        data = df_rei[(df_rei.date.dt.year == year) & (df_rei.retail_item == g)]
        sns.lineplot(x='week', y='price_gap', ci=None, data=data,label=year,alpha=.8)

有没有什么优雅的方法可以构建绘图数据,其中可以在熊猫中轻松完成不同列上的数据聚合?有没有其他方法可以做到这一点?有什么想法吗?

预期输出

这是我想要获得的所需输出: enter image description here

我应该如何制作绘图数据以获得这样的我想要的绘图?有什么想法吗?

1 个答案:

答案 0 :(得分:4)

Pandas groupby 功能非常通用,您可以显着减少代码行数以实现用于绘图的最终数据框。

static struct GUIVars
{
    float osc1Volume = 0.5, osc2Volume = 0.5;
    float lfoRate1 = 1, lfoRate2 = 1;
    float lfoAmount1 = 0, lfoAmount2 = 0;
    float aeAttack = 0.5, aeDecay = 0.5, aeSustain = 0.5, aeRelease = 0.5;
    float osc1Shift = 0, osc2Shift = 0;
    int osc1Shape = 0, osc2Shape = 0;
    int lfo1Shape = 0, lfo2Shape = 0;

    float* lfo1Target, *lfo2Target;
    float lfo1Initial, lfo2Initial;
} vars;

以正确的方式完成聚合后,使用 for 循环显示不同图中所需的每个度量。通过使用 pandas describe 特征实时计算最小值和最大值来绘制阴影范围:

plotdf = df_re.groupby([ 'retail_item',df_re['date'].dt.year,df_re['date'].dt.week]).agg({'number_of_ads':'sum','price_gap':'mean'}).unstack().T

enter image description here

使用更新的代码进行编辑:

f,axs = plt.subplots(2,1,figsize=(20,14))
axs=axs.ravel()

for i,x in enumerate(['number_of_ads','price_gap']):
    plotdf.loc[x].plot(rot=90,grid=True,ax=axs[i])
    plotdf.loc[x].T.describe().T[['min','max']].plot(kind='area',color=['w','grey'],alpha=0.3,ax=axs[i],title= x)