正如您在图例指南中引用的 paragraph on legend handlers 所引用的,元组列表中包含的每个元组中的项目的句柄被绘制在另一个之上。所以看起来解决方案应该是从元组中取出句柄:将这个[(bar1, line1), (bar2, line2)]更改为这个[bar1, bar2, line1, line2]。但是你会面临需要有相应数量的标签的问题,因为['Solution 1', 'Solution 2'] 的图例只会显示bar1, bar2 键。
为避免此问题,您可以使用上述图例处理程序段落中显示的最后一个示例中的legend_handler_HandlerTuple 类。然后,您的图例代码将如下所示(请注意,我在以下所有代码 sn-ps 中将 bar1, bar2 重命名为 bars1, bars2;设置了图例参数,以便格式如下图所示) :
import matplotlib.pyplot as plt
from matplotlib.legend_handler import HandlerTuple
...
# Import data, draw plots
...
axis1.legend([(bar1, line1), (bar2, line2)], ['Solution 1', 'Solution 2'],
loc='upper left', edgecolor='black', borderpad=0.7, handlelength=7,
handletextpad=1.5, handler_map={tuple: HandlerTuple(ndivide=None, pad=1.5)})
这可以完成工作,但还有一个更优雅的替代方案。让我根据您提供的图像和this example 上的条形代码的完整示例进行说明。从您共享的代码 sn-p 中,我想您的代码结构有点像这样:
import numpy as np # v 1.19.2
import matplotlib.pyplot as plt # v 3.3.2
# Compute variables to plot
var_bars1 = np.arange(1, 8)
var_bars2 = var_bars1/2
var_line1 = 2+var_bars1**1.3
var_line2 = 5+var_bars2**1.6
x = np.arange(len(var_bars1))
# Create grouped bar chart
bar_width = 0.3
fig, axis1 = plt.subplots(figsize=(9, 6))
# notice that the bar plot functions return a BarContainer object which contains
# the colored rectangles (stored as matplotlib.patches.Rectangle objects)
bars1 = axis1.bar(x-bar_width/2, var_bars1, bar_width, label='Solution 1')
bars2 = axis1.bar(x+bar_width/2, var_bars2, bar_width, label='Solution 2')
axis1.set_xlabel('x both', labelpad=15, fontsize=12)
axis1.set_ylabel('y bars', labelpad=15, fontsize=12)
# Create line chart over bar chart using same x axis
axis2 = axis1.twinx()
# notice that the plot functions return a list containing the single line (with
# markers), the comma after the variable name unpacks the list
line1, = axis2.plot(x, var_line1, 'kx', linestyle='-', ms=8, label='Solution 1')
line2, = axis2.plot(x, var_line2, 'ko', linestyle='-', ms=8, label='Solution 2')
axis2.set_ylabel('y lines', labelpad=15, fontsize=12)
以下是如何在不使用 HandlerTuple 类的情况下创建图例:
# Create custom legend using handles extracted from plots and manually
# inserting the corresponding labels, leaving strings empty for the first
# column of legend handles (aka legend keys) and adding columnspacing=0 to
# remove the extra whitespace created by the empty strings
axis1.legend((bars1, bars2, line1, line2), ('', '', 'Solution 1', 'Solution 2'),
loc='upper left', ncol=2, handlelength=3, edgecolor='black',
borderpad=0.7, handletextpad=1.5, columnspacing=0)
图例的参数在文档here中有详细说明。在显示输出的样子之前,值得注意的是,可以通过自动创建图例的方式简化此代码。可以通过使用get_legend_handles_labels 函数将其重写为避免将每个绘图函数的输出存储为新变量,如下所示:
fig, axis1 = plt.subplots(figsize=(9, 6))
# Create grouped bar chart
axis1.bar(x-bar_width/2, var_bars1, bar_width, label='Solution 1')
axis1.bar(x+bar_width/2, var_bars2, bar_width, label='Solution 2')
axis1.set_xlabel('x both', labelpad=15, fontsize=12)
axis1.set_ylabel('y bars', labelpad=15, fontsize=12)
# Create line chart over bar chart using same x axis
axis2 = axis1.twinx()
axis2.plot(x, var_line1, 'kx', linestyle='-', ms=8, label='Solution 1')
axis2.plot(x, var_line2, 'ko', linestyle='-', ms=8, label='Solution 2')
axis2.set_ylabel('y lines', labelpad=15, fontsize=12)
handles1, labels1 = axis1.get_legend_handles_labels()
handles2, labels2 = axis2.get_legend_handles_labels()
# Create custom legend by unpacking tuples containing handles and using
# only one set of unpacked labels along with set of unpacked empty strings
# (using None instead of empty strings gives the same result)
axis1.legend((*handles1, *handles2), (*len(labels1)*[''], *labels2),
loc='upper left', ncol=2, handlelength=3, edgecolor='black',
borderpad=0.7, handletextpad=1.5, columnspacing=0)
plt.show()
最后一点,知道这个图中有两个轴,技术上可以通过重叠两个轴的图例来绘制一个图例,如下例所示,尽管这很明显需要进行大量手动调整才能根据需要设置句柄和标签的格式。
# Create legend by overlapping the legends from both axes by adjusting the
# bbox location and size, and by removing labels of the first legend
leg1 = axis1.legend(loc='upper left', bbox_to_anchor=(0., 0.5, 0.25, 0.5),
edgecolor='black', mode="expand")
for text in leg1.texts:
text.set_visible(False)
axis2.legend(bbox_to_anchor=(0.05, 0.5, 0.2, 0.5), frameon=False)
可以通过legend class 上的文档中列出的图例方法访问更多图例功能。