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