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()
.
Ответы
Ответ 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]()