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

博文

[转载]Python空间绘图-Colorbar详解

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

refer to: https://cloud.tencent.com/developer/article/1790249?from=article.detail.1790529

一、色条Colorbar的基础

在我们绘制有色阶的图片时,多会用到colorbar这个关联利器,色条可以直接将数值与颜色连接在一起。常用的scatter、contourf是非常适合使用的。第一节我们来简要谈谈常用的colorbar参数,以后例子都基于contourf命令。

第一个参数为colorbar传入参数,代表colorbar所关联的contourf,这种方式是最简单的默认传入,绘制出来的colorbar和cf是相匹配的,展示的也是cf的信息。

cf=ax.contourf(... ...)fig.colorbar(cf)

第二个参数为colorbar绘制的默认子图位置参数,代表当前这个colorbar将要摆放的子图位置。

import numpy as npimport matplotlib.pyplot as pltimport matplotlib.ticker as mticker
plt.rcParams['font.sans-serif']=['SimHei']plt.rcParams['axes.unicode_minus']=False#负号
def data():
    datax=np.linspace(-10,10,200)
    datay=np.linspace(-10,10,200)
    X,Y=np.meshgrid(datax,datay)
    Z=np.sqrt(X**2+Y**2)
    return X,Y,Zx,y,z=data()fig=plt.figure(figsize=(5,2),dpi=500)ax1=fig.add_axes([0,0,0.4,1])ax1.set_title('ax1')acf1=ax1.contourf(x,y,z)ax2=fig.add_axes([0.5,0,0.4,1])ax2.set_title('ax2')acf2=ax2.contourf(x,y,z,cmap='Spectral_r')fig.colorbar(acf1,ax=ax2)

在上面这段程序中最后一句,fig.colorbar(acf1,ax=ax2),虽然我们传入了acf1即ax1里的等值线,但是我们指定colorbar中ax=ax2,所以绘制出来的colorbar将被放置在ax2旁边。

ruad9tipd3.png

第三个为指定色条位置参数cax,我们放在后面专开一节讲。

第四个为使色条展示尖角的参数extend,他可以使色条展现出角的形状,其可选命令both表示两头都变尖,max表示数值大的那头变尖,min表示小的那头变尖。

cf=ax.contourf(x,y,z,extend='both')fig.colorbar(cf,extend='both')

jxhzewc5zq.png

第五个参数为缩放参数shrink,从0-1,色条将会按照输入值被缩放:

cf=ax.contourf(x,y,z)fig.colorbar(cf,shrink=0.5)

a9lz3wmsj7.png

第六个参数为距离参数pad,该参数控制色条与子图的间距:

cf=ax.contourf(x,y,z)fig.colorbar(cf,pad=0.005)

jufvpv2hf9.png

第七个为色条方向参数orientation,控制色条时横纵方向,当为horizontal时,色条将被平放在下方:

cf=ax.contourf(x,y,z)fig.colorbar(cf,orientation='horizontal')

xpv9w4lb8z.png

第八个为ticks,你可以传入一个列表,显示你想展示的刻度,其他刻度将消失。类似于ax.set_yticks( ).

cf=ax.contourf(x,y,z)fig.colorbar(cf,ticks=[0,2,4,16])

cvacnyp9ov.png

第九个为format,用于控制色条上刻度的格式,比如将其保留两位小数:

cf=ax.contourf(x,y,z)fig.colorbar(cf,format='%.2f')

tz9bcq2pla.png

第十个为label,简单的给色条一个标签:

cf=ax.contourf(x,y,z)fig.colorbar(cf,label='色条')

lbtatvyldr.png

当然,上面的都是最为基础的参数,你还可以进一步的做美化,其中,最常用的就是将色条作为一个子图来进行操作。

cf=ax.contourf(x,y,z)fc=fig.colorbar(cf)#使用fc省称
ax2=fc.ax#调出colorbar的ax属性
ax2.set_title('这是色条的标题',fontsize=5)ax2.tick_params(which='major',direction='in',labelsize=4,length=7.5)ax2.tick_params(which='minor',direction='in')ax2.yaxis.set_minor_locator(mticker.MultipleLocator(0.5))#显示x轴副刻度

p9ew2wka7f.png

接下来就要讲一讲关于cax的应用了,这个参数在fig.add_axes下特别好用,可以实现非常棒的色条插入效果。从前面简单的参数来看,colorbar自身很难实现在多子图之间挪动,而cax则可以轻松实现。

import numpy as npimport matplotlib.pyplot as pltimport matplotlib.ticker as mticker
plt.rcParams['font.sans-serif']=['SimHei']plt.rcParams['axes.unicode_minus']=False#负号
def data():
    datax=np.linspace(-10,10,200)
    datay=np.linspace(-10,10,200)
    X,Y=np.meshgrid(datax,datay)
    Z=np.sqrt(X**2+Y**2)
    return X,Y,Zx,y,z=data()fig=plt.figure(figsize=(5,3),dpi=500)ax1=fig.add_axes([0,0.3,0.4,0.7])ax1.set_title('ax1')acf1=ax1.contourf(x,y,z)ax2=fig.add_axes([0.5,0.3,0.4,0.7])ax2.set_title('ax2')acf2=ax2.contourf(x,y,z)ax3=fig.add_axes([0.2,0.17,0.5,0.05])fig.colorbar(acf1,cax=ax3,orientation='horizontal')

r1eo6q9vhc.png

将上面这幅图与本文第一张图比较,如果使用fig.colorbar直接生成色条,那么图像上将会有两个子图,生成的colorbar不算子图。而cax方式相当于有三个子图,ax1,ax2与ax3,其中ax3用来存放色条。而只要更改添加子图的位置参数,就可以在图上随意移动。这在多子图上添加规范色条时非常方便。

m5ix8qiio2.png

关于指数标签,一般来说,在contourf中使用了指数标签命令后,色条会自动变成指数模式。

import numpy as npimport matplotlib.pyplot as pltimport matplotlib.ticker as mticker
from matplotlib.colors import LogNorm
plt.rcParams['font.sans-serif']=['SimHei']plt.rcParams['axes.unicode_minus']=False#负号
def data():
    datax=np.linspace(-10,10,200)
    datay=np.linspace(-10,10,200)
    X,Y=np.meshgrid(datax,datay)
    Z=np.sqrt(X**2+Y**2)
    return X,Y,Zx,y,z=data()fig=plt.figure(figsize=(2.6,2),dpi=500)ax=fig.add_axes([0,0,1,1])cf=ax.contourf(x,y,z*100,norm=LogNorm())###在这里有不同
fc=fig.colorbar(cf)ax2=fc.ax
ax2.set_title('指数色条',fontsize=5)ax2.tick_params(which='major',direction='in',labelsize=4,length=7.5)ax2.tick_params(which='minor',direction='in')ax.set_title('使用指数标签')

gk1yt1a662.png

接下来,是一些比较没多大用处,但很有意思的colorbar操作。

一、如何使色条两侧各有一种刻度

10xckdr9vg.png

比如这张图的色条,左边是数值刻度,右边是文字刻度。当然,两边是否对称,是否数值文字都取决于你的设置,你还可以做出螺旋上升的色条标签。

import numpy as np
from matplotlib.colors import Normalizeimport matplotlib as mplimport pandas as pdimport cartopy.crs as ccrsimport cartopy.feature as cfeat
from cartopy.mpl.gridliner import LONGITUDE_FORMATTER, LATITUDE_FORMATTERfrom cartopy.io.shapereader import Reader
from scipy.interpolate import Rbfimport matplotlib.pyplot as pltimport matplotlib.ticker as mtickerimport sys
sys.path.append(r"C:\Users\lenovo\Desktop")import maskout
plt.rcParams['font.sans-serif']=['SimHei']extent=[108.2,110.8,29.1,31.401]proj= ccrs.PlateCarree() fig = plt.figure(figsize=(7, 10),dpi=500)  ax = fig.subplots(1, 1, subplot_kw={'projection': proj})  reader = Reader(r'E:\家园\区划-省界\恩施.shp')cities = cfeat.ShapelyFeature(reader.geometries(), proj, edgecolor='k', facecolor='none')ax.add_feature(cities, linewidth=0.7)ax.set_extent(extent, crs=proj)gl = ax.gridlines(crs=ccrs.PlateCarree(), draw_labels=True,linewidth=0.7, color='k', alpha=0.5, linestyle='--')gl.xlabels_top = False 
gl.ylabels_right = False 
gl.xformatter = LONGITUDE_FORMATTER gl.yformatter = LATITUDE_FORMATTER gl.xlocator = mticker.FixedLocator(np.arange(extent[0], extent[1]+0.5, 0.4))gl.ylocator = mticker.FixedLocator(np.arange(extent[2], extent[3]+0.5, 0.4))gl.xlabel_style={'size':10}gl.ylabel_style={'size':10}
    ###############################以下为添加县市名称和点########################################
nameandstation={"恩施":[109.5,30.2],"利川":[109,30.3],"巴东":[110.34,31.04],"建始":[109.72,30.6],"宣恩":[109.49,29.987],"来凤":[109.407,29.493],"咸丰":[109.14,29.665],"鹤峰":[110.034,29.89]}for key,value in nameandstation.items():
    ax.scatter(value[0] , value[1] , marker='.' , s=90 , color = "k" , zorder = 3)
    ax.text(value[0]-0.07 , value[1]+0.03 , key , fontsize = 12 , color = "k")
    ##############################################读取文件打包数据###########################################
filename=r'C:\Users\lenovo\Desktop\累年降水数据.xlsx'#数据文件地址,这个数据是我捏造的,没有实际意义
df=pd.read_excel(filename)#读取文件
lon=df['lon']#读取站点经度
lat=df['lat']#读取站点纬度
rain=df['precipitation']#读取站点累计年降水量
olon=np.linspace(108,111,30)#设置网格经度
olat=np.linspace(29,32,30)#设置网格纬度
olon,olat=np.meshgrid(olon,olat)#网格化
func=Rbf(lon,lat,rain,function='linear')#定义插值函数
rain_new=func(olon,olat)#获得插值后的网格累计降水量
cs= ax.contourf(olon,olat,rain_new,levels=np.arange(900,2000,100),cmap='GnBu',extend='both')#画图
clip=maskout.shp2clip(cs, ax,r'E:\enshi\恩施.shp' ,0) plt.title('恩施州去年累计降水',size=20)##########################################################################################
position=fig.add_axes([0.97,0.25,0.04,0.5])cb=fig.colorbar(cs,cax=position,shrink=0.4,extend='both')#绘制colorbar并省称为cb
ax2=cb.ax#召唤出cb的ax属性并省称为ax2,这时ax2即视为一个子图
ax2.yaxis.set_ticks_position('left')#将数值刻度移动到左侧
ax2.tick_params(labelsize=10,left=True,right=True)#修改刻度样式,并使左右都有刻度
ax3=ax2.secondary_yaxis('right')#新建ax3,使ax3与ax2完全相同
ax3.spines['right'].set_bounds(900,1900)#截去多余的部分
ax3.set_yticks([900,1100,1300,1500,1700,1900])ax3.set_yticklabels(['缺水','一般性缺水','收支充足','降水丰沛','有可能涝灾','成灾'])#将ax3上的定量数值转化为定性文字

我在文章里插入了读者讨论,貌似可以充当互动,有问题可以直接留言,也可以后台留言。

二、如何实现colorbar与其他子图的互动操作

这个是好像有一位小伙伴问过的,于是简单的做了一个,使折线图与色条在视觉上共用一个坐标轴(实际上是没有的)。

gal8agq7wh.png

import numpy as np
from matplotlib.colors import Normalizeimport matplotlib as mplimport pandas as pdimport cartopy.crs as ccrsimport cartopy.feature as cfeat
from cartopy.mpl.gridliner import LONGITUDE_FORMATTER, LATITUDE_FORMATTERfrom cartopy.io.shapereader import Reader
from scipy.interpolate import Rbfimport matplotlib.pyplot as pltimport matplotlib.ticker as mtickerimport sys
sys.path.append(r"C:\Users\lenovo\Desktop")import maskout
plt.rcParams['font.sans-serif']=['SimHei']extent=[108.2,110.8,29.1,31.401]proj= ccrs.PlateCarree() fig = plt.figure(figsize=(7, 5),dpi=500)  ax = fig.add_axes([0,0,0.6,1],projection=proj)reader = Reader(r'E:\家园\区划-省界\恩施.shp')cities = cfeat.ShapelyFeature(reader.geometries(), proj, edgecolor='k', facecolor='none')ax.add_feature(cities, linewidth=0.7)ax.set_extent(extent, crs=proj)gl = ax.gridlines(crs=ccrs.PlateCarree(), draw_labels=True,linewidth=0.7, color='k', alpha=0.5, linestyle='--')gl.xlabels_top = False 
gl.ylabels_right = False 
gl.xformatter = LONGITUDE_FORMATTER gl.yformatter = LATITUDE_FORMATTER gl.xlocator = mticker.FixedLocator(np.arange(extent[0], extent[1]+0.5, 0.4))gl.ylocator = mticker.FixedLocator(np.arange(extent[2], extent[3]+0.5, 0.4))gl.xlabel_style={'size':10}gl.ylabel_style={'size':10}
    ###############################以下为添加县市名称和点########################################
nameandstation={"恩施":[109.5,30.2],"利川":[109,30.3],"巴东":[110.34,31.04],"建始":[109.72,30.6],"宣恩":[109.49,29.987],"来凤":[109.407,29.493],"咸丰":[109.14,29.665],"鹤峰":[110.034,29.89]}for key,value in nameandstation.items():
    ax.scatter(value[0] , value[1] , marker='.' , s=90 , color = "k" , zorder = 3)
    ax.text(value[0]-0.07 , value[1]+0.03 , key , fontsize = 12 , color = "k")
    ##############################################读取文件打包数据###########################################
filename=r'C:\Users\lenovo\Desktop\累年降水数据.xlsx'#数据文件地址
df=pd.read_excel(filename)#读取文件
lon=df['lon']#读取站点经度
lat=df['lat']#读取站点纬度
rain=df['precipitation']#读取站点累计年降水量
olon=np.linspace(108,111,30)#设置网格经度
olat=np.linspace(29,32,30)#设置网格纬度
olon,olat=np.meshgrid(olon,olat)#网格化
func=Rbf(lon,lat,rain,function='linear')#定义插值函数
rain_new=func(olon,olat)#获得插值后的网格累计降水量
cs= ax.contourf(olon,olat,rain_new,levels=np.arange(900,2000,100),cmap='GnBu')#画图
clip=maskout.shp2clip(cs, ax,r'E:\enshi\恩施.shp' ,0)#白化 
plt.title('恩施州去年累计降水',size=20)##########################################################################################
position=fig.add_axes([0.66,0.13,0.03,0.74])#添加子图用来存放色条
cb=fig.colorbar(cs,cax=position,shrink=0.4)#绘制colorbar并省称为cb
ax2=cb.ax#召唤出cb的ax属性并省称为ax2,这时ax2即视为一个子图
ax2.yaxis.set_ticks_position('left')#将数值刻度移动到左侧
ax2.tick_params(which='both',labelsize=10,left=True,direction='in')#修改刻度样式,并使左右都有刻度
ax2.yaxis.set_minor_locator(mticker.MultipleLocator(50))#############################################################################################
ax3=fig.add_axes([0.69,0.13,0.25,0.74])ax3.tick_params(which='both',direction='in',left=False,right=False)ax3.yaxis.set_ticks_position('right')#将数值刻度移动到左侧
ax3.yaxis.set_major_locator(mticker.NullLocator())#去掉y轴坐标
ax3.xaxis.set_minor_locator(mticker.MultipleLocator(100))#显示x轴副刻度
ax3x=np.array([200,400,800,1400,1200,900,700,450,200,100])ax3y=np.arange(900,1900,100)ax3.plot(ax3x,ax3y)ax3.set(title='累计降水分布面积',xlim=(0,1500),xlabel='分布面积(平方千米)')

以上数据和各种标准都是我虚构的,没有实际意义。

三、不等距的色条

这是matplotlib官网上的一个例子,比较有意思,于是就搬过来了。基本上照源代码修改就能用了。

position=fig.add_axes([0.9,0,0.05,1])cmap = mpl.colors.ListedColormap(colordict)cmap.set_over('0.25')cmap.set_under('0.75')bounds = colorlevel
norm2 = mpl.colors.BoundaryNorm(bounds, cmap.N)fig.colorbar(
    mpl.cm.ScalarMappable(cmap=cmap, norm=norm2),
    cax=position,
    boundaries=[0] + bounds + [501], 
    extend='both',
    ticks=bounds,
    spacing='proportional')

3slcqaqnuc.png

本文分享自微信公众号 - DataCharm(shujumeili)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-10-28

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。




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

上一篇:[转载]Interpolations for imshow
下一篇:arXiv-1.27
收藏 IP: 119.78.226.*| 热度|

0

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

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

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

GMT+8, 2024-12-26 09:32

Powered by ScienceNet.cn

Copyright © 2007- 中国科学报社

返回顶部