Python Matplotlib-将颜色条添加到一系列线图中

Python Matplotlib-将颜色条添加到一系列线图中,python,matplotlib,colorbar,Python,Matplotlib,Colorbar,我有两个变量(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.

我有两个变量(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()
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()
但是我有太多的图表,图例会覆盖图表。我希望有一个颜色条,指示对应于颜色的z值。我在galery中找不到类似的东西,我所有的尝试都失败了。显然,在尝试添加颜色条之前,我必须创建一个绘图集合

有没有一个简单的方法可以做到这一点?谢谢

编辑(澄清):

我想做这样的事情:

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

xs
ys
是x和y坐标列表,而
zs
是为每一行着色的不同条件列表。但感觉有点像是一根棍棒。。。我认为会有一个更简洁的方法来做到这一点。我喜欢
plt.plot()
函数的灵活性

这里有一种方法可以在仍然使用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.colorbar()进行多个绘图,而无需重新生成它的信息,这也不是很浪费

(我知道这是一个老问题,但…)色条需要一个
matplotlib.cm.ScalarMappable
plt.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)
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)
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)

以下是一个略为简化的示例,其灵感来源于和给出的顶级答案(感谢您的好主意!):

1. 离散色条 离散的colorbar更为复杂,因为由
mpl.cm.get\u cmap()
生成的colormap不是作为
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();
这将生成带有离散色条的绘图:


2. 连续色条 由于
mpl.cm.ScalarMappable()
允许我们为
colorbar()获取“图像”,因此连续色条较少涉及

这将生成具有连续色条的绘图:


[旁注]在这个例子中,我个人不知道为什么需要
cmap.set\u数组([])
(否则我们会收到错误消息)。如果有人理解幕后的原则,请发表评论:)

因为这里的其他答案尝试使用虚拟图,这不是很好的风格,这里是

离散色条 离散色条的生成方式与创建连续色条的方式相同,只是规格化不同。在这种情况下,应使用
边界规范

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

您的问题有点让人困惑——您是在尝试制作与z值颜色相对应的颜色条,还是只是创建一个颜色条,可以在一系列线图中附加到一个图形的侧面以节省空间?颜色条的一种替代方法可能是在定义图例时使用
bbox\u to\u anchor
在图形边界之外创建一个包含性图例。只需附加一个颜色条即可。我不介意使用一个内置的彩色地图。即使在图表之外,图例也不是一个可行的选择。我在这个图表中有50多行。此外,一个传奇将是远远超过读者需要的信息。这会把图表弄得乱七八糟。它们是针对不同温度值的模拟曲线。色条将充分告知读者每条曲线(热、冷、极冷)的温度范围。每条线路的准确温度值并不重要。实现这一点的方法是通过线路收集,就像您已经做的一样(尽管您可以稍微清理一些调用)
plot
返回
Line2D
对象,这些对象本身具有离散颜色,而不是可以显示在颜色栏上的“可映射”颜色。话虽如此,您可以从colormap创建一个“假”标量可映射对象,并为其显示颜色栏,但这不仅仅是使用线条集合。我知道这非常古老,但这似乎也很相关:伟大的解决方案!(对于这个问题,似乎没有一个简单的解决方案;除了使用linecollection)这个问题的不错的解决方案,但我认为更好的解决方案是创建一个标量可映射实例(参见我的答案)。有没有办法使用颜色条来实现这一点,该颜色条会在颜色方案中产生连续的变化,而不是带状的变化,上图中显示的离散?需要一些改进:根据颜色图,我猜蓝线的Z=-35,即使施加了-40。我更喜欢这种方法:这也不起作用<代码>类型错误:uuu init_uuuu()得到一个意外的关键字参数“max”
这对我来说很有效:我只是使用了linspace而不是z1,因为我正在绘制颜色映射本身,所以数字是任意的。:)看起来matplotlib v1.3的示例应该进行更多的调整,当前