【问题标题】:Plotting stacked bars with a total line and dates on xlabels在 xlabels 上绘制带有总行和日期的堆叠条形图
【发布时间】:2019-09-25 11:15:56
【问题描述】:

我正在使用 pandas 图生成一个堆积条形图,它与 matplotlib 的行为不同,但日期总是以错误的格式出现,我无法更改它。 我还想在图表上画一条“总计”线。但是当我尝试添加它时,之前的条形被删除了。 我想制作如下图(由 excel 生成)。黑线是条形的总和。

我在网上查看了一些解决方案,但它们只在条形不多的情况下看起来不错,因此您可以在标签之间留出一些空间。

这是我能做的最好的,下面是我使用的代码。

import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.ticker as plticker

# DATA (not the full series from the chart)
dates = ['2016-10-31', '2016-11-30', '2016-12-31', '2017-01-31', '2017-02-28', '2017-03-31',
         '2017-04-30', '2017-05-31', '2017-06-30', '2017-07-31', '2017-08-31', '2017-09-30',
         '2017-10-31', '2017-11-30', '2017-12-31', '2018-01-31', '2018-02-28', '2018-03-31',
         '2018-04-30', '2018-05-31', '2018-06-30', '2018-07-31', '2018-08-31', '2018-09-30',
         '2018-10-31', '2018-11-30', '2018-12-31', '2019-01-31', '2019-02-28', '2019-03-31']

variables = {'quantum ex sa': [6.878011, 6.557054, 3.229360, 3.739318, 1.006442, -0.117945,
                               -1.854614, -2.882032, -1.305225, 0.280100, 0.524068, 1.847649,
                               5.315940, 4.746596, 6.650303, 6.809901, 8.135243, 8.127328,
                               9.202209, 8.146417, 6.600906, 6.231881, 5.265775, 3.971435,
                               2.896829, 4.307549, 4.695687, 4.696656, 3.747793, 3.366878],
             'price ex sa': [-11.618681, -9.062433, -6.228452, -2.944336, 0.513788, 4.068517,
                             6.973203, 8.667524, 10.091766, 10.927501, 11.124805, 11.368854,
                             11.582204, 10.818471, 10.132152, 8.638781, 6.984159, 5.161404,
                             3.944813, 3.723371, 3.808564, 4.576303, 5.170760, 5.237303,
                             5.121998, 5.502981, 5.159970, 4.772495, 4.140812, 3.568077]}

df = pd.DataFrame(index=pd.to_datetime(dates), data=variables)

# PLOTTING
ax = df.plot(kind='bar', stacked=True, width=1)
# df['Total'] = df.sum(axis=1)
# df['Total'].plot(ax=ax)
ax.axhline(0, linewidth=1)
ax.yaxis.set_major_formatter(plticker.PercentFormatter())

plt.tight_layout()
plt.show()

编辑

这是最适合我的。这比使用 pandas df.plot(kind='bar', stacked=True) 效果更好,因为它可以更好地格式化 x 轴上的日期标签,并且还可以为条形图提供任意数量的系列。

    for count, col in enumerate(df.columns):
        old = df.iloc[:, :count].sum(axis=1)
        bottom_series = ((old >= 0) == (df[col] >= 0)) * old

        ax.bar(df.index, df[col], label=col, bottom=bottom_series, width=31)

    df['Total'] = df.sum(axis=1)
    ax.plot(df.index, df['Total'], color='black', label='Total')

【问题讨论】:

    标签: python pandas matplotlib


    【解决方案1】:

    这是你想要的吗:

    fig, ax = plt.subplots(1,1, figsize=(16,9))
    # PLOTTING
    ax.bar(df.index, df['price ex sa'], bottom=df['quantum ex sa'],width=31, label='price ex sa')
    ax.bar(df.index, df['quantum ex sa'], width=31, label='quantum ex sa')
    
    total = df.sum(axis=1)
    ax.plot(total.index, total, color='r', linewidth=3, label='total')
    
    ax.legend()
    plt.show()
    

    编辑:使用日期时间进行绘图似乎存在错误(功能)。我试图将索引转换为字符串,它可以工作:

    df.index=df.index.strftime('%Y-%m')
    
    ax = df.plot(kind='bar', stacked=True, width=1)
    df['Total'] = df.sum(axis=1)
    df['Total'].plot(ax=ax, label='total')
    ax.legend()
    


    编辑 2:我想我知道发生了什么。问题是

    ax = df.plot(kind='bar', stacked=True)
    

    ax 的x 轴返回/设置为range(len(df)),由df.index 中的相应值标记,但不是df.index 本身。这就是为什么如果我们在同一个ax 上绘制第二个系列,它不会显示(由于 xaxis 的比例不同)。所以我尝试了:

    # PLOTTING
    colums = df.columns
    
    ax = df.plot(kind='bar', stacked=True, width=1, figsize=(10, 6))
    ax.plot(range(len(df)), df.sum(1), label='Total')
    ax.legend()
    plt.show()
    

    它按预期工作

    【讨论】:

    • 这是针对这种情况的解决方案,这里只有两个系列。有没有办法概括,以便我可以有任意数量的酒吧系列?
    • @GustavoAmarante 查看编辑以进行复飞。我可能会有更好的技巧。
    • 是的,我也明白了。但是你的第一个答案给了我一个想法。让我试试看,如果可行,我会在这里发布。
    • 我最终选择了另一种解决方案,但它受到了您的第一个答案的启发。感谢您的帮助。
    猜你喜欢
    • 1970-01-01
    • 2016-11-12
    • 1970-01-01
    • 2015-09-15
    • 2022-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多