Search code examples
pythonmatplotlibprojectionsubplotcartopy

How to deal well with normal and cartopy projection on the same figure?


I want to produce this kind of figure, taken from Sallee et al. (2021) directly from Python if it is possible :

Figure goal

There is a Cartopy projection cartopy.crs.Robinson(central_longitude=0, globe=None) in the main subplot and at the right of it something close to a density function (over the latitudes) of my value on the Cartopy projection. Managing the labels with Robinson projection is not convenient for me, whereas with cartopy.crs.PlateCarree(central_longitude=0.0, globe=None) I did not have any issues labelling axis.

This is the most related topics (combination of normal and cartopy subplots within the same figure) that I have founded on stack for now but that doesn't ring any bell since my goal plot is a bit more complicated (size of the colorbar above the Robinson projection, two dashed lines to link the subplots, labelling longitudes and latitudes).

Thank you !


Solution

  • Is there anything specific that you didn't manage to create? Most of what you ask for is readily available from Cartopy/Matplotlib.

    Additional annotation, like the inset zoom lines are possible with Matplotlib, see for example:
    https://matplotlib.org/stable/gallery/subplots_axes_and_figures/zoom_inset_axes.html

    But I personally would avoid that and simply align the axes to make sure they share the same latitude. That's probably more intuitive for users trying to interpret the data.

    A quick example with some random data:

    lats = np.linspace(90-6, -90+6, 15)
    data = np.random.randn(15, 32)
    
    proj = ccrs.Robinson(central_longitude=0, globe=None)
    
    fig = plt.figure(figsize=(11, 5), dpi=86, facecolor="w")
    spec = fig.add_gridspec(9, 5)
    
    ax1 = fig.add_subplot(spec[1:, :4], projection=proj)
    im = ax1.imshow(
        data, cmap="Blues", vmin=-3, vmax=3,
        extent=[-180, 180,90,-90], transform=ccrs.PlateCarree())
    
    cax = fig.add_subplot(spec[0, 1:-2])
    cb1 = fig.colorbar(im, cax=cax, orientation="horizontal")
    cax.set_title("Something [-]")
    cax.xaxis.set_ticks_position('top')
    
    grd = ax1.gridlines(
        draw_labels=True, 
        xlocs=range(-180, 181, 90), 
        ylocs=range(-60, 61, 30), 
        color='k',
    )
    grd.top_labels = False
    
    ax1.add_feature(cfeature.LAND, facecolor="#eeeeee", zorder=99)
    
    
    ax2 = fig.add_subplot(spec[1:, -1])
    ax2.plot(data.mean(axis=1), lats)
    ax2.axvline(0, color="k", lw=1)
    ax2.set_xlim(-0.5, 0.5)
    ax2.set_yticks(range(-60, 61, 30))
    ax2.yaxis.set_label_position("right")
    ax2.yaxis.tick_right()
    ax2.grid(axis="y")
    ax2.set_ylabel("Latitude [deg]")
    

    enter image description here