如何在matplotlib中提取色图的子集作为新的色图?

时间:2013-09-20 21:17:50

标签: python matplotlib

我想使用matplotlib中的colormap,例如CMRmap。但我不想在开头使用“黑色”颜色,最后使用“白色”颜色。我有兴趣使用中间颜色绘制我的数据。我认为人们经常使用它,但我在互联网上搜索,无法找到任何简单的解决方案。如果有人建议任何解决方案,我将不胜感激。

5 个答案:

答案 0 :(得分:49)

staticmethod 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()

enter image description here

左侧的图表使用原始色彩图显示图像(在此示例中为jet)。右侧的图表使用new_cmap显示相同的图像。

答案 1 :(得分:6)

我最近才在自己身上挣扎。以下是一些可能的解决方案:


尝试在绘图功能中使用vminvmax个关键字参数。例如,假设您的数据介于0和1之间,但不喜欢0和1的colormap极值所使用的颜色。

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之间的值,而高于和低于的值将分别为青色和品红色。这可能无法准确解决您的问题,但如果您喜欢特定的色彩图并希望它在两端都有其他颜色,那么它可能会很有用。


如果您确实想要更改色彩映射,请查看文档hereLinearSegmentedColormap here

首先,

import matplotlib.cm as cm
cdict = cm.get_cmap('spectral_r')._segmentdata

这将返回构成色彩映射的所有颜色的字典。然而,弄清楚如何改变这本字典是非常棘手的。这个词有三个键red, green, bluecdict[key]会返回(x, y0, y1)形式的值列表。我们来看看cdict['red']的两个连续元素:

((0.0, 0.0, 0.0)
 (0.5, 1.0, 1.0),...

这意味着带有z的数据(假设我们正在做pcolorimshow)介于0.0和0.5之间将使rgb颜色的红色成分与之相关联数据将从0.0(无红色)增加到1.0(最大红色)。这意味着要更改色彩映射的颜色,您必须检查rgb的三个组件中的每个组件如何在您感兴趣的色彩映射区域中进行插值。只需确保对于每种颜色,第一个最后一个条目分别以x=0x=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)

答案 2 :(得分:2)

在我的 CMasher 包中,我提供了 get_sub_cmap() 函数 (https://cmasher.readthedocs.io/user/usage.html#sub-colormaps),它接受一个颜色图和一个范围,并返回一个包含请求范围的新颜色图。

因此,例如,如果您想采用 viridis 颜色图的 20% 到 80% 之间的颜色,您可以这样做:

import cmasher as cmr

cmap = cmr.get_sub_cmap('viridis', 0.2, 0.8)

PS:不要使用jet(或CMRmap),因为它们在感知上不是统一的顺序。 相反,使用 matplotlib 中的 5 个正确颜色图或由 cmocean 或我的 CMasher 提供的颜色图。

编辑:在最新版本的 CMasher 中,还可以使用相同的函数通过为函数提供要采用的段数来从任何颜色图创建离散/定性颜色图。 例如,如果您想在 20% 到 80% 范围内创建 viridis 的定性颜色图,您可以使用:

cmap = cmr.get_sub_map('viridis', 0.2, 0.8, N=5)

答案 3 :(得分:1)

这里是对先前答案的改编,其中嵌入了绘图功能:

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

visual of output from truncate_colormap():

如果您需要多次调用函数,则具有嵌入绘图功能的紧凑函数将很有帮助。

答案 4 :(得分:0)

previous answer带来的可视化效果略有改善(受that的启发)

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()

enter image description here