Я хочу построить 2D-данные в небольшом скрипте и позволить пользователю выбрать vmin/vamx (я называю их порогом и порогом) значений в наборе данных для построения. В идеале я хочу, чтобы все значения ниже/выше vmin/vamx были прозрачными. Средняя точка палитры всегда должна быть на 0 и быть белой!. Я хотел бы иметь как можно больше динамического диапазона. Цвет должен варьироваться от синего для отрицательного до белого при 0 и красного для положительных значений! Пороговое значение и число_контуров устанавливаются пользователем, и масштаб должен быть адаптирован соответствующим образом.
Я нашел несколько советов по различным формам, но не смог заставить их работать на меня. Вот что я нашел до сих пор:
Если я использую решение, предоставленное в третьей ссылке пользователем Paul H, я получаю сообщение об ошибке r, g, b, a = cmap(ri) TypeError: 'str' object is not callable независимо от того, что я делать. Я попытался использовать решение midpointnorm, которое также можно найти по ссылкам выше. Вот небольшой пример:
from numpy import*
import matplotlib
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
import pylab
from matplotlib.colors import Normalize
# class to norm a color sacle so the midpoint is ecatcly in the middle of the colormap . This is usefull if a colormap goes form color1 to white to color2
class MidPointNorm(Normalize):
def __init__(self, midpoint=0, vmin=None, vmax=None, clip=False):
Normalize.__init__(self,vmin, vmax, clip)
self.midpoint = midpoint
def __call__(self, value, clip=None):
if clip is None:
clip = self.clip
result, is_scalar = self.process_value(value)
self.autoscale_None(result)
vmin, vmax, midpoint = self.vmin, self.vmax, self.midpoint
if not (vmin < midpoint < vmax):
raise ValueError("midpoint must be between maxvalue and minvalue.")
elif vmin == vmax:
result.fill(0) # Or should it be all masked? Or 0.5?
elif vmin > vmax:
raise ValueError("maxvalue must be bigger than minvalue")
else:
vmin = float(vmin)
vmax = float(vmax)
if clip:
mask = ma.getmask(result)
result = ma.array(np.clip(result.filled(vmax), vmin, vmax),
mask=mask)
# ma division is very slow; we can take a shortcut
resdat = result.data
#First scale to -1 to 1 range, than to from 0 to 1.
resdat -= midpoint
resdat[resdat>0] /= abs(vmax - midpoint)
resdat[resdat<0] /= abs(vmin - midpoint)
resdat /= 2.
resdat += 0.5
result = ma.array(resdat, mask=result.mask, copy=False)
if is_scalar:
result = result[0]
return result
def inverse(self, value):
if not self.scaled():
raise ValueError("Not invertible until scaled")
vmin, vmax, midpoint = self.vmin, self.vmax, self.midpoint
if cbook.iterable(value):
val = ma.asarray(value)
val = 2 * (val-0.5)
val[val>0] *= abs(vmax - midpoint)
val[val<0] *= abs(vmin - midpoint)
val += midpoint
return val
else:
val = 2 * (val - 0.5)
if val < 0:
return val*abs(vmin-midpoint) + midpoint
else:
return val*abs(vmax-midpoint) + midpoint
# Make some illustrative fake data:
x = np.arange(0, np.pi, 0.1)
y = np.arange(0, 2*np.pi, 0.1)
X, Y = np.meshgrid(x, y)
Z = np.cos(X) * np.sin(Y) * 10
# Make the color i want to use
cdict3 = {'red': ((0.0, 0.0, 0.0),
(0.25, 0.0, 0.0),
(0.5, 0.8, 1.0),
(0.75, 1.0, 1.0),
(1.0, 0.4, 1.0)),
'green': ((0.0, 0.0, 0.0),
(0.25, 0.0, 0.0),
(0.5, 0.9, 0.9),
(0.75, 0.0, 0.0),
(1.0, 0.0, 0.0)),
'blue': ((0.0, 0.0, 0.4),
(0.25, 1.0, 1.0),
(0.5, 1.0, 0.8),
(0.75, 0.0, 0.0),
(1.0, 0.0, 0.0))
}
# Make a modified version of cdict3 with some transparency
# in the middle of the range.
cdict4 = cdict3.copy()
cdict4['alpha'] = ((0.0, 1.0, 1.0),
# (0.25,1.0, 1.0),
(0.5, 0.3, 0.3),
# (0.75,1.0, 1.0),
(1.0, 1.0, 1.0))
#########################################MY questions start here###########################################
threshold=10 # i only want to plot data in the range [-threshold,threshold]
number_of_contours=100
##Instead of just giving a number of contours i thought about giving a predefined list wich contains that speciefies the point of the contours.
##The poinst denisty should be heigher at the Ends of the intervall as the data at theses ends is of higher interest for me. The total number of points should be variable.
#levels = [-threshold, -0.005, -0.001, 0, 0.001,0.005, threshold]
norm = MidPointNorm(midpoint=0,vmin=-threshold, vmax=threshold) # norm the colormap
plt.register_cmap(name='BlueRedAlpha', data=cdict4)
im4 = pylab.contourf(x,y,Z,number_of_contours, cmap='BlueRedAlpha',interpolation='nearest',norm=norm)
#im4 = pylab.contourf(x,y,Z,number_of_contours, cmap='BlueRedAlpha',interpolation='nearest',vmin=-threshold,vmax=threshold,norm=norm)# is it enough to give the norm parameter after the normalisation or do i have to give vmin/vmas to be sure?
sm = plt.cm.ScalarMappable(cmap='BlueRedAlpha', norm=plt.Normalize(vmin=-threshold, vmax=threshold))
sm._A = []
plt.colorbar(sm,extend="both")
plt.show()
Это как-то работает сейчас. Я не понимаю код в классе midpointnorm. Достаточно ли передать параметр norm в containerf после нормализации или мне нужно указать значения vmin/vmax, чтобы быть уверенным, что отображаются только значения между vmin и vmax, и чтобы быть уверенным? Игнорируются ли vmin и vmax, если я указываю параметр нормы?
Но я хотел бы изменить динамический диапазон таким образом, чтобы цветовая шкала не была насыщенной для значений vmin и vmax.
Что еще более важно, на данный момент я отображаю в коде значения от -10 до 10. В моих данных я отображаю значения от -0,03 до 0,03, и все, что близко к этим значениям, уже насыщено, поскольку оно находится в верхней части динамического диапазона. Но этот регион представляет для меня большой интерес. Мне нужна цветовая шкала, которая идет от синего (отрицательного) до красного (положительного). Я хотел бы иметь некоторый контроль над поведением контурных линий.
Я знаю, что вы можете дать список контурных линий для контура. Есть ли у кого-нибудь идея, как заполнить список длиной (number_of_contours+1) в диапазоне от значений от -threshold до +threshold, где расстояние между элементами ближе к положительному и отрицательному концу диапазона? У вас есть другая идея?
MidpointNormalize
(просто придумайте некоторые данные), из которого вы можете объясните что не так. - person ImportanceOfBeingErnest   schedule 10.05.2017