堆叠颜色映射
有没有简单的方法可以把两个现有的颜色图叠加在一起,形成一个新的颜色图?
我想做的是另一个颜色编码的散点图,其中颜色对应的变量从很大的负值到很大的正值变化。我想让接近零的值颜色淡一些——简单来说,我希望能从一个现成的颜色图中(比如说,cm.Blues_r
)为负值选择颜色,而从另一个颜色图中(比如说,cm.Oranges
)为正值选择颜色。
2 个回答
我觉得自己制作颜色映射表会更简单,尤其是颜色不多的时候。这个颜色映射表是橙色、白色和蓝色。
cdict = {'red': [ (0.0, 0.0, 0.0),
(0.475, 1.0, 1.0),
(0.525, 1.0, 1.0),
(1.0, 1.0, 1.0)
],
'green': [ (0.0, 0.0, 0.0),
(0.475, 1.0, 1.0),
(0.525, 1.0, 1.0),
(1.0, 0.65, 0.0)
],
'blue': [ (0.0, 1.0, 1.0),
(0.475, 1.0, 1.0),
(0.525, 1.0, 1.0),
(1.0, 0.0, 0.0)
]
}
rwb_cmap = matplotlib.colors.LinearSegmentedColormap(name = 'rwb_colormap', colors = cdict, N = 256)
颜色映射表其实就是一个字典,用来存储RGB颜色值。对于每种颜色,会有一个包含不同段落的列表。每个段落是沿着z轴的一个点,范围从0到1。颜色的变化是根据这些段落来计算的。
segment z-axis end start
i z[i] v0[i] v1[i]
i+1 z[i+1] v0[i+1] v1[i+1]
i+2 z[i+2] v0[i+2] v1[i+2]
在z[i]
和z[i+1]
之间的层级,会有v1[i]
和v0[i+1]
之间的颜色等等。这就让我们可以“跳跃”颜色。v0[0]
和v1[-1]
是不会被使用的。你可以根据需要使用任意数量的段落。(改编自这里:http://matplotlib.org/api/colors_api.html#matplotlib.colors.LinearSegmentedColormap)
N
是量化级别的数量。所以如果N = 256
,它会为256个级别进行插值。我用256是因为懒惰。我想当你设置N = 6
并且制作4个轮廓时,你得小心。
0.475和0.525是为了确保中间的轮廓确实是白色的。对于级别[-1.5, -0.5, 0.5, 1.5]
,填充的颜色现在是橙色、白色和蓝色。如果我用0.5,那个中间的级别就会是蓝色和橙色的混合。
橙色的RGB代码是255-165-0,或者如果按0到1的比例来看,就是1-0.65-0。
这段内容没有经过测试,但作为初步尝试,我会建议你创建一个简单的 colors.Colormap
的子类。
class split_cmap(colors.Colormap):
def __init__(self, cmap_a, cmap_b, split=.5):
'''Makes a split color map cmap_a is the low range,
cmap_b is the high range
split is where to break the range
'''
self.cmap_a, self.cmap_b = cmap_a, cmap_b
self.split = split
def __call__(self, v):
if v < self.split:
return self.cmap_a(v)
# or you might want to use v / self.split
else:
return self.cmap_b(v)
# or you might want to use (v - self.split) / (1 - self.split)
def set_bad(self,*args, **kwargs):
self.cmap_a.set_bad(*args, **kwargs)
self.cmap_b.set_bad(*args, **kwargs)
def set_over(self, *args, **kwargs):
self.cmap_a.set_over(*args, **kwargs) # not really needed
self.cmap_b.set_over(*args, **kwargs)
def set_under(self, *args, **kwargs):
self.cmap_a.set_under(*args, **kwargs)
self.cmap_b.set_under(*args, **kwargs) # not really needed
def is_gray(self):
return False
你还需要深入了解 Normalize
类。颜色映射只知道范围是 [0, 1]
,所以你需要确保你的 norm
在你想要改变的地方映射到 .5
。
你可能可以将这个功能扩展到接受一个映射列表和分割点,这样就可以有任意数量的颜色映射了。这也需要进行各种合理性检查。
如果你重新规范化输入,你还可以利用这个方法制作任何现有颜色映射的周期性版本,只需传入颜色映射及其反向映射即可。