Подтвердить что ты не робот

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 and y 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 and y 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().

4b9b3361

Ответ 1

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

import matplotlib as mpl
import matplotlib.pyplot as plt

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

# Setting up a colormap that 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

Ответ 2

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

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)

Ответ 3

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

1. Дискретный цветовой бар

Дискретная цветовая панель более сложна, потому что mpl.cm.get_cmap() сгенерированная 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([]) (в противном случае мы получили бы сообщения об ошибках). Если кто-то понимает принципы под капотом, пожалуйста, прокомментируйте :)

Ответ 4

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

Дискретный цветовой бар

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