【问题标题】:Pandas and Matplotlib plotting df as subplots with 2 y-axesPandas 和 Matplotlib 将 df 绘制为具有 2 个 y 轴的子图
【发布时间】:2017-07-01 08:56:22
【问题描述】:

我正在尝试使用 pandas 和 matplotlib.pyplot 将数据框绘制到几个子图上。但我想让两列使用不同的 y 轴,并在所有子图之间共享。

目前我的代码是:

import pandas as pd
import matplotlib.pyplot as plt

df = pd.DataFrame({'Area':['A', 'A', 'A', 'B', 'B', 'C','C','C','D','D','D','D'],
              'Rank':[1,2,3,1,2,1,2,3,1,2,3,4],
              'Count':[156,65,152,70,114,110,195,92,44,179,129,76],
              'Value':[630,426,312,191,374,109,194,708,236,806,168,812]}
             )
df = df.set_index(['Area', 'Rank'])

fig = plt.figure(figsize=(6,4))

for i, l in enumerate(['A','B','C','D']):

if i == 0:
    sub1 = fig.add_subplot(141+i)

else:
    sub1 = fig.add_subplot(141+i, sharey=sub1)

df.loc[l].plot(kind='bar', ax=sub1)

这会产生:

这可以并排绘制 4 个图表,这是我想要的,但两列使用相同的 y 轴我想让“计数”列在左侧使用公共 y 轴,“ Value' 列在右侧使用一个通用的辅助 y 轴。

有人可以建议一种方法吗?到目前为止,我的尝试导致每个图表都有自己独立的 y 轴。

【问题讨论】:

    标签: python pandas matplotlib


    【解决方案1】:

    要创建辅助 y 轴,您可以使用 twinax = ax.twinx()。然后可以通过轴Groupertwinax.get_shared_y_axes().join(twinax1, twinax2)join 方法加入这些双轴。有关详细信息,请参阅this question

    接下来的问题是让两个不同的条形图彼此相邻。由于我认为没有办法使用 pandas 绘图包装器来做到这一点,因此可以使用 matplotlib 条形图,它允许定量地指定条形位置。然后左侧条的位置将移动条的宽度。

    import pandas as pd
    import matplotlib.pyplot as plt
    
    df = pd.DataFrame({'Area':['A', 'A', 'A', 'B', 'B', 'C','C','C','D','D','D','D'],
                  'Rank':[1,2,3,1,2,1,2,3,1,2,3,4],
                  'Count':[156,65,152,70,114,110,195,92,44,179,129,76],
                  'Value':[630,426,312,191,374,109,194,708,236,806,168,812]}
                 )
    df = df.set_index(['Area', 'Rank'])
    
    fig, axes = plt.subplots(ncols=len(df.index.levels[0]), figsize=(6,4), sharey=True)
    twinaxes = []
    for i, l in enumerate(df.index.levels[0]):
        axes[i].bar(df["Count"].loc[l].index.values-0.4,df["Count"].loc[l], width=0.4, align="edge" )
        ax2 = axes[i].twinx()
        twinaxes.append(ax2)
        ax2.bar(df["Value"].loc[l].index.values,df["Value"].loc[l], width=0.4, align="edge", color="C3" )
        ax2.set_xticks(df["Value"].loc[l].index.values)
        ax2.set_xlabel("Rank")
    
    
    [twinaxes[0].get_shared_y_axes().join(twinaxes[0], ax) for ax in twinaxes[1:]]
    [ax.tick_params(labelright=False) for ax in twinaxes[:-1]]
    
    axes[0].set_ylabel("Count")
    axes[0].yaxis.label.set_color('C0')
    axes[0].tick_params(axis='y', colors='C0')
    twinaxes[-1].set_ylabel("Value")
    twinaxes[-1].yaxis.label.set_color('C3')
    twinaxes[-1].tick_params(axis='y', colors='C3')
    twinaxes[0].relim()
    twinaxes[0].autoscale_view()
    
    plt.show()
    

    【讨论】:

    • 完美!不幸的是,不可能通过 pandas 更整洁地做到这一点,但这看起来很棒,非常感谢。请问[twinaxes[0].get_shared_y_axes().join(twinaxes[0], ax) for ax in twinaxes[1:]] [ax.tick_params(labelright=False) for ax in twinaxes[:-1]] 这些行是什么你使用列表推导作为 for 循环的缩短版本?
    • 没错,这只是 for 循环的缩短版本。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-06
    • 2021-10-07
    • 1970-01-01
    • 2012-07-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多