如何使用matplotlib为许多子图创建单个图例?

poc*_*ese 137 python matplotlib

我正在绘制相同类型的信息,但对于不同的国家/地区,使用matplotlib的多个子图.也就是说,我在3x3网格上有9个图,所有线都相同(当然,每行不同的值).

但是,我还没想出如何在图上只放一个图例(因为所有9个子图都有相同的线).

我怎么做?

小智 106

figlegend可能是你要找的:http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.figlegend

示例:http://matplotlib.org/examples/pylab_examples/figlegend_demo.html

另一个例子:

plt.figlegend( lines, labels, loc = 'lower center', ncol=5, labelspacing=0. )
Run Code Online (Sandbox Code Playgroud)

要么:

fig.legend( lines, labels, loc = (0.5, 0), ncol=5 )
Run Code Online (Sandbox Code Playgroud)

  • 我知道要放入图例中的行,但是如何将“lines”变量放入“legend”的参数中? (2认同)

Ben*_*man 99

get_legend_handles_labels()你可以在最后一个轴上调用一个很好的函数(如果你迭代它们),它们将从label=参数中收集你需要的所有东西:

handles, labels = ax.get_legend_handles_labels()
fig.legend(handles, labels, loc='upper center')
Run Code Online (Sandbox Code Playgroud)

  • 只是为了补充这个很好的答案。如果您的绘图上有辅助 y 轴并且需要合并它们,请使用以下命令:`handles, labels = [(a + b) for a, b in zip(ax1.get_legend_handles_labels(), ax2.get_legend_handles_labels())] ` (11认同)
  • 这应该是最好的答案. (10认同)
  • 如何删除子图的图例? (3认同)
  • `plt.gca().get_legend_handles_labels()` 对我有用。 (3认同)
  • 对于其他 pandas 绘图员,请在绘图函数中传递“legend=0”以隐藏子图中的图例。 (3认同)

car*_*rla 16

你只需要在循环之外询问一次传奇.

例如,在这种情况下,我有4个子图,具有相同的线和一个图例.

from matplotlib.pyplot import *

ficheiros = ['120318.nc', '120319.nc', '120320.nc', '120321.nc']

fig = figure()
fig.suptitle('concentration profile analysis')

for a in range(len(ficheiros)):
    # dados is here defined
    level = dados.variables['level'][:]

    ax = fig.add_subplot(2,2,a+1)
    xticks(range(8), ['0h','3h','6h','9h','12h','15h','18h','21h']) 
    ax.set_xlabel('time (hours)')
    ax.set_ylabel('CONC ($\mu g. m^{-3}$)')

    for index in range(len(level)):
        conc = dados.variables['CONC'][4:12,index] * 1e9
        ax.plot(conc,label=str(level[index])+'m')

    dados.close()

ax.legend(bbox_to_anchor=(1.05, 0), loc='lower left', borderaxespad=0.)
         # it will place the legend on the outer right-hand side of the last axes

show()
Run Code Online (Sandbox Code Playgroud)

  • `fig.legend()`的问题是它需要识别所有的线(图)...因为,对于每个子图,我使用一个循环来生成线,这是我想出的唯一解决方案是在第二个循环之前创建一个空列表,然后在创建它们时附加行...然后我使用这个列表作为`fig.legend()`函数的参数. (11认同)
  • 被埃弗特淹没的`figlegend`似乎是一个更好的解决方案;) (3认同)

Sau*_*tro 15

对于figure具有多个轴的单个图例的自动定位,如获得的那些subplots(),以下解决方案非常有效:

plt.legend( lines, labels, loc = 'lower center', bbox_to_anchor = (0,-0.1,1,1),
            bbox_transform = plt.gcf().transFigure )
Run Code Online (Sandbox Code Playgroud)

使用bbox_to_anchorbbox_transform=plt.gcf().transFigure您定义一个大小的新边界框figure作为参考loc.使用(0,-0.1,1,1)稍微向下移动这个装饰盒以防止将图例放在其他艺术家身上.

OBS:fig.set_size_inches()在您使用之后和使用之前使用此解决方案fig.tight_layout()

  • 或者简单的 `loc='upper center', bbox_to_anchor=(0.5, 0), bbox_transform=plt.gcf().transFigure` 并且它肯定不会重叠。 (2认同)
  • 我仍然不确定为什么,但埃弗特的解决方案对我不起作用——传奇不断被切断。这个解决方案(连同 davor 的评论)工作得非常干净——图例按预期放置并且完全可见。谢谢! (2认同)

gbo*_*ffi 9

我注意到没有答案显示带有单个图例的图像,该图例引用了不同子图中的许多曲线,因此我必须向您展示一个……让您感到好奇……

在此处输入图片说明

现在,您想看一下代码,不是吗?

from numpy import linspace
import matplotlib.pyplot as plt

# Calling the axes.prop_cycle returns an itertoools.cycle

color_cycle = plt.rcParams['axes.prop_cycle']()

# I need some curves to plot

x = linspace(0, 1, 51)
f1 = x*(1-x)   ; lab1 = 'x - x x'
f2 = 0.25-f1   ; lab2 = '1/4 - x + x x' 
f3 = x*x*(1-x) ; lab3 = 'x x - x x x'
f4 = 0.25-f3   ; lab4 = '1/4 - x x + x x x'

# let's plot our curves (note the use of color cycle, otherwise the curves colors in
# the two subplots will be repeated and a single legend becomes difficult to read)
fig, (a13, a24) = plt.subplots(2)

a13.plot(x, f1, label=lab1, **next(color_cycle))
a13.plot(x, f3, label=lab3, **next(color_cycle))
a24.plot(x, f2, label=lab2, **next(color_cycle))
a24.plot(x, f4, label=lab4, **next(color_cycle))

# so far so good, now the trick

lines_labels = [ax.get_legend_handles_labels() for ax in fig.axes]
lines, labels = [sum(lol, []) for lol in zip(*lines_labels)]

# finally we invoke the legend (that you probably would like to customize...)

fig.legend(lines, labels)
plt.show()
Run Code Online (Sandbox Code Playgroud)

两条线

lines_labels = [ax.get_legend_handles_labels() for ax in fig.axes]
lines, labels = [sum(lol, []) for lol in zip(*lines_labels)]
Run Code Online (Sandbox Code Playgroud)

值得解释—为此,我将棘手的部分封装在一个函数中,只有四行代码,但注释严重

def fig_legend(fig, **kwdargs):

    # generate a sequence of tuples, each contains
    #  - a list of handles (lohand) and
    #  - a list of labels (lolbl)
    tuples_lohand_lolbl = (ax.get_legend_handles_labels() for ax in fig.axes)
    # e.g. a figure with two axes, ax0 with two curves, ax1 with one curve
    # yields:   ([ax0h0, ax0h1], [ax0l0, ax0l1]) and ([ax1h0], [ax1l0])

    # legend needs a list of handles and a list of labels, 
    # so our first step is to transpose our data,
    # generating two tuples of lists of homogeneous stuff(tolohs), i.e
    # we yield ([ax0h0, ax0h1], [ax1h0]) and ([ax0l0, ax0l1], [ax1l0])
    tolohs = zip(*tuples_lohand_lolbl)

    # finally we need to concatenate the individual lists in the two
    # lists of lists: [ax0h0, ax0h1, ax1h0] and [ax0l0, ax0l1, ax1l0]
    # a possible solution is to sum the sublists - we use unpacking
    handles, labels = (sum(list_of_lists, []) for list_of_lists in tolohs)

    # call fig.legend with the keyword arguments, return the legend object

    return fig.legend(handles, labels, **kwdargs)
Run Code Online (Sandbox Code Playgroud)

附言:我认识到,sum(list_of_lists, [])将列表列表扁平化是一种效率很低的方法,但是?我喜欢它的紧凑性,通常在一些子图中有一些曲线吗?Matplotlib和效率?;-)


hei*_*ner 7

以gboffi 和 Ben Usman 的答案为基础:

在不同子图中具有相同颜色和标签的不同线条的情况下,可以按照以下方式执行操作:

labels_handles = {
  label: handle for ax in fig.axes for handle, label in zip(*ax.get_legend_handles_labels())
}

fig.legend(
  labels_handles.values(),
  labels_handles.keys(),
  loc = "upper center",
  bbox_to_anchor = (0.5, 0),
  bbox_transform = plt.gcf().transFigure,
)
Run Code Online (Sandbox Code Playgroud)


Not*_*le1 5

如果您使用带有条形图的子图,每个条形图具有不同的颜色,则使用 自行创建工件可能会更快mpatches

r假设您有、mc、 和四个不同颜色的条形图k,您可以按如下方式设置图例:

import matplotlib.patches as mpatches
import matplotlib.pyplot as plt
labels = ['Red Bar', 'Magenta Bar', 'Cyan Bar', 'Black Bar']


#####################################
# Insert code for the subplots here #
#####################################


# Now, create an artist for each color
red_patch = mpatches.Patch(facecolor='r', edgecolor='#000000') # This will create a red bar with black borders, you can leave out edgecolor if you do not want the borders
black_patch = mpatches.Patch(facecolor='k', edgecolor='#000000')
magenta_patch = mpatches.Patch(facecolor='m', edgecolor='#000000')
cyan_patch = mpatches.Patch(facecolor='c', edgecolor='#000000')
fig.legend(handles = [red_patch, magenta_patch, cyan_patch, black_patch], labels=labels,
       loc="center right",
       borderaxespad=0.1)
plt.subplots_adjust(right=0.85) # Adjust the subplot to the right for the legend
Run Code Online (Sandbox Code Playgroud)