Search code examples
pythonmatplotlibtransformcartopy

How to transpose from cartopy to axes coords


I have a cartopy GeoAxesSubplot with some points, and potentially lines or polygons. The projection could be any that is supported by cartopy, including orthographic.

I can plot using different transformations, as explained here:

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

# Projection could be any, e.g. globe or Arctic Stereopolar...
ax = plt.axes(projection=ccrs.Mollweide())
ax.coastlines()

# Plot using the coordinate system of the Axes
a = ax.plot(0.45, 0.5, transform=ax.transAxes, marker='o', ms=10)

# Plot using the projected coordinates using cartopy.crs
b = ax.plot(0, 0, transform=ccrs.PlateCarree() , marker='o', ms=10)

enter image description here

I would like to transform geographical coordinates to get the cartesian coordinates of the object in the axis (e.g. a subplot). That is, the coordinates in the range [0,1] in the axes of the figure, with (0,0) in the lower-left corner, and (1,1) in the upper-right.

In the case above, b should be converted to (0.5, 0, 5) as it is in the center of the map.

Something similar can be done using transform_points, however, I have not been able to transpose to axes-coords.

A number of parameters are defined in matplotlib and cartopy to control where the object is on the map (extent, projection, center meridian, view elevation etc). Hence, introduce another library might be awkward.


Answer given e.g. here explains how the reverse is achievable, however, the example does not give the right answer for how to generate axes coords.


Solution

  • Keep in mind that "geographical coordinates" is not that well defined, since you're mixing two projections (Mollweide & PlateCarree) which both use "geographical coordinates". Also be careful with using the exact center, since that might accidentally look correct, even if you use incorrect coordinates.

    So you might first need to convert your data to the projection of the map (projection).

    Other than that the Matplotlib transformation tutorial you link to provides all the information necessary to do the transforms.

    Setting up the inputs:

    from matplotlib import pyplot as plt
    import cartopy.crs as ccrs
    
    # sample point coordinates in Plate-Carree
    x_pc = -110.0 # longitude
    y_pc = 45.0 # latitude
    
    map_proj = ccrs.Mollweide()
    data_proj = ccrs.PlateCarree()
    

    The conversion depends on the xlim and ylim of the axes, so it's important to set use ax.set_global() first. That gives a proper mapping from the projection to the display coordinates (and subsequent axes coordinates).

    fig, ax = plt.subplots(subplot_kw=dict(projection=map_proj), facecolor='w')
    ax.set_global()
    ax.coastlines()
    
    b = ax.plot(x_pc, y_pc, 'go', transform=data_proj, ms=5)
    
    # convert to map-coordinates (Mollweide)
    x_mollw, y_mollw = ax.projection.transform_point(x_pc, y_pc, data_proj)
    
    # convert to display coordinates
    x_disp, y_disp = ax.transData.transform((x_mollw, y_mollw))
    
    # convert to axes coordinates
    x_axes, y_axes = ax.transAxes.inverted().transform((x_disp, y_disp))
    
    # plot same point but using axes coordinates
    ax.plot(x_axes, y_axes, 'ro', transform=ax.transAxes, ms=10, mfc='none', mew=2)
    

    enter image description here