-
Notifications
You must be signed in to change notification settings - Fork 389
Description
Description
I have a wind field : eastward component u and northward component v, in m s-1. I want to make a quiver plot of this field in north stereographic projection. I would expect the correct command to be:
ax = plt.axes(projection =ccrs.NorthPolarStereo())
ax.quiver(lon, lat, u, v, transform = ccrs.PlateCarree(), angles = "xy")( The complete test code is below.) However, this produces arrows in the wrong direction. It appears that the way to obtain the correct direction for the arrows is to write:
ax.quiver(lon, lat, u / np.cos(lat / 180 * np.pi) , v, transform = ccrs.PlateCarree(), angles = "xy")Note that the magnitude of the vector is not correct then, we should also renormalize it to get the correct magnitude. Compare this with the behavior of basemap:
m = basemap.Basemap(projection="npstere", boundinglat = 50, lon_0 = 0)
u_rot, v_rot, x, y = m.rotate_vector(u, v, lon ,lat, returnxy=True)
m.quiver(x, y, u_rot, v_rot, angles = "xy")which produces correct arrows.
I think this is a bug, or a bad feature of cartopy. The problem comes from the transform_vectors method, as shown in the test code below. In this test code, we want to plot a single vector at longitude 0°, latitude 89°N. The vector is almost westward: u < 0 and v is very small compared to u. In the north stereographic projection, the components of the projected vector should be almost the same than the original components. We see with the test code below that the rotate_vector method of basemap correctly produces this result. However, the transform_vectors of cartopy surprisingly does not produce this result. To get the correct result with transform_vectors, we have to divide u by the cosine of latitude, and renormalize the result from transform_vectors. It seems that transform_vectors expects the derivative of longitude instead of the wind. This is quite awkward to use and counter-intuitive, I think, or a bug. The test code below goes on to plot the single vector, with basemap and with cartopy. We see the red arrow with cartopy in the wrong direction.
Code to reproduce
Here is the complete test code.
#!/usr/bin/env python3
from mpl_toolkits import basemap
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
import numpy as np
m = basemap.Basemap(projection="npstere", boundinglat = 50, lon_0 = 0)
proj = ccrs.NorthPolarStereo()
src_crs = ccrs.PlateCarree()
lon = np.array([0])
lat = np.array([89])
u = np.array([-3])
v = np.array([0.1])
print("m.rotate_vector(u, v, lon ,lat):", m.rotate_vector(u, v, lon ,lat))
print("proj.transform_vectors(src_crs, lon, lat, u, v):",
proj.transform_vectors(src_crs, lon, lat, u, v))
u_rot, v_rot = proj.transform_vectors(src_crs, lon, lat,
u / np.cos(lat /180 * np.pi), v)
print("u_rot, v_rot:", u_rot, v_rot)
renorm = np.sqrt((u**2 + v**2) / (u_rot**2 + v_rot**2))
print("array((u_rot, v_rot)) * renorm:", np.array((u_rot, v_rot)) * renorm)
plt.figure()
u_rot, v_rot, x, y = m.rotate_vector(u, v, lon ,lat, returnxy=True)
m.quiver(x, y, u_rot, v_rot, angles = "xy")
m.drawcoastlines()
plt.title("with basemap")
plt.figure()
ax = plt.axes(projection = proj)
ax.coastlines()
ax.set_extent((-180, 180, 50, 90), src_crs)
ax.quiver(lon, lat, u, v, transform = src_crs, angles = "xy", color = "red")
ax.quiver(lon, lat, u / np.cos(lat / 180 * np.pi), v, transform = src_crs,
angles = "xy")
plt.title("with cartopy")
plt.show()Here is the standard output of the script:
m.rotate_vector(u, v, lon ,lat): (array([-2.99999999]), array([ 0.10000035]))
proj.transform_vectors(src_crs, lon, lat, u, v): (array([-1.3922597]), array([ 2.65925044]))
u_rot, v_rot: [-171.80062661] [ 5.72817851]
array((u_rot, v_rot)) * renorm: [[-2.99999913]
[ 0.10002601]]
And here are the two resulting figures:


Full environment definition
Operating system
Linux Mint 19 Cinnamon
Cartopy version
0.16.0
pip list
apt-clone (0.2.1)
apturl (0.5.2)
asn1crypto (0.24.0)
basemap (1.1.0)
beautifulsoup4 (4.6.0)
Brlapi (0.6.6)
bsddb3 (6.1.0)
Cartopy (0.16.0)
certifi (2018.1.18)
chardet (3.0.4)
command-not-found (0.3)
configobj (5.0.6)
cryptography (2.1.4)
cupshelpers (1.0)
cycler (0.10.0)
Cython (0.26.1)
decorator (4.1.2)
defer (1.0.6)
gpg (1.10.0)
gramps (4.2.8)
graphviz (0.5.2)
httplib2 (0.9.2)
idna (2.6)
ipython (5.5.0)
ipython-genutils (0.2.0)
louis (3.5.0)
lxml (4.2.1)
macaroonbakery (1.1.3)
Mako (1.0.7)
MarkupSafe (1.0)
matplotlib (2.1.1)
mutagen (1.38)
netCDF4 (1.3.1)
netifaces (0.10.4)
numpy (1.15.4)
onboard (1.4.1)
openshot-qt (2.4.1)
OWSLib (0.16.0)
PAM (0.4.2)
paramiko (2.0.0)
pexpect (4.2.1)
pickleshare (0.7.4)
Pillow (5.1.0)
pip (9.0.1)
prompt-toolkit (1.0.15)
protobuf (3.0.0)
psutil (5.4.2)
pyasn1 (0.4.2)
pycairo (1.16.2)
pycrypto (2.6.1)
pycups (1.9.73)
pycurl (7.43.0.1)
Pygments (2.2.0)
pygobject (3.26.1)
PyICU (1.9.8)
pyinotify (0.9.6)
pymacaroons (0.13.0)
PyNaCl (1.1.2)
pyparsing (2.2.0)
pyproj (1.9.5.1)
pyRFC3339 (1.0)
pyshp (2.0.1)
python-apt (1.6.3)
python-dateutil (2.6.1)
python-debian (0.1.32)
python-xapp (1.2.0)
python-xlib (0.20)
pytz (2018.3)
pyxdg (0.25)
PyYAML (3.12)
pyzmq (16.0.2)
reportlab (3.4.0)
requests (2.18.4)
requests-unixsocket (0.1.5)
scipy (0.19.1)
sessioninstaller (0.0.0)
setproctitle (1.1.10)
setuptools (40.6.0)
Shapely (1.6.4.post2)
simplegeneric (0.8.1)
six (1.11.0)
system-service (0.3)
systemd-python (234)
traitlets (4.3.2)
ubuntu-drivers-common (0.0.0)
ufw (0.35)
urllib3 (1.22)
wcwidth (0.1.7)
wheel (0.30.0)
xdot (0.9)
xkit (0.0.0)
youtube-dl (2018.11.7)