绘图技巧|如何创建自定义colormap

2022-09-23 14:13:46 浏览数 (1)

之前悄悄送了一次可视化书籍,大家都留言催更可视化的推文,这就来了。之所以推这篇文章,是因为看到了一个不错的colormap,苦于没有源文件,只能截图然后识别出颜色,但识别效果看起来又没那么好了(如下图)。

左侧为看到卫星亮温观测colormap,右侧为识别出的colormap

整体上来看也还算可以,但达不到满意的效果,便想根据颜色自行创建一个,成图效果如下。好不好看暂且不说,这篇文章的主要目的是想说:绘图的时候颜色的选择不必拘泥于使用软件提供的colormap,应该根据想要强调的内容选择,比如这里想要强调亮温的不同温度区间,那么使用不同颜色就是一个很好的选择。但应该注意,对于相近区间的颜色应达到一定的对比度,要不然不太好区分。

实现后的效果图

绘图代码如下:

代码语言:javascript复制
((tbb.tbb_13.sortby('latitude')
            .sel(longitude=slice(105, 125), latitude=slice(20, 35)) - 273.15)
            .plot(vmin=-80, vmax=50, cmap=tbb_cmap2, cbar_kwargs=dict(ticks=np.arange(-80, 51, 10))))

颜色调整的代码没那么复杂,主要就是选择以及调整颜色的时候较为繁琐。

代码语言:javascript复制
from matplotlib import cm
from matplotlib import colors

gray = cm.get_cmap('gray', 128)
blues = cm.get_cmap('blues', 128)
yellow = cm.get_cmap('orange1', 128)
orange = cm.get_cmap('orange5', 128)
red = cm.get_cmap('reds', 128)

g = list(gray(np.linspace(0, 1, 80)))
b = list(blues(np.linspace(0, 1, 80)))
y = list(yellow(np.linspace(0, 1, 50)))
o = list(orange(np.linspace(0, 1, 80)))
r = list(red(np.linspace(0, 1, 60)))

tbb_cmap2 = colors.ListedColormap((g   b[30:70:2]   y[40:10:-3]   o[30:50:2]   r[35:55:2])[::-1], N=130)

想着以后创建colormap有不少功能都有用,便把一些能想到的功能都实现了,分门别类写成了函数,比如离散点颜色、多颜色的合并组合等。

代码语言:javascript复制
def discrete_cmap(N, base_cmap=None, start=0, stop=1):
    """Create an N-bin discrete colormap from the specified input map
    :param N(int): 
    :param base_cmap(string, colormap instance or None): colormap used to discrete
    :param start(int): start index of colormap, default 0 
    :param stop(int): stop index of colormap, default 1
    
    :return discrete colormap
    
    Note: 
      if base_cmap is a string or None, you can simply do return plt.cm.get_cmap(base_cmap, N), 
      it works for string, None, or a colormap instance.
      
    Ref:
      https://gist.github.com/jakevdp/91077b0cae40f8f8244a
    """
    from matplotlib import cm

    base = cm.get_cmap(base_cmap)
    color_list = base(np.linspace(start, stop, num=N, endpoint=True))
    cmap_name = base.name   str(N)
    
    return cm.colors.ListedColormap(color_list, color_list, N)

离散点colormap

实现完之后发现 proplot 已经有了这些函数而且功能上要更强大,几乎实现了平时用到的功能。

比如,更高阶一些的控制不同颜色的比例:

代码语言:javascript复制
import proplot as plot
import numpy as np
state = np.random.RandomState(51423)
data = state.rand(30, 30).cumsum(axis=1)

# Generate figure
fig, axs = plot.subplots([[0, 1, 1, 0], [2, 2, 3, 3]], axwidth=2.4, span=False)
axs.format(
    xlabel='xlabel', ylabel='ylabel',
    suptitle='Merging existing colormaps'
)

# SciVisColor examples
title2 = 'SciVisColor example with equal ratios'
cmap2 = plot.Colormap(
    'Greens1_r', 'Oranges1', 'Blues1_r', 'Blues6',
    name='SciVisColorEqual', save=True
)
title3 = 'SciVisColor example'
cmap3 = plot.Colormap(
    'Greens1_r', 'Oranges1', 'Blues1_r', 'Blues6',
    ratios=(1, 3, 5, 10), name='SciVisColor', save=True
)

# Plot examples
for ax, cmap, title in zip(axs, (cmap1, cmap2, cmap3), (title1, title2, title3)):
    m = ax.pcolormesh(data, cmap=cmap, levels=500)
    ax.colorbar(m, loc='b', locator='null', label=cmap.name)
    ax.format(title=title)

proplot的官方文档中给出了非常详细的使用说明,感兴趣的可以点击阅读原文去官方文档看看,这里就不细说了。

—END—

0 人点赞