如何为等高线图创建图例?

44
我似乎无法在任何地方找到答案!我在这里找到了一个讨论链接,但是尝试后我得到了一个TypeError: 'NoneType' object is not iterable的错误。
>>> import numpy as np
>>> import matplotlib.pyplot as plt
>>> x, y = np.meshgrid(np.arange(10),np.arange(10))
>>> z = x + y
>>> cs = plt.contourf(x,y,z,levels=[2,3])
>>> cs.collections[0].set_label('test')
>>> plt.legend()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/matplotlib/pyplot.py", line 2791, in legend
    ret =  gca().legend(*args, **kwargs)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/matplotlib/axes.py", line 4475, in legend
    self.legend_ = mlegend.Legend(self, handles, labels, **kwargs)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/matplotlib/legend.py", line 365, in __init__
    self._init_legend_box(handles, labels)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/matplotlib/legend.py", line 627, in _init_legend_box
    handlebox)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/matplotlib/legend_handler.py", line 110, in __call__
    handlebox.get_transform())
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/matplotlib/legend_handler.py", line 352, in create_artists
    width, height, fontsize)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/matplotlib/legend_handler.py", line 307, in get_sizes
    size_max = max(orig_handle.get_sizes())*legend.markerscale**2
TypeError: 'NoneType' object is not iterable

编辑:我正在寻找像这样的东西:

kamland solar delta chi-squared map


2
contourf上的图例对我来说没有意义。你是指colorbar吗? - Avaris
我已经更新了我的问题,并提供了一个我正在寻找的示例。 - user545424
我想我正在寻找的是一种方法,既可以标记contour()绘图中的等高线,又可以标记contourf()绘图中的填充区域。 - user545424
当我尝试为contour()图标注时,也会出现相同的错误。 - user545424
4个回答

60

您也可以直接使用轮廓线,而不必使用代理图形进行操作。

import matplotlib
import numpy as np
import matplotlib.cm as cm
import matplotlib.mlab as mlab
import matplotlib.pyplot as plt

matplotlib.rcParams['xtick.direction'] = 'out'
matplotlib.rcParams['ytick.direction'] = 'out'

delta = 0.025
x = np.arange(-3.0, 3.0, delta)
y = np.arange(-2.0, 2.0, delta)
X, Y = np.meshgrid(x, y)
Z1 = mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
Z2 = mlab.bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
# difference of Gaussians
Z = 10.0 * (Z2 - Z1)



# Create a simple contour plot with labels using default colors.  The
# inline argument to clabel will control whether the labels are draw
# over the line segments of the contour, removing the lines beneath
# the label
plt.figure()
CS = plt.contour(X, Y, Z)
plt.clabel(CS, inline=1, fontsize=10)
plt.title('Simplest default with labels')

labels = ['line1', 'line2','line3','line4',
           'line5', 'line6']
for i in range(len(labels)):
    CS.collections[i].set_label(labels[i])

plt.legend(loc='upper left')

将生成:

带有图例和标签的图

然而,您可能还想研究一下自己需要的注释。在我看来,这将为您提供更精细的控制,使您可以在图像上写入内容并指定位置,以下是使用一些注释的相同示例:

### better with annotation, more flexible
plt.figure(2)
CS = plt.contour(X, Y, Z)
plt.clabel(CS, inline=1, fontsize=10)
plt.title('Simplest default with labels')

plt.annotate('some text here',(1.4,1.6))
plt.annotate('some text there',(-2,-1.5))

带注释的图片


2
我想补充一下,您可以使用轮廓的值,通过 for i, label in enumerate(CS.cvalues): CS.collections[i].set_label(label) 进行设置。 - slek120
5
set_label()在matplotlib 3.5.2中无法正确渲染,请使用以下解决方案或legend_elements() - jiegec

45

您可以创建代理艺术家来创建图例:

import numpy as np
import matplotlib.pyplot as plt
x, y = np.meshgrid(np.arange(10),np.arange(10))
z = np.sqrt(x**2 + y**2)
cs = plt.contourf(x,y,z,levels=[2,3,4,6])

proxy = [plt.Rectangle((0,0),1,1,fc = pc.get_facecolor()[0]) 
    for pc in cs.collections]

plt.legend(proxy, ["range(2-3)", "range(3-4)", "range(4-6)"])
plt.show()

在此输入图片描述


5
Matplotlib也支持使用阴影轮廓线,你可以通过将代理更改为proxy = [pylab.Rectangle((0, 0), 1, 1, fc=pc.get_facecolor()[0], hatch=pc.get_hatch()) for pc in im.collections]来包含它们。 - regeirk

4

这个答案的基础上,为了使其更少手动操作:

import numpy as np
import matplotlib.pyplot as plt
x, y = np.meshgrid(np.arange(10),np.arange(10))
z = np.sqrt(x**2 + y**2)
levels=[2,3,4,6]
cs = plt.contourf(x,y,z,levels=levels)

proxy = [plt.Rectangle((0,0),1,1,fc = pc.get_facecolor()[0]) 
    for pc in cs.collections]

plt.legend(proxy, [f"{lower:2.1f} - {upper:2.1f}" for lower, upper in zip(levels[:-1], levels[1:])])
plt.show()

Contour plot


1

我有一个类似的问题,但需要在HYRY的答案的基础上更进一步。为了使包更加用户友好,我希望ax.legend()可以不要求用户传递任何句柄,这可以通过传递标签到代理来实现。

proxy = plt.Rectangle((0, 0), 1, 1, fc='red', label='some label')

然后将代理添加到轴的补丁中:

ax.patches += [proxy]

要获取当前轴,执行ax = plt.gca()

更详细的说明请参见此答案


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接