Python 使用熊猫绘图时,图例仅显示一个标签

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21988196/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 00:02:13  来源:igfitidea点击:

Legend only shows one label when plotting with pandas

pythonmatplotlibplotpandas

提问by Artturi Bj?rk

I have two Pandas DataFrames that I'm hoping to plot in single figure. I'm using IPython notebook.

我有两个 Pandas DataFrames,我希望将它们绘制成单个图形。我正在使用 IPython 笔记本。

I would like the legend to show the label for both of the DataFrames, but so far I've been able to get only the latter one to show. Also any suggestions as to how to go about writing the code in a more sensible way would be appreciated. I'm new to all this and don't really understand object oriented plotting.

我希望图例显示两个 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()

Legend is missing one of the labels

图例缺少其中一个标签

采纳答案by Rutger Kassies

This is indeed a bit confusing. I think it boils down to how Matplotlib handles the secondary axes. Pandas probably calls ax.twinx()somewhere which superimposes a secondary axes on the first one, but this is actually a separate axes. Therefore also with separate lines & labels and a separate legend. Calling plt.legend()only applies to one of the axes (the active one) which in your example is the second axes.

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

Pandas fortunately does store both axes, so you can grab all line objects from both of them and pass them to the .legend()command yourself. Given your example data:

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

You can plot exactly as you did:

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

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

Both axes objects are available with ax(left axe) and ax.right_ax, so you can grab the line objects from them. Matplotlib's .get_lines()return a list so you can merge them by simple addition.

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

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

The line objects have a label property which can be used to read and pass the label to the .legend()command.

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

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

And the rest of the plotting:

其余的绘图:

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

enter image description here

在此处输入图片说明

edit:

编辑:

It might be less confusing if you separate the Pandas (data) and the Matplotlib (plotting) parts more strictly, so avoid using the Pandas build-in plotting (which only wraps Matplotlib anyway):

如果更严格地将 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()

回答by luart

When multiple series are plotted then the legend is not displayed by default.
The easy way to display custom legends is just to use the axis from the last plotted series / dataframes (my code from IPython Notebook):

当绘制多个系列时,默认情况下不显示图例。
显示自定义图例的简单方法是使用最后绘制的系列/数据帧中的轴(我的代码来自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'])

The plot with custom legends

带有自定义图例的情节

回答by Alexander

You can use pd.concatto merge the two dataframes and then plot is using a secondary y-axis:

您可以使用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)

chart

图表