我想使用 matplotlib 中的颜色图,例如 CMRmap。但我不想在开头使用“黑色”颜色,最后使用“白色”颜色。我有兴趣使用中间颜色绘制我的数据。我认为 ppl 经常使用它,但我在互联网上搜索并且无法找到任何简单的解决方案。如果有人提出任何解决方案,我将不胜感激。
5 回答
静态方法colors.LinearSegmentedColormap.from_list可用于创建新的LinearSegmentedColormaps。下面,我在 0.2 和 0.8 之间的 100 个点处对原始颜色图进行采样:
cmap(np.linspace(0.2, 0.8, 100))
并使用这些颜色生成新的颜色图:
import matplotlib.pyplot as plt
import matplotlib.colors as colors
import numpy as np
def truncate_colormap(cmap, minval=0.0, maxval=1.0, n=100):
new_cmap = colors.LinearSegmentedColormap.from_list(
'trunc({n},{a:.2f},{b:.2f})'.format(n=cmap.name, a=minval, b=maxval),
cmap(np.linspace(minval, maxval, n)))
return new_cmap
arr = np.linspace(0, 50, 100).reshape((10, 10))
fig, ax = plt.subplots(ncols=2)
cmap = plt.get_cmap('jet')
new_cmap = truncate_colormap(cmap, 0.2, 0.8)
ax[0].imshow(arr, interpolation='nearest', cmap=cmap)
ax[1].imshow(arr, interpolation='nearest', cmap=new_cmap)
plt.show()
左侧的图显示了使用原始颜色图的图像(在本例中为jet
)。右边的图显示了相同的图像,使用new_cmap
.
我最近自己也在努力解决这个问题。以下是一些可能的解决方案:
尝试在绘图函数中使用vmin
,vmax
关键字参数。例如,假设您有介于 0 和 1 之间的数据,但不喜欢在 0 和 1 的颜色图的极端使用的颜色。
import matplotlib.pyplot as plt
import matplotlib.cm as cm
my_cmap = cm.spectral_r
my_cmap.set_over('c')
my_cmap.set_under('m')
plt.pcolor(data, vmin=0.01, vmax=0.99, cmap=my_cmap)
这将强制将整个颜色图用于 0.01 和 0.99 之间的值,并且上面和下面的值将分别为青色和洋红色。这可能无法完全解决您的问题,但如果您喜欢特定的颜色图并希望它在两端都有额外的颜色,它可能会很有用。
如果您真的想更改颜色图,请查看此处的文档和此处的LinearSegmentedColormap文档。
第一的,
import matplotlib.cm as cm
cdict = cm.get_cmap('spectral_r')._segmentdata
这将返回组成颜色图的所有颜色的字典。然而,弄清楚如何修改这本字典是相当棘手的。这个字典有三个键,red, green, blue
. cdict[key]
返回表单的值列表(x, y0, y1)
。让我们看一下 的两个连续元素cdict['red']
:
((0.0, 0.0, 0.0)
(0.5, 1.0, 1.0),...
这意味着z
(假设我们正在做 apcolor
或imshow
)介于 0.0 和 0.5 之间的数据将具有与该数据相关联的 rgb 颜色的红色分量将从 0.0(无红色)增加到 1.0(最大红色)。这意味着要更改颜色图的颜色,您必须检查 rgb 的三个分量中的每一个如何在您感兴趣的颜色图区域内插值。只需确保对于每种颜色,第一个和最后一个条目分别以x=0
和开头x=1
;您必须覆盖 [0, 1] 的整个范围。
如果要更改开始和结束颜色,请尝试
import matplotlib.cm as cm
from matplotlib.colors import LinearSegmentedColormap
cdict = cm.get_cmap('spectral_r')._segmentdata
cdict['red'][0] = (0, 0.5, 0.5) # x=0 for bottom color in colormap
cdict['blue'][0] = (0, 0.5, 0.5) # y=0.5 gray
cdict['green'][0] = (0, 0.5, 0.5) # y1=y for simple interpolation
cdict['red'][-1] = (1, 0.5, 0.5) # x=1 for top color in colormap
cdict['blue'][-1] = (1, 0.5, 0.5)
cdict['green'][-1] = (1, 0.5, 0.5)
my_cmap = LinearSegmentedColormap('name', cdict)
然后在您的绘图功能中使用此 cmap。
我想做的是将spectral_r
颜色图末尾的灰色更改为纯白色。这是使用
# Using imports from above
cdict = matplotlib.cm.get_cmap('spectral_r')._segmentdata
cdict['red'][0] = (0, 1, 1)
cdict['green'][0] = (0, 1, 1)
cdict['blue'][0] = (0, 1, 1)
my_cmap = LinearSegmentedColormap('my_cmap', cdict)
在我的 CMasher 包中,我提供了get_sub_cmap()
-function ( https://cmasher.readthedocs.io/user/usage.html#sub-colormaps ),它接受一个颜色图和一个范围,并返回一个包含请求范围的新颜色图。
因此,例如,如果您想获取颜色图的 20% 到 80% 之间的viridis
颜色,您可以这样做:
import cmasher as cmr
cmap = cmr.get_sub_cmap('viridis', 0.2, 0.8)
PS:不要使用jet
(或CMRmap
),因为它们在感知上不是统一的顺序。相反,请使用 matplotlib 中的 5 个正确颜色图或 cmocean 或我的 CMasher 提供的颜色图。
编辑:在最新版本的 CMasher 中,还可以使用相同的函数通过向函数提供要采用的段数来从任何颜色图中创建离散/定性颜色图。例如,如果您想创建viridis
20% 到 80% 范围内的定性颜色图,您可以这样做:
cmap = cmr.get_sub_map('viridis', 0.2, 0.8, N=5)
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
def truncate_colormap(cmap, minval=0.0, maxval=1.0, n=100):
'''
https://stackoverflow.com/a/18926541
'''
if isinstance(cmap, str):
cmap = plt.get_cmap(cmap)
new_cmap = mpl.colors.LinearSegmentedColormap.from_list(
'trunc({n},{a:.2f},{b:.2f})'.format(n=cmap.name, a=minval, b=maxval),
cmap(np.linspace(minval, maxval, n)))
return new_cmap
cmap_base = 'jet'
vmin, vmax = 0.2, 0.8
cmap = truncate_colormap(cmap_base, vmin, vmax)
fig, ax = plt.subplots(nrows=2)
sm = mpl.cm.ScalarMappable(cmap=cmap_base)
cbar = plt.colorbar(sm, cax=ax[0], orientation='horizontal')
sm = mpl.cm.ScalarMappable(cmap=cmap)
cbar = plt.colorbar(sm, cax=ax[1], orientation='horizontal')
plt.show()
这是对嵌入绘图功能的先前答案的改编:
import matplotlib.pyplot as plt
import matplotlib.colors as colors
import numpy as np
################### Function to truncate color map ###################
def truncate_colormap(cmapIn='jet', minval=0.0, maxval=1.0, n=100):
'''truncate_colormap(cmapIn='jet', minval=0.0, maxval=1.0, n=100)'''
cmapIn = plt.get_cmap(cmapIn)
new_cmap = colors.LinearSegmentedColormap.from_list(
'trunc({n},{a:.2f},{b:.2f})'.format(n=cmapIn.name, a=minval, b=maxval),
cmapIn(np.linspace(minval, maxval, n)))
arr = np.linspace(0, 50, 100).reshape((10, 10))
fig, ax = plt.subplots(ncols=2)
ax[0].imshow(arr, interpolation='nearest', cmap=cmapIn)
ax[1].imshow(arr, interpolation='nearest', cmap=new_cmap)
plt.show()
return new_cmap
cmap_mod = truncate_colormap(minval=.2, maxval=.8) # calls function to truncate colormap
如果您需要多次调用该函数,则具有嵌入绘图的紧凑函数会很有帮助。