我想在一个小脚本中绘制2D数据,并让用户选择要绘制的数据集中的值的vmin / vamx(我称之为阈值和阈值)。理想情况下,我希望vmin / vamx下方/上方的所有值都是透明的。色图的中点应始终为0和白色!我想拥有尽可能多的动态范围。颜色应该从蓝色到负值到白色在0到红色到正值!值阈值和number_of_contours由用户设置,并且必须相应地调整比例。 我在各种表格上找到了一些提示,但无法让它们对我起作用。这是我到目前为止发现的: Solution1 Solution2 Solution3
如果我使用用户Paul H在第三个链接中提供的解决方案,我会收到错误 r,g,b,a = cmap(ri)TypeError:' str'无论我做什么,对象都不可调用。我尝试使用解决方案" 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()
现在以某种方式运作。我不明白class midpointnorm中的代码。是否足以在规范化之后将norm参数传递给contourf,或者我必须给出vmin / vmax值以确保只绘制vmin和vmax之间的值并确定?如果给出一个norm参数,是否会忽略vmin和vmax?
但我希望以某种方式改变动态范围,即vmin和vmax值的色标不饱和。
更重要的是,目前我在代码中显示的值介于-10和10之间。在我的Datas i中,绘制的值介于-0.03和0.03之间,接近这些值的所有值都已经饱和,因为它位于动态范围的上端。但这个地区对我来说很有意义。我需要一个从蓝色(负面)到红色(正面)的色阶。我想对轮廓线的行为有一些控制。 我知道你可以给contourf一个轮廓线列表。有人知道如何填充长度(number_of_contours + 1)的列表,范围从&#34; -threshold&#34;到&#34; +门槛&#34;元素的间距是否在范围的正负端更接近? 你还有其他想法吗?
提前谢谢