Misleading error messages in the plotting functions
I've been having some problems with the plot
function in pyicon
, with the error messages being given not really pointing to the problem. I've detailed some of these errors below. I'll submit a pull request to try and improve the error messages later this week.
Producing the errors
Problem 1
import xarray as xr
import pyicon as pyic
ds = xr.open_mfdataset(
"/home/m/m301014/work.me/exp.TropAtl/data/raw/exp.TropAtl.r2b6/exp.TropAtl.r2b6_production_1955????T000000Z.nc",
decode_cf=False,
)
ds["vort"].isel(time=10, depth=0).pyic.plot()
File /work/mh0256/m301014/.conda/envs/age-tracer/lib/python3.11/site-packages/pyicon/pyicon_accessor.py:26, in pyiconDataArray.plot(self, **kwargs)
23 @functools.wraps(pyic.plot, assigned=("__doc__", "__anotations__"))
24 def plot(self, **kwargs):
25 da = self._obj
---> 26 ax, hm = pyic.plot(da, **kwargs)
27 return ax, hmFile /work/mh0256/m301014/.conda/envs/age-tracer/lib/python3.11/site-packages/pyicon/pyicon_plotting.py:1966, in plot(data, Plot, ax, cax, asp, fig_size_fac, mask_data, logplot, lon_reg, lat_reg, central_longitude, clim, cmap, conts, contfs, clevs, use_pcol_or_contf, contcolor, cincr, clabel, cbticks, xlabel, ylabel, xticks, yticks, template, cbar_str, cbar_pos, title_right, title_left, title_center, projection, coastlines_color, land_facecolor, axes_facecolor, noland, do_plot_settings, do_xyticks, do_gridlines, gname, fpath_tgrid, plot_method, grid_type, res, fpath_ckdtree, coordinates, lonlat_for_mask)
1963 fpath_ckdtree = f'{path_grid}/{gname}/ckdtree/rectgrids/{gname}_res{res:3.2f}_180W-180E_90S-90N.nc'
1965 if grid_type=='auto':
-> 1966 if Dgrid["name"].startswith("healpix"):
1967 grid_type = 'healpix'
1968 else:UnboundLocalError: cannot access local variable 'Dgrid' where it is not associated with a value
This is fixed by including grid_type="native"
in the function call. But then we get a new error....
Problem 2
ds["vort"].isel(time=10, depth=0).pyic.plot(
grid_type="native",
)
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
File /work/mh0256/m301014/.conda/envs/age-tracer/lib/python3.11/site-packages/xarray/backends/file_manager.py:211, in CachingFileManager._acquire_with_cache_info(self, needs_lock)
210 try:
--> 211 file = self._cache[self._key]
212 except KeyError:File /work/mh0256/m301014/.conda/envs/age-tracer/lib/python3.11/site-packages/xarray/backends/lru_cache.py:56, in LRUCache.__getitem__(self, key)
55 with self._lock:
---> 56 value = self._cache[key]
57 self._cache.move_to_end(key)KeyError: [<class 'netCDF4._netCDF4.Dataset'>, ('/work/mh0033/m300602/icon/grids/none/ckdtree/rectgrids/none_res0.30_180W-180E_90S-90N.nc',), 'r', (('clobber', True), ('diskless', False), ('format', 'NETCDF4'), ('persist', False)), 'ab78d15b-6e6b-4165-a718-d702fcc4afe4']During handling of the above exception, another exception occurred:FileNotFoundError Traceback (most recent call last)
Cell In[242], line 1
----> 1 ds["vort"].isel(time=10, depth=0).pyic.plot(
2 grid_type="native"
3 )File /work/mh0256/m301014/.conda/envs/age-tracer/lib/python3.11/site-packages/pyicon/pyicon_accessor.py:26, in pyiconDataArray.plot(self, **kwargs)
23 @functools.wraps(pyic.plot, assigned=("__doc__", "__anotations__"))
24 def plot(self, **kwargs):
25 da = self._obj
---> 26 ax, hm = pyic.plot(da, **kwargs)
27 return ax, hmFile /work/mh0256/m301014/.conda/envs/age-tracer/lib/python3.11/site-packages/pyicon/pyicon_plotting.py:1994, in plot(data, Plot, ax, cax, asp, fig_size_fac, mask_data, logplot, lon_reg, lat_reg, central_longitude, clim, cmap, conts, contfs, clevs, use_pcol_or_contf, contcolor, cincr, clabel, cbticks, xlabel, ylabel, xticks, yticks, template, cbar_str, cbar_pos, title_right, title_left, title_center, projection, coastlines_color, land_facecolor, axes_facecolor, noland, do_plot_settings, do_xyticks, do_gridlines, gname, fpath_tgrid, plot_method, grid_type, res, fpath_ckdtree, coordinates, lonlat_for_mask)
1989 #if 'grid_mapping' in list(data.attrs):
1990 # plot_method = 'healpix'
1991
1992 # --- interpolate and cut to region
1993 if grid_type=='native' and plot_method=='nn':
-> 1994 datai = interp_to_rectgrid_xr(data.compute(), fpath_ckdtree, lon_reg=lon_reg, lat_reg=lat_reg, coordinates=coordinates)
1995 lon = datai.lon
1996 lat = datai.latFile /work/mh0256/m301014/.conda/envs/age-tracer/lib/python3.11/site-packages/pyicon/pyicon_tb.py:241, in interp_to_rectgrid_xr(arr, fpath_ckdtree, lon_reg, lat_reg, coordinates, radius_of_influence, compute, mask_out_of_range, mask_out_of_range_before)
238 print(fpath_ckdtree)
240 # --- load interpolation indices
--> 241 ds_ckdt = xr.open_dataset(fpath_ckdtree)
242 if ('clon' in coordinates) or (coordinates==''):
243 inds = ds_ckdt.ickdtree_cFile /work/mh0256/m301014/.conda/envs/age-tracer/lib/python3.11/site-packages/xarray/backends/api.py:572, in open_dataset(filename_or_obj, engine, chunks, cache, decode_cf, mask_and_scale, decode_times, decode_timedelta, use_cftime, concat_characters, decode_coords, drop_variables, inline_array, chunked_array_type, from_array_kwargs, backend_kwargs, **kwargs)
560 decoders = _resolve_decoders_kwargs(
561 decode_cf,
562 open_backend_dataset_parameters=backend.open_dataset_parameters,
(...)
568 decode_coords=decode_coords,
569 )
571 overwrite_encoded_chunks = kwargs.pop("overwrite_encoded_chunks", None)
--> 572 backend_ds = backend.open_dataset(
573 filename_or_obj,
574 drop_variables=drop_variables,
575 **decoders,
576 **kwargs,
577 )
578 ds = _dataset_from_backend_dataset(
579 backend_ds,
580 filename_or_obj,
(...)
590 **kwargs,
591 )
592 return dsFile /work/mh0256/m301014/.conda/envs/age-tracer/lib/python3.11/site-packages/xarray/backends/netCDF4_.py:593, in NetCDF4BackendEntrypoint.open_dataset(self, filename_or_obj, mask_and_scale, decode_times, concat_characters, decode_coords, drop_variables, use_cftime, decode_timedelta, group, mode, format, clobber, diskless, persist, lock, autoclose)
572 def open_dataset( # type: ignore[override] # allow LSP violation, not supporting **kwargs
573 self,
574 filename_or_obj: str | os.PathLike[Any] | BufferedIOBase | AbstractDataStore,
(...)
590 autoclose=False,
591 ) -> Dataset:
592 filename_or_obj = _normalize_path(filename_or_obj)
--> 593 store = NetCDF4DataStore.open(
594 filename_or_obj,
595 mode=mode,
596 format=format,
597 group=group,
598 clobber=clobber,
599 diskless=diskless,
600 persist=persist,
601 lock=lock,
602 autoclose=autoclose,
603 )
605 store_entrypoint = StoreBackendEntrypoint()
606 with close_on_error(store):File /work/mh0256/m301014/.conda/envs/age-tracer/lib/python3.11/site-packages/xarray/backends/netCDF4_.py:400, in NetCDF4DataStore.open(cls, filename, mode, format, group, clobber, diskless, persist, lock, lock_maker, autoclose)
394 kwargs = dict(
395 clobber=clobber, diskless=diskless, persist=persist, format=format
396 )
397 manager = CachingFileManager(
398 netCDF4.Dataset, filename, mode=mode, kwargs=kwargs
399 )
--> 400 return cls(manager, group=group, mode=mode, lock=lock, autoclose=autoclose)File /work/mh0256/m301014/.conda/envs/age-tracer/lib/python3.11/site-packages/xarray/backends/netCDF4_.py:347, in NetCDF4DataStore.__init__(self, manager, group, mode, lock, autoclose)
345 self._group = group
346 self._mode = mode
--> 347 self.format = self.ds.data_model
348 self._filename = self.ds.filepath()
349 self.is_remote = is_remote_uri(self._filename)File /work/mh0256/m301014/.conda/envs/age-tracer/lib/python3.11/site-packages/xarray/backends/netCDF4_.py:409, in NetCDF4DataStore.ds(self)
407 @property
408 def ds(self):
--> 409 return self._acquire()File /work/mh0256/m301014/.conda/envs/age-tracer/lib/python3.11/site-packages/xarray/backends/netCDF4_.py:403, in NetCDF4DataStore._acquire(self, needs_lock)
402 def _acquire(self, needs_lock=True):
--> 403 with self._manager.acquire_context(needs_lock) as root:
404 ds = _nc4_require_group(root, self._group, self._mode)
405 return dsFile /work/mh0256/m301014/.conda/envs/age-tracer/lib/python3.11/contextlib.py:137, in _GeneratorContextManager.__enter__(self)
135 del self.args, self.kwds, self.func
136 try:
--> 137 return next(self.gen)
138 except StopIteration:
139 raise RuntimeError("generator didn't yield") from NoneFile /work/mh0256/m301014/.conda/envs/age-tracer/lib/python3.11/site-packages/xarray/backends/file_manager.py:199, in CachingFileManager.acquire_context(self, needs_lock)
196 @contextlib.contextmanager
197 def acquire_context(self, needs_lock=True):
198 """Context manager for acquiring a file."""
--> 199 file, cached = self._acquire_with_cache_info(needs_lock)
200 try:
201 yield fileFile /work/mh0256/m301014/.conda/envs/age-tracer/lib/python3.11/site-packages/xarray/backends/file_manager.py:217, in CachingFileManager._acquire_with_cache_info(self, needs_lock)
215 kwargs = kwargs.copy()
216 kwargs["mode"] = self._mode
--> 217 file = self._opener(*self._args, **kwargs)
218 if self._mode == "w":
219 # ensure file doesn't get overridden when opened again
220 self._mode = "a"File src/netCDF4/_netCDF4.pyx:2469, in netCDF4._netCDF4.Dataset.__init__()File src/netCDF4/_netCDF4.pyx:2028, in netCDF4._netCDF4._ensure_nc_success()FileNotFoundError: [Errno 2] No such file or directory: '/work/mh0033/m300602/icon/grids/none/ckdtree/rectgrids/none_res0.30_180W-180E_90S-90N.nc'
This is fixed by gname="r2b6_oce_r0004"
but leads to problem 3... I think we can fix this by raising an error when gname is set to None.
Problem 3
ds["vort"].isel(time=10, depth=0).pyic.plot(
grid_type="native",
gname="r2b6_oce_r0004",
)
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
Cell In[243], line 1
----> 1 ds["vort"].isel(time=10, depth=0).pyic.plot(
2 grid_type="native",
3 gname="r2b6_oce_r0004",
4 )File /work/mh0256/m301014/.conda/envs/age-tracer/lib/python3.11/site-packages/pyicon/pyicon_accessor.py:26, in pyiconDataArray.plot(self, **kwargs)
23 @functools.wraps(pyic.plot, assigned=("__doc__", "__anotations__"))
24 def plot(self, **kwargs):
25 da = self._obj
---> 26 ax, hm = pyic.plot(da, **kwargs)
27 return ax, hmFile /work/mh0256/m301014/.conda/envs/age-tracer/lib/python3.11/site-packages/pyicon/pyicon_plotting.py:1994, in plot(data, Plot, ax, cax, asp, fig_size_fac, mask_data, logplot, lon_reg, lat_reg, central_longitude, clim, cmap, conts, contfs, clevs, use_pcol_or_contf, contcolor, cincr, clabel, cbticks, xlabel, ylabel, xticks, yticks, template, cbar_str, cbar_pos, title_right, title_left, title_center, projection, coastlines_color, land_facecolor, axes_facecolor, noland, do_plot_settings, do_xyticks, do_gridlines, gname, fpath_tgrid, plot_method, grid_type, res, fpath_ckdtree, coordinates, lonlat_for_mask)
1989 #if 'grid_mapping' in list(data.attrs):
1990 # plot_method = 'healpix'
1991
1992 # --- interpolate and cut to region
1993 if grid_type=='native' and plot_method=='nn':
-> 1994 datai = interp_to_rectgrid_xr(data.compute(), fpath_ckdtree, lon_reg=lon_reg, lat_reg=lat_reg, coordinates=coordinates)
1995 lon = datai.lon
1996 lat = datai.latFile /work/mh0256/m301014/.conda/envs/age-tracer/lib/python3.11/site-packages/pyicon/pyicon_tb.py:285, in interp_to_rectgrid_xr(arr, fpath_ckdtree, lon_reg, lat_reg, coordinates, radius_of_influence, compute, mask_out_of_range, mask_out_of_range_before)
283 # --- interpolate by nearest neighbor
284 inds = inds.flatten()
--> 285 arr_interp = xr.DataArray(arr.data[inds].reshape(lat.size, lon.size), dims=['lat', 'lon'], coords=dict(lat=lat, lon=lon))
287 # --- mask values where nearest neighbor is too far away
288 # (doing this after compute seems to be faster) FIXME check that!
289 if mask_out_of_range_before:IndexError: index 203212 is out of bounds for axis 0 with size 120947
This is fixed by coordinates="vlon vlat"
and I suspect we can get pyicon to automatically guess how to fix this type of problem.
So the final working piece of code is
ds["vort"].isel(time=10, depth=0).pyic.plot(
grid_type="native",
gname="r2b6_oce_r0004",
coordinates="vlon vlat",
)