Python 修改离散LinearSegmentedColormap
我是一名气候学家,经常使用“蓝-白-红”彩色地图绘制温度场等异常情况。为了使绘图更具可读性,我使用我在互联网上“找到”的一个函数(但我并不真正理解它),将彩色地图离散化为一定数量的级别(箱): 大概是这样的:Python 修改离散LinearSegmentedColormap,python,matplotlib,Python,Matplotlib,我是一名气候学家,经常使用“蓝-白-红”彩色地图绘制温度场等异常情况。为了使绘图更具可读性,我使用我在互联网上“找到”的一个函数(但我并不真正理解它),将彩色地图离散化为一定数量的级别(箱): 大概是这样的: import matplotlib.pyplot as plt import numpy as np from matplotlib import cm import matplotlib.colors as cols from numpy.random import randn def
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm
import matplotlib.colors as cols
from numpy.random import randn
def cmap_discretize(cmap, N):
colors_i = np.concatenate((np.linspace(0, 1., N), (0.,0.,0.,0.)))
colors_rgba = cmap(colors_i)
indices = np.linspace(0, 1., N+1)
cdict = {}
for ki,key in enumerate(('red','green','blue')):
cdict[key] = [ (indices[i], colors_rgba[i-1,ki], colors_rgba[i,ki]) for i in xrange(N+1) ]
# Return colormap object.
return cols.LinearSegmentedColormap(cmap.name + "_%d"%N, cdict, 1024)
cmap_disc= cmap_discretize(cm.RdBu_r,12)
fig, ax = plt.subplots()
data = np.clip(randn(250, 250), -1, 1)
cax = ax.pcolor(data, cmap=cmap_disc)
plt.colorbar(cax)
plt.show()
这导致
现在我想将最中间的两段(即接近0的那两段)设置为白色,因为我不想显示非常小的偏差
我的目标是以类似的方式结束:
我真的很难弄清楚这些LinearSegmentedColormap是如何相应地修改的。有人能帮我吗 您找到的函数构建了一个数据结构(在
cdict
中),用于定义不执行任何插值的段(即,行i
中的y1
始终与行i+1
中的y0
相同,这给出了恒定或离散的颜色“带”)
cdict
是一个奇怪的数据结构,一个包含键'red'
、'green'
和'blue'
的字典。每个键的值都是一个列表结构,包含(x,y0,y1)
形式的元组x
是颜色贴图坐标,它是介于0和1之间的某个浮点数y0
是x
左侧的颜色值,y1
是x
右侧的颜色值。颜色在x
的连续值之间线性插值;如果第一个元组由(0,A,B)
给出,第二个元组由(X,C,D)
给出,那么0
和X
之间的点t
的颜色将由(t-0)/(X-0)*(C-B)+B给出
出于您的目的,您的函数运行得很好,但需要将颜色贴图中间附近的“条带”替换为白色。您可以尝试以下方法:
def cmap_discretize(cmap, N):
colors_i = np.concatenate((np.linspace(0, 1., N), (0.,0.,0.,0.)))
colors_rgba = cmap(colors_i)
indices = np.linspace(0, 1., N+1)
cdict = {}
for ki,key in enumerate(('red','green','blue')):
cdict[key] = [ (indices[i], colors_rgba[i-1,ki], colors_rgba[i,ki]) for i in xrange(N+1) ]
# "white out" the bands closest to the middle
num_middle_bands = 2 - (N % 2)
middle_band_start_idx = (N - num_middle_bands) // 2
for middle_band_idx in range(middle_band_start_idx,
middle_band_start_idx + num_middle_bands):
for key in cdict.keys():
old = cdict[key][middle_band_idx]
cdict[key][middle_band_idx] = old[:2] + (1.,)
old = cdict[key][middle_band_idx + 1]
cdict[key][middle_band_idx + 1] = old[:1] + (1.,) + old[2:]
# Return colormap object.
return cols.LinearSegmentedColormap(cmap.name + "_%d"%N, cdict, 1024)
让我们从浏览已有的代码开始
# get some uniformly sampled data, padded out a bit
colors_i = np.concatenate((np.linspace(0, 1., N), (0.,0.,0.,0.)))
# sample the input colormap at our sample points
colors_rgba = cmap(colors_i)
# indices for color map
indices = np.linspace(0, 1., N+1)
# dict to pass to the LinearSegmentedColormap
cdict = {}
# loop over the colors
for ki,key in enumerate(('red','green','blue')):
# in each color assemble a list that looks like
#[...,
# (indices[2], colors_rgba[1,ki], colors_rgba[2,ki]),
# (indices[3], colors_rgba[2,ki], colors_rgba[3,ki]),
# ....]
cdict[key] = [ (indices[i], colors_rgba[i-1,ki], colors_rgba[i,ki]) for i in xrange(N+1) ]
# The color for a number between [indices[2], indices[3]] are interpolated
# between colors_rgba[2,ki] and colors_rgba[2,ki] which are the same
# which is what gives you the discrete blocks.
# Construct and return colormap object.
return cols.LinearSegmentedColormap(cmap.name + "_%d"%N, cdict, 1024)
现在的问题是如何在中间创建一个“双”白色带的彩色地图。我会更改函数位,使其包含两个颜色贴图(顶部和底部)
导入matplotlib.pyplot作为plt
将numpy作为np导入
从matplotlib导入cm
将matplotlib.colors导入为cols
从numpy.random导入randn
def cmap_double_离散化(cmap_底部,cmap_顶部,N,分割=.5):
"""
使用两个现有颜色贴图生成已描述的颜色贴图
参数
----------
cmap_底部:cmap
底部cmap
cmap_顶部:cmap
顶级cmap
N:int
每个颜色贴图中的存储箱数
拆分:浮动,可选
加入地图的位置必须在[0,1]中
"""
#健康检查
断言split<1和split>0
#建立数据结构
cdict={lab:[]用于实验室输入('red'、'green'、'blue'))
#在一个奇妙的循环中这样做,a)节省打字,b)使操作变得容易
#改装以进行任意拆分
对于cmap,在拉链中结束((cmap_底部,cmap_顶部),((0,拆分),(拆分,1)):
#为每个颜色贴图运行整个范围
颜色i=np.连接((np.linspace(0,1,N),(0,0,0,0.))
#映射颜色
颜色\u rgba=cmap(颜色\u i)
#获取值
索引=np.linspace(结束[0],结束[1],N+1,结束=True)
对于ki,输入枚举(‘红色’、‘绿色’、‘蓝色’):
cdict[key].xrange(N+1)中i的扩展((索引[i],颜色[i-1,ki],颜色[i,ki]))
#打印cdict
#返回colormap对象。
返回cols.LinearSegmentedColormap(cmap.name+“u%d”%N,cdict,1024)
红色=红色:[(0,0,1),
(1, 1, 0)],
“蓝色”:[(0,0,0),
(1, 1, 0)],
“绿色”:[(0,0,0),
(1, 1, 0)]}
蓝色(cdict={'blue':[(0,0,1),
(1, 1, 0),],
“红色”:[(0,0,1),
(1, 0, 0)],
“绿色”:[(0,0,1),
(1, 0, 0)]}
红色\u cmap=cols.LinearSegmentedColormap('red',红色\u cdict,1024)
blue\u cmap=cols.LinearSegmentedColormap('blue',blue\u cdict,1024)
测试cmap=cmap双离散化(红色cmap,蓝色cmap,6)
#这些不是真的变成白色的!
#test\u cmap=cmap\u double\u离散化(cm.get\u cmap('Reds\u r'),cm.get\u cmap('Blues'),6)
图,ax=plt.子批次()
数据=np.clip(随机数(250250),-1,1)
cax=ax.pcolor(数据,cmap=test\u cmap)
打印颜色条(cax)
plt.show()
您可以很容易地修改它,将其拆分为两个以上的颜色贴图。请阅读:它清楚地描述了颜色贴图的工作原理。使用代码并传入两个描述的颜色贴图,您可能会得到一些启发。这很好,但我仍然需要通过它来理解ITI有点轻而易举地达到这样的效果,因为你正在用一种非透明的方式使彩色地图非线性。这也是有效的,但不支持中间有白色的预定义彩色图(如BWR、地震、RdBu、RdGy……)。还是非常感谢你的努力
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm
import matplotlib.colors as cols
from numpy.random import randn
def cmap_double_discretize(cmap_bottom, cmap_top, N, split=.5):
"""
Generates a descritized color map using two existing color maps
Parameters
----------
cmap_bottom : cmap
The bottom cmap
cmap_top : cmap
The top cmap
N : int
The number of bins in each color map
split : float, optional
Where to join the maps, must be in [0, 1]
"""
# sanity check
assert split < 1 and split > 0
# set up the data structure
cdict = {lab: [] for lab in ('red','green','blue')}
# do this in a fancy loop to a) save typing, b) make it easy to
# retrofit to do arbitrary splits
for cmap, ends in zip((cmap_bottom, cmap_top), ((0, split), (split, 1))):
# run over the _whole_ range for each color map
colors_i = np.concatenate((np.linspace(0, 1., N), (0.,0.,0.,0.)))
# map the color
colors_rgba = cmap(colors_i)
# get the values
indices = np.linspace(ends[0], ends[1], N+1, endpoint=True)
for ki,key in enumerate(('red','green','blue')):
cdict[key].extend((indices[i], colors_rgba[i-1,ki], colors_rgba[i,ki]) for i in xrange(N+1))
# print cdict
# Return colormap object.
return cols.LinearSegmentedColormap(cmap.name + "_%d"%N, cdict, 1024)
red_cdict = {'red': [(0, 0, 1),
(1, 1, 0)],
'blue': [(0, 0, 0),
(1, 1, 0)],
'green': [(0, 0, 0),
(1, 1, 0)]}
blue_cdict = {'blue': [(0, 0, 1),
(1, 1, 0),],
'red': [(0, 0, 1),
(1, 0, 0)],
'green': [(0, 0, 1),
(1, 0, 0)]}
red_cmap = cols.LinearSegmentedColormap('red', red_cdict, 1024)
blue_cmap = cols.LinearSegmentedColormap('blue', blue_cdict, 1024)
test_cmap = cmap_double_discretize(red_cmap, blue_cmap, 6)
# these don't actually go to white!
# test_cmap = cmap_double_discretize(cm.get_cmap('Reds_r'), cm.get_cmap('Blues'), 6)
fig, ax = plt.subplots()
data = np.clip(randn(250, 250), -1, 1)
cax = ax.pcolor(data, cmap=test_cmap)
plt.colorbar(cax)
plt.show()