使用matplotlib为离散间隔数据绘制colorbar

首页 / 科技区 / 正文

在进行科研绘图中,我们常常会有这样一个需求:①对多个图层采用相同的配色方案并依次导出;②把导出的各子图拼成一个大图像;③在大图中插入统一的目标色带。

前两步通常用 ArcGIS Pro 就可以搞定了。而在第三步时,ArcGIS Pro 的布局中虽也能生成色带,但有以下两个重要缺陷:1)生成离散性变量(如 Natural Breaks 等方法自动生成的间隔)会逐个展示颜色斑块与对应的范围,显得冗余而杂乱。如果有大于7个变量的话,会占用很大一块地方,造成画布空间的浪费(见下图);2)哪怕能够生成连续的色带,ArcGIS Pro 对于色带辅助信息(如刻度样式,上下标、符号等特殊文本,边框样式等)的自定义程度也很薄弱。

iShot_2023-01-27_23.43.50

这两个缺陷难以在 ArcGIS 中克服。因此,我想使用 matplotlib 直接为离散间隔数据绘制 colorbar,经一番探索后取得了理想的效果。绘制流程如下所述:

引入包

import matplotlib.pyplot as plt
import matplotlib as mpl
from matplotlib.colors import ListedColormap

定义色带与数据范围

首先是定义色带与数据范围。为了展示绘制多个、不规则的离散间隔色带,我使用截图软件从经典的“蓝-黄-红”色带中提取了 32 个颜色,将结果保存在了clist变量中。它们对应于vlist变量中的 33 个数据标签(首、尾、加 31 个间隔)。

color_record = ["599FCD", "68A5C9", "76ABC6", "81B0C1", "8BB7BE", 
         "96BCBA", "A1C1B7", "AAC8B2", "B4CFAC", "BED4A8", 
         "C5DAA4", "CEE1A1", "D8E69C", "DFEC97", "E7F393",
         "EFF88E", "F2F689", "F3EA81", "F2E17B", "F2D675", 
         "F0CB6E", "F1C068", "EDB460", "EDA95B", "ED9E56", 
         "EA924F", "E98649", "E67A43", "E46E3D", "E15F38", 
         "DF5132", "DD3F2F"]

clist = ["#" + i for i in color_record]

vlist = [0, 263, 555, 837, 1175, 1523, 1832, 2105, 2424, 2776, 3181, 3622, 4106, 4571, 4914, 
         5314, 5784, 6221, 6593, 7086, 7664, 8154, 8659, 9139, 9600, 10073, 10483, 10905, 
         11379, 11853, 12520, 13189, 13450]

单独绘制 colorbar

通过ListedColormap()clist这个列表中创建 colormap 对象,然后通过mpl.colors.BoundaryNorm()vlist变量创建色带的 index,绘制好色带的 ticksticklabels

这里有几个注意点。一是要根据实际情况设置好图像长宽;二是要通过设置spacing='proportional'来控制颜色间隔与数据间隔相匹配;三是在标题中设定上标格式的写法。最终结果展示如下:

fig, ax = plt.subplots(figsize=(18, 0.5), dpi=300)
cmap = ListedColormap(clist)
norm = mpl.colors.BoundaryNorm(vlist, len(vlist))
fig.colorbar(mpl.cm.ScalarMappable(norm=norm, cmap=cmap), ticks = vlist, 
             cax = ax, spacing = "proportional", orientation='horizontal')
ax.set_xticklabels(vlist, rotation=-45)
ax.set_title("Area (unit: $\mathregular{m^2}$)")
plt.savefig("result.png", dpi=300, transparent=False, facecolor='white', bbox_inches='tight')

result

相关参考

https://matplotlib.org/stable/tutorials/colors/colorbar_only.html

https://zhajiman.github.io/post/matplotlib_colormap/

评论区
头像
    头像
    wyeorhvzpg
    2024年11月14日 04:05
    回复

    博主太厉害了!

    头像
    iwkjlxjdqk
    2024年10月19日 14:24
    回复

    哈哈哈,写的太好了https://www.cscnn.com/

    头像
    dzzahbvtal
    2024年09月23日 08:54
    回复

    看的我热血沸腾啊

文章目录