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.43k stars 365 forks source link

gridline labels repeated on sides of a limited view #1819

Open evas-ssec opened 3 years ago

evas-ssec commented 3 years ago

Description

The left and right gridline labels for a geostationary projection are duplicated and misplaced.

gridtest

Code to reproduce

import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import cartopy.crs as crs

# This geostationary projection matches that of GOES 17.
proj_object = crs.Geostationary(central_longitude=-137.0, satellite_height=35786023.0, sweep_axis='x', )
bounding_axes = [-2505021.8, 2505021.8, 1583173.8, 4589200.0]

fig = plt.figure( )
axes = fig.add_subplot(111, projection=proj_object)
axes.set_extent(bounding_axes, crs=proj_object)

# draw some lat/lon gridlines
gl_obj = axes.gridlines(draw_labels=True,)

fig.savefig("./gridtest.png", )
plt.close(fig)

Traceback

(No error message is generated, only the faulty image output.)

Full environment definition python 3.6.10 ### Operating system MacOS 10.15.7 ### Cartopy version cartopy 0.18.0 ### conda list ``` # packages in environment at /opt/anaconda3/envs/aitf_ql: # # Name Version Build Channel _anaconda_depends 2020.02 py36_0 aitf-ql CSPP.ABI.Quicklooks.v0.7 dev_0 alabaster 0.7.12 py_0 conda-forge anaconda custom py36_1 anaconda-client 1.7.2 py_0 conda-forge anaconda-project 0.8.3 py_0 conda-forge applaunchservices 0.2.1 py_0 conda-forge appnope 0.1.0 py36h9f0ad1d_1001 conda-forge appscript 1.1.0 py36h37b9a7d_1 conda-forge argh 0.26.2 py36_1001 conda-forge asn1crypto 1.3.0 py36h9f0ad1d_1 conda-forge astroid 2.4.1 py36h9f0ad1d_0 conda-forge astropy 4.0.1.post1 py36h37b9a7d_0 conda-forge atomicwrites 1.4.0 pyh9f0ad1d_0 conda-forge attrs 19.3.0 py_0 conda-forge autopep8 1.5.2 pyh9f0ad1d_0 conda-forge babel 2.8.0 py_0 conda-forge backcall 0.1.0 py_0 conda-forge backports 1.0 py_2 conda-forge backports.shutil_get_terminal_size 1.0.0 py_3 conda-forge beautifulsoup4 4.9.1 py36h9f0ad1d_0 conda-forge bitarray 1.2.2 py36h37b9a7d_0 conda-forge bkcharts 0.2 py36_0 conda-forge blas 1.0 mkl bleach 3.1.5 pyh9f0ad1d_0 conda-forge blosc 1.18.1 h4a8c4bd_0 conda-forge bokeh 2.0.1 py36h9f0ad1d_0 conda-forge boost-cpp 1.72.0 hdf9ef73_0 conda-forge boto 2.49.0 py_0 conda-forge bottleneck 1.3.2 py36h255dfe6_1 conda-forge brotlipy 0.7.0 py36h37b9a7d_1000 conda-forge bzip2 1.0.8 h0b31af3_2 conda-forge ca-certificates 2021.5.30 h033912b_0 conda-forge cairo 1.16.0 hec6a9b0_1003 conda-forge cartopy 0.18.0 py36h5a1ef21_0 conda-forge certifi 2021.5.30 py36h79c6626_0 conda-forge cffi 1.14.0 py36h356ff06_0 conda-forge cfitsio 3.470 h389770f_2 conda-forge cftime 1.1.3 py36h255dfe6_0 conda-forge chardet 3.0.4 py36h9f0ad1d_1006 conda-forge click 7.1.2 pyh9f0ad1d_0 conda-forge cloudpickle 1.4.1 py_0 conda-forge clyent 1.2.2 py_1 conda-forge colorama 0.4.3 py_0 conda-forge contextlib2 0.6.0.post1 py_0 conda-forge contextvars 2.4 py_0 conda-forge cryptography 2.9.2 py36hc9d8292_0 conda-forge curl 7.69.1 h2d98d24_0 conda-forge cycler 0.10.0 py_2 conda-forge cython 0.29.19 py36h0130604_0 conda-forge cytoolz 0.10.1 py36h0b31af3_0 conda-forge dask 2.17.2 py_0 conda-forge dask-core 2.17.2 py_0 conda-forge dbus 1.13.6 h2f22bb5_0 conda-forge decorator 4.4.2 py_0 conda-forge defusedxml 0.6.0 py_0 conda-forge diff-match-patch 20181111 py_0 conda-forge distributed 2.17.0 py36h9f0ad1d_0 conda-forge docutils 0.16 py36h9f0ad1d_1 conda-forge entrypoints 0.3 py36h9f0ad1d_1001 conda-forge et_xmlfile 1.0.1 py_1001 conda-forge expat 2.2.9 h4a8c4bd_2 conda-forge fastcache 1.1.0 py36h37b9a7d_1 conda-forge filelock 3.0.12 pyh9f0ad1d_0 conda-forge flake8 3.7.9 py36h9f0ad1d_1 conda-forge flask 1.1.2 pyh9f0ad1d_0 conda-forge fontconfig 2.13.1 h6b1039f_1001 conda-forge freetype 2.10.2 h8da9a1a_0 conda-forge freexl 1.0.5 h1de35cc_1002 conda-forge fsspec 0.7.4 py_0 conda-forge future 0.18.2 py36h9f0ad1d_1 conda-forge gdal 3.0.4 py36h5a1ef21_6 conda-forge geos 3.8.1 h4a8c4bd_0 conda-forge geotiff 1.5.1 hd8796ba_10 conda-forge get_terminal_size 1.0.0 h7520d66_0 gettext 0.19.8.1 h46ab8bc_1002 conda-forge gevent 20.5.2 py36h37b9a7d_1 conda-forge giflib 5.2.1 h0b31af3_2 conda-forge glib 2.64.3 h577aef8_0 conda-forge glob2 0.7 py_0 conda-forge gmp 6.2.0 h4a8c4bd_2 conda-forge gmpy2 2.1.0b1 py36h4160ff4_0 conda-forge greenlet 0.4.15 py36h37b9a7d_1 conda-forge h5py 2.10.0 nompi_py36h106b333_102 conda-forge hdf4 4.2.13 h84186c3_1003 conda-forge hdf5 1.10.5 nompi_h0cbb7df_1103 conda-forge heapdict 1.0.1 py_0 conda-forge html5lib 1.0.1 py_0 conda-forge hypothesis 5.16.0 py_0 conda-forge icu 64.2 h6de7cb9_1 conda-forge idna 2.9 py_1 conda-forge imagecodecs-lite 2019.12.3 py36h255dfe6_1 conda-forge imageio 2.8.0 py_0 conda-forge imagesize 1.2.0 py_0 conda-forge immutables 0.14 py36h37b9a7d_0 conda-forge importlib-metadata 1.6.0 py36h9f0ad1d_0 conda-forge importlib_metadata 1.6.0 0 conda-forge intel-openmp 2019.4 233 intervaltree 3.0.2 py_0 conda-forge ipykernel 5.3.0 py36h95af2a2_0 conda-forge ipython 7.15.0 py36h9f0ad1d_0 conda-forge ipython_genutils 0.2.0 py_1 conda-forge ipywidgets 7.5.1 py_0 conda-forge isort 4.3.21 py36h9f0ad1d_1 conda-forge itsdangerous 1.1.0 py_0 conda-forge jbig 2.1 h0b31af3_2002 conda-forge jdcal 1.4.1 py_0 conda-forge jedi 0.15.2 py36_0 conda-forge jinja2 2.11.2 pyh9f0ad1d_0 conda-forge joblib 0.15.1 py_0 conda-forge jpeg 9d h0b31af3_0 conda-forge json-c 0.13.1 h575e443_1002 conda-forge json5 0.9.0 py_0 conda-forge jsonschema 3.2.0 py36h9f0ad1d_1 conda-forge jupyter 1.0.0 py_2 conda-forge jupyter_client 6.1.3 py_0 conda-forge jupyter_console 6.1.0 py_1 conda-forge jupyter_core 4.6.3 py36h9f0ad1d_1 conda-forge jupyterlab 2.1.4 py_0 conda-forge jupyterlab_server 1.1.5 py_0 conda-forge kealib 1.4.13 h2324030_0 conda-forge keyring 21.2.1 py36h9f0ad1d_0 conda-forge kiwisolver 1.2.0 py36h863e41a_0 conda-forge krb5 1.17.1 h1752a42_0 conda-forge lazy-object-proxy 1.4.3 py36h37b9a7d_2 conda-forge libarchive 3.3.3 h02796b4_1008 conda-forge libclang 9.0.1 default_hf57f61e_0 conda-forge libcurl 7.69.1 hc0b9707_0 conda-forge libcxx 10.0.0 h1af66ff_2 conda-forge libcxxabi 4.0.1 hcfea43d_1 libdap4 3.20.6 h8c15375_0 conda-forge libedit 3.1.20191231 hed1e85f_0 conda-forge libffi 3.2.1 h4a8c4bd_1007 conda-forge libgdal 3.0.4 ha92c1e4_6 conda-forge libgfortran 3.0.1 0 conda-forge libiconv 1.15 h0b31af3_1006 conda-forge libkml 1.3.0 h169b8f9_1011 conda-forge liblief 0.9.0 h3e78482_1 conda-forge libllvm8 8.0.1 h770b8ee_0 conda-forge libllvm9 9.0.1 h7475705_1 conda-forge libnetcdf 4.7.4 nompi_he461dc0_101 conda-forge libpng 1.6.37 hbbe82c9_1 conda-forge libpq 12.2 h489d428_1 conda-forge libsodium 1.0.17 h01d97ff_0 conda-forge libspatialindex 1.9.3 h4a8c4bd_3 conda-forge libspatialite 4.3.0a h658e6c1_1038 conda-forge libssh2 1.9.0 h39bdce6_2 conda-forge libtiff 4.1.0 h2ae36a8_6 conda-forge libwebp-base 1.1.0 h0b31af3_3 conda-forge libxml2 2.9.10 h53d96d6_0 conda-forge libxslt 1.1.33 h320ff13_0 conda-forge llvm-openmp 10.0.0 h28b9765_0 conda-forge llvmlite 0.31.0 py36hde82470_1 conda-forge locket 0.2.0 py_2 conda-forge lxml 4.5.1 py36h2ab0afd_0 conda-forge lz4-c 1.9.2 h4a8c4bd_1 conda-forge lzo 2.10 h1de35cc_1000 conda-forge markupsafe 1.1.1 py36h37b9a7d_1 conda-forge matplotlib 3.2.1 0 conda-forge matplotlib-base 3.2.1 py36h83d3ec1_0 conda-forge mccabe 0.6.1 py_1 conda-forge mistune 0.8.4 py36h37b9a7d_1001 conda-forge mkl 2019.5 281 conda-forge mkl-service 2.3.0 py36h0b31af3_0 conda-forge mkl_fft 1.1.0 py36h3b54f70_1 conda-forge mkl_random 1.1.1 py36h959d312_0 mock 4.0.2 py36h9f0ad1d_0 conda-forge more-itertools 8.3.0 py_1 conda-forge mpc 1.1.0 h4160ff4_1007 conda-forge mpfr 4.0.2 h65ac59c_1 conda-forge mpmath 1.1.0 py_0 conda-forge msgpack-python 1.0.0 py36h863e41a_1 conda-forge multipledispatch 0.6.0 py_0 conda-forge nbconvert 5.6.1 py36h9f0ad1d_1 conda-forge nbformat 5.0.6 py_0 conda-forge ncurses 6.1 h0a44026_1002 conda-forge netcdf4 1.5.3 nompi_py36h9b46daf_103 conda-forge networkx 2.4 py_1 conda-forge nltk 3.4.4 py_0 conda-forge nose 1.3.7 py36h9f0ad1d_1004 conda-forge notebook 6.0.3 py36h9f0ad1d_0 conda-forge nspr 4.20 h0a44026_1000 conda-forge nss 3.47 hc0980d9_0 conda-forge numba 0.48.0 py36h4f17bb1_0 conda-forge numexpr 2.7.1 py36hcc1bba6_1 conda-forge numpy 1.18.1 py36h7241aed_0 numpy-base 1.18.1 py36h3304bdc_1 numpydoc 1.0.0 pyh9f0ad1d_0 conda-forge olefile 0.46 py_0 conda-forge openjpeg 2.3.1 h254dc36_3 conda-forge openpyxl 3.0.3 py_0 conda-forge openssl 1.1.1k h0d85af4_0 conda-forge owslib 0.19.2 py_1 conda-forge packaging 20.4 pyh9f0ad1d_0 conda-forge pandas 1.0.4 py36hcc1bba6_0 conda-forge pandoc 2.9.2.1 0 conda-forge pandocfilters 1.4.2 py_1 conda-forge parso 0.5.2 py_0 partd 1.1.0 py_0 conda-forge path 14.0.1 py36h9f0ad1d_0 conda-forge path.py 10.3.1 py36_0 conda-forge pathlib2 2.3.5 py36h9f0ad1d_1 conda-forge pathtools 0.1.2 py_1 conda-forge patsy 0.5.1 py_0 conda-forge pcre 8.44 h4a8c4bd_0 conda-forge pep8 1.7.1 py_0 conda-forge pexpect 4.8.0 py36h9f0ad1d_1 conda-forge pickleshare 0.7.5 py36h9f0ad1d_1001 conda-forge pillow 7.1.1 py36h2ae5dfa_0 conda-forge pip 20.1.1 py_1 conda-forge pixman 0.38.0 h01d97ff_1003 conda-forge pkginfo 1.5.0.1 py_0 conda-forge pluggy 0.13.1 py36h9f0ad1d_1 conda-forge ply 3.11 py_1 conda-forge poppler 0.67.0 h16886b5_8 conda-forge poppler-data 0.4.9 1 conda-forge postgresql 12.2 h62ab893_1 conda-forge proj 7.0.0 hbce2d5c_4 conda-forge prometheus_client 0.8.0 pyh9f0ad1d_0 conda-forge prompt-toolkit 3.0.5 py_0 conda-forge prompt_toolkit 3.0.5 0 conda-forge psutil 5.7.0 py36h37b9a7d_1 conda-forge ptyprocess 0.6.0 py_1001 conda-forge py 1.8.1 py_0 conda-forge py-lief 0.9.0 py36h0ceac7d_1 conda-forge pycodestyle 2.5.0 py_0 conda-forge pycosat 0.6.3 py36h37b9a7d_1004 conda-forge pycparser 2.20 py_0 conda-forge pycrypto 2.6.1 py36h37b9a7d_1004 conda-forge pycurl 7.43.0.5 py36h75a5311_0 conda-forge pydocstyle 5.0.2 py_0 conda-forge pyepsg 0.4.0 py_0 conda-forge pyflakes 2.1.1 py36_0 pygments 2.6.1 py_0 conda-forge pylint 2.5.2 py36h9f0ad1d_0 conda-forge pyodbc 4.0.30 py36h4a8c4bd_0 conda-forge pyopenssl 19.1.0 py_1 conda-forge pyparsing 2.4.7 pyh9f0ad1d_0 conda-forge pyproj 2.6.1.post1 py36h216762d_0 conda-forge pyqt 5.12.3 py36haa9e2f4_3 conda-forge pyqt5-sip 4.19.18 pypi_0 pypi pyqtchart 5.12 pypi_0 pypi pyqtwebengine 5.12.1 pypi_0 pypi pyrsistent 0.16.0 py36h37b9a7d_0 conda-forge pyshp 2.1.0 py_0 conda-forge pysocks 1.7.1 py36h9f0ad1d_1 conda-forge pytables 3.6.1 py36h6f8395a_1 conda-forge pytest 5.4.3 py36h9f0ad1d_0 conda-forge pytest-arraydiff 0.3 py_0 conda-forge pytest-astropy 0.7.0 py_0 conda-forge pytest-astropy-header 0.1.2 py_0 conda-forge pytest-doctestplus 0.7.0 pyh9f0ad1d_0 conda-forge pytest-openfiles 0.4.0 py_0 conda-forge pytest-remotedata 0.3.1 py_0 conda-forge python 3.6.10 h4334963_1011_cpython conda-forge python-dateutil 2.8.1 py_0 conda-forge python-jsonrpc-server 0.3.4 pyh9f0ad1d_1 conda-forge python-language-server 0.31.10 py36h9f0ad1d_0 conda-forge python-libarchive-c 2.9 py36_0 conda-forge python.app 1.3 py36h37b9a7d_1 conda-forge python_abi 3.6 1_cp36m conda-forge pytz 2020.1 pyh9f0ad1d_0 conda-forge pywavelets 1.1.1 py36h255dfe6_1 conda-forge pyyaml 5.3.1 py36h37b9a7d_0 conda-forge pyzmq 19.0.1 py36h820b253_0 conda-forge qdarkstyle 2.8.1 pyh9f0ad1d_0 conda-forge qt 5.12.5 h514805e_3 conda-forge qtawesome 0.7.2 pyh9f0ad1d_0 conda-forge qtconsole 4.7.4 pyh9f0ad1d_0 conda-forge qtpy 1.9.0 py_0 conda-forge readline 8.0 hcfe32e1_0 conda-forge requests 2.23.0 pyh8c360ce_2 conda-forge ripgrep 12.1.1 h0b31af3_0 conda-forge rope 0.17.0 pyh9f0ad1d_0 conda-forge rtree 0.9.4 py36he053a7a_1 conda-forge ruamel_yaml 0.15.80 py36h37b9a7d_1001 conda-forge scikit-image 0.17.2 py36hcc1bba6_0 conda-forge scikit-learn 0.22.1 py36h27c97d8_0 scipy 1.4.1 py36h9fa6033_0 seaborn 0.10.1 py_0 conda-forge send2trash 1.5.0 py_0 conda-forge setuptools 47.1.1 py36h9f0ad1d_0 conda-forge shapely 1.7.0 py36hda0b814_3 conda-forge simplegeneric 0.8.1 py_1 conda-forge singledispatch 3.4.0.3 py36_1000 conda-forge sip 4.19.22 py36h0130604_0 conda-forge six 1.15.0 pyh9f0ad1d_0 conda-forge snappy 1.1.8 h4a8c4bd_1 conda-forge snowballstemmer 2.0.0 py_0 conda-forge sortedcollections 1.1.2 py_0 conda-forge sortedcontainers 2.1.0 py_0 conda-forge soupsieve 2.0.1 py36h9f0ad1d_0 conda-forge sphinx 3.0.4 py_0 conda-forge sphinxcontrib 1.0 py36_1 sphinxcontrib-applehelp 1.0.2 py_0 conda-forge sphinxcontrib-devhelp 1.0.2 py_0 conda-forge sphinxcontrib-htmlhelp 1.0.3 py_0 conda-forge sphinxcontrib-jsmath 1.0.1 py_0 conda-forge sphinxcontrib-qthelp 1.0.3 py_0 conda-forge sphinxcontrib-serializinghtml 1.1.4 py_0 conda-forge sphinxcontrib-websupport 1.2.2 pyh9f0ad1d_0 conda-forge spyder 4.1.3 py36h9f0ad1d_0 conda-forge spyder-kernels 1.9.1 py36h9f0ad1d_0 conda-forge sqlalchemy 1.3.17 py36h37b9a7d_0 conda-forge sqlite 3.30.1 h93121df_0 conda-forge statsmodels 0.11.1 py36h37b9a7d_1 conda-forge sympy 1.6 py36h9f0ad1d_0 conda-forge tbb 2019.9 ha1b3eb9_1 conda-forge tblib 1.6.0 py_0 conda-forge terminado 0.8.3 py36h9f0ad1d_1 conda-forge testpath 0.4.4 py_0 conda-forge tifffile 2020.6.3 py_0 conda-forge tiledb 1.7.7 h84aa2a7_3 conda-forge tk 8.6.10 hbbe82c9_0 conda-forge toml 0.10.1 pyh9f0ad1d_0 conda-forge toolz 0.10.0 py_0 conda-forge tornado 6.0.4 py36h37b9a7d_1 conda-forge tqdm 4.46.1 pyh9f0ad1d_0 conda-forge traitlets 4.3.3 py36h9f0ad1d_1 conda-forge typed-ast 1.4.1 py36h0b31af3_0 conda-forge typing_extensions 3.7.4.2 py_0 conda-forge tzcode 2020a h0b31af3_0 conda-forge ujson 1.35 py36h0130604_1002 conda-forge unicodecsv 0.14.1 py_1 conda-forge unixodbc 2.3.7 h72f44dd_1000 conda-forge urllib3 1.25.9 py_0 conda-forge watchdog 0.10.2 py36h0b31af3_0 conda-forge wcwidth 0.2.3 pyh9f0ad1d_0 conda-forge webencodings 0.5.1 py_1 conda-forge werkzeug 1.0.1 pyh9f0ad1d_0 conda-forge wheel 0.34.2 py_1 conda-forge widgetsnbextension 3.5.1 py36_0 conda-forge wrapt 1.11.2 py36h37b9a7d_0 conda-forge wurlitzer 2.0.0 py36h9f0ad1d_1 conda-forge xerces-c 3.2.2 h8f8adb3_1004 conda-forge xlrd 1.2.0 py_0 conda-forge xlsxwriter 1.2.9 pyh9f0ad1d_0 conda-forge xlwings 0.19.4 py36h9f0ad1d_0 conda-forge xlwt 1.3.0 py_1 conda-forge xz 5.2.5 h0b31af3_0 conda-forge yaml 0.2.5 h0b31af3_0 conda-forge yapf 0.29.0 py_0 conda-forge zeromq 4.3.2 h6de7cb9_2 conda-forge zict 2.0.0 py_0 conda-forge zipp 3.1.0 py_0 conda-forge zlib 1.2.11 h0b31af3_1006 conda-forge zstd 1.4.4 h4b3e974_3 conda-forge ```
djhoese commented 2 years ago

I tried tracking this down, but am coming up empty on a final solution. If you lower the Y extents about ~300-500k meters south then you don't get the same issue and you even get more longitude lines. With the original code I went into the cartopy Gridliner source code with pycharm's debugger and as far as I can tell there are indeed duplicate Label objects in the list. There are other Labels that are duplicated (they have the same text and are on the same side of the axes) but one of the duplicates is always set to invisible so it isn't a problem. I'm having trouble following the low-level logic that generates these Labels from the list of ticks. And to be clear, the list of ticks to generate is as expected (ex. [15.0, 20.0, 25.0, 30.0, 35.0, 40.0, 45.0, 50.0]) and does not include duplicates.

It has to happen somewhere in this logic which leads to the generation of "heads" and "tails" and then from there the generation of the labels:

https://github.com/SciTools/cartopy/blob/591fb5450e11b42b6de1cebe4f240112f915bd52/lib/cartopy/mpl/gridliner.py#L817-L830

Given this is the geostationary projection and includes points outside of the lon/lat space, my guess is cartopy is failing to check the bounds/overlaps/intersections between the graticule lines and the map bounding box.