id,node_id,number,title,user,state,locked,assignee,milestone,comments,created_at,updated_at,closed_at,author_association,active_lock_reason,draft,pull_request,body,reactions,performed_via_github_app,state_reason,repo,type 1244977848,I_kwDOAMm_X85KNNq4,6629,`plot.imshow` with datetime coordinate fails,6872529,closed,0,,,5,2022-05-23T10:56:46Z,2024-04-28T20:16:44Z,2024-04-28T20:16:44Z,NONE,,,,"### What happened? When trying to plot a 2d DataArray that has one of the 2 coordinates as datetime with `da.plot.imshow`, the following error is returned: ``` TypeError: ufunc 'isfinite' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe'' ``` I know that I can use `pcolormesh` instead but on large arrays, `imshow` is much faster. It also behaves nicer with transparency and interpolation so or regularly sampled data, I find `imshow` a better choice. Here is a minimal working example: ```python import numpy as np from xarray import DataArray from pandas import date_range time = date_range('2020-01-01', periods=7, freq='D') y = np.linspace(0, 10, 11) da = DataArray( np.random.rand(time.size, y.size), coords=dict(time=time, y=y), dims=('time', 'y') ) da.plot.imshow(x='time', y='y') ``` ### What did you expect to happen? I suggest the following solution which can be added after https://github.com/pydata/xarray/blob/4da7fdbd85bb82e338ad65a532dd7a9707e18ce0/xarray/plot/plot.py#L1366 ```python left, right = map(date2num, (left, right)) ``` and then adding: ```python ax.xaxis_date() plt.setp(ax.get_xticklabels(), rotation=30, ha='right') ``` ### Minimal Complete Verifiable Example ```Python import numpy as np from xarray import DataArray from pandas import date_range # creating the data time = date_range('2020-01-01', periods=7, freq='D') y = np.linspace(0, 10, 11) da = DataArray( np.random.rand(time.size, y.size), coords=dict(time=time, y=y), dims=('time', 'y') ) import matplotlib.pyplot as plt from matplotlib.dates import date2num, AutoDateFormatter # from https://github.com/pydata/xarray/blob/4da7fdbd85bb82e338ad65a532dd7a9707e18ce0/xarray/plot/plot.py#L1348 def _center_pixels(x): """"""Center the pixels on the coordinates."""""" if np.issubdtype(x.dtype, str): # When using strings as inputs imshow converts it to # integers. Choose extent values which puts the indices in # in the center of the pixels: return 0 - 0.5, len(x) - 0.5 try: # Center the pixels assuming uniform spacing: xstep = 0.5 * (x[1] - x[0]) except IndexError: # Arbitrary default value, similar to matplotlib behaviour: xstep = 0.1 return x[0] - xstep, x[-1] + xstep # Center the pixels: left, right = _center_pixels(da.time) top, bottom = _center_pixels(da.y) # the magical step # vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv left, right = map(date2num, (left, right)) # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # plotting fig, ax = plt.subplots() ax.imshow( da.T, extent=(left, right, top, bottom), origin='lower', aspect='auto' ) ax.xaxis_date() plt.setp(ax.get_xticklabels(), rotation=30, ha='right') ``` ### MVCE confirmation - [x] Minimal example — the example is as focused as reasonably possible to demonstrate the underlying issue in xarray. - [X] Complete example — the example is self-contained, including all data and the text of any traceback. - [X] Verifiable example — the example copy & pastes into an IPython prompt or [Binder notebook](https://mybinder.org/v2/gh/pydata/xarray/main?urlpath=lab/tree/doc/examples/blank_template.ipynb), returning the result. - [X] New issue — a search of GitHub Issues suggests this is not a duplicate. ### Relevant log output ```Python --------------------------------------------------------------------------- TypeError Traceback (most recent call last) /var/folders/bj/czjbfh496258q1lc3p01lyz00000gn/T/ipykernel_59425/1460104966.py in ----> 1 da.plot.imshow(x='time', y='y') ~/miniconda3/lib/python3.8/site-packages/xarray/plot/plot.py in plotmethod(_PlotMethods_obj, x, y, figsize, size, aspect, ax, row, col, col_wrap, xincrease, yincrease, add_colorbar, add_labels, vmin, vmax, cmap, colors, center, robust, extend, levels, infer_intervals, subplot_kws, cbar_ax, cbar_kwargs, xscale, yscale, xticks, yticks, xlim, ylim, norm, **kwargs) 1306 for arg in [""_PlotMethods_obj"", ""newplotfunc"", ""kwargs""]: 1307 del allargs[arg] -> 1308 return newplotfunc(**allargs) 1309 1310 # Add to class _PlotMethods ~/miniconda3/lib/python3.8/site-packages/xarray/plot/plot.py in newplotfunc(darray, x, y, figsize, size, aspect, ax, row, col, col_wrap, xincrease, yincrease, add_colorbar, add_labels, vmin, vmax, cmap, center, robust, extend, levels, infer_intervals, colors, subplot_kws, cbar_ax, cbar_kwargs, xscale, yscale, xticks, yticks, xlim, ylim, norm, **kwargs) 1208 ax = get_axis(figsize, size, aspect, ax, **subplot_kws) 1209 -> 1210 primitive = plotfunc( 1211 xplt, 1212 yplt, ~/miniconda3/lib/python3.8/site-packages/xarray/plot/plot.py in imshow(x, y, z, ax, **kwargs) 1394 z[np.any(z.mask, axis=-1), -1] = 0 1395 -> 1396 primitive = ax.imshow(z, **defaults) 1397 1398 # If x or y are strings the ticklabels have been replaced with ~/miniconda3/lib/python3.8/site-packages/matplotlib/_api/deprecation.py in wrapper(*args, **kwargs) 454 ""parameter will become keyword-only %(removal)s."", 455 name=name, obj_type=f""parameter of {func.__name__}()"") --> 456 return func(*args, **kwargs) 457 458 # Don't modify *func*'s signature, as boilerplate.py needs it. ~/miniconda3/lib/python3.8/site-packages/matplotlib/__init__.py in inner(ax, data, *args, **kwargs) 1410 def inner(ax, *args, data=None, **kwargs): 1411 if data is None: -> 1412 return func(ax, *map(sanitize_sequence, args), **kwargs) 1413 1414 bound = new_sig.bind(ax, *args, **kwargs) ~/miniconda3/lib/python3.8/site-packages/matplotlib/axes/_axes.py in imshow(self, X, cmap, norm, aspect, interpolation, alpha, vmin, vmax, origin, extent, interpolation_stage, filternorm, filterrad, resample, url, **kwargs) 5450 # update ax.dataLim, and, if autoscaling, set viewLim 5451 # to tightly fit the image, regardless of dataLim. -> 5452 im.set_extent(im.get_extent()) 5453 5454 self.add_image(im) ~/miniconda3/lib/python3.8/site-packages/matplotlib/image.py in set_extent(self, extent) 980 self._extent = xmin, xmax, ymin, ymax = extent 981 corners = (xmin, ymin), (xmax, ymax) --> 982 self.axes.update_datalim(corners) 983 self.sticky_edges.x[:] = [xmin, xmax] 984 self.sticky_edges.y[:] = [ymin, ymax] ~/miniconda3/lib/python3.8/site-packages/matplotlib/axes/_base.py in update_datalim(self, xys, updatex, updatey) 2474 """""" 2475 xys = np.asarray(xys) -> 2476 if not np.any(np.isfinite(xys)): 2477 return 2478 self.dataLim.update_from_data_xy(xys, self.ignore_existing_data_limits, TypeError: ufunc 'isfinite' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe'' ``` ### Anything else we need to know? _No response_ ### Environment
INSTALLED VERSIONS ------------------ commit: None python: 3.8.12 | packaged by conda-forge | (default, Oct 12 2021, 21:21:17) [Clang 11.1.0 ] python-bits: 64 OS: Darwin OS-release: 21.4.0 machine: arm64 processor: arm byteorder: little LC_ALL: None LANG: None LOCALE: (None, 'UTF-8') libhdf5: 1.12.1 libnetcdf: 4.8.1 xarray: 2022.3.0 pandas: 1.3.4 numpy: 1.21.4 scipy: 1.7.3 netCDF4: 1.5.8 pydap: None h5netcdf: None h5py: None Nio: None zarr: 2.10.3 cftime: 1.6.0 nc_time_axis: 1.4.0 PseudoNetCDF: None rasterio: None cfgrib: 0.9.8.5 iris: None bottleneck: 1.3.2 dask: 2022.04.0 distributed: 2022.4.0 matplotlib: 3.5.0 cartopy: 0.20.2 seaborn: 0.11.2 numbagg: None fsspec: 2022.5.0 cupy: None pint: 0.18 sparse: None setuptools: 62.3.2 pip: 22.1.1 conda: 4.12.0 pytest: None IPython: 7.30.1 sphinx: None
","{""url"": ""https://api.github.com/repos/pydata/xarray/issues/6629/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed,13221727,issue 558977158,MDU6SXNzdWU1NTg5NzcxNTg=,3743,A suggested solution to the `TypeError: Invalid value for attr:` error upon `.to_netcdf`,6872529,open,0,,,3,2020-02-03T10:10:51Z,2023-04-06T17:43:37Z,,NONE,,,,"Even though netcdf conventions don't allow some data types in the attributes, it might be usefull to simply serialize those as strings rather than throw an error. Maybe add a `force_serialization` keyword argument to the `.to_netcdf` method. Example: Setup a DataArray with _bad values_ in the attributes: ```python import numpy as np from xarray import DataArray, load_dataset from pandas import Timestamp from numbers import Number valid_types = (str, Number, np.ndarray, np.number, list, tuple) da = DataArray( name='bad_values', attrs=dict( bool_value=True, none_value=None, datetime_value=Timestamp.now() ) ) ds = da.to_dataset() ds.bad_values.attrs ``` Output: ```python {'bool_value': True, 'none_value': None, 'datetime_value': Timestamp('2020-02-03 10:53:02.350105')} ``` The code in the except clause can be easily impolemented under [`_validate_attrs`](https://github.com/pydata/xarray/blob/4c96d53e6caa78d56b785f4edee49bbd4037a82f/xarray/backends/api.py#L185). ```python try: ds.to_netcdf('test.nc') # Fails with TypeError: Invalid value for attr: ... except TypeError as e: print(e.__class__.__name__, e) for variable in ds.variables.values(): for k, v in variable.attrs.items(): if not isinstance(v, valid_types) or isinstance(v, bool): variable.attrs[k] = str(v) ds.to_netcdf('test.nc') # Works as expected ds_from_file = load_dataset('test.nc') ds_from_file.bad_values.attrs ``` Output: ```python TypeError Invalid value for attr: None must be a number, a string, an ndarray or a list/tuple of numbers/strings for serialization to netCDF files {'bool_value': 'True', 'none_value': 'None', 'datetime_value': '2020-02-03 10:43:38.479866'} ```","{""url"": ""https://api.github.com/repos/pydata/xarray/issues/3743/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,,13221727,issue 517192343,MDU6SXNzdWU1MTcxOTIzNDM=,3482,geo raster accessor,6872529,closed,0,,,1,2019-11-04T14:34:27Z,2022-04-09T02:28:38Z,2022-04-09T02:28:25Z,NONE,,,,"Hi, I have put together a very [simple package](https://github.com/shaharkadmiel/rasterx) that provides a universal `read` function for reading various raster formats including of course netCDF but also any other format that gdal or rasterio can recognize. This read function can also handle merging several tiles into one dataset. In addition, the package provides a `.geo` dataset accessor that currently adds trimming functionality to extract a geographical subset of the data. I plan to also add reprojection and spatial resampling methods which will wrap either rasterio functionality or directly use gdal's api. I hope this is of interest to the geosciences community and perhaps even a broader community. Contributions and any other input from others is of course welcome. Have a quick look at the [**Demo section**](https://github.com/shaharkadmiel/rasterx#demo) in the readme file to get some ideas as to what this package can do for you. ","{""url"": ""https://api.github.com/repos/pydata/xarray/issues/3482/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed,13221727,issue 445355249,MDU6SXNzdWU0NDUzNTUyNDk=,2970,decode_cf,6872529,closed,0,,,1,2019-05-17T09:41:28Z,2020-03-29T14:02:24Z,2020-03-29T14:02:24Z,NONE,,,,"To me this name is a bit confusing as it actually _encodes_ an in memory object to look like a _decoded_ netcdf file. I have a class which inherits (I know about `dataset_accessor`, still seems easier to simply inherit...) ``xarray.Dataset`` to which I've added a method `_make_cf`: ```python import xarray as xr class XResult(xr.Dataset): def __init__(self, data=None, coords=None, attrs=None, **kwargs): if isinstance(data, str): kwargs = dict(READ_KWARGS, **kwargs) with xr.open_dataset(data, **kwargs) as data: attrs = data.attrs super().__init__(data, coords, attrs) self._make_cf() def _make_cf(self): self = xr.decode_cf(self) ``` I expect the XResult object to be _decoded_ but it is not. if I do `xresult = xarray.decode_cf(XResult(...))` than the object is indeed _decoded_ but is no longer an `XResult` object and loses the attached functionality. It would be quite convenient to have a `decode_cf` or `encode_cf` method part of the `Dataset` class that will operate inplace.","{""url"": ""https://api.github.com/repos/pydata/xarray/issues/2970/reactions"", ""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",,completed,13221727,issue