SciTools / cartopy

Cartopy - a cartographic python library with matplotlib support
https://scitools.org.uk/cartopy/docs/latest
BSD 3-Clause "New" or "Revised" License
1.41k stars 359 forks source link

strange behaviour of set_extent with Stereographic projection #1331

Open joernu76 opened 5 years ago

joernu76 commented 5 years ago

Description

Using set_extent to determine the bounding box of the plot gives strange results for Stereographic projections ad extents given in longitude/latitude coordinates.

The example below demonstrates the behaviour. The extent of the projection shall go from -45E/0N in the lower left cornert to 135E/0N in the upper right corner. The first figure has a correct upper right corner, but in my case the lower left crner is located at -45E/-20N. For the second figure, I compute the desired coordinates of the bound using the projection and apply them in projectio-space.

Expected behaviour: Identical plots in both figures.

Code to reproduce

import os
import matplotlib.pyplot as plt
from netCDF4 import Dataset as netcdf_dataset
import numpy as np

from cartopy import config
import cartopy.crs as ccrs

# get the path of the file. It can be found in the repo data directory.
fname = os.path.join(config["repo_data_dir"],
                     'netcdf', 'HadISST1_SST_update.nc')

dataset = netcdf_dataset(fname)
sst = dataset.variables['sst'][0, :, :]
lats = dataset.variables['lat'][:]
lons = dataset.variables['lon'][:]

prj = ccrs.Stereographic(central_longitude=0, central_latitude=90)

fig = plt.figure()
ax = fig.add_subplot(1, 1, 1, projection=prj)
print("default", ax.get_extent())
ax.set_extent([45, -135, 0, 0], ccrs.PlateCarree())
print("set1", ax.get_extent())
ax.contour(lons, lats, sst, 60, transform=ccrs.PlateCarree())
ax.coastlines()

fig = plt.figure()
ax = fig.add_subplot(1, 1, 1, projection=prj)
print("default", ax.get_extent())
coords = prj.transform_points(                                                                
    ccrs.PlateCarree(), np.asarray([45, -135]), np.asarray([0, 0]))
ax.set_extent([coords[0, 0], coords[1, 0], coords[0, 1], coords[1, 1]], prj)
print("set2", ax.get_extent())
ax.contour(lons, lats, sst, 60, transform=ccrs.PlateCarree())
ax.coastlines()

plt.show()

Traceback

not applicable

Operating system

Linux

Cartopy version

0.16.0

### conda list ``` _ipyw_jlab_nb_ext_conf 0.1.0 py37_0 alabaster 0.7.12 py37_0 amqp 2.4.2 py_0 conda-forge anaconda-client 1.7.2 py37_0 anaconda-navigator 1.9.2 py37_0 anaconda-project 0.8.2 py37_0 apipkg 1.5 py37_0 appdirs 1.4.3 py37h28b3542_0 argcomplete 1.9.4 py37_0 asn1crypto 0.24.0 py37_0 astroid 2.1.0 py37_0 astropy 3.0.5 py37h7b6447c_0 atomicwrites 1.2.1 py37_0 attrs 18.2.0 py37h28b3542_0 automat 0.7.0 py37_0 autopep8 1.4.3 py37_0 babel 2.6.0 py37_0 backcall 0.1.0 py37_0 backports 1.0 py37_1 backports.os 0.1.1 py37_0 backports.shutil_get_terminal_size 1.0.0 py37_2 basemap 1.2.0 py37h705c2d8_0 bcrypt 3.1.4 py37h14c3975_0 beautifulsoup4 4.6.3 py37_0 billiard 3.5.0.4 py37h14c3975_1000 conda-forge bitarray 0.8.3 py37h14c3975_0 bkcharts 0.2 py37_0 blas 1.0 mkl blaze 0.11.3 py37_0 bleach 3.0.2 py37_0 blosc 1.14.4 hdbcaa40_0 bokeh 1.0.2 py37_0 boto 2.49.0 py37_0 bottleneck 1.2.1 py37h035aef0_1 breathe 4.13.0 py_0 conda-forge bzip2 1.0.6 h14c3975_5 ca-certificates 2019.5.15 0 cached-property 1.5.1 py37_0 cairo 1.14.12 h8948797_3 cartopy 0.16.0 py37hfa13621_0 celery 4.2.1 py_0 conda-forge certifi 2019.3.9 py37_0 cffi 1.11.5 py37he75722e_1 cftime 1.0.3.4 py37hdd07704_0 chameleon 3.5 py37_0 chardet 3.0.4 py37_1 click 7.0 py37_0 cloudpickle 0.6.1 py37_0 clyent 1.2.2 py37_1 cmocean 1.2 py_0 conda-forge colorama 0.4.0 py37_0 conda 4.6.14 py37_0 conda-build 3.17.1 py37_0 conda-env 2.6.0 1 constantly 15.1.0 py37h28b3542_0 contextlib2 0.5.5 py37_0 coverage 4.5.2 py37h7b6447c_0 cryptography 2.3.1 py37hc365091_0 curl 7.61.0 h84994c4_0 cycler 0.10.0 py37_0 cython 0.29 py37he6710b0_0 cytoolz 0.9.0.1 py37h14c3975_1 dask 1.0.0 py37_0 dask-core 1.0.0 py37_0 datashape 0.5.4 py37_1 dbus 1.13.2 h714fa37_1 decorator 4.3.0 py37_0 defusedxml 0.5.0 py37_1 distributed 1.25.0 py37_0 doc8 0.8.0 pypi_0 pypi docutils 0.14 py37_0 easyprocess 0.2.3 py37_1000 conda-forge ecmwf-api-client 1.5.3 pypi_0 pypi entrypoints 0.3 py37_0 et_xmlfile 1.0.1 py37_0 execnet 1.5.0 py37_0 expat 2.2.6 he6710b0_0 fastcache 1.0.2 py37h14c3975_2 fdb 2.0.0 py_0 conda-forge ffmpeg 4.0 hcdf2ecd_0 filelock 3.0.10 py37_0 flake8 3.7.6 py37_0 conda-forge flask 1.0.2 py37_1 flask-cors 3.0.7 py37_0 flask-httpauth 3.2.4 py_0 conda-forge fontconfig 2.13.0 h9420a91_0 freeglut 3.0.0 hf484d3e_5 freetype 2.9.1 h8a8886c_1 fribidi 1.0.5 h7b6447c_0 fs 2.3.0 py37_0 conda-forge fs.sshfs 0.10.1 py37_0 conda-forge fs.webdavfs 0.3.3 py37_1000 conda-forge fs_filepicker 0.3.7 py37_2 conda-forge furl 2.0.0 py37_0 future 0.17.1 py37_0 geos 3.6.2 heeff764_2 get_terminal_size 1.0.0 haa9412d_0 gevent 1.3.7 py37h7b6447c_1 gitdb2 2.0.5 py37_0 gitpython 2.1.11 py37_0 glib 2.56.2 hd408876_0 glob2 0.6 py37_1 gloripy 1.0.0.dev0 dev_0 gmp 6.1.2 h6c8ec71_1 gmpy2 2.0.8 py37h10f8cd9_2 graphite2 1.3.12 h23475e2_2 graphviz 2.40.1 h21bd128_2 greenlet 0.4.15 py37h7b6447c_0 gst-plugins-base 1.14.0 hbbd80ab_1 gstreamer 1.14.0 hb453b48_1 h5py 2.8.0 py37h989c5e5_3 harfbuzz 1.8.8 hffaf4a1_0 hdf4 4.2.13 h3ca952b_2 hdf5 1.10.2 hba1933b_1 heapdict 1.0.0 py37_2 html5lib 1.0.1 py37_0 humanfriendly 4.17 py37_0 hyperlink 18.0.0 py37_0 icu 58.2 h9c2bf20_1 idna 2.7 py37_0 imageio 2.4.1 py37_0 imagesize 1.1.0 py37_0 importlib_metadata 0.6 py37_0 incremental 17.5.0 py37_0 intel-openmp 2019.0 118 ipykernel 5.1.0 py37h39e3cac_0 ipython 7.2.0 py37h39e3cac_0 ipython_genutils 0.2.0 py37_0 ipywidgets 7.4.2 py37_0 isodate 0.6.0 py37_0 isort 4.3.4 py37_0 itsdangerous 1.1.0 py37_0 jasper 2.0.14 h07fcdf6_1 jbig 2.1 hdba287a_0 jdcal 1.4 py37_0 jedi 0.13.1 py37_0 jeepney 0.4 py37_0 jinja2 2.10 py37_0 jpeg 9b h024ee3a_2 jplephem 2.9 pyh11f86e8_0 conda-forge jsonschema 2.6.0 py37_0 jupyter 1.0.0 py37_7 jupyter_client 5.2.3 py37_0 jupyter_console 6.0.0 py37_0 jupyter_core 4.4.0 py37_0 jupyterlab 0.35.3 py37_0 jupyterlab_launcher 0.13.1 py37_0 jupyterlab_server 0.2.0 py37_0 juregrid3d 0.9.0.dev0 pypi_0 pypi keyring 16.1.1 py37_0 kiwisolver 1.0.1 py37hf484d3e_0 kombu 4.4.0 py_0 conda-forge latexcodec 1.0.7 py_0 conda-forge lazy-object-proxy 1.3.1 py37h14c3975_2 libarchive 3.3.3 h7d0bbab_1 libcurl 7.61.0 h1ad7b7a_0 libedit 3.1.20170329 h6b74fdf_2 libffi 3.2.1 hd88cf55_4 libgcc-ng 8.2.0 hdf63c60_1 libgfortran-ng 7.3.0 hdf63c60_0 libglu 9.0.0 hf484d3e_1 liblief 0.9.0 h7725739_1 libnetcdf 4.6.1 h10edf3e_1 libopencv 3.4.2 hb342d67_1 libopus 1.3 h7b6447c_0 libpng 1.6.35 hbc83047_0 libsodium 1.0.16 h1bed415_0 libssh2 1.8.0 h9cfc8f7_4 libstdcxx-ng 8.2.0 hdf63c60_1 libtiff 4.0.9 he85c1e1_2 libtool 2.4.6 h544aabb_3 libuuid 1.0.3 h1bed415_2 libvpx 1.7.0 h439df22_0 libxcb 1.13 h1bed415_1 libxml2 2.9.9 he19cac6_0 libxslt 1.1.33 h7d1a2b0_0 llvmlite 0.26.0 py37hd408876_0 locket 0.2.0 py37_1 lxml 4.3.1 py37hefd8a0e_0 lz4-c 1.8.1.2 h14c3975_0 lzo 2.10 h49e0be7_2 markupsafe 1.1.0 py37h7b6447c_0 matplotlib 3.0.2 py37h5429711_0 mccabe 0.6.1 py37_1 metpy 0.10.0 py37_1001 conda-forge mistune 0.8.4 py37h7b6447c_0 mkl 2018.0.3 1 mkl-service 1.1.2 py37h90e4bf4_5 mkl_fft 1.0.6 py37h7dd41cf_0 mkl_random 1.0.1 py37h4414c95_1 mock 2.0.0 py37_0 more-itertools 4.3.0 py37_0 mpc 1.1.0 h10f8cd9_1 mpfr 4.0.1 hdf1c602_3 mpmath 1.0.0 py37_2 msgpack-python 0.5.6 py37h6bb024c_1 multipledispatch 0.6.0 py37_0 navigator-updater 0.2.1 py37_0 nbconvert 5.4.0 py37_1 nbformat 4.4.0 py37_0 ncurses 6.1 hf484d3e_0 netcdf4 1.4.2 py37h4b4f87f_0 networkx 2.2 py37_1 nltk 3.3.0 py37_0 nose 1.3.7 py37_2 notebook 5.7.2 py37_0 numba 0.41.0 py37h962f231_0 numexpr 2.6.8 py37hd89afb7_0 numpy 1.15.4 py37h1d66e8a_0 numpy-base 1.15.4 py37h81de0dd_0 numpydoc 0.8.0 py37_0 odo 0.5.1 py37_0 olefile 0.46 py37_0 opencv 3.4.2 py37h6fd60c2_1 openpyxl 2.5.11 py37_0 openssl 1.0.2s h7b6447c_0 orderedmultidict 1.0 py37_0 oset 0.1.3 py_1 conda-forge owslib 0.17.0 py37_0 packaging 18.0 py37_0 pandas 0.23.4 py37h04863e7_0 pandoc 1.19.2.1 hea2e7c5_1 pandocfilters 1.4.2 py37_1 pango 1.42.4 h049681c_0 paramiko 2.4.2 py37_0 parso 0.3.1 py37_0 partd 0.3.9 py37_0 paste 3.0.6 py37_0 patchelf 0.9 hf484d3e_2 path.py 11.5.0 py37_0 pathlib2 2.3.2 py37_0 patsy 0.5.1 py37_0 pbr 5.1.1 py37_0 pcre 8.42 h439df22_0 pep8 1.7.1 py37_0 pexpect 4.6.0 py37_0 pickleshare 0.7.5 py37_0 pillow 5.3.0 py37h34e0f95_0 pint 0.9 py_0 conda-forge pip 18.1 py37_0 pixman 0.34.0 hceecf20_3 pkginfo 1.4.2 py37_1 pluggy 0.8.0 py37_0 ply 3.11 py37_0 pooch 0.2.1 py37_1000 conda-forge powerline-status 2.7 py37h470a237_0 conda-forge proj4 5.0.1 h14c3975_0 prometheus_client 0.4.2 py37_0 prompt_toolkit 2.0.7 py37_0 psutil 5.4.8 py37h7b6447c_0 ptyprocess 0.6.0 py37_0 py 1.7.0 py37_0 py-lief 0.9.0 py37h7725739_1 py-opencv 3.4.2 py37hb342d67_1 pyasn1 0.4.4 py37h28b3542_0 pyasn1-modules 0.2.2 py37_0 pybtex 0.22.2 py37_0 conda-forge pybtex-docutils 0.2.1 py37_1000 conda-forge pycodestyle 2.5.0 py37_0 pycosat 0.6.3 py37h14c3975_0 pycparser 2.19 py37_0 pycrypto 2.6.1 py37h14c3975_9 pycurl 7.43.0.2 py37hb7f436b_0 pyepsg 0.4.0 py37_0 pyflakes 2.1.0 py37_0 pygments 2.2.0 py37_0 pyhamcrest 1.9.0 py37_2 pylint 2.2.2 py37_0 pymongo 3.7.2 py37he6710b0_0 pynacl 1.3.0 py37h7b6447c_0 pyodbc 4.0.24 py37he6710b0_0 pyopenssl 18.0.0 py37_0 pyparsing 2.3.0 py37_0 pyproj 1.9.5.1 py37h7b21b82_1 pyqt 5.9.2 py37h05f1152_2 pyshp 1.2.12 py37_0 pysocks 1.6.8 py37_0 pytables 3.4.4 py37ha205bf6_0 pytest 4.2.1 py37_0 pytest-arraydiff 0.2 py37h39e3cac_0 pytest-astropy 0.4.0 py37_0 pytest-cache 1.0 py37_1 pytest-cov 2.6.1 py37_0 pytest-doctestplus 0.2.0 py37_0 pytest-flake8 1.0.4 py37_0 conda-forge pytest-openfiles 0.3.1 py37_0 pytest-pep8 1.0.6 py37_1 pytest-remotedata 0.3.1 py37_0 pytest-runner 4.2 py37_0 python 3.7.0 h6e4f718_3 python-dateutil 2.7.5 py37_0 python-graphviz 0.10.1 py_0 python-libarchive-c 2.8 py37_6 pytz 2018.7 py37_0 pyvirtualdisplay 0.2.1 py37_1000 conda-forge pywavelets 1.0.1 py37hdd07704_0 pyyaml 3.13 py37h14c3975_0 pyzmq 17.1.2 py37h14c3975_0 qt 5.9.6 h8703b6f_2 qtawesome 0.5.3 py37_0 qtconsole 4.4.2 py37_0 qtpy 1.5.2 py37_0 readline 7.0 h7b6447c_5 requests 2.21.0 py37_0 restructuredtext-lint 1.2.2 pypi_0 pypi rope 0.11.0 py37_0 ruamel_yaml 0.15.46 py37h14c3975_0 scikit-image 0.14.0 py37hf484d3e_1 scikit-learn 0.20.1 py37h4989274_0 scipy 1.1.0 py37hfa4b5c9_1 scons 3.0.1 py37_1 seaborn 0.9.0 py37_0 secretstorage 3.1.0 py37_0 send2trash 1.5.0 py37_0 service_identity 17.0.0 py37h28b3542_0 setuptools 40.6.2 py37_0 sgp4 1.4 pyh24bf2e0_3 conda-forge shapely 1.6.4 py37h7ef4460_0 simplegeneric 0.8.1 py37_2 simplejson 3.16.0 py37h14c3975_0 singledispatch 3.4.0.3 py37_0 sip 4.19.8 py37hf484d3e_0 six 1.11.0 py37_1 skyfield 1.10 py_0 conda-forge smmap2 2.0.5 py37_0 snappy 1.1.7 hbae5bb6_3 snowballstemmer 1.2.1 py37_0 sortedcollections 1.0.1 py37_0 sortedcontainers 2.1.0 py37_0 sphinx 1.8.4 py37_0 sphinx_rtd_theme 0.4.2 py37_0 sphinxcontrib 1.0 py37_1 sphinxcontrib-bibtex 0.4.2 py_0 conda-forge sphinxcontrib-websupport 1.1.0 py37_1 spyder 3.3.2 py37_0 spyder-kernels 0.3.0 py37_0 sqlalchemy 1.2.14 py37h7b6447c_0 sqlite 3.25.3 h7b6447c_0 statsmodels 0.9.0 py37h035aef0_0 stevedore 1.30.0 pypi_0 pypi sympy 1.3 py37_0 tblib 1.3.2 py37_0 terminado 0.8.1 py37_1 testpath 0.4.2 py37_0 tk 8.6.8 hbc83047_0 toolz 0.9.0 py37_0 tornado 5.1.1 py37h7b6447c_0 tqdm 4.28.1 py37h28b3542_0 traitlets 4.3.2 py37_0 twisted 18.9.0 py37h7b6447c_0 typed-ast 1.1.0 py37h14c3975_0 unicodecsv 0.14.1 py37_0 unixodbc 2.3.7 h14c3975_0 urllib3 1.23 py37_0 vine 1.3.0 py_0 conda-forge wcwidth 0.1.7 py37_0 webdavclient2 0.1.1 py_0 conda-forge webencodings 0.5.1 py37_1 werkzeug 0.14.1 py37_0 wheel 0.32.3 py37_0 widgetsnbextension 3.4.2 py37_0 wrapt 1.10.11 py37h14c3975_2 wurlitzer 1.0.2 py37_0 xarray 0.11.0 py37_0 xlrd 1.1.0 py37_1 xlsxwriter 1.1.2 py37_0 xlwt 1.3.0 py37_0 xz 5.2.4 h14c3975_4 yaml 0.1.7 had09818_2 zeromq 4.2.5 hf484d3e_1 zict 0.1.3 py37_0 zlib 1.2.11 ha838bed_2 zope 1.0 py37_1 zope.interface 4.6.0 py37h7b6447c_0 zstd 1.3.3 h84994c4_0 ``` ### pip list ``` Package Version Location ---------------------------------- ----------- ------------------------ alabaster 0.7.12 amqp 2.4.2 anaconda-client 1.7.2 anaconda-navigator 1.9.2 anaconda-project 0.8.2 apipkg 1.5 appdirs 1.4.3 argcomplete 1.9.4 asn1crypto 0.24.0 astroid 2.1.0 astropy 3.0.5 atomicwrites 1.2.1 attrs 18.2.0 Automat 0.7.0 autopep8 1.4.3 Babel 2.6.0 backcall 0.1.0 backports.os 0.1.1 backports.shutil-get-terminal-size 1.0.0 basemap 1.2.0 bcrypt 3.1.4 beautifulsoup4 4.6.3 billiard 3.5.0.4 bitarray 0.8.3 bkcharts 0.2 blaze 0.11.3 bleach 3.0.2 bokeh 1.0.2 boto 2.49.0 Bottleneck 1.2.1 breathe 4.13.0 cached-property 1.5.1 Cartopy 0.16.0 celery 4.2.1 certifi 2019.3.9 cffi 1.11.5 cftime 1.0.3.4 Chameleon 3.5 chardet 3.0.4 Click 7.0 cloudpickle 0.6.1 clyent 1.2.2 cmocean 1.2 colorama 0.4.0 conda 4.6.14 conda-build 3.17.1 constantly 15.1.0 contextlib2 0.5.5 coverage 4.5.2 cryptography 2.3.1 cycler 0.10.0 Cython 0.29 cytoolz 0.9.0.1 dask 1.0.0 datashape 0.5.4 decorator 4.3.0 defusedxml 0.5.0 distributed 1.25.0 doc8 0.8.0 docutils 0.14 EasyProcess 0.2.3 ecmwf-api-client 1.5.3 entrypoints 0.3 et-xmlfile 1.0.1 execnet 1.5.0 fastcache 1.0.2 fdb 2.0.0 filelock 3.0.10 flake8 3.7.6 Flask 1.0.2 Flask-Cors 3.0.7 Flask-HTTPAuth 3.2.4 fs 2.3.0 fs-filepicker 0.3.7 fs.sshfs 0.10.1 fs.webdavfs 0.3.3 furl 2.0.0 future 0.17.1 gevent 1.3.7 gitdb2 2.0.5 GitPython 2.1.11 glob2 0.6 gloripy 1.0.0.dev0 /home/icg173/src/gloripy gmpy2 2.0.8 graphviz 0.10.1 greenlet 0.4.15 h5py 2.8.0 heapdict 1.0.0 html5lib 1.0.1 humanfriendly 4.17 hyperlink 18.0.0 idna 2.7 imageio 2.4.1 imagesize 1.1.0 importlib-metadata 0.6 incremental 17.5.0 ipykernel 5.1.0 ipython 7.2.0 ipython-genutils 0.2.0 ipywidgets 7.4.2 isodate 0.6.0 isort 4.3.4 itsdangerous 1.1.0 jdcal 1.4 jedi 0.13.1 jeepney 0.4 Jinja2 2.10 jplephem 2.9 jsonschema 2.6.0 jupyter 1.0.0 jupyter-client 5.2.3 jupyter-console 6.0.0 jupyter-core 4.4.0 jupyterlab 0.35.3 jupyterlab-launcher 0.13.1 jupyterlab-server 0.2.0 juregrid3d 0.9.0.dev0 keyring 16.1.1 kiwisolver 1.0.1 kombu 4.4.0 latexcodec 1.0.7 lazy-object-proxy 1.3.1 libarchive-c 2.8 lief 0.9.0 llvmlite 0.26.0 locket 0.2.0 lxml 4.3.1 MarkupSafe 1.1.0 matplotlib 3.0.2 mccabe 0.6.1 MetPy 0.10.0 mistune 0.8.4 mkl-fft 1.0.6 mkl-random 1.0.1 mock 2.0.0 more-itertools 4.3.0 mpmath 1.0.0 msgpack 0.5.6 multipledispatch 0.6.0 navigator-updater 0.2.1 nbconvert 5.4.0 nbformat 4.4.0 netCDF4 1.4.2 networkx 2.2 nltk 3.3 nose 1.3.7 notebook 5.7.2 numba 0.41.0 numexpr 2.6.8 numpy 1.15.4 numpydoc 0.8.0 odo 0.5.1 olefile 0.46 openpyxl 2.5.11 orderedmultidict 1.0 oset 0.1.3 OWSLib 0.17.0 packaging 18.0 pandas 0.23.4 pandocfilters 1.4.2 paramiko 2.4.2 parso 0.3.1 partd 0.3.9 Paste 3.0.6 path.py 11.5.0 pathlib2 2.3.2 patsy 0.5.1 pbr 5.1.1 pep8 1.7.1 pexpect 4.6.0 pickleshare 0.7.5 Pillow 5.3.0 Pint 0.9 pip 18.1 pkginfo 1.4.2 pluggy 0.8.0 ply 3.11 pooch 0.2.1 powerline-status 2.7 prometheus-client 0.4.2 prompt-toolkit 2.0.7 psutil 5.4.8 ptyprocess 0.6.0 py 1.7.0 pyasn1 0.4.4 pyasn1-modules 0.2.2 pybtex 0.22.2 pybtex-docutils 0.2.1 pycodestyle 2.5.0 pycosat 0.6.3 pycparser 2.19 pycrypto 2.6.1 pycurl 7.43.0.2 pyepsg 0.4.0 pyflakes 2.1.0 Pygments 2.2.0 PyHamcrest 1.9.0 pylint 2.2.2 pymongo 3.7.2 PyNaCl 1.3.0 pyodbc 4.0.24 pyOpenSSL 18.0.0 pyparsing 2.3.0 pyproj 1.9.5.1 pyshp 1.2.12 PySocks 1.6.8 pytest 4.2.1 pytest-arraydiff 0.2 pytest-astropy 0.4.0 pytest-cache 1.0 pytest-cov 2.6.1 pytest-doctestplus 0.2.0 pytest-flake8 1.0.4 pytest-openfiles 0.3.1 pytest-pep8 1.0.6 pytest-remotedata 0.3.1 pytest-runner 4.2 python-dateutil 2.7.5 pytz 2018.7 PyVirtualDisplay 0.2.1 PyWavelets 1.0.1 PyYAML 3.13 pyzmq 17.1.2 QtAwesome 0.5.3 qtconsole 4.4.2 QtPy 1.5.2 requests 2.21.0 restructuredtext-lint 1.2.2 rope 0.11.0 ruamel-yaml 0.15.46 scikit-image 0.14.0 scikit-learn 0.20.1 scipy 1.1.0 scons 3.0.1 seaborn 0.9.0 SecretStorage 3.1.0 Send2Trash 1.5.0 service-identity 17.0.0 setuptools 40.6.2 sgp4 1.4 Shapely 1.6.4.post1 simplegeneric 0.8.1 simplejson 3.16.0 singledispatch 3.4.0.3 six 1.11.0 skyfield 1.10 smmap2 2.0.5 snowballstemmer 1.2.1 sortedcollections 1.0.1 sortedcontainers 2.1.0 Sphinx 1.8.4 sphinx-rtd-theme 0.4.2 sphinxcontrib-bibtex 0.4.2 sphinxcontrib-websupport 1.1.0 spyder 3.3.2 spyder-kernels 0.3.0 SQLAlchemy 1.2.14 statsmodels 0.9.0 stevedore 1.30.0 sympy 1.3 tables 3.4.4 tblib 1.3.2 terminado 0.8.1 testpath 0.4.2 toolz 0.9.0 tornado 5.1.1 tqdm 4.28.1 traitlets 4.3.2 Twisted 18.9.0 typed-ast 1.1.0 unicodecsv 0.14.1 urllib3 1.23 vine 1.3.0 wcwidth 0.1.7 webdavclient2 0.1.1 webencodings 0.5.1 Werkzeug 0.14.1 wheel 0.32.3 widgetsnbextension 3.4.2 wrapt 1.10.11 wurlitzer 1.0.2 xarray 0.11.0 xlrd 1.1.0 XlsxWriter 1.1.2 xlwt 1.3.0 zict 0.1.3 zope.interface 4.6.0 ```
joernu76 commented 5 years ago

Cross-link to related issue of MSS project at https://bitbucket.org/wxmetvis/mss/issues/420/cartopy-bounding-box-setting-with

kdpenner commented 3 years ago

In digging around to solve another set_extent issue I think I've found the culprit for this one. There seems to be a numerical problem with cartopy.trace.project_linear. Comparing cartopy's performance with pyproj's:

import cartopy
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
from pyproj import CRS, Transformer
from pyproj.crs.coordinate_operation import StereographicConversion
from pyproj.crs import ProjectedCRS
from pyproj import Geod
from shapely.geometry import LineString
import numpy as np

lonlat_crs = CRS('EPSG:4326')
stereo = StereographicConversion(latitude_natural_origin=90)
stereo_crs = ProjectedCRS(conversion=stereo)
stereo_transform_func = Transformer.from_crs(
                            lonlat_crs, stereo_crs, always_xy=True).transform
lonlat_transform_func = Transformer.from_crs(
                            stereo_crs, lonlat_crs, always_xy=True).transform

region = [45, -135, 0, 0]
x1, x2, y1, y2 = region
bbox = [[x1, y1], [x2, y1], [x2, y2], [x1, y2], [x1, y1]]

g = Geod(ellps="WGS84")
pts_pyproj = []

for i, pts in enumerate(bbox[:-1]):
    pts_lonlat = np.array(g.npts(*pts, *bbox[i+1], 7))
    pts_lonlat = np.insert(pts_lonlat, 0, pts, axis=0)
    xs, ys = stereo_transform_func(*pts_lonlat.T)
    pts_pyproj.extend(list(zip(xs, ys)))

pts_pyproj = np.array(pts_pyproj).T
lons_pyproj, lats_pyproj = lonlat_transform_func(*pts_pyproj)

lonlat_crs_plt = ccrs.PlateCarree()
stereo_crs_plt = ccrs.Stereographic(central_longitude=0, central_latitude=90)

xs, ys = cartopy.trace.project_linear(LineString(bbox), lonlat_crs_plt,
                                      stereo_crs_plt)[0].xy
lonlatz_cartopy = lonlat_crs_plt.transform_points(stereo_crs_plt, np.array(xs),
                                                  np.array(ys))
lons_cartopy, lats_cartopy = lonlatz_cartopy[:, 0:2].T

fig = plt.figure(figsize=(10, 4))

ax1 = fig.add_subplot(1, 2, 1)
ax1.scatter(*pts_pyproj, color="tab:blue", label="pyproj")
ax1.scatter(xs, ys, color="tab:orange", label="cartopy")
ax1.set_title("extent -> projected")

ax2 = fig.add_subplot(1, 2, 2)
ax2.scatter(lons_pyproj, lats_pyproj, color="tab:blue", label="pyproj")
ax2.scatter(lons_cartopy, lats_cartopy, color="tab:orange", label="cartopy")
ax2.set_title("extent -> projected -> back to lon lat")

ax1.legend()
ax2.legend()

plt.savefig("stereo.png", bbox_inches="tight")

plt.close()

produces this:

stereo

the extent in projected space is set by the bounds of the geometries in the plot on the left.

kdpenner commented 3 years ago

I take back my previous comment. set_extent behaves differently between a CRS and a geodetic. Instead of passing ccrs.PlateCarree() in set_extent, you need to pass ccrs.PlateCarree().as_geodetic() or omit it.

joernu76 commented 3 years ago

Ha! I can confirm that this works. The behaviour and probably the code has changed in the last 18 month as also my unmodified testcase looks "better" than before.

To make the two figures look identical, the as_geodetic() has to be added. This works as expected:

import os
import matplotlib.pyplot as plt
from netCDF4 import Dataset as netcdf_dataset
import numpy as np

from cartopy import config
import cartopy.crs as ccrs

# get the path of the file. It can be found in the repo data directory.
fname = os.path.join(config["repo_data_dir"],
                     'netcdf', 'HadISST1_SST_update.nc')

dataset = netcdf_dataset(fname)
sst = dataset.variables['sst'][0, :, :]
lats = dataset.variables['lat'][:]
lons = dataset.variables['lon'][:]

prj = ccrs.Stereographic(central_longitude=0, central_latitude=90)

fig = plt.figure()
ax = fig.add_subplot(1, 1, 1, projection=prj)
print("default", ax.get_extent())
ax.set_extent([45, -135, 0, 0], ccrs.PlateCarree().as_geodetic())  # <-- changed here
print("set1", ax.get_extent())
ax.contour(lons, lats, sst, 60, transform=ccrs.PlateCarree())
ax.coastlines()

fig = plt.figure()
ax = fig.add_subplot(1, 1, 1, projection=prj)
print("default", ax.get_extent())
coords = prj.transform_points(                                                                
    ccrs.PlateCarree(), np.asarray([45, -135]), np.asarray([0, 0]))
ax.set_extent([coords[0, 0], coords[1, 0], coords[0, 1], coords[1, 1]], prj)
print("set2", ax.get_extent())
ax.contour(lons, lats, sst, 60, transform=ccrs.PlateCarree())
ax.coastlines()

plt.show()

Issue can be closed IMO.

kdpenner commented 3 years ago

The solution here has to do with the choices discussed in #131 and #645, so it might be useful to keep open.