I've run into an issue where the call to ax.clabel plots contour labels as desired, yet the clabel object itself is somehow 'None'. This becomes an issue because I then wipe my contour and contour label objects clean after each iteration of a long loop, as in this answer, but a TypeError
is thrown because of course it can't iterate over a NoneType object. (I've used this method with no issue for about 4 years now, until yesterday. This is with matplotlib 3.2.2 and cartopy 0.18.0 on a Win64 PC running Anaconda.
I think I've narrowed it down to cartopy somehow being the issue... but how, I have no idea.
Here's a short script that illustrates that clabels are handled just fine when dealing with a basic 2D plot, but something goes haywire when trying to use pyplot in tandem with cartopy.
import matplotlib as mpl
mpl.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
from time import time
from datetime import datetime, timedelta
from siphon.catalog import TDSCatalog
import cartopy.crs as ccrs
# Recreate the gridded data from the matplotlib contour example
delta = 0.025
x = np.arange(-3.0, 3.0, delta)
y = np.arange(-2.0, 2.0, delta)
X, Y = np.meshgrid(x, y)
Z1 = np.exp(-X**2 - Y**2)
Z2 = np.exp(-(X - 1)**2 - (Y - 1)**2)
Z = (Z1 - Z2) * 2
# Contour it and label it to show that labels work and can be removed as desired
fig, ax = plt.subplots()
cN = ax.contour(X, Y, Z)
lbl = ax.clabel(cN)
#plt.show()
print("\n\nContour label for a basic 2D plot is: ")
print(lbl)
# Now remove those labels
# Will work as intended for lbl
for label in lbl:
label.remove()
# Now try a dataset that needs to be geographically referenced
# Use siphon to get a weather model dataset
# This dataset link will expire on approximately March 9, 2021
model_url = "https://www.ncei.noaa.gov/thredds/catalog/model-rap130/202009/20200909/catalog.xml?dataset=rap130/202009/20200909/rap_130_20200909_1800_000.grb2"
vtime = datetime.strptime('2020090918','%Y%m%d%H')
# Get the data
model = TDSCatalog(model_url)
ds = model.datasets[0]
ncss = ds.subset()
query = ncss.query()
query.accept('netcdf')
query.time(vtime) # Set to the analysis hour only
query.add_lonlat()
query.variables('Geopotential_height_isobaric')
data = ncss.get_data(query)
# Get the lats and lons and a data field from the file
lats = data.variables['lat'][:,:]
lons = data.variables['lon'][:,:]
hght = data.variables['Geopotential_height_isobaric'][0,24,:,:] # 700 hPa is 24th element
# Contour that weather data grid
# This requires cartopy, which seems to be the problem
# Redefine the figure, because this time we need to georeference it
fig = plt.figure(5, figsize=(1600/96,1600/96))
ax = fig.add_subplot(111, projection=ccrs.PlateCarree())
cN2 = ax.contour(lons, lats, hght)
lbl2 = ax.clabel(cN2)
#plt.show()
print("\n\nContour label for weather data plot is: ")
print(lbl2)
# Removing labels will not work for lbl2 because it can't iterate over a NoneType object
for label in lbl2:
label.remove()