Home > Software design >  Cartopy: set extent for perfectly square map
Cartopy: set extent for perfectly square map

Time:01-03

Assume I need to plot a map with Cartopy and the resulting figure should have square dimensions. In my (simplistic) understanding, this should be easy using the plate carrée projection, since longitude and latitude are directly used as planar coordinates. This means I expect a square map if the extent covered by latitude and longitude are the same.

However, while the following code works if the extent starts at the equator (e.g. [-120, -60, 0, 60]), it fails for an extent apart from the equator. How does the extent have to be computed that the resulting map is a square? (I found this post, but it did not really help since the coordinate transformation only returned the given coordinates).

import cartopy.crs as ccrs
import matplotlib.pyplot as plt

fig, ax = plt.subplots(figsize=[5, 5], subplot_kw={'projection': ccrs.PlateCarree()})
fig.subplots_adjust(left=0.0, bottom=0.0, right=1.0, top=1.0)
ax.set_extent([-120, -60, 15, 75])
ax.stock_img()
fig.savefig('Test.pdf')

The following image shows the output, which unfortunately contains white borders at the vertical edges:

CodePudding user response:

Could it be a property of the chosen projection? You can see it happening when adding the transformation by inspecting the ax._position, ax._originalPosition attributes:

Bbox([[0.015576512213622107, 0.0], [0.9844234877863779, 1.0]])
Bbox([[0.0, 0.0], [1.0, 1.0]])

You can add ax.set_adjustable('datalim') to make it change the limits, instead of the box (of the axes) to fill the given extent. Note how this slightly changes the ax.get_xlim() & ax.get_ylim(), so make sure that's acceptable for your application. I personally often explicitly add the dpi and bbox when saving, to make sure the output has the intended dimensions, see the example below.

When I use a different projection, I can get it to work straightaway, the code below produces a clean 500x500px image with only the axes visible in the output, not the red figure. So perhaps it's a property of the PlateCarree projection?

map_proj = ccrs.Mercator()

fig, ax = plt.subplots(
    figsize=(5, 5), dpi=100, facecolor="r",
    subplot_kw={'projection': map_proj},
)

fig.subplots_adjust(left=0.0, bottom=0.0, right=1.0, top=1.0)
ax.set_extent([-10000000, 10000000, -10000000, 10000000], crs=map_proj)
ax.coastlines()

fig.savefig('Test.png', bbox_inches=0, dpi=100)
  • Related