我是气象学家,经常使用例如“蓝-白色-红色”的颜色图绘制温度场距平值。为了使图表更具可读性,我使用在互联网上“找到”的函数对颜色图进行一定数量的级别(箱)离散化(但我并不完全理解它):
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
如何能够相应地进行修改。有人可以帮助我解决这个问题吗?
2、解决方案
方法 1:
第一个回答者提供了以下解决方案:
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)
方法 2:
第二个回答者提供了以下解决方案:
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()
你也可以很容易地修改它来跨越两个以上的颜色图。