最全colormap和colorbar教程

2021-12-28 氣象匯

本節提要:關於colormap與colorbar的一站式教程。

章節引言:

在matplotlib和cartopy中,其常見的繪圖命令,若是帶有顏色映射的collection(s)類,則基本都可以引入cmap與colorbar功能來分析數據。cmap即是顏色映射表,colorbar即是顏色分析色條,前者只起到對繪圖對象上色的功能,後者實現色階與數值的對應。

常見的繪圖命令scatter、contour、contourf、pcolormesh等都可以引入cmap與colorbar,下面四幅圖分別使用了前述四種繪圖命令繪製,並更改了每一幅圖使用的顏色映射表:

cmap的引入

作為一個專門的數據可視化庫包,matplotlib專門開闢了一個cm功能來供繪圖者使用,如果需要使用一個顏色映射表,你可以使用get語句獲取該顏色映射表:

importmatplotlib as mpl                                                                                    colormap=mpl.cm.get_cmap(' Reds ' )                                                              ax.contourf(cmap=colormap)

你也可以在cm後直接加上顏色映射表名稱,而不是字符串,這兩種方法在此處是等效的:

當然,這種get命令的在此處顯得繁瑣了,更簡便的方法是徑直將代表該顏色映射表的字符串直接傳入繪圖命令中的cmap中:

ax.contourf(cmap='Reds ')

使用顏色映射表時不必要記住全部的代表字符串,我們可以在使用的時候去官網查找後使用。

Matplotlib的默認cmap是viridis。

翻轉cmap的顏色順序

由於cmap的顏色映射表是有固定存儲順序的數組,所以我們可以在需要的時候翻轉cmap與數值的對應順序,翻轉命令為在顏色映射表的字符串最後加上』_r』。

ax1.contourf(X,Y,Z,cmap='Reds')                                               ax2.contourf(X,Y,Z,cmap='Reds_r')

cmap的分類

matplotlib專門提供了多樣的顏色映射表,他們在官網Tutorials下的Choosing Colormaps in Matplotlib說明書有詳細講解。

按照官網的說明,colormap簡要有以下六類:

1. 連續類(Sequential):色彩的亮度和飽和度遞增變化,用單一色調展示有序的信息。Matplotlib的默認cmap——『viridis』,即屬於這一類。這類視覺衝擊性較小,在梯度劃分較細時,連續臨近的色階在一定的時候可能出現混淆的情況。

2. 分色類(Diverging):不同顏色的亮度和飽和度逐漸變化。主要用於展示關於0對稱的數據。

3. 循環類(Cyclic):兩種不同顏色的亮度逐漸變化,在色彩映射的中間位置以及開始(或結束)端以非飽和色結束。一般應用於在端點處循環的值。

4. 定性類(Qualitative):將各個顏色無序拼接的顏色映射表。用於展示無序的信息。

5.  混雜類(Miscellaneous):多種對比明顯的各種顏色拼接在一起,一般用於展示信息中的細節變化。

以下為matplotlib官網提供的各種顏色映射表:

這裡推薦幾種比較實用的cmap:

GnBu、gray、cool、bwr、RdBu、tab20c

其中GnBu、RdBu、tab20c比較溫和,cool、bwr視覺衝擊性強。

引入外部cmap

由於matplotlib提供的顏色映射表是有限的,所以我們還需要藉助外部的庫包提供額外的顏色映射表。大氣科學與海洋科學常用的兩個外部顏色庫包為Palettable與cmaps,這兩個庫包都可以使用conda命令安裝。Palettable作為經典顏色庫包在很多地方都有使用;cmaps庫包是將NCL平臺的顏色移植到python平臺,嘉惠學林。

下面是cmaps一些顏色映射表舉例:

更多的顏色映射表名稱請至官網查詢。

在使用cmaps時,只需引入庫包,然後填寫顏色名,引入後可以視為正常的matplotlib內部colormap對待與實用:

import cmaps                                                               cmap=cmaps.MPL_RdYlGn                                                  ax.contourf(cmap=cmap)

截取cmap

在日常使用時,一條colormap我們很可能只需要其中一部分,這時候就需要進行cmap的截取工作,前面已經提到了作為一連串的顏色列表合併的數組是cmap的本質,所以我們很容易想到通過切片的方式來截取cmap,通過切片,我們將jet_r顏色條中的暖色調全部截去不用。

import numpy asnp                                                            importmatplotlib as mpl                                                         importmatplotlib.pyplot as plt                                                  frommatplotlib.colors import ListedColormap                                   cmap=mpl.cm.jet_r#獲取色條                                                    newcolors=cmap(np.linspace(0,1,256))#分片操作                                  newcmap=ListedColormap(newcolors[125:])#切片取捨                                  fig=plt.figure(figsize=(1.5,0.3),dpi=500)                                  ax1=fig.add_axes([0,0,1,0.45])                                                 ax2=fig.add_axes([0,0.5,1,0.45])                                              norm =mpl.colors.Normalize(vmin=0, vmax=10)                                fc1=fig.colorbar(mpl.cm.ScalarMappable(norm=norm,cmap='jet_r'),                               cax=ax1,                                                                       orientation='horizontal',                                                                          extend='both')                                                                    fc2=fig.colorbar(mpl.cm.ScalarMappable(norm=norm,cmap=newcmap),                                                             cax=ax2,                                                                       orientation='horizontal',                                                          extend='both')                                                 for i in[fc1,fc2]:                                                               i.ax.tick_params(labelsize=3,width=0.5,length=0.5)                               i.outline.set_linewidth(0.5)                                              

拼接cmap

既然能夠通過切片的方式截取cmap,那麼自然反向的我們可以通過組合的方式拼接cmap。

import numpy asnp                                                        importmatplotlib as mpl                                                       importmatplotlib.pyplot as plt                                                        frommatplotlib.colors import ListedColormap                                 import cmaps                                                                    plt.rcParams['font.sans-serif']=['FangSong']                                 cmap1=cmaps.spread_15lev_r                                                   cmap2=cmaps.sunshine_diff_12lev                                                list_cmap1=cmap1(np.linspace(0,1,15))                                      list_cmap2=cmap2(np.linspace(0,1,12))                                           new_color_list=np.vstack((list_cmap1,list_cmap2))                            new_cmap=ListedColormap(new_color_list,name='new_cmap ')                                                                      fig=plt.figure(figsize=(1.5,0.5),dpi=500)                                        ax1=fig.add_axes([0,0,1,0.33])                                                 ax2=fig.add_axes([0,0.33,1,0.33])                                            ax3=fig.add_axes([0,0.66,1,0.33])                                              norm =mpl.colors.Normalize(vmin=0, vmax=10)                              fc1=fig.colorbar(mpl.cm.ScalarMappable(norm=norm,                                             cmap=cmap1),cax=ax1,                                                      orientation='horizontal',extend='both')                       fc2=fig.colorbar(mpl.cm.ScalarMappable(norm=norm,                                       cmap=cmap2),cax=ax2,                                                       orientation='horizontal',extend='both')                    fc3=fig.colorbar(mpl.cm.ScalarMappable(norm=norm,                                          cmap=new_cmap),cax=ax3,                                                 orientation='horizontal',extend='both')                    

colorbar基礎

colorbar是在有顏色映射的繪圖命令中使用的一種表徵顏色與數值的對應關係的特殊圖形。與Legend圖例命令不同,matplotlib允許使用者在不使用其他功能的情況下,無限次的添加colorbar。

colorbar的引入既可以是有源的,也可以是無源的。此處的有源無源,針對的是colorbar與子圖繪圖命令的關聯性。

colorbar的添加可以使用如下命令:

importmatplotlib.pyplot as plt                                               fig=plt.figure()                                                               fig.colorbar()

有源colorbar引入

有源colorbar指直接與當前要添加色條的子圖的繪圖命令相關聯的添加方式,具體來說,就是縮寫代稱該繪圖命令,然後作為映射源傳入生成colorbar命令中,如:

CS=ax1.contourf(X,Y,Z,cmap=cmaps.sunshine_diff_12lev)                    cb=fig.colorbar(CS,shrink=1,ax=ax1)                                     CS2=ax2.contourf(X,Y,Z,cmap=cmaps.MPL_RdYlGn)                        cb2=fig.colorbar(CS2,shrink=1,ax=ax2)                        

這裡的兩張圖形都是有源的colorbar,其中在子圖1中,我們稱CS、CS2為我們生成的colorbar的源頭。通過傳入CS、CS2代表的contourfcollections,我們比較簡便的生成了colorbar。 

無源colorbar引入

無源colorbar主要是指不使用子圖中的繪圖命令的關聯性,由使用者通過定義norm、cmap等參數,生成一個與子圖沒有直接映射關係的colorbar,如:

CS=ax1.contourf(X,Y,Z,cmap=cmaps.MPL_RdYlGn)                        cb=fig.colorbar(CS,ax=ax1)                                      ax2.contourf(X,Y,Z,cmap=cmaps.MPL_RdYlGn)                                   cmap=cmaps.MPL_RdYlGn                                                        bounds=np.arange(-2.0,2.5,0.5)                                               norm =mpl.colors.BoundaryNorm(bounds,cmap.N)                            cb2=fig.colorbar(mpl.cm.ScalarMappable(norm=norm,cmap=cmap),                          ax=ax2)

通過使用者聲明的norm與cmap,我們獲得了一個與有源colorbar一模一樣的colorbar。這裡固然不如直接傳入有源的辦法簡捷,但是在後期某些高級定製時,是比較有用的。

Colorbar重要參數列舉

colorbar作為一個繪製圖形命令,自身必定攜帶多樣的修飾參數。下面簡答列舉各參數:

1.  mappable(可映射源)

該參數即需要繪製的映射圖像源頭,一般默認當前子圖的繪圖命令,如上節提到的CS,或者mpl.cm.ScalarMappable自動生成的映射源。對於fig.colorbar命令來說,該參數是必要的,但是plt.colorbar命令在使用時如果沒有填寫顯性的源頭,程序會自動確認當前子圖可映射項。

2.  ax(colorbar擺放的子圖位置)

該參數控制繪製的colorbar擺放在某個子圖旁邊,默認為當前子圖。可以傳入單獨的一個子圖,也可以傳入一個子圖的列表。

3.  cax(colorbar擺放的子圖位置)

該參數設定後,擁有最高優先級,將覆蓋shrink 、ax、aspect等參數,colorbar將放置在指定位置,如:

cax=fig.add_axes([0.33,0,0.4,0.05])                                         CS=ax1.contourf(X,Y,Z,cmap=cmaps.MPL_RdYlGn)                        cb=fig.colorbar(CS,shrink=1,cax=cax,orientation='horizontal')                ax2.contourf(X,Y,Z,cmap=cmaps.MPL_RdYlGn)                             

4.  orientation(axes特性,colorbar擺放的橫豎位置)

該參數控制colorbar的橫豎位置。默認為豎向。其中豎向命令為vertical,橫向命令為horizontal,如3中圖片所示。

5.  shrink(axes特性,colorbar的收縮比例)

該參數控制colorbar的收縮比例,在收縮時,colorbar長寬都會變化,如:

CS=ax1.contourf(X,Y,Z,cmap=cmaps.MPL_RdYlGn)                                  cb=fig.colorbar(CS,shrink=0.5,ax=ax1)                                     CS2=ax2.contourf(X,Y,Z,cmap=cmaps.MPL_RdYlGn)                          cb2=fig.colorbar(CS,shrink=1.25,ax=ax2)                                 

6.  aspect(axes特性,colorbar的長寬比例)

該參數控制colorbar長寬的比例,如:

7.  pad(axes特性,colorbar與子圖距離)

該參數控制colorbar與子圖的間距,如:

8.  extend(colorbar特性,colorbar兩端擴充)

該參數可以控制colorbar兩端是否允許擴充,擴充後生成尖角,可選擇的變量有'neither','both', 'min', 'max'。需要注意,該參數不僅是生成尖角,填色亦會出現變化,如:

9.  extendfrac(colorbar特性,colorbar兩端擴充的相對長度)

該參數控制衍生的小三角與colorbar主體的相對長度,如:

10.  extendrect(colorbar特性,colorbar兩端擴充的相對形狀)

該參數控制兩端衍生的小三角的形狀,擁有True、False兩個可選變量,False時兩端為小三角,True時兩端為矩形,如:

11.  spacing(colorbar特性,colorbar填色間隔)

該參數控制colorbar的填色間隔是否與數值間隔相關,擁有uniform, proportional兩個可選變量。其中uniform表示無論數值間隔是否相等,所有填色長度均勻相等,這是默認變量。proportional表示若數值間隔有大有小,則填色長度亦隨之變化,數值間隔越大,填色長度也越長,反之相反,如:

12.  ticks(colorbar特性,colorbar刻度間隔)

該參數控制顏色條的刻度顯示。

13.  format(colorbar特性,colorbar刻度單位制)

該參數控制colorbar顯示的刻度值的單位,如:

14.  drawedges(colorbar特性,colorbar是否在邊界上劃線)

該參數控制是否在每個顏色交界處畫線,布爾值控制,如:

15.  label(colorbar特性,colorbar的label)

該參數允許傳入一個字符串,將作為colorbar的標籤。

Colorbar的axes特性

在生成腳本中我們可知,colorbar是必然要生成一個axes來作為寄生軸的,所以colobar可以調用一些子圖的特性,調用方式如下:

CS=ax1.contourf(X,Y,Z,cmap=cmaps.MPL_RdYlGn)                            cb=fig.colorbar(CS,shrink=1,ax=ax1)                                      cb.ax                                                                       

在調用了子圖屬性以後,我們可以使用子圖的屬性來進一步修飾colorbar,如:

def make_colorbar(cb):                                                          cb.ax.tick_params(labelsize=4,length=0.5,width=0.5)                          cb.outline.set_color('none')                                                 cb=fig.colorbar(CS,shrink=1,ax=ax1)                                       cb2=fig.colorbar(mpl.cm.ScalarMappable(norm=norm,cmap=cmap),                          ax=ax2)                          for cb in[cb,cb2]:                                                               make_colorbar(cb)                                                     

我們還可以使用在前面提到的刻度生成器的方式修飾colorbar,如:

CS=ax1.contourf(X,Y,Z,cmap=cmaps.MPL_RdYlGn)                             cb=fig.colorbar(CS,shrink=1,ax=ax1)                                        cb.ax.yaxis.set_minor_locator(mticker.MultipleLocator(0.25))                  ax2.contourf(X,Y,Z,cmap=cmaps.MPL_RdYlGn)                            cmap=cmaps.MPL_RdYlGn                                                    bounds=np.arange(-2.5,2.5,0.5)                                             norm =mpl.colors.BoundaryNorm(bounds,cmap.N)                         cb2=fig.colorbar(mpl.cm.ScalarMappable(norm=norm,cmap=cmap),                          ax=ax2)                          

不同特色的colorbar繪製技巧

在某些時候,程序自動生成的colorbar在修飾後,仍然不能滿足我們的需求,這時,我們就會利用一些手段,製造各種不同特色的colorbar,下面我們介紹幾種常見異形colorbar的繪製方法。

  1.  環狀colorbar

環狀colorbar表現在其色條不為直線型,在目前matplotlib的框架下,不能利用現有的colorbar參數修改為類似的形狀。這時,我們只能利用其它的方式仿製出colorbar

這裡我們提供兩種方式:第一,使用極坐標系下的柱形圖方法;第二,使用楔形形狀命令繪製圓環。

1.1極坐標系下的柱形圖繪製方法

由於極坐標系可以繪製柱狀圖,而柱狀圖又可以通過facecolor參數實現上色,所以可以用到環狀colorbar的繪製中來,如:

import numpy asnp                                                               import xarray asxr                                                           importmatplotlib.pyplot as plt                                                  importcartopy.crs as ccrs                                                          importcartopy.feature as cfeature                                             importcartopy.io.shapereader as shpreader                                        importmatplotlib.path as mpath                                                    importmatplotlib as mpl                                                         fromcartopy.util import add_cyclic_point                                           from matplotlibimport cm,colors                                                 fromcartopy.mpl.gridliner import LONGITUDE_FORMATTER,              LATITUDE_FORMATTER                                                            plt.rcParams['font.sans-serif']=['FangSong']plt.rcParams['axes.unicode_minus']=Falsefile=r'E:\aaaa\datanc\2019.6.23\fnl_20190620_00_00.grib2'                data=xr.open_dataset(file,engine='cfgrib',                                   backend_kwargs={'filter_by_keys':{'typeOfLevel': 'surface'}})                                                     data['t']-273.15                                                             data['latitude']                                                                 data['longitude']                                                             cycle_t,cycle_lon = add_cyclic_point(data['t']-273.15,                         coord=data['longitude'])                                      cycle_LON,cycle_LAT = np.meshgrid(cycle_lon,data['latitude'])                 fig=plt.figure(figsize=(2,2),dpi=700)                                             ax1=fig.add_axes([0,0,1,1],polar=True)                                    ax1.set_axis_off()                                                            ax2=fig.add_axes([0.127,0.123,0.75,0.75],                                  projection=ccrs.SouthPolarStereo())                    ax2.add_feature(cfeature.LAND)                                              ax2.add_feature(cfeature.OCEAN)                                                ax2.add_feature(cfeature.COASTLINE,lw=0.75)                               theta =np.linspace(0, 2*np.pi, 100)                                       center, radius =[0.5, 0.5], 0.5                                               verts =np.vstack([np.sin(theta), np.cos(theta)]).T                             circle =mpath.Path(verts * radius + center)                                    ax2.set_boundary(circle,transform=ax2.transAxes)                          cs=ax2.contourf(cycle_LON,cycle_LAT, cycle_t,                              levels=np.arange(60,60,10),                               cmap='RdBu_r',transform=ccrs.PlateCarree())              cs.levels                                                                    cmap=cm.get_cmap('RdBu_r',len(cs.levels)-1)                                 angle=np.arange(0,0.5*np.pi,0.5*np.pi/(len(cs.levels)-1))                  radius=np.array([2,2,2,2,2,2,2,2,2,2,2])                                     cmaps=cmap(range(len(cs.levels)-1))                                    ax1.set_theta_offset(np.pi/2)                                               ax1.bar(angle,radius,width=0.5*np.pi/11,color=cmaps,align='center')           for i,x,y inzip(cs.levels,angle,radius):                                             ax1.text(x-0.1,y+0.17,i,fontsize=3)                                      ax1.text(0.9,2.6,'氣溫:℃',fontsize=4)                                       

1.2楔形圖形繪製環狀colorbar

利用matplotlib.patches中的楔形圖形命令Wedge,在循環迭代的方式下,添加一個環狀的colorbar。

import numpy asnp                                                                  import xarray asxr                                                        importmatplotlib.pyplot as plt                                                 importcartopy.crs as ccrs                                                     importcartopy.feature as cfeature                                            importcartopy.io.shapereader as shpreader                                   importmatplotlib.path as mpath                                                importmatplotlib as mpl                                                     fromcartopy.util import add_cyclic_point                                      from matplotlibimport cm,colors                                                fromcartopy.mpl.gridliner import LONGITUDE_FORMATTER,                 LATITUDE_FORMATTER                  frommatplotlib.patches import Wedge                                           plt.rcParams['font.sans-serif']=['FangSong']                                plt.rcParams['axes.unicode_minus']=False                                    file=r'E:\aaaa\datanc\2019.6.23特大暴雨\fnl_20190620_00_00.grib2'             data=xr.open_dataset(file,engine='cfgrib',                                          backend_kwargs={'filter_by_keys':{'typeOfLevel': 'surface'}})                data['t']-273.15                                                             data['latitude']                                                                   data['longitude']                                                               cycle_t,cycle_lon = add_cyclic_point(data['t']-273.15,                             coord=data['longitude'])                               cycle_LON,cycle_LAT = np.meshgrid(cycle_lon,data['latitude'])           fig=plt.figure(figsize=(2,2),dpi=700)                                            ax=fig.add_axes([0,0,1,1],projection=ccrs.PlateCarree())                    ax.add_feature(cfeature.LAND)                                            ax.add_feature(cfeature.OCEAN)                                               ax.add_feature(cfeature.COASTLINE,lw=0.3)                                   ax.spines['geo'].set_linewidth(0.5)                                        cs=ax.contourf(cycle_LON,cycle_LAT, cycle_t,                                              levels=np.arange(-60,60,10),cmap='RdBu_r',                           transform=ccrs.PlateCarree(),extend='both')          cmap=cm.get_cmap('RdBu_r',len(cs.levels)-1)                                cmaps=cmap(range(len(cs.levels)-1))                                       ax2=fig.add_axes([0.05,0.3,0.2,0.2])                                            delta=360/(len(cs.levels)-1)                                                  for c,p inzip(cmaps,range(len(cs.levels)-1)):                                        wedge=Wedge((0.5,0.5),0.4,delta*p,delta*(p+1),facecolor=c,             edgecolor='k',width=0.1,linewidth=0.1)                                 ax2.add_patch(wedge)                                               ax2.axis('off')                                                                   

  2.  兩端三角形與色條主體分離的colorbar

import numpy asnp                                                                  import xarray asxr                                                        importmatplotlib.pyplot as plt                                                  importmatplotlib.path as mpath                                               importmatplotlib as mpl                                                       from matplotlibimport cm,colors                                              from matplotlib.patchesimport Rectangle                                      importcartopy.crs as ccrs                                                   fromcartopy.util import add_cyclic_point                                       fromcartopy.mpl.gridliner import LONGITUDE_FORMATTER,               LATITUDE_FORMATTER                  importcartopy.feature as cf                                                   importcartopy.io.shapereader as shpreader                                         plt.rcParams['font.sans-serif']=['SimHei']                                     file=r'E:\aaaa\datanc\2019.6.23\fnl_20190620_00_00.grib2'                    data=xr.open_dataset(file,engine='cfgrib',                                 backend_kwargs={'filter_by_keys':{'typeOfLevel': 'surface'}})t=data['t']-278.15                                                            lat=data['latitude']                                                               lon=data['longitude']                                                             proj=ccrs.LambertConformal(central_longitude=105,central_latitude=35)    reader= shpreader.Reader( r'F:\B\china.shp')                                           provinces=cf.ShapelyFeature(reader.geometries(),                              crs=ccrs.PlateCarree(),                       edgecolor='k',                                 facecolor='none',                                alpha=1,lw=0.5)                            extent=[80,130,10,60]                                                      fig=plt.figure(figsize=(1.5,1.5),dpi=800)                                      ax=fig.add_axes([0,0.1,1,0.85],projection=proj)                               ax.add_feature(cf.COASTLINE.with_scale('50m'),lw=0.25)                    ax.add_feature(cf.OCEAN.with_scale('50m'),lw=0.5)                           ax.add_feature(cf.LAND.with_scale('50m'),lw=0.5,edgecolor='none')         ax.add_feature(cf.RIVERS.with_scale('50m'),lw=0.25)                        ax.add_feature(provinces,linewidth=0.3)                                       ax.add_geometries(shpreader.Reader(r'F:\B\nine.shp').geometries(),                            crs=ccrs.PlateCarree(),edgecolor='k',                     facecolor='k',alpha=1,lw=0.5)                          ax.spines['geo'].set_linewidth(0.25)                                           ax.set_extent(extent)                                                       ax2=fig.add_axes([0.054,0,0.892,0.1])                                          ax2.tick_params(axis='both',which='major',                                    direction='in',width=0.5,                                      length=0.5,labelsize=3)                                 for i in ['top','bottom','left','right']:                                                  ax2.spines[i].set_linewidth(0.5)                                           ac=ax.contourf(lon,lat,t,cmap='Spectral_r',                                  levels=np.arange(-20,40,2),                             transform=ccrs.PlateCarree())                            ax.spines['geo'].set_linewidth(0.5)                                             ax2.set(xlim=(-3,30),ylim=(0,1))                                            num=ac.levels                                                                 colormap=cm.get_cmap('Spectral_r',len(num)-1)                                  cmaps=colormap(range(len(num)-1))                                          camps=cmaps.tolist()                                                        for i,x,y,colorin zip(range(len(num)-2),                                                          range(len(num)-2),                                                                [0.25]*(len(num)-2),                                                            cmaps[1:-1]):                                                    rectangle=Rectangle([x,y],1,0.5,                                                               facecolor=color,                                                                 alpha=1,                                                                             edgecolor='k',                                                                    linewidth=0.02)                                                   ax2.add_patch(rectangle)                                                       left=plt.Polygon(xy=[[-0.75,0.31],[-0.75, 0.69], [-2.5,0.5]],            facecolor=cmaps[0],edgecolor='k',linewidth=0.02)           right=plt.Polygon(xy=[[27.75,0.31],[27.75,0.69],[29.5,0.5]],              facecolor=cmaps[-1],edgecolor='k',linewidth=0.02)              ax2.add_patch(left)                                                              ax2.add_patch(right)                                                            for s in['top','bottom','left','right']:                                                    ax2.spines[s].set_linewidth(0.5)                                            ax2.axis('off')

  3.  雙刻度列colorbar

使colorbar擁有兩條ticks,用於表現不一樣的量度。

import numpy asnp                                                            importmatplotlib as mpl                                                         importmatplotlib.pyplot as plt                                                  importmatplotlib.colors as mcolors                                               plt.rcParams['font.sans-serif']=['SimHei']                                  fig=plt.figure(figsize=(1.5,0.2),dpi=500)                                        ax=fig.add_axes([0,0,1,0.5])                                                 colorlevel=[0.1,10.0,25.0,50.0,100.0,250.0,500.0]colordict=['#A6F28F','#3DBA3D','#61BBFF','#0000FF','#FA00FA','#800040']cmap=mcolors.ListedColormap(colordict)norm=mcolors.BoundaryNorm(colorlevel,cmap.N)fc=fig.colorbar(mpl.cm.ScalarMappable(norm=norm,cmap=cmap),                             cax=ax,orientation='horizontal',extend='both')                   fc.ax.tick_params(which='major',labelsize=3,                                   direction='out',width=0.5,length=1)                           fc.outline.set_linewidth(0.3)                                                 ax2=fc.axax2.xaxis.set_ticks_position('top')ax2.tick_params(labelsize=3,top=True,width=0.5,length=1)式,並使上有刻度                                                                   ax3=ax2.secondary_xaxis('bottom')                                                                           ax3.tick_params(labelsize=3,width=0.5,length=1)                              ax3.spines['bottom'].set_bounds(0.1,500)ax3.set_xticks([40,120,210,290,380,460])                                   ax3.set_xticklabels(['小雨','中雨','大雨','暴雨','大暴雨','特大暴雨'])                    ax3.spines['bottom'].set_linewidth(0.3)

  4.  刻度列與colorbar主體分離

在使用中,實現刻度列於colorbar主體分離的視覺效果。

import numpy asnp                                                               importmatplotlib as mpl                                                       importmatplotlib.pyplot as plt                                             importmatplotlib.colors as mcolors                                           plt.rcParams['font.sans-serif']=['SimHei']                                  fig=plt.figure(figsize=(1.5,0.2),dpi=500)                                     ax=fig.add_axes([0,0,1,0.5])                                                  cmap =mpl.cm.cool                                                             norm = mpl.colors.Normalize(vmin=5,vmax=10)                              fc=fig.colorbar(mpl.cm.ScalarMappable(norm=norm,cmap=cmap),                        cax=ax, orientation='horizontal')                               fc.ax.tick_params(which='major',labelsize=3,                                 direction='out',width=0.5,length=1)                         fc.outline.set_linewidth(0.3)                                                 ax2=fc.axax2.xaxis.set_ticks_position('top')ax2.tick_params(labelsize=3,top=True,width=0.5,length=1)                  ax3=ax2.secondary_xaxis('bottom')ax3.tick_params(labelsize=3,width=0.5,length=3)                              ax3.spines['bottom'].set_bounds(5,10)ax3.set_xticks([5,10])                                                         ax3.set_xticklabels(['0.1mm','500mm'])ax3.spines['bottom'].set_linewidth(0.3)labels=fc.ax.get_xticklabels()                                                    ax2.axis('off')                                                                   fc.outline.set_color('none')                                                      ax3.spines['bottom'].set_position(('outward',10))

  5.使用Legend命令生成仿colorbar

在繪製圖片時,我們還可以使用Legend命令來生成仿colorbar,在一些氣象預報降雨量圖和文獻數值範圍參考比較常見。在levels較少的情況下,且已經知道全部顏色色號,可以手動添加圖例,如:

larger1=mpatches.Rectangle((0,0), 1, 1, facecolor="#A6F28F")             larger2=mpatches.Rectangle((0,0), 1, 1, facecolor="#3DBA3D")               larger3=mpatches.Rectangle((0,0), 1, 1, facecolor="#61BBFF")              larger4=mpatches.Rectangle((0,0), 1, 1, facecolor="#0000FF")               larger5=mpatches.Rectangle((0,0), 1, 1, facecolor="#FA00FA")               labels=['0-10','10-25','25-50','50-100','100-250']                              ax.legend([larger1,larger2,larger3,larger4,larger5],labels,                                    fontsize=12,frameon=False,                                          title='圖例(mm)',facecolor='none',                                  loc='lower left', bbox_to_anchor=(-0.01,-0.02),                                 fancybox=False)

Legend的詳細參數在基礎繪圖命令章節,請互相參閱。

在不清楚每節具體色號時,我們可以使用循環的方法添加圖例,如:

cs=ax.contourf(cycle_LON,cycle_LAT, cycle_t,                                   levels=np.arange(-60,60,10),cmap='RdBu_r',extend='both')                  cmap=cm.get_cmap('RdBu_r',len(cs.levels)-1)                                 color_list=(cmap(range(len(cs.levels)-1)))                                 Rectangles=[ ]                                                                    text=[ ]                                                                       for l incs.levels[::-1]:                                                           text.append(f'{int(l-10)}~{int(l)}')                                          for color incolor_list[::-1]:                                                       Rectangles.append(mpatches.Rectangle((0,0), 1, 1, facecolor=color)) ax.legend(handles=Rectangles,labels=text,loc='lowerright', fontsize=3,                                   title='溫度',                                                                    frameon=False,                                                               fancybox=False,                                                              handletextpad=2,                                                                handlelength=3,                                                               handleheight=1.5,                                                              title_fontsize=5,                                                               bbox_to_anchor=(1.25,0),                                                      labelspacing=0.5)                           

這裡使用的是直接操作colormap方式生成新的legend,你也可以使用get_facecolor來獲取當前contourf的顏色:

  6.  一個數值間隔對應多個顏色問題的處理

這個問題是在不正確的使用顏色映射表時發生的,發生問題有兩個原因:一、不恰當的使用了顏色映射規則,如在定製化cmap與colorbar章節的norm中使用了Normalize規則,則必然使一個數值間隔對應多個顏色;二、由於colormap中存儲的顏色數組長度少於levels數組長度。其中後一個原因在使用cmaps引入NCL中的cmap時比較容易發生。例如:

pc1=ax1.contourf(olon,olat,rain_new,                                    levels=np.arange(0,500,                             cmap=cmaps.sunshine_9lev)                                     pc2=ax2.contourf(olon,olat,rain_new,                               levels=np.array([0,50,100,250,300,500]),                  cmap=cmaps.sunshine_9lev)

這個時候,只能將levels的長度縮短,使其短於cmap存儲的顏色數組長度。NCL的顏色條存儲的顏色是不一致的,例如上面引入的sunshine_9lev,該cmap只存儲了10種顏色,而你設定的levels竟然達到100,則必然出現錯位的情況。

Matplotlib的colormap基本不存在這種情況,因為其每個cmap都存有256個顏色。

定製化cmap與colorbar

在實際數據可視化使用中,cmap其實只是一連串的存儲的代表顏色的數組,與數值沒有確實的聯繫。例如在contourf繪製填色等值線圖時,只要修改levels參數,就會使某個顏色代表的數值出現變化,為了體現這種變化,matplotlib的colors模塊提供了規範化類語句,以實現我們的客觀需求。讀者可以去官網參考全部的規範化類語句。這裡我們僅僅深入研討幾種常用類語句。

  1.LinearSegmentedColormap

混色分割類函數,該命令可以針對使用者輸入的顏色列表和切割N值,調配出新的colormap。該命令類似美術中的調色板,同過原始顏色列表中的臨近顏色混合出新的顏色。而隨著顏色列表與N值的改變,生成的新cmap也會改變,如下面,給出兩個顏色'tab:red','tab:blue'和不同的N值來生成新cmap:

import matplotlib.colorsas mcolors                                            color_list=['tab:red','tab:blue']                                             new_cmap=mcolors.LinearSegmentedColormap.from_list('new_cmap',                                                    color_list,N=2)                    norm=mpl.colors.Normalize(vmin=5,vmax=10)                            fc=fig.colorbar(mpl.cm.ScalarMappable(norm=norm,cmap=new_cmap),                         cax=ax, orientation='horizontal')

這裡我們只要求新生成的cmap只有兩個顏色即可,所以我們輸入的兩個顏色不經過調色,直接被輸出出來。當我們修改N為5,與數值間隔數量相同時:

new_cmap=mcolors.LinearSegmentedColormap.from_list('new_cmap',                                                       color_list,N=5)

這時,colorbar中間部分明顯體現出兩種顏色混交出新的顏色。通過更改原始顏色列表和N值,我們可以調配出更多的colormap,如:

color_list=['tab:red','tab:blue','tab:green','new_cmap=mcolors.LinearSegmentedColormap.from_list('new_cmap',                         color_list,50)                       norm=mpl.colors.Normalize(vmin=5,vmax=10)                              fc=fig.colorbar(mpl.cm.ScalarMappable(norm=norm,cmap=new_cmap),                       cax=ax, orientation='horizontal')                                 

這個命令默認只使臨近的兩個顏色之間調配出新的顏色。

  2.ListedColormap

拼接顏色列表類函數,該命令只能單純拼接顏色列表裡的全部顏色,顏色分割線明顯,不會出現混調色。最常使用的是氣象降水量色條的定製,以及其他需要使用者自定義顏色條的情況。

colorlevel=[0.1,10.0,25.0,50.0,100.0,250.0,500.0]                                  colorlist=['           'cmap=mcolors.ListedColormap(colorlist)                                    norm=mcolors.BoundaryNorm(colorlevel,cmap.N)                             fc=fig.colorbar(mpl.cm.ScalarMappable(norm=norm,cmap=cmap),                          cax=ax, orientation='horizontal')                                

  3.norm

正如之前提到的,我們需要針對顏色與數值來形成映射,這種映射規則在colors模塊中叫做norm。常規繪製contourf時,我們輸入的levels就叫做一種norm,此時的映射規則擁有最高的優先性,使用levels參數將會掩蓋其他norm命令。這是最常見的情況,在使用默認cmap時常用這種方式。當然在我們之後的使用中,因為繪圖的特殊需求,我們還需要其他的映射規則。

Matplotlib的開發者並沒有將設定等級的levels命令進行普遍化,造成該便捷命令只能在contour、contourf裡使用。而像其他的常見顏色映射命令scatter、pcolormesh是無法使用的,只有設定上下線的vmin、vmax可以限制範圍,這時我們可以使用norm來指定數值與顏色的映射規則,例如:

import numpy asnp                                                               import pandas aspd                                                        importmatplotlib.pyplot as plt                                                  importmatplotlib.colors as mcolors                                            importmatplotlib.ticker as mticker                                             importcartopy.crs as ccrs                                                        importcartopy.io.shapereader as shpreader                                   importcartopy.mpl.ticker as cmt                                             import cmaps                                                               importmatplotlib as mpl                                                        fromscipy.interpolate import Rbf                                             plt.rcParams['font.sans-serif']=['FangSong']                                     plt.rcParams['axes.unicode_minus']=False                                     pro=ccrs.PlateCarree()                                                         extent=[108.3,109.4,29.7,30.7]                                               def create_map(ax,extent):                                                        ax.add_geometries(shpreader.Reader(r'E:\利川.shp').geometries(),                              crs=ccrs.PlateCarree(),linewidth=0.5,                                       edgecolor='k',facecolor='none')                                ax.set_extent([108.3,109.35,29.7,30.7],crs=pro)                                  ax.set_xticks(np.arange(extent[0],extent[1], 0.2))                                 ax.set_yticks(np.arange(extent[2],extent[3]+0.2, 0.2))                       ax.tick_params(which='both',labelsize=4,top=True,                                  ax.tick_params(which='both',labelsize=4,top=True,                                                     right=True,width=0.5)       ax.xaxis.set_major_formatter(cmt.LongitudeFormatter())                       ax.yaxis.set_major_formatter(cmt.LatitudeFormatter())                       ax.grid(axis='both',which='major',linewidth=0.6,color='w',                                             alpha=0.45,linestyle='--',zorder=5)                               ax.spines['geo'].set_linewidth(0.5)                                                ax.minorticks_on()                                                            fig=plt.figure(figsize=(5,4.2),dpi=700)                                        ax1=plt.subplot(221,projection=pro,facecolor='#E8E6E7')                    ax2=plt.subplot(222,projection=pro,facecolor='#E8E6E7')                       ax3=plt.subplot(223,projection=pro,facecolor='#E8E6E7')                        ax4=plt.subplot(224,projection=pro,facecolor='#E8E6E7')                          for ax in [ax1,ax2,ax3,ax4]:                                                    create_map(ax,extent)                                                    filename=r'C:\Users\lenovo\Desktop\3.xlsx'                                      df=pd.read_excel(filename)                                                    lon=df['經度']                                                                   lat=df['緯度']                                                                    rain=df['rain']                                                                as1=ax1.scatter(lon,lat,c=rain,s=24,cmap='plasma_r')                            cb1=fig.colorbar(as1,ax=[ax1],shrink=0.9)                                    ax1.set_title('默認norm的scatter',fontsize=7)                                       cmap =mpl.cm.plasma_r                                                     colorlevel=[0.1,10,25,50,100,200,250,500]                                       norm=mcolors.BoundaryNorm(colorlevel,cmap.N)                               as2=ax2.scatter(lon,lat,c=rain,s=24,cmap='plasma_r',norm=norm)                       cb2=fig.colorbar(as2,ax=[ax2],shrink=0.9)                                ax2.set_title('指定norm的scatter',fontsize=7)                                        olon=np.linspace(108,111,110)                                              olat=np.linspace(29,32,110)                                                   olon,olat=np.meshgrid(olon,olat)                                               func=Rbf(lon,lat,rain,function='linear')                                                rain_new=func(olon,olat)                                                      pc1=ax3.pcolormesh(olon,olat,rain_new,cmap='viridis_r')                    cb3=fig.colorbar(pc1,ax=[ax3],shrink=0.9)                                  ax3.set_title('默認norm的pcolormesh',fontsize=7)                                 cmap2 =mpl.cm.viridis_r                                                                  norm2=mcolors.BoundaryNorm(colorlevel,cmap2.N)                           pc2=ax4.pcolormesh(olon,olat,rain_new,norm=norm2,cmap='viridis_r')                cb4=fig.colorbar(pc2,ax=[ax4],shrink=0.9)                                      ax4.set_title('指定norm的pcolormesh',fontsize=7)                            for cb in[cb1,cb2,cb3,cb4]:                                                            cb.ax.tick_params(length=2,labelsize=4)                                       

通過比較兩個默認norm的scatter、pcolormesh圖片我們可以看出,由於嚴格的線性映射,色階與數值的關係劣化嚴重,尤其是低數值面積對應的單色調區域佔圖片幅面面積較大。然後通過我們指定新的norm,使顏色與數值的對應映射關係得到改善。下面介紹常見的幾種norm:

3.1 Normalize

即默認的norm,即所有顏色均勻排列,與數值間隔大小無關係,數值之間沒有清晰的分界線,同一個數值間隔可以對應若干個顏色間隔,如:

  3.2  BoundaryNorm

顧名思義,該命令下的顏色與數值間隔一一對應,擁有明顯的分界線,一個數值間隔只有一個顏色與之相匹配。這是我們常見的使用方法,如:

  3.3  CenteredNorm 

偏度中心映射規則,使我們的中心值附近鈍化,默認中心值為0,如:

該命令在matplotlib3.4.2版本中被注釋掉,暫時無法使用。

  3.4 LogNorm

指數化數值顏色對應規則,詳參官網文檔。

  3.5 PowerNorm

Power law映射規則,通過改變gamma值,來改變原本的Normalize對應關係,改變後,一個數值間隔仍然可能包含多個顏色,但比原來默認效果稍好,如:

  3.6 TwoSlopeNorm

該命令使色條圍繞中心產生相同的刻度比例,如果是拼接色條,vcenter給出的值的位置就是拼接位置,如:

在上兩條colorbar中,設定vcenter=300時,則兩色條拼接處鉚定300;設定vcenter=0時,則兩色條拼接處鉚定0。

從這個特性來看,我們在繪製類似鉚定0值時的colormap時有特別的用處,如:

在使用上圖3顏色條時,我們需要使紅藍陰陽色關於0值對稱,但是可以發現,藍色的賦值其實都在0~-0.5的範圍,深藍色的部分實際上是沒有被使用過的。這時如果如圖1單純只改變vmin、vmax範圍,則會造成0刻度掉入藍色區,紅藍陰陽色不再關於0值對稱。如果使用TwoSlopeNorm,則可以鉚定0值為中心值,如圖二:

Reds=mpl.cm.get_cmap('Reds')                                                    Blues_r=mpl.cm.get_cmap('Blues_r')                                           Redslist=Reds(np.linspace(0,1, 256))                                              Bluerlist=Blues_r(np.linspace(0.25,1,256))                                   new_list=np.vstack((Bluerlist,Redslist))                                      ncmap=mcolors.LinearSegmentedColormap(colors=new_list,                                                          name='newcmap')                    norm=mcolors.TwoSlopeNorm(vmin=-0.5,vcenter=0,vmax=1)             

  3.7 FuncNorm

使用者自定義函數來映射顏色,詳參官網文檔,該命令matplotlib3.4.2版本中被注釋掉,暫時無法使用。

相關焦點

  • 氣象繪圖|最全的matplotlib colorbar設置,總有一款能滿足你!
    colorbar、收縮colorbar的主副刻度、雙刻度列colorbar、截取與拼接cmap、外部顏色引入cmaps與palettable庫包、特別的格式定製、levels等距而colorbar刻度距離不等距、其他類型的偽colorbar、使刻度側的框線與colorbar柱體分離。
  • Python 選取colorbar中部分顏色
    今天給大家分享一個我覺得挺實用的,NCL無敵簡單,但是python我花了很久才解決的colorbar的問題。
  • 再談Matlab-colorbar(附中國區域DEM地形數據)
    0 Matlab繪製兩端帶尖角的colorbar《Matlab繪製兩端帶尖角的colorbar》1 普通colorbar('eastoutside');caxis([-100,2400])colormap([m_colmap('gland',80)]);%%添加句柄及中國地圖hold onma=shaperead('F:/Rpeng/32/data/henan_province.shp');m_line([ma(:).X],[ma(:).Y],'color','k');%繪製範圍內的地圖m_grid('linestyle
  • Python可視化 | 多樣Colorbar定製化繪製技巧
    colorbar的仿製:彎曲與環形的colorbar、兩端分離的colorbar、收縮colorbar的主副刻度、雙刻度列colorbar、截取與拼接cmap、外部顏色引入cmaps與palettable庫包、特別的格式定製、levels等距而colorbar刻度距離不等距、其他類型的偽colorbar、使刻度側的框線與colorbar柱體分離。
  • Python氣象數據處理與繪圖:Python繪圖如何自定義或使用NCL中的colormap
    不夠豐富,本文介紹Matplotlib的自帶色板,並介紹Python繪圖如何使用NCL中的colormap,甚至自定義色板(比如使用氣象家園調色盤生成的色板)。一、Matplotlib 自帶colormap在繪製等高線圖也就是contourf時,需要設置合適的colormap(cmap)。下面給出Matplotlib自帶的colormap。
  • Python-matplotlib 多子圖共用colorbar
    在推出散點顏色密度圖的matplotlib 繪製教程後
  • Python空間繪圖-Colorbar詳解
    第一個參數為colorbar傳入參數,代表colorbar所關聯的contourf,這種方式是最簡單的默認傳入,繪製出來的colorbar和cf是相匹配的,展示的也是cf的信息。cf=ax.contourf(... ...)fig.colorbar(cf)第二個參數為colorbar繪製的默認子圖位置參數,代表當前這個colorbar將要擺放的子圖位置。
  • python畫圖自定義colorbar
    自定義colorbar包含兩方面:這兩項比較簡單和實用,matplotlib和seaborn都可以嘗試。
  • 用MATLAB做二維colorbar
    不知道大家看到這兩幅圖片的感覺是怎樣,可能第一感覺是雖然圖花裡胡哨的,但是還蠻好看的,這是因為作者繪圖採用了「二維colorbar
  • 教程| 海外新冠疫情最新動態!南丁格爾玫瑰圖Origin畫這個圖需要25...
    通過本文教程可以學習25項技巧,這些都是在平常繪圖中經常會用到的技巧。1. 南丁格爾玫瑰圖這是什麼圖?她有一個美麗的名字:南丁格爾玫瑰圖南丁格爾玫瑰圖其實是一種柱狀圖(或直方圖),南丁格爾將傳統柱狀圖變換成美麗生動的玫瑰圖。她將直角坐標系轉換成極坐標系。非常偉大!南丁格爾!
  • GraphPad繪圖最全教程!
    長按二維碼關注,回覆:軟體和模板即可長按二維碼關注,回覆:箱線和折線圖查看然後把處理好的圖片組合在半欄或者全欄裡:3、免費下載:Origin2021破解版本+最全教程!4、教你用Origin做300張科研論文圖!5、手把手教你OriginPro繪製各種統計圖(附中文版安裝包免費下載)6、教你用Image J處理各種科研論文圖!
  • 嵌體、全冠、樁冠、固定橋……牙體預備最全教程
    嵌體、全冠、樁冠、固定橋……牙體預備最全教程
  • 手殘向 最全的基礎手法可愛髮型教程
    5、將臉周的頭髮從耳上位置的頭髮開始向上做外卷。6、取距離步驟5間隔一段距離的發束做內卷,直至全頭。3、取最靠近臉的發束,先以編麻花辮的手法,將發束從上方編至剩餘兩個發束的中央,再取離臉部最遠的發束,同樣從上方編至其餘兩個發束的中央。
  • 教程|PPT繪製箭頭最全攻略,收藏一下!
    那麼,我們從最簡單的開始。首先,PPT繪製箭頭有哪些方法呢?首先是QQ截圖顯示的箭頭,我們通過插入和編輯頂點來做。教程|科研繪圖PPT三維建模系列教程(這裡面有我課堂地址)獲取軟體或文件下載方法:任選精彩回放推文分享至朋友圈,截圖發後臺或低調推薦本號給好友增粉,截圖發後臺回復關鍵字:PPT箭頭
  • InDesign設計排版,最全教程來襲!
    生活中排版無處不在,小至巴掌大的名片大導幾層樓巨幅海報,可有的像工藝品,想拍下來,收藏起來,有的瞄一眼就斷定是廢紙想丟進垃圾桶,這其中的生死法則就是然而在網絡上,卻很少有理論+實戰+技巧 的 InDesign排版教程並且同時涵蓋:
  • 最全Sublime Text教程
    # 摘要(Abstract)本文系統全面的介紹了 Sublime Text,旨在成為最優秀的Sublime Text 中文教程。而這樣優秀的編輯器卻沒有一個靠譜的中文教程,所以我試圖通過本文彌補這個缺陷。
  • 《旅行青蛙》最全的中文版圖文攻略教程
    《旅行青蛙》沉迷了一天,超級好玩,還不知道這款遊戲的玩家,或者還沒入手的玩家,下面小編就為玩家帶來《旅行青蛙》新手入門教程,一起來看看吧
  • 眼妝教程 | 外雙、內雙、單眼皮最全眼妝教程!
    但是睜開眼睛後,除了外雙,內雙和單眼皮是完全看不到眼影的。這個最常見的畫法,也是最自然放大眼睛的方法。這個範圍加一點點外眼線(眼線筆)和同色系的下眼影,就可以很自然放大眼睛,最適合日常畫。這兩年很火的粉色系眼影,怕眼腫的妹紙,就可以按照這個範圍試著畫一畫。