简体   繁体   English

如何在 Matplotlib 中生成嵌套图例

[英]How to produce nested legends in Matplotlib

I have to plot in Matplotlib a quantity which is the sum of various contributions.我必须在 Matplotlib 中的 plot 一个数量,这是各种贡献的总和

I would like to highlight this fact in the legend of the plot by listing the various contribution as sub-elements of the main legend entry.我想通过将各种贡献列为主要图例条目的子元素,在 plot 的图例中强调这一事实。

A sketch of the result I would like to obtain can be found in the picture below.我想获得的结果草图可以在下面的图片中找到。 Note that I do not need to necessarily achieve exactly the legend that is depicted, but just something similar.请注意,我不一定要完全实现所描绘的图例,而只是类似的东西。

You can try creating two separate legends to your figure.您可以尝试为您的人物创建两个单独的图例。 Sure, it's a trick rather than a direct feature of the legend object, as there seems to be no implementation of what you need in matplotlib.当然,这是一个技巧,而不是传说中的 object 的直接功能,因为 matplotlib 中似乎没有实现您需要的功能。 But playing with the numbers in bbox and the fontsize you can customize it pretty nicely.但是使用 bbox 中的数字和字体大小,您可以很好地自定义它。

import matplotlib.pyplot as plt 
import numpy as np

x = np.arange(0.0, 1, 0.01)
x1 = np.sin(2*np.pi*x)
x2 = np.sin(2*np.pi*x+1)
x3 = np.sin(2*np.pi*x+2)


fig, ax = plt.subplots()
f1, = ax.plot(x1, 'r', lw=4)
f2, = ax.plot(x2, 'k', lw=2)
f3, = ax.plot(x3, 'b', lw=2)

legend1 = plt.legend([f1], ["Main legend"], fontsize=12, loc=3, bbox_to_anchor=(0,0.1,0,0), frameon=False)
legend2 = plt.legend((f2, f3), ('sublegend 1', 'sublegend 2'), fontsize=9,
                 loc=3, bbox_to_anchor=(0.05,0,0,0), frameon=False)
plt.gca().add_artist(legend1)
plt.show()

在此处输入图像描述

EDIT:编辑:

Well, if we insert 2 legends, why not just inserting a completely new figure as inset inside the bigger figure, dedicated for a legend, inside which you can draw and write whatever you like?好吧,如果我们插入 2 个图例,为什么不在更大的图中插入一个全新的图形作为插图,专用于一个图例,在其中你可以画和写任何你喜欢的东西? Admittedly it's a hard work, you have to design each and every line inside including the precise location coordinates.诚然,这是一项艰巨的工作,您必须设计内部的每一条线,包括精确的位置坐标。 But that's the way I could think of for doing what you wanted:但这就是我能想到的做你想做的事的方式:

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(0.0, 1, 0.01)
x1 = np.sin(2*np.pi*x)
x2 = np.sin(2*np.pi*x+1)
x3 = np.sin(2*np.pi*x+2)


fig, ax = plt.subplots()
f1, = ax.plot(x1, 'r', lw=4)
f2, = ax.plot(x2, 'k', lw=2)
f3, = ax.plot(x3, 'b', lw=2)

## set all lines for inner figure
yline1 = np.array([-0.15, -0.15]) 
line1 = np.array([2, 10])
yline2 = np.array([3, 0])
line2 = np.array([4, 4])
yline3 = np.array([1.5, 1.5])
line3 = np.array([4, 6])
yline4 = np.array([1.5, 1.5])
line4 = np.array([7, 10])
yline5 = np.array([3, 3])
line5 = np.array([4, 6])
yline6 = np.array([3, 3])
line6 = np.array([7, 10])

## inset figure
axin1 = ax.inset_axes([2.5, -1, 30, 0.5], transform=ax.transData)  # 

## plot all lines
axin1.plot(line1, yline1, linewidth=4, c='r')
axin1.plot(line2, yline2, 'k', lw=1)
axin1.plot(line3, yline3, 'k', lw=1)
axin1.plot(line4, yline4, 'b', lw=3)
axin1.plot(line5, yline5, 'k', lw=1)
axin1.plot(line6, yline6, 'k', lw=3)

## text
axin1.text(12, 0, 'MAIN', fontsize=12)
axin1.text(12, 1.7, 'Subtext 1', fontsize=10)
axin1.text(12, 3.2, 'Subtext 2', fontsize=10)

## adjust
axin1.set_ylim([4, -1])
axin1.set_xlim([0, 27])
axin1.set_xticklabels('')
axin1.set_yticklabels('')

在此处输入图像描述

I looked for a custom example in the legend and could not see any indication of lowering the level.我在图例中寻找了一个自定义示例,并没有看到任何降低级别的迹象。 You can just line up the objects in the legend.您只需排列图例中的对象即可。 I've created a hierarchy of the presented images in the form of colors and markers.我以 colors 和标记的形式创建了呈现图像的层次结构。 The official reference has been customized.官方参考已定制。 This has the effect of eliminating the need to annotate only the legend in a special way.这具有消除以特殊方式仅注释图例的需要的效果。

import matplotlib.pyplot as plt
from matplotlib.legend_handler import HandlerLineCollection, HandlerTuple

fig, ax1 = plt.subplots(1, 1, constrained_layout=True)

params = {'legend.fontsize': 16,
          'legend.handlelength': 3}

plt.rcParams.update(params)

x = np.linspace(0, np.pi, 25)
xx = np.linspace(0, 2*np.pi, 25)
xxx = np.linspace(0, 3*np.pi, 25)

p1, = ax1.plot(x, np.sin(x), lw=5, c='r')
p2, = ax1.plot(x, np.sin(xx), 'm-d', c='g')
p3, = ax1.plot(x, np.sin(xxx), 'm-s', c='b')

# Assign two of the handles to the same legend entry by putting them in a tuple
# and using a generic handler map (which would be used for any additional
# tuples of handles like (p1, p2)).
l = ax1.legend([p1, (p1, p2), (p1, p3)], ['Legend entry', 'Contribution 1', 'Contribution 2'], scatterpoints=1,
               numpoints=1, markerscale=1.3, handler_map={tuple: HandlerTuple(ndivide=None, pad=1.0)})

plt.show()

在此处输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM