0

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 !

Vitalizzare
  • 4,496
  • 7
  • 13
  • 32
Only god knows
  • 307
  • 1
  • 10

1 Answers1

2

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

Rutger Kassies
  • 61,630
  • 17
  • 112
  • 97
  • Thank you, I think I can follow what you propose and not add the two lines. Yet two issues remain. First, the y-axis are not perfectly consistent between your two figures (30°N/60°N gridline is above the 30/60 gridline of the right panel, the inverse is observed for the Southern Hemisphere). Second, something is struggling me, while copying your code, I am getting rotating y label on the Cartopy map.. is there an issue with my Cartopy version or something ? – Only god knows May 26 '22 at 14:38
  • (adding 'grd.right_labels = False' is deleting right labels + 180° 90°W, which are bottom labels) – Only god knows May 26 '22 at 14:47
  • Robinson and lat/lon aren't completely linear on the latitude, so if you want to align both exactly it's probably best to plot the second axes also using Robinson coordinates, and set the yticks/ticklabels based on the matching latitudes. You can for example use pyproj for such a coordinate conversion. – Rutger Kassies May 27 '22 at 07:03