cartopy
cartopy copied to clipboard
Quiver and Barbs plots require modification of set_UVC behavior
Description
Quiver.set_UVC and Barbs.set_UVC functions are provided by matplotlib for faster update of vector data. Cartopy redefines Quiver and Barbs for GeoAxes to correctly apply the axis projection; however, set_UVC needs to be modified to apply projections as well.
Code to reproduce
This script plots a vector field that should point towards the north pole everywhere, using two approaches which should lead to identical plots. The first plot works correctly, but the second (updating data with set_UVC) loses the projection information and plots vectors pointing in the screen-up direction.
import matplotlib.pyplot as plt
import numpy as np
import cartopy.crs as ccrs
import cartopy.feature as cfeature
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1, projection=ccrs.Orthographic(90, 80))
ax.add_feature(cfeature.OCEAN, zorder=0)
ax.add_feature(cfeature.LAND, zorder=0, edgecolor='black')
ax.set_global()
ax.gridlines()
x = np.linspace(0, 300, 31)
y = np.linspace(60, 80, 3)
x2d, y2d = np.meshgrid(x, y)
# Vector field that points uniformly towards north pole, i.e., up in the PlateCarree projection.
u = np.zeros(x2d.shape)
v = np.ones(x2d.shape)
Q = ax.quiver(x, y, u, v, transform=ccrs.PlateCarree())
ax.set_title('Vectors plotted using geoaxes.quiver')
plt.savefig('arrows_1.jpg')
Q.set_UVC(u, v)
ax.set_title('Vectors plotted using set_UVC')
plt.savefig('arrows_2.jpg')
arrows_1.jpg (the one that plots correctly):
arrows_2.jpg (the one that fails to apply the projection):
Similar behavior has also been observed in https://stackoverflow.com/questions/66291698.
Impact
Due to this issue, Quiver and Barbs plotting behavior when using Cartopy does not match Matplotlib; one application that relies on set_UVC for performance is animation of vector fields on maps.
Although it's hard to be quite sure, likely this overlaps with the older issue #1684.
I'm guessing we'd need to add a GeoQuiver and GeoBarb collection to handle these updates properly, similar to what we've done for GeoQuadMesh: https://github.com/SciTools/cartopy/blob/main/lib/cartopy/mpl/geocollection.py which we then return in pcolormesh()
calls here https://github.com/SciTools/cartopy/blob/60c8c20b4f1c481468acc6058299fba440020ed0/lib/cartopy/mpl/geoaxes.py#L1782-L1784