Matplotlib迭代以合并图例句柄和标签

时间:2019-05-27 22:38:16

标签: python matplotlib legend

如果我具有以下绘制例程,该例程绘制散点图和相应的线性回归并结合了图例手柄:

import pandas as pd
from scipy.stats import linregress
import numpy as np
import matplotlib.pyplot as plt

#data and Regression
x = np.arange(0,5,1)
y = np.arange(0,10,2)
df = pd.DataFrame(data = {'x':x,'y':y})
s, intcpt, r, p, serr = linregress(df.x, df.y)
xHat = np.linspace(0,5,100)


# do the plotting
fig,ax = plt.subplots()
df.plot(x='x',y='y',ax=ax,label='series1',ls=' ',marker='x',c='blue')
ls_handle, = ax.plot(xHat, s*xHat + intcpt, linestyle='-', marker=None, c='blue')
handle2merge = [ls_handle]
handles, labels = ax.get_legend_handles_labels()
handle_combined = zip(handles, handle2merge)
ax.legend(handle_combined, labels)

返回标记和线手柄合并的位置,如下所示:

enter image description here

现在,我想以类似的方式绘制另一个数据集:

#get current axis handles and labels
handle_start, label_start = ax.get_legend_handles_labels()

#second dataset and regression
x1 = np.arange(0,5,1)
y1 = np.arange(0,2.5,0.5)
df1 = pd.DataFrame(data = {'x':x1,'y':y1})
s1, intcpt1, r1, p1, serr1 = linregress(df1.x, df1.y)
xHat1 = np.linspace(0,5,100)

#plot second data set on same figure
marker_handle2, = ax.plot(df1.x, df1.y, marker = 'x', zorder=10,c='k', linestyle=' ')
line_handle2, = ax.plot(xHat, s1*xHat1 + intcpt1, linestyle='--', marker=None, c='k') 
new_line_handles = [line_handle2]
new_marker_handles= [marker_handle2]

ax.legend(handle_start + zip(new_marker_handles,new_line_handles), label_start + ['series2'])

这将返回一个图,其中series1图例句柄的句柄仅包含标记。

enter image description here

当我用len(handle_start)=1构造手柄时,为什么handle_combined = zip(handles, handle2merge)是这样?

2 个答案:

答案 0 :(得分:1)

我已经在代码中稍加戳了一下。您正在做的是将list中的tuples传递到ax.legend,这显然将每个tuple中的每个Artist都作为图例中的一个条目。我实际上从未遇到过这种行为;可能是错误,也可能是ax.legend的意外使用。

尽管如此,我认为在这种情况下,由于您事先知道行的外观,因此不必通过zip和其他东西来回旋,您可以将自定义Line2D传递给直接legend

import numpy as np

from scipy.stats import linregress

from matplotlib import pyplot as plt
from matplotlib import lines

x1 = np.arange(0, 5, 1)
y1 = np.arange(0, 10, 2)
x2 = np.arange(0, 5, 1)
y2 = np.arange(0, 2.5, 0.5)

m1, c1, r1, p1, serr1 = linregress(x1, y1)
m2, c2, r2, p2, serr2 = linregress(x2, y2)

x_pred = np.linspace(0,5,100)

fig, ax = plt.subplots()

first_line, = ax.plot(x_pred, x_pred * m1 + c1, ls='-', c='blue')
first_scatter = ax.scatter(x1, y1, marker='x', c='blue')

second_line, = ax.plot(x_pred, x_pred * m2 + c2, ls='--', c='black')
second_scatter = ax.scatter(x2, y2, marker='x', c='black')

ax.legend([lines.Line2D([0], [0], marker='x', ls='-', c='blue'),
           lines.Line2D([0], [0], marker='x', ls='--', c='black')],
          ['series_1', 'series_2'])

enter image description here

我稍微整理了一下代码,但是可以随意接受最后一行和必要的导入。

答案 1 :(得分:0)

在最后一行中,仅使用已创建的合并句柄handle_combined而不是handle_start

ax.legend(handle_combined + list(zip(new_marker_handles,new_line_handles)), 
          label_start + ['series2'])

长度为1,但是如果您查看列表的内容,则它是一个由两个对象组成的元组。如果打印handle_combined,则会得到两个Line2D对象的列表,其中一个是标记,另一个是行。

print (handle_combined)
# [(<matplotlib.lines.Line2D object at xxxxxxxxx>, <matplotlib.lines.Line2D object at xxxxxxxxx>)]

但是,如果您打印handle_start,它只会返回一个Line2D对象

print (handle_start)
# [<matplotlib.lines.Line2D object at xxxxxxxxx>]

enter image description here