Spencer Hill
Spencer Hill

Reputation: 899

How to get "L" shaped ticklabels when using cartopy and AxesGrid

(Copied over from this Github issue)

I am attempting to modify the ticklabels of Axes that use cartopy + AxesGrid, following the example shown in the cartopy docs here. But unlike the example, I only want ticklabels in an "L" shape, i.e. vertical ticklabels on the leftmost column and horizontal ticklabels on the bottom row.

When I edit the horizontal ticklabels of any ax, the horizontal ticklabels of all axes in that column get changed with it. And likewise for vertical ticklabels and all axes in that row. (This is true w/ AxesGrid with or without cartopy, but in the latter case I can just set label_mode='L' and not have to bother with changing them manually.)

I created a MWE in this gist which is reproduced here:

import cartopy.crs as ccrs
from cartopy.mpl.geoaxes import GeoAxes
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.axes_grid1 import AxesGrid

fig = plt.figure()
projection = ccrs.PlateCarree()
axes_class = (GeoAxes,
              dict(map_projection=projection))

axgrid = AxesGrid(fig, 111, axes_class=axes_class,
                  nrows_ncols=(2, 2), 
                  axes_pad=0.3,
                  label_mode='')

for n, ax in enumerate(axgrid):
    ax.set_xticks(np.linspace(-180, 180, 5), crs=projection)
    ax.set_yticks(np.linspace(-90, 90, 5), crs=projection)

# Removing the xticklabels from the upper right corner panel
# also removes them from the lower right corner panel
axgrid[1].set_xticklabels([])

Upvotes: 2

Views: 174

Answers (1)

Spencer Hill
Spencer Hill

Reputation: 899

A workaround solution, thanks to @spencerkclark, is available in this gist and reproduced here.

fig = plt.figure()
projection = ccrs.PlateCarree()
axes_class = (GeoAxes,
              dict(map_projection=projection))

axgrid = AxesGrid(fig, 111, axes_class=axes_class,
                  nrows_ncols=(2, 2), 
                  axes_pad=0.3,
                  label_mode='')

for n, ax in enumerate(axgrid):
    ax.set_xlim(-180, 180)
    ax.set_ylim(-90, 90)
    ax.set_xticks(np.linspace(-180, 180, 5), crs=projection)
    ax.set_yticks(np.linspace(-90, 90, 5), crs=projection)


# Make ticklabels on inner axes invisible
axes = np.reshape(axgrid, axgrid.get_geometry())
for ax in axes[:-1, :].flatten():
    ax.xaxis.set_tick_params(which='both', 
                             labelbottom=False, labeltop=False)

for ax in axes[:, 1:].flatten():
    ax.yaxis.set_tick_params(which='both', 
                             labelbottom=False, labeltop=False)

EDIT: this logic fails if the number of panels is less than nrows*ncols, e.g. if it's a 4x2 grid but only 7 panels. The following works for those cases also:

def _hide_inner_ax_ticklabels(axgrid):
     """Produce 'L' shaped ticklabels: left row and bottom column only.

    Must do this manually when using axgrid + cartopy due to bug.
    See https://github.com/SciTools/cartopy/issues/939.
    """
    total_panels = axgrid._nrows * axgrid._ncols
    blank_panels = total_panels - axgrid.ngrids
    newgrid = np.concatenate([axgrid, [None]*blank_panels])
    axes = np.reshape(newgrid, axgrid.get_geometry())
    for ax in axes[:-1, :].flatten():
        try:
            ax.xaxis.set_tick_params(which='both', labelbottom=False, 
                                     labeltop=False)
        except AttributeError:
            pass

    for ax in axes[:, 1:].flatten():
        try:
            ax.yaxis.set_tick_params(which='both', labelbottom=False, 
                                     labeltop=False)
        except AttributeError:
            pass

Upvotes: 2

Related Questions