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, соответствующее цвету. Я не могу найти ничего подобного в галерее, и все мои попытки справиться с цветовой панелью потерпели неудачу. Видимо я должен создать коллекцию сюжетов перед попыткой добавить цветовую панель.

существует ли простой способ сделать это? Спасибо.

EDIT (уточнение):

Я хотел сделать что-то вроде этого:

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 это список различных условий для раскрашивания каждой строки. Хотя это немного похоже на Клудж... Я думал, что будет более аккуратный способ сделать это. Мне нравится гибкость

4   52  

4 ответа:

вот один из способов сделать это, все еще используя plt.сюжет.)( В принципе, вы делаете выбрасываемый сюжет и получаете цветную полосу оттуда.

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() без регенерации информации для него.

enter image description here

(Я знаю, это старый вопрос, но...) Colorbars требуют matplotlib.cm.ScalarMappable,plt.plot создает линии, которые не являются скалярными отображаемыми, поэтому, чтобы сделать цветовую панель, нам нужно будет сделать скалярную отображаемую.

ОК. Так что конструктор ScalarMappable принимает cmap и norm экземпляра. (нормы масштабируют данные в диапазоне 0-1, cmaps, с которыми вы уже работали, и берут число между 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 creation to:

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

надеюсь, что это кому-то поможет.

EDIT: для 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)

EDIT: для 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)

вот немного упрощенный пример, вдохновленный верхним ответом, данным Борис и крючок (Спасибо за отличную идею!):

1. дискретные colorbar

дискретные colorbar является более сложным, потому что цветов создается с помощью mpl.cm.get_cmap() не является отображаемым изображением, необходимым как

поскольку другие ответы здесь пытаются использовать фиктивные графики, что не очень хороший стиль, вот общий код для

дискретные colorbar

дискретная цветовая панель создается таким же образом, как и непрерывная цветовая панель, только с другой нормализацией. В этом случае 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([])

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