cartopy icon indicating copy to clipboard operation
cartopy copied to clipboard

Contourf not plotting negative contours in certain cases

Open dsroberts opened this issue 11 months ago • 2 comments

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: mpl38_cl0 Cartopy main, matplotlib 3.8.3, central_longitude=0 mpl38_cl1 Cartopy main, matplotlib 3.8.3, central_longitude=1 cartopy_main_mpl37_cl1 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

dsroberts avatar Mar 04 '24 03:03 dsroberts

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!) image

Whereas zero give this (good!) image

A workaround for your researcher might be to use levels=np.linspace(-2, 2, 21), which gives me this:

image

rcomer avatar Mar 05 '24 14:03 rcomer

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. 044 try_plot(-4.44e-16) 000 try_plot(0) 050 try_plot(-5e-16) 040 try_plot(-4e-16) 045 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?

dsroberts avatar Mar 06 '24 01:03 dsroberts