|||
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旁边。
第三个为指定色条位置参数cax,我们放在后面专开一节讲。
第四个为使色条展示尖角的参数extend,他可以使色条展现出角的形状,其可选命令both表示两头都变尖,max表示数值大的那头变尖,min表示小的那头变尖。
cf=ax.contourf(x,y,z,extend='both')fig.colorbar(cf,extend='both')
第五个参数为缩放参数shrink,从0-1,色条将会按照输入值被缩放:
cf=ax.contourf(x,y,z)fig.colorbar(cf,shrink=0.5)
第六个参数为距离参数pad,该参数控制色条与子图的间距:
cf=ax.contourf(x,y,z)fig.colorbar(cf,pad=0.005)
第七个为色条方向参数orientation,控制色条时横纵方向,当为horizontal时,色条将被平放在下方:
cf=ax.contourf(x,y,z)fig.colorbar(cf,orientation='horizontal')
第八个为ticks,你可以传入一个列表,显示你想展示的刻度,其他刻度将消失。类似于ax.set_yticks( ).
cf=ax.contourf(x,y,z)fig.colorbar(cf,ticks=[0,2,4,16])
第九个为format,用于控制色条上刻度的格式,比如将其保留两位小数:
cf=ax.contourf(x,y,z)fig.colorbar(cf,format='%.2f')
第十个为label,简单的给色条一个标签:
cf=ax.contourf(x,y,z)fig.colorbar(cf,label='色条')
当然,上面的都是最为基础的参数,你还可以进一步的做美化,其中,最常用的就是将色条作为一个子图来进行操作。
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轴副刻度
接下来就要讲一讲关于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')
将上面这幅图与本文第一张图比较,如果使用fig.colorbar直接生成色条,那么图像上将会有两个子图,生成的colorbar不算子图。而cax方式相当于有三个子图,ax1,ax2与ax3,其中ax3用来存放色条。而只要更改添加子图的位置参数,就可以在图上随意移动。这在多子图上添加规范色条时非常方便。
关于指数标签,一般来说,在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('使用指数标签')
接下来,是一些比较没多大用处,但很有意思的colorbar操作。
一、如何使色条两侧各有一种刻度
比如这张图的色条,左边是数值刻度,右边是文字刻度。当然,两边是否对称,是否数值文字都取决于你的设置,你还可以做出螺旋上升的色条标签。
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与其他子图的互动操作
这个是好像有一位小伙伴问过的,于是简单的做了一个,使折线图与色条在视觉上共用一个坐标轴(实际上是没有的)。
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')
本文分享自微信公众号 - DataCharm(shujumeili)
原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。
原始发表时间:2020-10-28
本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。
Archiver|手机版|科学网 ( 京ICP备07017567号-12 )
GMT+8, 2024-12-26 09:32
Powered by ScienceNet.cn
Copyright © 2007- 中国科学报社