zsh2270365028的个人博客分享 http://blog.sciencenet.cn/u/zsh2270365028

博文

[转载]Python-matplotlib 多子图共用colorbar

已有 5981 次阅读 2022-1-25 19:25 |个人分类:Python|系统分类:科研笔记|文章来源:转载

refer to: https://cloud.tencent.com/developer/article/1790529

01. 引言

在推出散点颜色密度图的matplotlib 绘制教程后,有小伙伴反应能否出一篇多子图共用一个colorbar的系列教程,这里也就使用自己的数据进行绘制(数据一共四列,具体为真实值和使用三个模型计算的预测值)。

02. 实现颜色和数值间的对应关系

在绘制多子图共用colorbar时,最重要的就是对颜色映射进行设置,这里使用了matplotlib.color.Normalize()进行颜色和数值对应设置。先看一下使用默认设置的结果,每个子图对应一个colorbar。效果如下:

One Colorbar for one plot.png

可以看出,每个子图对应的值颜色都是不同,这样不利于对比,采用matplotlib.color.Normalize()操作后就可有效解决此问题:

#将颜色映射到 vmin~vmax 之间
norm = matplotlib.colors.Normalize(vmin=0, vmax=60)

效果如下:

518pq27u66_002.png

至于其他拟合线、EE等的设置,可以参考之前的文章Python-matplotlib 学术散点图 EE 统计及绘制 Python-matplotlib 学术散点图完善

03. 详细代码

多子图共用colorbar的详细代码如下:

import pandas as pdimport numpy as npimport matplotlibimport matplotlib.cm as cmimport matplotlib.pyplot as plt
plt.rcParams['font.family'] = ['Arial']test_data = pd.read_excel('GBRT_SVR_DNN_esti_save_angle_process.xlsx')x = test_data['true_data'].values.ravel() #真实值
y = test_data['model01_estimated'].values.ravel()#预测值
y2 = test_data['SVR_estimated'].values.ravel()#预测值2y3 = test_data['DNN_model01_estimated'].values.ravel()#预测值3nbins = 150#模型一结果H, xedges, yedges = np.histogram2d(x, y, bins=nbins)H = np.rot90(H)H = np.flipud(H)Hmasked = np.ma.masked_where(H==0,H)#模型二结果H2, xedges2, yedges2 = np.histogram2d(x, y2, bins=nbins)H2 = np.rot90(H2)H2 = np.flipud(H2)Hmasked2 = np.ma.masked_where(H2==0,H2)#模型三结果H3, xedges3, yedges3 = np.histogram2d(x, y3, bins=nbins)H3 = np.rot90(H3)H3 = np.flipud(H3)Hmasked3 = np.ma.masked_where(H3==0,H3)#可视化绘制
fig, (ax1, ax2,ax3) = plt.subplots(nrows=1,ncols=3,figsize=(12,3),dpi=200)#将颜色映射到 vmin~vmax 之间
norm = matplotlib.colors.Normalize(vmin=0, vmax=60)#模型一结果绘图
im1 = ax1.pcolormesh(xedges, yedges, Hmasked, cmap=cm.get_cmap('jet'),norm=norm)#fig.colorbar(im1, ax=ax1)#模型二结果绘图
im2 = ax2.pcolormesh(xedges2, yedges2, Hmasked2, cmap=cm.get_cmap('jet'), norm=norm)#fig.colorbar(im2, ax=ax2)#模型二结果绘图
im3 = ax3.pcolormesh(xedges3, yedges3, Hmasked3, cmap=cm.get_cmap('jet'), norm=norm,)#fig.colorbar(im3, ax=ax3)#前面三个子图的总宽度 为 全部宽度的 0.9;剩下的0.1用来放置colorbar
fig.subplots_adjust(right=0.9)position = fig.add_axes([0.92, 0.12, 0.015, .78 ])#位置[左,下,右,上]cb = fig.colorbar(im3, cax=position)#设置colorbar标签字体等
colorbarfontdict = {"size":15,"color":"k",'family':'Times New Roman'}cb.ax.set_title('Counts',fontdict=colorbarfontdict,pad=8)cb.ax.tick_params(labelsize=11,direction='in')cb.ax.set_yticklabels(['0','10','20','30','40','50','>60'],family='Times New Roman')#suptitle()中x,y 属性的设置为调整title与子图(subplots)之间的距离
fig.suptitle('One Colorbar for Multiple Plot ',size=20,family='Times New Roman',x=.5,y=1.05)plt.savefig(r'E:\Data_resourses\DataCharm 公众号\Python\学术图表绘制\scatter_One_Colorbar.png',
            width=7,height=5,dpi=900,bbox_inches='tight')plt.show()

这里:

#设置colorbar标签字体等
colorbarfontdict = {"size":15,"color":"k",'family':'Times New Roman'}cb.ax.set_title('Counts',fontdict=colorbarfontdict,pad=8)cb.ax.tick_params(labelsize=11,direction='in')cb.ax.set_yticklabels(['0','10','20','30','40','50','>60'],family='Times New Roman')

实现了对colorbar的定制化需求。

此外,我们设置colorbar也不是只绘制最后一个子图的colorbar,而其他子图不绘制,那样容易导致子图大小不一。这里单独绘制了colorbar,代码如下

fig.subplots_adjust(right=0.9)position = fig.add_axes([0.92, 0.12, 0.015, .78 ])#位置[左,下,右,上]cb = fig.colorbar(im3, cax=position)

这也是多子图共用一个colorbar避免大小不一的一个小技巧,希望大家可以记住。

04. 高斯核密度估计颜色映射

还有小伙伴想绘制如下的颜色密度散点图:

cvqlh1gs4t.png

可以看出颜色密集部分出现“光滑”处理,其实就是通过核密度估计函数将 真实值和预测值之间进行密度值估计,再进行一个排序即可,详细代码如下:

import numpy as npimport matplotlib.pyplot as plt
from scipy.stats import gaussian_kde

x = test_data['true_data'].values.ravel() #真实值
y = test_data['model01_estimated'].values.ravel()#预测值
#计算点密度
#np.vstack:按垂直方向(行顺序)堆叠数组构成一个新的数组
xy = np.vstack([x,y])z = gaussian_kde(xy)(xy)idx = z.argsort()x, y, z = x[idx], y[idx], z[idx]fig, ax = plt.subplots(figsize=(7,5),dpi=200)ax.scatter(x, y, c=z, s=3, edgecolor='')plt.savefig(r'E:\Data_resourses\DataCharm 公众号\Python\学术图表绘制\scatter_gaussian_kde.png',
            width=7,height=5,dpi=900,bbox_inches='tight')plt.show()

如果没有以下操作:

idx = z.argsort()x, y, z = x[idx], y[idx], z[idx]

所绘制的结果如下:

4axzxt8ivl.png

可以看出红圈中还是和排序前的有较大不同的。

05. 总结

原创不易,整理代码和数据更是不易,希望大家多一份理解和支持啊!




https://blog.sciencenet.cn/blog-587102-1322637.html

上一篇:2022.1.25日arXiv
下一篇:[转载]Matplotlib 系列:colorbar 的设置
收藏 IP: 119.78.226.*| 热度|

0

该博文允许注册用户评论 请点击登录 评论 (0 个评论)

数据加载中...
扫一扫,分享此博文

Archiver|手机版|科学网 ( 京ICP备07017567号-12 )

GMT+8, 2024-11-14 09:26

Powered by ScienceNet.cn

Copyright © 2007- 中国科学报社

返回顶部