简体   繁体   English

如何在 matplotlib 中为等高线图创建图例?

[英]How do you create a legend for a contour plot in matplotlib?

I can't seem to find the answer anywhere!我似乎无法在任何地方找到答案! I found a discussion here , but trying this I get a TypeError: 'NoneType' object is not iterable :我在这里找到了一个讨论,但尝试这个我得到一个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

EDIT : I'm looking for something like this:编辑:我正在寻找这样的东西:

kamland 太阳能三角洲卡方图

You could also do it directly with the lines of the contour, without using proxy artists.您也可以直接使用轮廓线来完成,而无需使用代理艺术家。

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')

Will produce:将产生:

图例和标签

However, you might also want to look into annotations for your own need.但是,您可能还想根据自己的需要查看注释。 In my opinion it will give you a more fine grained control on where and what you write on the image, here is the same example with some annotation:在我看来,它会给你一个更细粒度的控制你在图像上写的位置和内容,这是带有一些注释的相同示例:

### 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))

带注释的图

You can create proxy artists to make the legend:您可以创建代理艺术家来制作图例:

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()

在此处输入图像描述

Adding to this answer to make it less manual:添加到此答案以减少手动操作:

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()

等高线图

I had a similar question but needed to go a bit beyond HYRY's answer .我有一个类似的问题,但需要超出HYRY 的回答 To make a package user friendly I wanted ax.legend() to work without requiring users to pass any handles, which can be achieved by passing the label on to the proxy为了使包对用户友好,我希望ax.legend()在不需要用户传递任何句柄的情况下工作,这可以通过将标签传递给代理来实现

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

and then adding the proxy to the axis' patches:然后将代理添加到轴的补丁中:

ax.patches += [proxy]

(do ax = plt.gca() to get the current axis) (执行ax = plt.gca()以获取当前轴)

This is described in more detail in this answer .答案中对此进行了更详细的描述。

请当我使用上面的代码时,它给了我“无法解析名称 plot.figure”。

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

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