matplotlib中非对称的Colormap

Python
Article Directory
  1. 1. 解决思路

This article was last updated on <span id="expire-date"></span> days ago, the information described in the article may be outdated.

女朋友说想画一个非对称的Colormap的图出来(也即0还是对应于白色,但是两侧的数值范围是不一样的),于是就研究了一下,最后的效果如下

image-20231020110103054

解决思路

matplotlib里面原本的RdBu_r之类的颜色条两侧的颜色是对称的。在stack overflow上找到的高赞回答使用的函数DivergingNorm再大于3.2版本的matplotlib中已经无法使用了,重命名后的函数TwoSlopeNorm实测也做不出一样的效果。唯一的解决方法就是自己重新定义一个Colormap。matplotlib里面的Colormap有两类,一类是ListedColormap,画出来是离散的;一类是LinearSegmentedColormap,画出来是连续的。这里创建出来的非对称Colormap使用的是LinearSegmentedColormap

为了创建出Colormap我们需要自己定义出所用颜色的RGBA的值,获得的方法就是先将颜色条显示的值映射到索引[0, 1, 2, ..., 255]中,再利用映射后得到的索引取出对应的RGBA的值。由于我们想让0对应的颜色是白色(索引值127),因此0两侧的值是需要分开进行映射的。代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import matplotlib as mpl
from matplotlib.colors import LinearSegmentedColormap, BoundaryNorm, ListedColormap
import matplotlib.pyplot as plt
import numpy as np


if __name__ == '__main__':
# colorbar's value
value_list = np.asarray([-4, -2, 0, 2, 4, 6, 8, 10, 12, 14])
# RdBu_r.N = 256, white(0)'s index is 127
RdBu_r = mpl.colormaps["RdBu_r"]
# calculate the corresponding index in RGBA value of [2, 4, 6, 8]
# get 0 index in value_list
index_0 = np.where(value_list == 0)[0][0]
# take out [0, 2, 4, 6, 8]
value_positive = value_list[index_0:]
# scale it to range: [127, 128, 129, ...., 255]
value_positive = (value_positive - value_positive.min()) / (value_positive.max() - value_positive.min()) * (255 - 127) + 127
value_positive = value_positive.astype(int)
# take out [-4, -2, 0]
value_negative = value_list[:index_0 + 1]
# scale it to range: [0, 1, ...., 127]
value_negative = (value_negative - value_negative.min()) / (value_negative.max() - value_negative.min()) * 127
value_negative = value_negative.astype(int)
# concat positive and negative index
RGBA_index = np.hstack((value_negative[:-1], value_positive))
# get corresponding RGBA value
RGBA_value = RdBu_r(RGBA_index)
# create new colormap
new_RdBu_r = LinearSegmentedColormap.from_list("new_RdBu_r", RGBA_value, 256)

最后使用新创建的new_RdBu_r绘制图像,就能得到想要的效果了。contourf函数也能使用,画出离散的非对称颜色条。

image-20231020111926952

Author: Syize

Permalink: https://blog.syize.cn/2023/10/20/asymmetrical-colormap/

本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Syizeのblog

Comments