【问题标题】:Matplotlib Basemap: Customize Subplot and Colorbar PlacementsMatplotlib 底图:自定义子图和颜色条放置
【发布时间】:2019-11-07 01:21:33
【问题描述】:

我有 4 个不同值的地图,我想用 matplotlib Basemap 将它们一起绘制为 1 个图中的 4 个子图,每个子图都有自己的颜色条。但是我设置颜色条和子图大小和方向的努力似乎失败了(参见下面的代码)。有人知道我做错了什么吗?使用底图时不能自定义子图和颜色条设置吗?

import math
import matplotlib.cm as cm
import matplotlib.colors as colors
import matplotlib.image as mpimg
import matplotlib as mpl
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
import numpy.ma as ma
import numpy as np
import pylab

# Create Variables:

B = np.full((4,60,360), np.nan)
B[0] = np.random.randint(16, size=(60, 360)) + 291
B[1] = np.random.randint(201, size=(60, 360)) - 100
B[2] = np.random.randint(56, size=(60, 360)) - 50
B[3] = np.random.randint(46, size=(60, 360))

# Colorbar Boundary Definitions: 
cmap_1 = cm.jet    
cmap_2 = cm.BrBG   
cmap_3 = cm.hot     
cmap_4 = cm.CMRmap_r
B_plot = np.ma.array ( B, mask=np.isnan(B))
bounds_B = []
norm_B = []
for b in np.arange(4):
    bounds_B.append(b)
    norm_B.append(b)
bounds_B[0] =  np.arange(291, 306, 1)      
bounds_B[1] =  np.arange(-100, 110, 10)    
bounds_B[2] =  np.arange(-50, -7.5, 2.5)   
bounds_B[3] =  np.arange(0, 47.5, 2.5)     
norm_B[0] = mpl.colors.BoundaryNorm(bounds_B[0], cmap_1.N)   
norm_B[1] = mpl.colors.BoundaryNorm(bounds_B[1], cmap_2.N)   
norm_B[2] = mpl.colors.BoundaryNorm(bounds_B[2], cmap_3.N)    
norm_B[3] = mpl.colors.BoundaryNorm(bounds_B[3], cmap_4.N)    

lat = (-1) * (np.arange(-29.5, 30.5, 1))
lon = np.arange(0.5, 360.5, 1)

llc_LON = 0.5
urc_LON = 359.5
llc_LAT = -29.5
urc_LAT = 29.5

fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(9, 5))

# Variable 1
m1 = Basemap(projection='cyl', llcrnrlon=llc_LON, urcrnrlon=urc_LON, llcrnrlat=llc_LAT, urcrnrlat=urc_LAT, resolution='c')
m1.drawcoastlines(color='k')
m1.fillcontinents(color='white')          # mask land mass
lons, lats = np.meshgrid(lon,lat)
x, y = m1(lons,lats)
m1.pcolor(x, y, B_plot[0], cmap=cmap_1, norm=norm_B[0])
img_1 = m1.pcolor(x, y, B_plot[0], cmap=cmap_1, norm=norm_B[0])
axes[0, 0].set_title('Variable 1')
axes[0, 0].set_xlim(llc_LON, urc_LON)
axes[0, 0].set_xticks([0, 45, 90, 135, 180, 225, 270, 315, 360], ['0', '45E', '90E', '135E', '180', '135W', '90W', '45W', '0'])    # 0E to 360E
axes[0, 0].set_ylim(llc_LAT, urc_LAT)
axes[0, 0].set_yticks([-30, -15, 0, 15, 30], ['30S', '15S', '0', '15N', '30N'])    # 30S to 30N
axes[0, 0].set_ylabel('Latitude')
plt.grid()
# Variable 2
m2 = Basemap(projection='cyl', llcrnrlon=llc_LON, urcrnrlon=urc_LON, llcrnrlat=llc_LAT, urcrnrlat=urc_LAT, resolution='c')
m2.drawcoastlines(color='k')
m2.fillcontinents(color='white')          # mask land mass
lons, lats = np.meshgrid(lon,lat)
x, y = m2(lons,lats)
m2.pcolor(x, y, B_plot[1], cmap=cmap_2, norm=norm_B[1])
img_2 = m2.pcolor(x, y, B_plot[1], cmap=cmap_2, norm=norm_B[1])
axes[0, 1].set_title('Variable 2')
axes[0, 1].set_xlim(llc_LON, urc_LON)
axes[0, 1].set_xticks([0, 45, 90, 135, 180, 225, 270, 315, 360], ['0', '45E', '90E', '135E', '180', '135W', '90W', '45W', '0'])    # 0E to 360E
axes[0, 1].set_ylim(llc_LAT, urc_LAT)
axes[0, 1].set_yticks([-30, -15, 0, 15, 30], ['30S', '15S', '0', '15N', '30N'])    # 30S to 30N
plt.grid()
# Variable 3
m3 = Basemap(projection='cyl', llcrnrlon=llc_LON, urcrnrlon=urc_LON, llcrnrlat=llc_LAT, urcrnrlat=urc_LAT, resolution='c')
m3.drawcoastlines(color='k')
m3.fillcontinents(color='white')          # mask land mass
lons, lats = np.meshgrid(lon,lat)
x, y = m3(lons,lats)
m3.pcolor(x, y, B_plot[2], cmap=cmap_3, norm=norm_B[2])
img_3 = m3.pcolor(x, y, B_plot[2], cmap=cmap_3, norm=norm_B[2])
axes[1, 0].set_title('Variable 3')
axes[1, 0].set_xlim(llc_LON, urc_LON)
axes[1, 0].set_xticks([0, 45, 90, 135, 180, 225, 270, 315, 360], ['0', '45E', '90E', '135E', '180', '135W', '90W', '45W', '0'])    # 0E to 360E
axes[1, 0].set_ylim(llc_LAT, urc_LAT)
axes[1, 0].set_yticks([-30, -15, 0, 15, 30], ['30S', '15S', '0', '15N', '30N'])    # 30S to 30N
axes[1, 0].set_ylabel('Latitude')
plt.grid()
# Variable 4
m4 = Basemap(projection='cyl', llcrnrlon=llc_LON, urcrnrlon=urc_LON, llcrnrlat=llc_LAT, urcrnrlat=urc_LAT, resolution='c')
m4.drawcoastlines(color='k')
m4.fillcontinents(color='white')          # mask land mass
lons, lats = np.meshgrid(lon,lat)
x, y = m4(lons,lats)
m4.pcolor(x, y, B_plot[3], cmap=cmap_4, norm=norm_B[3])
img_4 = m4.pcolor(x, y, B_plot[3], cmap=cmap_4, norm=norm_B[3])
axes[1, 1].set_title('Variable 4')
axes[1, 1].set_xlim(llc_LON, urc_LON)
axes[1, 1].set_xticks([0, 45, 90, 135, 180, 225, 270, 315, 360], ['0', '45E', '90E', '135E', '180', '135W', '90W', '45W', '0'])    # 0E to 360E
axes[1, 1].set_ylim(llc_LAT, urc_LAT)
axes[1, 1].set_yticks([-30, -15, 0, 15, 30], ['30S', '15S', '0', '15N', '30N'])    # 30S to 30N
plt.grid()

plt.subplots_adjust(bottom=0.1, hspace=0.2)
colorbar_1 = fig.add_axes([0.1, 0.48, 0.30, 0.015])          
fig.colorbar(img_1, cax=colorbar_1, orientation="horizontal", label='Unit 1', ticks=[291, 293, 295, 297, 299, 301, 303, 305])
colorbar_2 = fig.add_axes([0.55, 0.48, 0.30, 0.015])             
fig.colorbar(img_2, cax=colorbar_2, orientation="horizontal", label='Unit 2', ticks=[-100, -80, -60, -40, -20, 0, 20, 40, 60, 80, 100])
plt.subplots_adjust(bottom=0.05, right=0.80, left=0.21, hspace=0.2)
colorbar_3 = fig.add_axes([0.1, 0.08, 0.30, 0.015])            
fig.colorbar(img_3, cax=colorbar_3, orientation="horizontal", label='Unit 3', ticks=[-50, -45, -40, -35, -30, -25, 20, -15, -10])
colorbar_4 = fig.add_axes([0.55, 0.08, 0.30, 0.015])            
fig.colorbar(img_4, cax=colorbar_4, orientation="horizontal", label='Unit 4', ticks=[0, 5, 10, 15, 20, 25, 30, 35, 40, 45])

plt.show()

【问题讨论】:

    标签: python matplotlib-basemap subplot colorbar


    【解决方案1】:

    主要问题是如何定义plotbar。在这里,我使用for 循环中的当前轴来执行此操作。此外,xthick 没有显示,为了显示它们我使用了set_xticklabels

    然后,我清理了你的代码,因为你大部分时间都在做同样的事情。

    import math
    import matplotlib.cm as cm
    import matplotlib.colors as colors
    import matplotlib.image as mpimg
    import matplotlib as mpl
    import matplotlib.pyplot as plt
    from mpl_toolkits.basemap import Basemap
    import numpy.ma as ma
    import numpy as np
    import pylab
    
    # Create Variables:
    B = np.array([np.random.randint(16, size=(60, 360)) + 291,
                  np.random.randint(201, size=(60, 360)) - 100,
                  np.random.randint(56, size=(60, 360)) - 50,
                  np.random.randint(46, size=(60, 360))])
    
    # Colorbar Boundary Definitions:
    cmap = [cm.jet, cm.BrBG, cm.hot, cm.CMRmap_r]
    
    B_plot = np.ma.array(B, mask=np.isnan(B))
    norm_B = []
    bounds_B = [np.arange(291, 306, 1),
              np.arange(-100, 110, 10),
              np.arange(-50, -7.5, 2.5),
              np.arange(0, 47.5, 2.5)]
    for b in np.arange(4):
        norm_B.append(mpl.colors.BoundaryNorm(bounds_B[b], cmap[b].N))
    
    lat = (-1) * (np.arange(-29.5, 30.5, 1))
    lon = np.arange(0.5, 360.5, 1)
    
    llc_LON = 0.5
    urc_LON = 359.5
    llc_LAT = -29.5
    urc_LAT = 29.5
    
    fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(9, 5))
    
    thicks = [[291, 293, 295, 297, 299, 301, 303, 305],
              [-100, -80, -60, -40, -20, 0, 20, 40, 60, 80, 100],
              [-50, -45, -40, -35, -30, -25, 20, -15, -10],
              [0, 5, 10, 15, 20, 25, 30, 35, 40, 45]]
    
    lons, lats = np.meshgrid(lon, lat)
    
    for row_ind in range(2):
        for col_ind in range(2):
            index = row_ind*2+col_ind
            current_ax = axes[row_ind, col_ind]
            print("row_ind: {0}    col_ind: {1}   index: {2}".format(row_ind, col_ind, index))
    
            map = Basemap(projection='cyl', llcrnrlon=llc_LON, urcrnrlon=urc_LON,
                          llcrnrlat=llc_LAT, urcrnrlat=urc_LAT, resolution='c',
                          ax=current_ax)
            map.drawcoastlines(color='k')
            map.fillcontinents(color='white')          # mask land mass
    
            x, y = map(lons, lats)
    
            img_colors = map.pcolor(x, y, B_plot[index], cmap=cmap[index], norm=norm_B[index])
    
            fig.colorbar(img_colors, ax=current_ax, orientation="horizontal",
                        label='Unit ' + str(index+1), ticks=thicks[index])
    
            current_ax.set_title('Variable ' + str(index+1))
            current_ax.set_xlim(llc_LON, urc_LON)
            current_ax.set_xticks([0, 45, 90, 135, 180, 225, 270, 315, 360]) 
            current_ax.set_xticklabels(['0', '45E', '90E', '135E', '180', '135W', '90W', '45W', '0'])  # 0E to 360E
            current_ax.set_ylim(llc_LAT, urc_LAT)
            current_ax.set_yticks([-30, -15, 0, 15, 30])  # 30S to 30N
            current_ax.set_yticklabels(['30S', '15S', '0', '15N', '30N'])
            current_ax.set_ylabel('Latitude')
    
    
    fig.suptitle('My maps')
    plt.show()
    

    【讨论】:

    • @Alexandre B. 有没有办法以现在编写代码的方式更改颜色条高度?我想让每个颜色条大约一半厚(高)。否则,该代码非常适合我的目的:)
    • 您可以使用fig.color中的fraction参数调整彩条的宽度。例如,fraction=0.03 ?
    • @Alexandre B. 谢谢。可以肯定,分数使颜色条垂直变薄,但我希望颜色条的宽度与子图的宽度保持相同(如上面的示例图所示),但使颜色条的垂直范围约为一半高。对于如何做到这一点,您有什么建议吗?
    • colorbar 调用中的aspect 参数是怎么回事?例如aspect=10.
    • 感谢您的建议!我找到了一个适合我的组合:“pad=0.15, shrink=1.0, aspect=30”
    猜你喜欢
    • 1970-01-01
    • 2021-05-03
    • 2020-09-28
    • 1970-01-01
    • 1970-01-01
    • 2012-08-09
    • 2021-10-16
    • 2016-11-15
    • 2015-02-19
    相关资源
    最近更新 更多