【问题标题】:Legend only shows one label when plotting with pandas使用 pandas 绘图时,图例仅显示一个标签
【发布时间】:2014-03-26 03:23:27
【问题描述】:

我有两个 Pandas DataFrame,我希望以单个图形绘制。我正在使用 IPython 笔记本。

我希望图例显示两个 DataFrame 的标签,但到目前为止,我只能显示后一个。此外,任何有关如何以更明智的方式编写代码的建议都将不胜感激。我对这一切都很陌生,并不真正了解面向对象的绘图。

%pylab inline
import pandas as pd

#creating data

prng = pd.period_range('1/1/2011', '1/1/2012', freq='M')
var=pd.DataFrame(randn(len(prng)),index=prng,columns=['total'])
shares=pd.DataFrame(randn(len(prng)),index=index,columns=['average'])

#plotting

ax=var.total.plot(label='Variance')
ax=shares.average.plot(secondary_y=True,label='Average Age')
ax.left_ax.set_ylabel('Variance of log wages')
ax.right_ax.set_ylabel('Average age')
plt.legend(loc='upper center')
plt.title('Wage Variance and Mean Age')
plt.show()

【问题讨论】:

    标签: python matplotlib plot pandas


    【解决方案1】:

    这确实有点令人困惑。我认为这归结为 Matplotlib 如何处理辅助轴。 Pandas 可能会在某个地方调用ax.twinx(),它将第二个轴叠加在第一个轴上,但这实际上是一个单独的轴。因此也有单独的线条和标签以及单独的图例。调用 plt.legend() 仅适用于您的示例中为第二个轴的轴之一(活动轴)。

    幸运的是,Pandas 确实存储了两个轴,因此您可以从它们中获取所有线对象并将它们自己传递给.legend() 命令。鉴于您的示例数据:

    您可以完全按照您的方式绘制:

    ax = var.total.plot(label='Variance')
    ax = shares.average.plot(secondary_y=True, label='Average Age')
    
    ax.set_ylabel('Variance of log wages')
    ax.right_ax.set_ylabel('Average age')
    

    ax(左轴)和ax.right_ax 都可以使用这两个轴对象,因此您可以从中获取线对象。 Matplotlib 的 .get_lines() 返回一个列表,因此您可以通过简单的添加合并它们。

    lines = ax.get_lines() + ax.right_ax.get_lines()
    

    线条对象有一个标签属性,可用于读取标签并将其传递给.legend() 命令。

    ax.legend(lines, [l.get_label() for l in lines], loc='upper center')
    

    以及其余的情节:

    ax.set_title('Wage Variance and Mean Age')
    plt.show()
    

    编辑:

    如果您将 Pandas(数据)和 Matplotlib(绘图)部分更严格地分开,可能不会那么混乱,因此请避免使用 Pandas 内置绘图(无论如何它只包装 Matplotlib):

    fig, ax = plt.subplots()
    
    ax.plot(var.index.to_datetime(), var.total, 'b', label='Variance')
    ax.set_ylabel('Variance of log wages')
    
    ax2 = ax.twinx()
    ax2.plot(shares.index.to_datetime(), shares.average, 'g' , label='Average Age')
    ax2.set_ylabel('Average age')
    
    lines = ax.get_lines() + ax2.get_lines()
    ax.legend(lines, [line.get_label() for line in lines], loc='upper center')
    
    ax.set_title('Wage Variance and Mean Age')
    plt.show()
    

    【讨论】:

      【解决方案2】:

      当绘制多个系列时,默认情况下不显示图例。
      显示自定义图例的简单方法是使用最后绘制的系列/数据帧中的轴(我的代码来自 IPython Notebook):

      %matplotlib inline  # Embed the plot
      import matplotlib.pyplot as plt
      
      ...
      rates[rates.MovieID <= 25].groupby('MovieID').Rating.count().plot()  # blue
      (rates[rates.MovieID <= 25].groupby('MovieID').Rating.median() * 1000).plot()  # green
      (rates[rates.MovieID <= 25][rates.RateDelta <= 10].groupby('MovieID').Rating.count() * 2000).plot()  # red
      ax = (rates[rates.MovieID <= 25][rates.RateDelta <= 10].groupby('MovieID').Rating.median() * 1000).plot()  # cyan
      
      ax.legend(['Popularity', 'RateMedian', 'FirstPpl', 'FirstRM'])
      

      【讨论】:

      • 不适用于辅助轴,辅助轴是这个问题的一部分
      【解决方案3】:

      您可以使用pd.concat 合并两个数据框,然后绘图使用辅助 y 轴:

      import numpy as np  # For generating random data.
      import pandas as pd
      
      # Creating data.
      np.random.seed(0)
      prng = pd.period_range('1/1/2011', '1/1/2012', freq='M')
      var = pd.DataFrame(np.random.randn(len(prng)), index=prng, columns=['total'])
      shares = pd.DataFrame(np.random.randn(len(prng)), index=prng, columns=['average'])
      
      # Plotting.
      ax = (
          pd.concat([var, shares], axis=1)
          .rename(columns={
              'total': 'Variance of Low Wages',
              'average': 'Average Age'
          })
          .plot(
              title='Wage Variance and Mean Age',
              secondary_y='Average Age')
      )
      ax.set_ylabel('Variance of Low Wages')
      ax.right_ax.set_ylabel('Average Age', rotation=-90)
      

      【讨论】:

        猜你喜欢
        • 2021-07-07
        • 1970-01-01
        • 2019-02-27
        • 1970-01-01
        • 2016-11-07
        • 2021-05-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多