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

pcolormesh no longer wraps around #1997

Closed mathause closed 2 years ago

mathause commented 2 years ago

Description

pcolormesh no longer draws the "other half" of gridpoints that have their center at the edge of the maps - see the example and figure. This may very well be an 'indended' consequence of #1646 but I thought I report it anyway.

This used to work in older versions of cartopy/ matplotlib (e.g. cartopy=0.19 and matplotlib=3.4)

Code to reproduce

import cartopy.crs as ccrs
import matplotlib.pyplot as plt
import numpy as np

lon = np.arange(-180, 151, 30)
lat = np.arange(75, -76, -30)

LON, LAT = np.meshgrid(lon, lat)

lon_edges = np.arange(-195, 181, 30)
lat_edges = np.arange(90, -91, -30)

data = np.ones(shape=lat.shape + lon.shape)

f, axs = plt.subplots(1, 2, subplot_kw=dict(projection=ccrs.PlateCarree()))
f.subplots_adjust(wspace=0.05)

# 1 - using edges

ax = axs[0]

ax.pcolormesh(
    lon_edges,
    lat_edges,
    data,
    transform=ccrs.PlateCarree(),
    cmap="Reds",
    ec="0.3",
    lw=0.5,
)
ax.set_title("using edges")

# 2 - using centers

ax = axs[1]

ax.pcolormesh(
    lon,
    lat,
    data,
    transform=ccrs.PlateCarree(),
    cmap="Reds",
    ec="0.3",
    lw=0.5,
)
ax.set_title("using centers")

for ax in axs:

    ax.plot(LON.flatten(), LAT.flatten(), "o", ms=1)
    ax.coastlines()
    ax.set_global()

no_wraparound

Full environment definition ### Operating system Linux ### Cartopy version 0.20.2 matplotlib.__version__ 3.5.1 ### conda list ``` # packages in environment at /home/mathause/.conda/envs/regionmask-docs: # # Name Version Build Channel _libgcc_mutex 0.1 conda_forge conda-forge _openmp_mutex 4.5 1_gnu conda-forge affine 2.3.0 py_0 conda-forge aiohttp 3.8.1 py310h6acc77f_0 conda-forge aiosignal 1.2.0 pyhd8ed1ab_0 conda-forge alabaster 0.7.12 py_0 conda-forge alsa-lib 1.2.3 h516909a_0 conda-forge appdirs 1.4.4 pyh9f0ad1d_0 conda-forge argon2-cffi 21.3.0 pyhd8ed1ab_0 conda-forge argon2-cffi-bindings 21.2.0 py310h6acc77f_1 conda-forge asttokens 2.0.5 pyhd8ed1ab_0 conda-forge async-timeout 4.0.2 pyhd8ed1ab_0 conda-forge attrs 21.4.0 pyhd8ed1ab_0 conda-forge babel 2.9.1 pyh44b312d_0 conda-forge backcall 0.2.0 pyh9f0ad1d_0 conda-forge backports 1.0 py_2 conda-forge backports.functools_lru_cache 1.6.4 pyhd8ed1ab_0 conda-forge black 21.12b0 pyhd8ed1ab_0 conda-forge bleach 4.1.0 pyhd8ed1ab_0 conda-forge blosc 1.21.0 h9c3ff4c_0 conda-forge bokeh 2.4.2 py310hff52083_0 conda-forge boost-cpp 1.74.0 h359cf19_5 conda-forge branca 0.4.2 pyhd8ed1ab_0 conda-forge brotli 1.0.9 h7f98852_6 conda-forge brotli-bin 1.0.9 h7f98852_6 conda-forge brotlipy 0.7.0 py310h6acc77f_1003 conda-forge bzip2 1.0.8 h7f98852_4 conda-forge c-ares 1.18.1 h7f98852_0 conda-forge ca-certificates 2021.10.8 ha878542_0 conda-forge cairo 1.16.0 ha00ac49_1009 conda-forge cartopy 0.20.2 py310he9c7799_3 conda-forge certifi 2021.10.8 py310hff52083_1 conda-forge cffi 1.15.0 py310h0fdd8cc_0 conda-forge cfitsio 4.0.0 h9a35b8e_0 conda-forge cftime 1.5.2 py310h96516ba_0 conda-forge charset-normalizer 2.0.10 pyhd8ed1ab_0 conda-forge click 8.0.3 py310hff52083_1 conda-forge click-plugins 1.1.1 py_0 conda-forge cligj 0.7.2 pyhd8ed1ab_1 conda-forge cloudpickle 2.0.0 pyhd8ed1ab_0 conda-forge colorama 0.4.4 pyh9f0ad1d_0 conda-forge cryptography 36.0.1 py310h685ca39_0 conda-forge curl 7.81.0 h2574ce0_0 conda-forge cycler 0.11.0 pyhd8ed1ab_0 conda-forge cytoolz 0.11.2 py310h6acc77f_1 conda-forge dask 2022.1.0 pyhd8ed1ab_0 conda-forge dask-core 2022.1.0 pyhd8ed1ab_0 conda-forge dataclasses 0.8 pyhc8e2a94_3 conda-forge dbus 1.13.6 h5008d03_3 conda-forge debugpy 1.5.1 py310h122e73d_0 conda-forge decorator 5.1.1 pyhd8ed1ab_0 conda-forge defusedxml 0.7.1 pyhd8ed1ab_0 conda-forge distributed 2022.1.0 py310hff52083_0 conda-forge docutils 0.17.1 py310hff52083_1 conda-forge entrypoints 0.3 pyhd8ed1ab_1003 conda-forge executing 0.8.2 pyhd8ed1ab_0 conda-forge expat 2.4.3 h9c3ff4c_0 conda-forge fiona 1.8.20 py310hfb73927_4 conda-forge flit-core 3.6.0 pyhd8ed1ab_0 conda-forge folium 0.12.1.post1 pyhd8ed1ab_1 conda-forge font-ttf-dejavu-sans-mono 2.37 hab24e00_0 conda-forge font-ttf-inconsolata 3.000 h77eed37_0 conda-forge font-ttf-source-code-pro 2.038 h77eed37_0 conda-forge font-ttf-ubuntu 0.83 hab24e00_0 conda-forge fontconfig 2.13.1 hba837de_1005 conda-forge fonts-conda-ecosystem 1 0 conda-forge fonts-conda-forge 1 0 conda-forge fonttools 4.28.5 py310h6acc77f_0 conda-forge freetype 2.10.4 h0708190_1 conda-forge freexl 1.0.6 h7f98852_0 conda-forge frozenlist 1.2.0 py310h6acc77f_1 conda-forge fsspec 2022.1.0 pypi_0 pypi gdal 3.4.1 pypi_0 pypi geopandas 0.10.2 pyhd8ed1ab_1 conda-forge geopandas-base 0.10.2 pyha770c72_1 conda-forge geos 3.10.2 h9c3ff4c_0 conda-forge geotiff 1.7.0 h6593c0a_6 conda-forge gettext 0.19.8.1 h73d1719_1008 conda-forge giflib 5.2.1 h36c2ea0_2 conda-forge gst-plugins-base 1.18.5 hf529b03_3 conda-forge gstreamer 1.18.5 h9f60fe5_3 conda-forge hdf4 4.2.15 h10796ff_3 conda-forge hdf5 1.12.1 nompi_h2750804_103 conda-forge heapdict 1.0.1 py_0 conda-forge icu 69.1 h9c3ff4c_0 conda-forge idna 3.3 pyhd8ed1ab_0 conda-forge imagesize 1.3.0 pyhd8ed1ab_0 conda-forge importlib-metadata 4.10.1 py310hff52083_0 conda-forge importlib_metadata 4.10.1 hd8ed1ab_0 conda-forge importlib_resources 5.4.0 pyhd8ed1ab_0 conda-forge intake 0.6.5 pyhd8ed1ab_0 conda-forge intake-geopandas 0.4.0 pypi_0 pypi ipykernel 6.7.0 py310hfdc917e_0 conda-forge ipython 8.0.1 py310hff52083_0 conda-forge ipython_genutils 0.2.0 py_1 conda-forge ipywidgets 7.6.5 pyhd8ed1ab_0 conda-forge jbig 2.1 h7f98852_2003 conda-forge jedi 0.18.1 py310hff52083_0 conda-forge jinja2 3.0.3 pyhd8ed1ab_0 conda-forge joblib 1.1.0 pyhd8ed1ab_0 conda-forge jpeg 9d h36c2ea0_0 conda-forge json-c 0.15 h98cffda_0 conda-forge jsonschema 4.4.0 pyhd8ed1ab_0 conda-forge jupyter 1.0.0 py310hff52083_7 conda-forge jupyter_client 7.1.2 pyhd8ed1ab_0 conda-forge jupyter_console 6.4.0 pyhd8ed1ab_0 conda-forge jupyter_core 4.9.1 py310hff52083_1 conda-forge jupyterlab_pygments 0.1.2 pyh9f0ad1d_0 conda-forge jupyterlab_widgets 1.0.2 pyhd8ed1ab_0 conda-forge kealib 1.4.14 h87e4c3c_3 conda-forge kiwisolver 1.3.2 py310h91b1402_1 conda-forge krb5 1.19.2 hcc1bbae_3 conda-forge lcms2 2.12 hddcbb42_0 conda-forge ld_impl_linux-64 2.36.1 hea4e1c9_2 conda-forge lerc 3.0 h9c3ff4c_0 conda-forge libblas 3.9.0 13_linux64_openblas conda-forge libbrotlicommon 1.0.9 h7f98852_6 conda-forge libbrotlidec 1.0.9 h7f98852_6 conda-forge libbrotlienc 1.0.9 h7f98852_6 conda-forge libcblas 3.9.0 13_linux64_openblas conda-forge libclang 13.0.0 default_hc23dcda_0 conda-forge libcurl 7.81.0 h2574ce0_0 conda-forge libdap4 3.20.6 hd7c4107_2 conda-forge libdeflate 1.8 h7f98852_0 conda-forge libedit 3.1.20191231 he28a2e2_2 conda-forge libev 4.33 h516909a_1 conda-forge libevent 2.1.10 h9b69904_4 conda-forge libffi 3.4.2 h7f98852_5 conda-forge libgcc-ng 11.2.0 h1d223b6_11 conda-forge libgdal 3.4.1 h7b6f8d3_2 conda-forge libgfortran-ng 11.2.0 h69a702a_11 conda-forge libgfortran5 11.2.0 h5c6108e_11 conda-forge libglib 2.70.2 h174f98d_1 conda-forge libgomp 11.2.0 h1d223b6_11 conda-forge libiconv 1.16 h516909a_0 conda-forge libkml 1.3.0 h238a007_1014 conda-forge liblapack 3.9.0 13_linux64_openblas conda-forge libllvm13 13.0.0 hf817b99_0 conda-forge libnetcdf 4.8.1 nompi_hb3fd0d9_101 conda-forge libnghttp2 1.43.0 h812cca2_1 conda-forge libnsl 2.0.0 h7f98852_0 conda-forge libogg 1.3.4 h7f98852_1 conda-forge libopenblas 0.3.18 pthreads_h8fe5266_0 conda-forge libopus 1.3.1 h7f98852_1 conda-forge libpng 1.6.37 h21135ba_2 conda-forge libpq 14.1 hd57d9b9_1 conda-forge librttopo 1.1.0 hf69c175_9 conda-forge libsodium 1.0.18 h36c2ea0_1 conda-forge libspatialindex 1.9.3 h9c3ff4c_4 conda-forge libspatialite 5.0.1 h0e567f8_14 conda-forge libssh2 1.10.0 ha56f1ee_2 conda-forge libstdcxx-ng 11.2.0 he4da1e4_11 conda-forge libtiff 4.3.0 h6f004c6_2 conda-forge libuuid 2.32.1 h7f98852_1000 conda-forge libvorbis 1.3.7 h9c3ff4c_0 conda-forge libwebp-base 1.2.2 h7f98852_1 conda-forge libxcb 1.13 h7f98852_1004 conda-forge libxkbcommon 1.0.3 he3ba5ed_0 conda-forge libxml2 2.9.12 h885dcf4_1 conda-forge libzip 1.8.0 h4de3113_1 conda-forge libzlib 1.2.11 h36c2ea0_1013 conda-forge locket 0.2.0 py_2 conda-forge lz4-c 1.9.3 h9c3ff4c_1 conda-forge mapclassify 2.4.3 pyhd8ed1ab_0 conda-forge markupsafe 2.0.1 py310h6acc77f_1 conda-forge matplotlib-base 3.5.1 py310h23f4a51_0 conda-forge matplotlib-inline 0.1.3 pyhd8ed1ab_0 conda-forge mistune 0.8.4 py310h6acc77f_1005 conda-forge msgpack-python 1.0.3 py310h91b1402_0 conda-forge multidict 6.0.1 py310h6acc77f_0 conda-forge munch 2.5.0 py_0 conda-forge munkres 1.1.4 pyh9f0ad1d_0 conda-forge mypy_extensions 0.4.3 py310hff52083_4 conda-forge mysql-common 8.0.28 ha770c72_0 conda-forge mysql-libs 8.0.28 hfa10184_0 conda-forge nbclient 0.5.10 pyhd8ed1ab_1 conda-forge nbconvert 6.4.0 py310hff52083_0 conda-forge nbformat 5.1.3 pyhd8ed1ab_0 conda-forge ncurses 6.2 h58526e2_4 conda-forge nest-asyncio 1.5.4 pyhd8ed1ab_0 conda-forge netcdf4 1.5.8 nompi_py310hd7ca5b8_101 conda-forge networkx 2.6.3 pyhd8ed1ab_1 conda-forge notebook 6.4.7 pyha770c72_0 conda-forge nspr 4.32 h9c3ff4c_1 conda-forge nss 3.74 hb5efdd6_0 conda-forge numpy 1.22.1 py310h454958d_0 conda-forge numpydoc 1.1.0 py_1 conda-forge olefile 0.46 pyh9f0ad1d_1 conda-forge openjpeg 2.4.0 hb52868f_1 conda-forge openssl 1.1.1l h7f98852_0 conda-forge packaging 21.3 pyhd8ed1ab_0 conda-forge pandas 1.4.0 py310hb5077e9_0 conda-forge pandoc 2.17.0.1 h7f98852_0 conda-forge pandocfilters 1.5.0 pyhd8ed1ab_0 conda-forge parso 0.8.3 pyhd8ed1ab_0 conda-forge partd 1.2.0 pyhd8ed1ab_0 conda-forge pathspec 0.9.0 pyhd8ed1ab_0 conda-forge pcre 8.45 h9c3ff4c_0 conda-forge pexpect 4.8.0 pyh9f0ad1d_2 conda-forge pickleshare 0.7.5 py_1003 conda-forge pillow 8.4.0 py310h07f4688_0 conda-forge pip 21.3.1 pyhd8ed1ab_0 conda-forge pixman 0.40.0 h36c2ea0_0 conda-forge platformdirs 2.3.0 pyhd8ed1ab_0 conda-forge pooch 1.6.0 pyhd8ed1ab_0 conda-forge poppler 21.11.0 ha39eefc_0 conda-forge poppler-data 0.4.11 hd8ed1ab_0 conda-forge postgresql 14.1 h2510834_1 conda-forge proj 8.2.1 h277dcde_0 conda-forge prometheus_client 0.12.0 pyhd8ed1ab_0 conda-forge prompt-toolkit 3.0.24 pyha770c72_0 conda-forge prompt_toolkit 3.0.24 hd8ed1ab_0 conda-forge psutil 5.9.0 py310h6acc77f_0 conda-forge pthread-stubs 0.4 h36c2ea0_1001 conda-forge ptyprocess 0.7.0 pyhd3deb0d_0 conda-forge pure_eval 0.2.2 pyhd8ed1ab_0 conda-forge pycparser 2.21 pyhd8ed1ab_0 conda-forge pygeos 0.12.0 py310h1b8dd88_1 conda-forge pygments 2.11.2 pyhd8ed1ab_0 conda-forge pyopenssl 21.0.0 pyhd8ed1ab_0 conda-forge pyparsing 3.0.7 pyhd8ed1ab_0 conda-forge pyproj 3.3.0 py310h9e0d750_1 conda-forge pyqt 5.12.3 py310hff52083_8 conda-forge pyqt-impl 5.12.3 py310h1f8e252_8 conda-forge pyqt5-sip 4.19.18 py310h122e73d_8 conda-forge pyqtchart 5.12 py310hfcd6d55_8 conda-forge pyqtwebengine 5.12.1 py310hfcd6d55_8 conda-forge pyrsistent 0.18.1 py310h6acc77f_0 conda-forge pyshp 2.1.3 pyh44b312d_0 conda-forge pysocks 1.7.1 py310hff52083_4 conda-forge python 3.10.2 h62f1059_0_cpython conda-forge python-dateutil 2.8.2 pyhd8ed1ab_0 conda-forge python_abi 3.10 2_cp310 conda-forge pytz 2021.3 pyhd8ed1ab_0 conda-forge pyyaml 6.0 py310h6acc77f_3 conda-forge pyzmq 22.3.0 py310h675a958_1 conda-forge qt 5.12.9 ha98a1a1_5 conda-forge qtconsole 5.2.2 pyhd8ed1ab_1 conda-forge qtconsole-base 5.2.2 pyhd8ed1ab_1 conda-forge qtpy 2.0.0 pyhd8ed1ab_0 conda-forge rasterio 1.2.10 py310h5e0f756_4 conda-forge readline 8.1 h46c0cb4_0 conda-forge regionmask 0.8.0.post1.dev24+g17855bf.d20220125 dev_0 requests 2.27.1 pyhd8ed1ab_0 conda-forge rtree 0.9.7 py310hbdcdc62_3 conda-forge scikit-learn 1.0.2 py310h1246948_0 conda-forge scipy 1.7.3 py310hea5193d_0 conda-forge send2trash 1.8.0 pyhd8ed1ab_0 conda-forge setuptools 59.8.0 py310hff52083_0 conda-forge shapely 1.8.0 py310h1b8dd88_5 conda-forge six 1.16.0 pyh6c4a22f_0 conda-forge snowballstemmer 2.2.0 pyhd8ed1ab_0 conda-forge snuggs 1.4.7 py_0 conda-forge sortedcontainers 2.4.0 pyhd8ed1ab_0 conda-forge sphinx 4.4.0 pyh6c4a22f_1 conda-forge sphinx_rtd_theme 1.0.0 pyhd8ed1ab_0 conda-forge sphinxcontrib-applehelp 1.0.2 py_0 conda-forge sphinxcontrib-devhelp 1.0.2 py_0 conda-forge sphinxcontrib-htmlhelp 2.0.0 pyhd8ed1ab_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.5 pyhd8ed1ab_1 conda-forge sqlite 3.37.0 h9cd32fc_0 conda-forge stack_data 0.1.4 pyhd8ed1ab_0 conda-forge tblib 1.7.0 pyhd8ed1ab_0 conda-forge terminado 0.12.1 py310hff52083_1 conda-forge testpath 0.5.0 pyhd8ed1ab_0 conda-forge threadpoolctl 3.0.0 pyh8a188c0_0 conda-forge tiledb 2.6.1 h2038895_0 conda-forge tk 8.6.11 h27826a3_1 conda-forge tomli 1.2.2 pyhd8ed1ab_0 conda-forge toolz 0.11.2 pyhd8ed1ab_0 conda-forge tornado 6.1 py310h6acc77f_2 conda-forge traitlets 5.1.1 pyhd8ed1ab_0 conda-forge typed-ast 1.5.1 py310h6acc77f_0 conda-forge typing-extensions 4.0.1 hd8ed1ab_0 conda-forge typing_extensions 4.0.1 pyha770c72_0 conda-forge tzcode 2021e h7f98852_0 conda-forge tzdata 2021e he74cb21_0 conda-forge urllib3 1.26.8 pyhd8ed1ab_1 conda-forge wcwidth 0.2.5 pyh9f0ad1d_2 conda-forge webencodings 0.5.1 py_1 conda-forge wheel 0.37.1 pyhd8ed1ab_0 conda-forge widgetsnbextension 3.5.2 py310hff52083_1 conda-forge xarray 0.20.2 pyhd8ed1ab_0 conda-forge xerces-c 3.2.3 h8ce2273_4 conda-forge xorg-kbproto 1.0.7 h7f98852_1002 conda-forge xorg-libice 1.0.10 h7f98852_0 conda-forge xorg-libsm 1.2.3 hd9c2040_1000 conda-forge xorg-libx11 1.7.2 h7f98852_0 conda-forge xorg-libxau 1.0.9 h7f98852_0 conda-forge xorg-libxdmcp 1.1.3 h7f98852_0 conda-forge xorg-libxext 1.3.4 h7f98852_1 conda-forge xorg-libxrender 0.9.10 h7f98852_1003 conda-forge xorg-renderproto 0.11.1 h7f98852_1002 conda-forge xorg-xextproto 7.3.0 h7f98852_1002 conda-forge xorg-xproto 7.0.31 h7f98852_1007 conda-forge xyzservices 2022.1.1 pyhd8ed1ab_0 conda-forge xz 5.2.5 h516909a_1 conda-forge yaml 0.2.5 h7f98852_2 conda-forge yarl 1.7.2 py310h6acc77f_1 conda-forge zeromq 4.3.4 h9c3ff4c_1 conda-forge zict 2.0.0 py_0 conda-forge zipp 3.7.0 pyhd8ed1ab_0 conda-forge zlib 1.2.11 h36c2ea0_1013 conda-forge zstd 1.5.2 ha95c52a_0 conda-forge ``` ### pip list ``` ```
mathause commented 2 years ago

Interestingly if you do lon + 30 or lon_edge + 30 it seems to work.

greglucas commented 2 years ago

Thanks for the analysis @mathause! This appears to be due to the pyproj upgrade actually and wrapping the coordinates over 180, but not less than -180. I put a fix in for that in #1998

mathause commented 2 years ago

Thank you for the quick fix! Feels like I keep throwing "edge" cases at you.

This appears to be due to the pyproj upgrade actually and wrapping the coordinates over 180, but not less than -180.

This also gives me an idea how to create a work around for now (use 0..360 instead of -180..180).


(Definitely not the same problem but if you try different crs with the above code (e.g.EckertIII or Robinson) you will also see some issues with the border cell)

```python import cartopy.crs as ccrs import matplotlib.pyplot as plt import numpy as np lon = np.arange(-180, 151, 30) lat = np.arange(75, -76, -30) data = np.ones(shape=lat.shape + lon.shape) f, ax = plt.subplots(1, 1, subplot_kw=dict(projection=ccrs.EckertIII())) ax.pcolormesh( lon_edges, lat_edges, data, transform=ccrs.PlateCarree(), cmap="Reds", ec="0.3", lw=0.5, ) ax.coastlines() ax.set_global() ```

artifacts

greglucas commented 2 years ago

I think that is to be expected here and I'm not sure how easy it would be to fix. I think what is happening is that the pcolormesh is QuadMesh, so everything is drawn in straight lines. So, your cells from 60-90 are all vertical. Except for the "wrapped" cells, which get drawn as a PolyCollection, and thus there is interpolation along the path that happens. This interpolation causes an extra point in the middle of the path, which is no longer a straight line. Thus, when the QuadMesh straight edges meet up with the PolyCollection interpolated edges, there can be a disconnect between the two.

mathause commented 2 years ago

Thanks, makes sense. Just something I saw trying out different projections.