Search code examples
python-3.xmatplotlibcartopy

Single-arrow quiver plots don't seem to work with the cartopy PlateCarree transform


I'm trying to create single arrows at a time (i.e. just showing a wind vector at one location) using plt.quiver on a map. However, using when doing so (by using the ccrs.PlateCarree() transform) I get an issue where some sub-function is trying to get the number of dims of the 0-dim array / int.

Here's some minimal working examples:

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

#### Works: simple quiver plot
plt.quiver(0,0,1,-1)


#### Works: simple quiver plot on a map axis, without specifying transform (this obviously would get the location wrong, but just to show what works/doesn't)
plt.subplot(projection=ccrs.EckertIV())
plt.quiver(0,0,1,-1)

#### Works: simple quiver plot on a map axis with some other transform
plt.subplot(projection=ccrs.EckertIV())
plt.quiver(0,0,1,-1,transform=ccrs.EckertIV())

#### Doesn't work: simple quiver plot on a map axis with the PlateCarree transform
plt.subplot(projection=ccrs.EckertIV())
plt.quiver(0,0,1,-1,transform=ccrs.PlateCarree())

This last call produces the following error:

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-93-dec36b09994d> in <module>
      1 plt.subplot(projection=ccrs.EckertIV())
----> 2 plt.quiver(0,0,1,-1,transform=ccrs.PlateCarree())

~/.conda/envs/climate1/lib/python3.7/site-packages/matplotlib/pyplot.py in quiver(data, *args, **kw)
   2791 def quiver(*args, data=None, **kw):
   2792     __ret = gca().quiver(
-> 2793         *args, **({"data": data} if data is not None else {}), **kw)
   2794     sci(__ret)
   2795     return __ret

~/.conda/envs/climate1/lib/python3.7/site-packages/cartopy/mpl/geoaxes.py in wrapper(self, *args, **kwargs)
    308 
    309         kwargs['transform'] = transform
--> 310         return func(self, *args, **kwargs)
    311     return wrapper
    312 

~/.conda/envs/climate1/lib/python3.7/site-packages/cartopy/mpl/geoaxes.py in quiver(self, x, y, u, v, *args, **kwargs)
   1837             # Transform the vectors if the projection is not the same as the
   1838             # data transform.
-> 1839             if (x.ndim == 1 and y.ndim == 1) and (x.shape != u.shape):
   1840                 x, y = np.meshgrid(x, y)
   1841             u, v = self.projection.transform_vectors(t, x, y, u, v)

AttributeError: 'int' object has no attribute 'ndim'

A workaround right now is to just plot the same arrow twice on top of itself, e.g.

plt.subplot(projection=ccrs.EckertIV())
plt.quiver(np.array([0,0]),np.array([0,0]),np.array([1,1]),np.array([-1,-1]),transform=ccrs.PlateCarree())

but I was wondering if I was missing something in terms of just getting this to work normally.

I'm using cartopy 0.18.0 and matplotlib 3.2.1.

Thanks in advance for any advice!


Solution

  • Sometimes one must adhere to the call signature strictly.

    Call signature:

    quiver([X, Y], U, V, [C], **kw)

    • X, Y: 1D or 2D array-like

    If all of the numbers of X,Y,U,V are put into array form:

    plt.quiver(np.array([0]),np.array([0]), \
               np.array([1]),np.array([-1]), transform=ccrs.PlateCarree())
    

    It will work.