Search code examples
pythonmatplotlibprojectioncolorbarcartopy

Colorbar labels are not appearing when plotted in subplots as cartopy projections


The colorbar appears nicely, but no values come with it. See the code below.

The code plots 2 columns, each with 4 rows for the maps and an additional row for the colorbars. The labels on the colorbars don't appear, and I don't know why.

import numpy as np
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
from cartopy.mpl.ticker import LatitudeFormatter, LongitudeFormatter

# for labeling lat and lon
lon_formatter = LongitudeFormatter(zero_direction_label=True)
lat_formatter = LatitudeFormatter()

# lon and lat
lon = np.linspace(-180,180,360)
lat = np.linspace(0,90,90)

# initate figure
fig, ax = plt.subplots(5,2,subplot_kw={'projection':  ccrs.PlateCarree(central_longitude=180)}, \
                       gridspec_kw={'height_ratios': [0.33,0.33,0.33,0.33,0.05],'width_ratios': [1, 1], 'wspace': 0.1, 'hspace': 0.1},figsize=[15,10])

# mundhenk plotting
for i in range(0,4):

    # create map
    referenced_data = 20.0 * np.random.rand(90,360)
    im1 = ax[i,0].contourf(lon,lat,referenced_data,cmap='Blues',levels=np.linspace(0,20,6),extend='max')
    ax[i,0].coastlines()
    ax[i,0].set_xticks([0, 60, 120, 180, 240, 300, 360], crs=ccrs.PlateCarree())
    ax[i,0].set_yticks([0, 20, 40, 60, 80], crs=ccrs.PlateCarree())
    if i < 3:
        ax[i,0].set_xticklabels([])
        ax[i,0].yaxis.set_major_formatter(lat_formatter)
    else:
        ax[i,0].xaxis.set_major_formatter(lon_formatter)
        ax[i,0].yaxis.set_major_formatter(lat_formatter)
    ax[i,0].set_ylim(20,80)
    ax[i,0].set_xlim(-100,150)

# Add a colorbar for all subplots
cbar1 = plt.colorbar(im1, cax=ax[4,0], orientation='horizontal', label='(AR Day) / day')
cbar1.ax.set_aspect(0.075)

# tempestextreme plotting
for i in range(0,4):

    # create map
    referenced_data = 20.0 * np.random.rand(90,360)
    im2 = ax[i,1].contourf(lon,lat,referenced_data,cmap='Blues',levels=np.linspace(0,20,6),extend='max')
    ax[i,1].coastlines()
    ax[i,1].set_xticks([0, 60, 120, 180, 240, 300, 360], crs=ccrs.PlateCarree())
    ax[i,1].set_yticks([0, 20, 40, 60, 80], crs=ccrs.PlateCarree())
    if i < 3:
        ax[i,1].set_xticklabels([])
    else:
        ax[i,1].xaxis.set_major_formatter(lon_formatter)
    ax[i,1].set_yticklabels([])
    ax[i,1].set_ylim(20,80)
    ax[i,1].set_xlim(-100,150)

cbar2 = plt.colorbar(im2,cax=ax[4,1],orientation='horizontal')
cbar2.ax.set_aspect(0.075)

enter image description here


Solution

    • ax[4, 0] and ax[4, 1] are specified as ccrs.PlateCarree projections, which is causing the colorbar to display incorrectly.
    • The easiest option seems to be:
      1. Create the subplots as you are doing with gridspec, so a position will be allocated for the colorbars.
      2. Remove the two Axes allocated for the colorbars.
      3. Add new subplots, in the same position, that aren't projections.
      • It's easiest because it doesn't require changing the existing loops.
    import numpy as np
    import matplotlib.pyplot as plt
    import cartopy.crs as ccrs
    from cartopy.mpl.ticker import LatitudeFormatter, LongitudeFormatter
    
    # for labeling lat and lon
    lon_formatter = LongitudeFormatter(zero_direction_label=True)
    lat_formatter = LatitudeFormatter()
    
    # lon and lat
    lon = np.linspace(-180, 180, 360)
    lat = np.linspace(0, 90, 90)
    
    # initate figure
    fig, ax = plt.subplots(5, 2, subplot_kw={'projection': ccrs.PlateCarree(central_longitude=180)},
                           gridspec_kw={'height_ratios': [0.33, 0.33, 0.33, 0.33, 0.05],
                                        'width_ratios': [1, 1],
                                        'wspace': 0.1, 'hspace': 0.1},
                           figsize=[15, 10])
    
    # remove the Axes with a projection
    ax[4, 0].remove()
    ax[4, 1].remove()
    
    # add new subplots that aren't projections
    ax9 = fig.add_subplot(5, 2, 9)
    ax10 = fig.add_subplot(5, 2, 10)
    
    # mundhenk plotting
    for i in range(0, 4):
    
        # create map
        referenced_data = 20.0 * np.random.rand(90,360)
        im1 = ax[i,0].contourf(lon,lat,referenced_data,cmap='Blues',levels=np.linspace(0,20,6),extend='max')
        ax[i,0].coastlines()
        ax[i,0].set_xticks([0, 60, 120, 180, 240, 300, 360], crs=ccrs.PlateCarree())
        ax[i,0].set_yticks([0, 20, 40, 60, 80], crs=ccrs.PlateCarree())
        if i < 3:
            ax[i,0].set_xticklabels([])
            ax[i,0].yaxis.set_major_formatter(lat_formatter)
        else:
            ax[i,0].xaxis.set_major_formatter(lon_formatter)
            ax[i,0].yaxis.set_major_formatter(lat_formatter)
        ax[i,0].set_ylim(20,80)
        ax[i,0].set_xlim(-100,150)
    
    # Add a colorbar for all subplots
    cbar1 = fig.colorbar(im1, cax=ax9, orientation='horizontal', label='(AR Day) / day')
    cbar1.ax.set_aspect(0.075)
    
    # tempestextreme plotting
    for i in range(0, 4):
    
        # create map
        referenced_data = 20.0 * np.random.rand(90,360)
        im2 = ax[i,1].contourf(lon,lat,referenced_data,cmap='Blues',levels=np.linspace(0,20,6),extend='max')
        ax[i,1].coastlines()
        ax[i,1].set_xticks([0, 60, 120, 180, 240, 300, 360], crs=ccrs.PlateCarree())
        ax[i,1].set_yticks([0, 20, 40, 60, 80], crs=ccrs.PlateCarree())
        if i < 3:
            ax[i,1].set_xticklabels([])
        else:
            ax[i,1].xaxis.set_major_formatter(lon_formatter)
        ax[i,1].set_yticklabels([])
        ax[i,1].set_ylim(20,80)
        ax[i,1].set_xlim(-100,150)
    
    cbar2 = fig.colorbar(im2, cax=ax10, orientation='horizontal')
    cbar2.ax.set_aspect(0.075)
    

    enter image description here


    # for labeling lat and lon
    lon_formatter = LongitudeFormatter(zero_direction_label=True)
    lat_formatter = LatitudeFormatter()
    
    # lon and lat
    lon = np.linspace(-180, 180, 360)
    lat = np.linspace(0, 90, 90)
    
    # create subplot mosaic with different keyword arguments
    fig, ax = plt.subplot_mosaic("AB;CD;EF;GH;IJ",
                                 per_subplot_kw={('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'): {'projection': ccrs.PlateCarree(central_longitude=180)}},
                                 gridspec_kw={'height_ratios': [0.33, 0.33, 0.33, 0.33, 0.05],
                                              'width_ratios': [1, 1],
                                              'wspace': 0.1, 'hspace': 0.1},
                                 figsize=[15, 10])
    
    # mundhenk plotting; iterate through the left Axes letters
    for v, i in enumerate(['A', 'C', 'E', 'G']):
    
        # create map
        referenced_data = 20.0 * np.random.rand(90,360)
        im1 = ax[i].contourf(lon,lat,referenced_data,cmap='Blues',levels=np.linspace(0,20,6),extend='max')
        ax[i].coastlines()
        ax[i].set_xticks([0, 60, 120, 180, 240, 300, 360], crs=ccrs.PlateCarree())
        ax[i].set_yticks([0, 20, 40, 60, 80], crs=ccrs.PlateCarree())
        if v < 3:
            ax[i].set_xticklabels([])
            ax[i].yaxis.set_major_formatter(lat_formatter)
        else:
            ax[i].xaxis.set_major_formatter(lon_formatter)
            ax[i].yaxis.set_major_formatter(lat_formatter)
        ax[i].set_ylim(20,80)
        ax[i].set_xlim(-100,150)
    
    # Add a colorbar for all subplots
    cbar1 = fig.colorbar(im1, cax=ax['I'], orientation='horizontal', label='(AR Day) / day')
    cbar1.ax.set_aspect(0.075)
    
    # tempestextreme plotting; iterate through the right Axes letters
    for v, i in enumerate(['B', 'D', 'F', 'H']):
    
        # create map
        referenced_data = 20.0 * np.random.rand(90,360)
        im2 = ax[i].contourf(lon,lat,referenced_data,cmap='Blues',levels=np.linspace(0,20,6),extend='max')
        ax[i].coastlines()
        ax[i].set_xticks([0, 60, 120, 180, 240, 300, 360], crs=ccrs.PlateCarree())
        ax[i].set_yticks([0, 20, 40, 60, 80], crs=ccrs.PlateCarree())
        if v < 3:
            ax[i].set_xticklabels([])
        else:
            ax[i].xaxis.set_major_formatter(lon_formatter)
        ax[i].set_yticklabels([])
        ax[i].set_ylim(20,80)
        ax[i].set_xlim(-100,150)
    
    cbar2 = fig.colorbar(im2, cax=ax['J'], orientation='horizontal')
    cbar2.ax.set_aspect(0.075)