cartopy
cartopy copied to clipboard
Contourf not plotting negative contours in certain cases
Description
In some very specific circumstances, negative contours will not be shown, and some odd contours are shown in a contourf plot. The code below demonstrates the issue, but the issue is not present when the central_longitude
argument to projection=ccrs.PlateCarree()
is 0 or removed, or when the contour levels are not centered around 0 or extended beyond levels=np.arange(-4,4.4,0.4)
. The researcher I'm helping with this has 3 other similar contourf plots (same levels, central_longitude=180
) that don't have this issue. The issue is present in the latest cartopy 0.22.0 conda-forge release, and in the current main
branch, though only present for Matplotlib >= 3.8. Example plots are below:
Cartopy
main
, matplotlib 3.8.3, central_longitude=0
Cartopy
main
, matplotlib 3.8.3, central_longitude=1
Cartopy
main
, matplotlib 3.7.5, central_longitude=1
Looking through some of the other contourf based issues, this one seems similar to #2288, #1822 and #1076, but distinct in some way from all of those.
Code to reproduce
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import numpy as np
import netCDF4
ds = netCDF4.Dataset('dataset.nc','r')
ax = plt.axes(projection=ccrs.PlateCarree(central_longitude=1))
ax.contourf(np.array(ds['lon']),np.array(ds['lat']),np.array(ds['a']),transform=ccrs.PlateCarree(),levels=np.arange(-2,2.2,0.2),extend='both')
plt.show()
With dataset.nc.gz
Full environment definition
Operating system
linux-64
Cartopy version
0.22.1.dev109+g36eb99ef
pip list
Package Version
--------------- -----------------------
Cartopy 0.22.1.dev109+g36eb99ef
certifi 2024.2.2
cftime 1.6.3
contourpy 1.2.0
cycler 0.12.1
fonttools 4.49.0
kiwisolver 1.4.5
matplotlib 3.8.3
netCDF4 1.6.5
numpy 1.26.4
packaging 23.2
pillow 10.2.0
pip 23.2.1
pyparsing 3.1.1
pyproj 3.6.1
pyshp 2.3.1
python-dateutil 2.9.0.post0
shapely 2.0.3
six 1.16.0
Thanks for the report and the clear reproducer @dsroberts. This seems reminiscent of #2224 which I ultimately solved by locating the specific problem level and analyzing that. I had some trouble locating the problem level in this case as it seems to be very specific to the slightly off-zero value generated by arange
. But now I have this:
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import numpy as np
import netCDF4
ds = netCDF4.Dataset('dataset.nc','r')
def try_plot(lev0):
ax = plt.axes(projection=ccrs.PlateCarree(central_longitude=1))
cf = ax.contourf(np.array(ds['lon']), np.array(ds['lat']), np.array(ds['a']), transform=ccrs.PlateCarree(), levels=[lev0, lev0+0.2], extend='both')
plt.colorbar(cf)
plt.show()
try_plot(-4.44e-16)
try_plot(0)
The slightly negative value give this (bad!)
Whereas zero give this (good!)
A workaround for your researcher might be to use levels=np.linspace(-2, 2, 21)
, which gives me this:
Thanks for looking into this @rcomer. I will pass your recommendation on. I played around with your try_plot
function and got some interesting results. The resultant contours are extremely sensitive to that central value.
try_plot(-4.44e-16)
try_plot(0)
try_plot(-5e-16)
try_plot(-4e-16)
try_plot(-4.5e-16)
I also added lev0
to the data (after casting it to float64
) which would align the 'zeros' in the data with the middle level, and this resulted in 5 identical plots. I guess this would indicate a floating point conversion and/or equality error somewhere?