Matplotlib-为一系列线条图添加色彩条

我有一个两个变量(x,y)的线性图序列,对应一个变量 z 的许多不同值。我通常会像这样添加具有图例的线性图:

import matplotlib.pyplot as plt


fig = plt.figure()
ax  = fig.add_subplot(111)
# suppose mydata is a list of tuples containing (xs, ys, z)
# where xs and ys are lists of x's and y's and z is a number.
legns = []
for(xs,ys,z) in mydata:
pl = ax.plot(xs,ys,color = (z,0,0))
legns.append("z = %f"%(z))
ax.legends(legns)
plt.show()

但我有太多的图表和传说将涵盖图表。我更希望有一个颜色条,指示与颜色对应的 z 值。我在画廊里找不到这样的东西我所有的尝试都失败了。显然,在试图添加色彩条之前,我必须创建一个情节集合。

有什么简单的方法吗? 谢谢。

编辑(澄清) :

我想做这样的事情:

import matplotlib.pyplot as plt
import matplotlib.cm     as cm


fig = plt.figure()
ax  = fig.add_subplot(111)
mycmap = cm.hot
# suppose mydata is a list of tuples containing (xs, ys, z)
# where xs and ys are lists of x's and y's and z is a number between 0 and 1
plots = []
for(xs,ys,z) in mydata:
pl = ax.plot(xs,ys,color = mycmap(z))
plots.append(pl)
fig.colorbar(plots)
plt.show()

但是根据 Matplotlib 引用,这不会起作用,因为不管这意味着什么,图的列表都不是“可映射的”。

我已经使用 LineCollection创建了一个替代情节函数:

def myplot(ax,xs,ys,zs, cmap):
plot = lc([zip(x,y) for (x,y) in zip(xs,ys)], cmap = cmap)
plot.set_array(array(zs))
x0,x1 = amin(xs),amax(xs)
y0,y1 = amin(ys),amax(ys)
ax.add_collection(plot)
ax.set_xlim(x0,x1)
ax.set_ylim(y0,y1)
return plot

xsys是 x 和 y 坐标的列表,而 zs是使每一行着色的不同条件的列表。这感觉有点像一个包围... 我认为有一个更整洁的方式来做到这一点。我喜欢 plt.plot()功能的灵活性。

62174 次浏览

这里有一种在仍然使用 plt.plot ()的情况下执行此操作的方法。基本上,你做一个一次性的情节,并从那里得到的色彩。

import matplotlib as mpl
import matplotlib.pyplot as plt


min, max = (-40, 30)
step = 10


# Setting up a colormap that's a simple transtion
mymap = mpl.colors.LinearSegmentedColormap.from_list('mycolors',['blue','red'])


# Using contourf to provide my colorbar info, then clearing the figure
Z = [[0,0],[0,0]]
levels = range(min,max+step,step)
CS3 = plt.contourf(Z, levels, cmap=mymap)
plt.clf()


# Plotting what I actually want
X=[[1,2],[1,2],[1,2],[1,2]]
Y=[[1,2],[1,3],[1,4],[1,5]]
Z=[-40,-20,0,30]
for x,y,z in zip(X,Y,Z):
# setting rgb color based on z normalized to my range
r = (float(z)-min)/(max-min)
g = 0
b = 1-r
plt.plot(x,y,color=(r,g,b))
plt.colorbar(CS3) # using the colorbar info I got from contourf
plt.show()

有点浪费,但很方便。如果您创建多个绘图,比如可以调用 plt.color bar () ,而不需要为其重新生成信息,那么这也不会非常浪费。

enter image description here

(我知道这是一个老问题,但是...)颜色条需要一个 matplotlib.cm.ScalarMappableplt.plot产生的线是不标量映射,因此,为了使一个颜色条,我们将需要使一个标量映射。

好吧。因此,ScalarMappable的构造函数接受一个 cmap和一个 norm实例。(规范将数据缩放到0-1范围内,cmap 您已经使用过,取0-1之间的一个数字并返回一个颜色)。所以对你来说:

import matplotlib.pyplot as plt
sm = plt.cm.ScalarMappable(cmap=my_cmap, norm=plt.normalize(min=0, max=1))
plt.colorbar(sm)

因为您的数据已经在0-1的范围内,所以您可以将 sm的创建简化为:

sm = plt.cm.ScalarMappable(cmap=my_cmap)

希望这对谁有帮助。

编辑 : 对于 matplotlib v1.2或更高版本,代码变成:

import matplotlib.pyplot as plt
sm = plt.cm.ScalarMappable(cmap=my_cmap, norm=plt.normalize(vmin=0, vmax=1))
# fake up the array of the scalar mappable. Urgh...
sm._A = []
plt.colorbar(sm)

编辑 : 对于 matplotlib v1.3或更高版本,代码变成:

import matplotlib.pyplot as plt
sm = plt.cm.ScalarMappable(cmap=my_cmap, norm=plt.Normalize(vmin=0, vmax=1))
# fake up the array of the scalar mappable. Urgh...
sm._A = []
plt.colorbar(sm)

编辑 : 对于 matplotlib v3.1或更大的简化,可以:

import matplotlib.pyplot as plt
sm = plt.cm.ScalarMappable(cmap=my_cmap, norm=plt.Normalize(vmin=0, vmax=1))
plt.colorbar(sm)

Here is a slightly simplied example inspired by the top answer given by 鲍里斯 and 上钩了 (Thanks for the great idea!):

1. 离散色条

离散的颜色条更为复杂,因为由 mpl.cm.get_cmap()生成的颜色图不是作为 colorbar()参数所需的可映射图像。需要生成如下所示的虚拟映射:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl


n_lines = 5
x = np.linspace(0, 10, 100)
y = np.sin(x[:, None] + np.pi * np.linspace(0, 1, n_lines))
c = np.arange(1, n_lines + 1)


cmap = mpl.cm.get_cmap('jet', n_lines)


fig, ax = plt.subplots(dpi=100)
# Make dummie mappable
dummie_cax = ax.scatter(c, c, c=c, cmap=cmap)
# Clear axis
ax.cla()
for i, yi in enumerate(y.T):
ax.plot(x, yi, c=cmap(i))
fig.colorbar(dummie_cax, ticks=c)
plt.show();

这将产生一个具有离散色彩条的情节: enter image description here


2. 连续色带

连续颜色条是较少涉及的,因为 mpl.cm.ScalarMappable()允许我们为 colorbar()获得一个“图像”。

import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl




n_lines = 5
x = np.linspace(0, 10, 100)
y = np.sin(x[:, None] + np.pi * np.linspace(0, 1, n_lines))
c = np.arange(1, n_lines + 1)


norm = mpl.colors.Normalize(vmin=c.min(), vmax=c.max())
cmap = mpl.cm.ScalarMappable(norm=norm, cmap=mpl.cm.jet)
cmap.set_array([])


fig, ax = plt.subplots(dpi=100)
for i, yi in enumerate(y.T):
ax.plot(x, yi, c=cmap.to_rgba(i + 1))
fig.colorbar(cmap, ticks=c)
plt.show();

这将产生一个具有连续颜色条的情节: enter image description here

[边注] 在这个例子中,我个人不知道为什么需要 cmap.set_array([])(否则我们会得到错误消息)。如果有人了解引擎盖下的原理,请评论:)

由于这里的其他答案尝试使用虚构的图形,这并不是一个很好的风格,因此这里有一个用于

离散色条

生成离散色条的方式与创建连续色条的方式相同,只是使用了不同的标准化。在这种情况下,应该使用 BoundaryNorm

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors


n_lines = 5
x = np.linspace(0, 10, 100)
y = np.sin(x[:, None] + np.pi * np.linspace(0, 1, n_lines))
c = np.arange(1., n_lines + 1)


cmap = plt.get_cmap("jet", len(c))
norm = matplotlib.colors.BoundaryNorm(np.arange(len(c)+1)+0.5,len(c))
sm = plt.cm.ScalarMappable(norm=norm, cmap=cmap)
sm.set_array([])  # this line may be ommitted for matplotlib >= 3.1


fig, ax = plt.subplots(dpi=100)
for i, yi in enumerate(y.T):
ax.plot(x, yi, c=cmap(i))
fig.colorbar(sm, ticks=c)
plt.show()

enter image description here