diff --git a/doc/conf.py b/doc/conf.py index 8a6d5ae4c4d..eb71c926375 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -323,4 +323,5 @@ 'iris': ('http://scitools.org.uk/iris/docs/latest/', None), 'numpy': ('https://docs.scipy.org/doc/numpy/', None), 'numba': ('https://numba.pydata.org/numba-doc/latest/', None), + 'matplotlib': ('https://matplotlib.org/', None), } diff --git a/doc/whats-new.rst b/doc/whats-new.rst index 10182df7831..4149432b117 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -32,7 +32,7 @@ Enhancements By `Ryan Abernathey `_. - Experimental support for parsing ENVI metadata to coordinates and attributes in :py:func:`xarray.open_rasterio`. - By `Matti Eskelinen ` + By `Matti Eskelinen `_. .. _Zarr: http://zarr.readthedocs.io/ @@ -40,17 +40,21 @@ Enhancements Bug fixes ~~~~~~~~~ -- Bug fix in vectorized assignment (:issue:`1743`, `1744`). - Now item assignment to :py:meth:`~DataArray.__setitem__` checks +- Bug fix in vectorized assignment (:issue:`1743`, :issue:`1744`). + Now item assignment to :py:meth:`DataArray.__setitem__` checks coordinates of target, destination and keys. If there are any conflict among these coordinates, ``IndexError`` will be raised. By `Keisuke Fujii `_. +- Properly point :py:meth:`DataArray.__dask_scheduler__` to + ``dask.threaded.get``. By `Matthew Rocklin `_. +- Bug fixes in :py:meth:`DataArray.plot.imshow`: all-NaN arrays and arrays + with size one in some dimension can now be plotted, which is good for + exploring satellite imagery. (:issue:`1780`) + By `Zac Hatfield-Dodds `_. .. _whats-new.0.10.0: -- Properly point DataArray.__dask_scheduler__ to dask.threaded.get - v0.10.0 (20 November 2017) -------------------------- diff --git a/xarray/plot/plot.py b/xarray/plot/plot.py index 4dd1b1284cd..94556d70f6c 100644 --- a/xarray/plot/plot.py +++ b/xarray/plot/plot.py @@ -158,7 +158,7 @@ def line(darray, *args, **kwargs): """ Line plot of 1 dimensional DataArray index against values - Wraps matplotlib.pyplot.plot + Wraps :func:`matplotlib:matplotlib.pyplot.plot` Parameters ---------- @@ -220,7 +220,7 @@ def hist(darray, figsize=None, size=None, aspect=None, ax=None, **kwargs): """ Histogram of DataArray - Wraps matplotlib.pyplot.hist + Wraps :func:`matplotlib:matplotlib.pyplot.hist` Plots N dimensional arrays by first flattening the array. @@ -565,10 +565,9 @@ def imshow(x, y, z, ax, **kwargs): """ Image plot of 2d DataArray using matplotlib.pyplot - Wraps matplotlib.pyplot.imshow - - ..note:: + Wraps :func:`matplotlib:matplotlib.pyplot.imshow` + .. note:: This function needs uniformly spaced coordinates to properly label the axes. Call DataArray.plot() to check. @@ -581,8 +580,15 @@ def imshow(x, y, z, ax, **kwargs): 'pcolormesh or contour(f)') # Centering the pixels- Assumes uniform spacing - xstep = (x[1] - x[0]) / 2.0 - ystep = (y[1] - y[0]) / 2.0 + try: + xstep = (x[1] - x[0]) / 2.0 + except IndexError: + # Arbitrary default value, similar to matplotlib behaviour + xstep = .1 + try: + ystep = (y[1] - y[0]) / 2.0 + except IndexError: + ystep = .1 left, right = x[0] - xstep, x[-1] + xstep bottom, top = y[-1] + ystep, y[0] - ystep @@ -608,7 +614,7 @@ def contour(x, y, z, ax, **kwargs): """ Contour plot of 2d DataArray - Wraps matplotlib.pyplot.contour + Wraps :func:`matplotlib:matplotlib.pyplot.contour` """ primitive = ax.contour(x, y, z, **kwargs) return primitive @@ -619,7 +625,7 @@ def contourf(x, y, z, ax, **kwargs): """ Filled contour plot of 2d DataArray - Wraps matplotlib.pyplot.contourf + Wraps :func:`matplotlib:matplotlib.pyplot.contourf` """ primitive = ax.contourf(x, y, z, **kwargs) return primitive @@ -635,6 +641,8 @@ def _infer_interval_breaks(coord, axis=0): """ coord = np.asarray(coord) deltas = 0.5 * np.diff(coord, axis=axis) + if deltas.size == 0: + deltas = np.array(0.0) first = np.take(coord, [0], axis=axis) - np.take(deltas, [0], axis=axis) last = np.take(coord, [-1], axis=axis) + np.take(deltas, [-1], axis=axis) trim_last = tuple(slice(None, -1) if n == axis else slice(None) @@ -647,7 +655,7 @@ def pcolormesh(x, y, z, ax, infer_intervals=None, **kwargs): """ Pseudocolor plot of 2d DataArray - Wraps matplotlib.pyplot.pcolormesh + Wraps :func:`matplotlib:matplotlib.pyplot.pcolormesh` """ # decide on a default for infer_intervals (GH781) diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py index 169aa121e9e..2ed9c5e3f2a 100644 --- a/xarray/plot/utils.py +++ b/xarray/plot/utils.py @@ -165,6 +165,11 @@ def _determine_cmap_params(plot_data, vmin=None, vmax=None, cmap=None, calc_data = np.ravel(plot_data[~pd.isnull(plot_data)]) + # Handle all-NaN input data gracefully + if calc_data.size == 0: + # Arbitrary default for when all values are NaN + calc_data = np.array(0.0) + # Setting center=False prevents a divergent cmap possibly_divergent = center is not False diff --git a/xarray/tests/test_plot.py b/xarray/tests/test_plot.py index ea0ffa6f3a3..1d62f7856f9 100644 --- a/xarray/tests/test_plot.py +++ b/xarray/tests/test_plot.py @@ -624,6 +624,14 @@ def test_plot_nans(self): clim2 = self.plotfunc(x2).get_clim() self.assertEqual(clim1, clim2) + def test_can_plot_all_nans(self): + # regression test for issue #1780 + self.plotfunc(DataArray(np.full((2, 2), np.nan))) + + def test_can_plot_axis_size_one(self): + if self.plotfunc.__name__ not in ('contour', 'contourf'): + self.plotfunc(DataArray(np.ones((1, 1)))) + def test_viridis_cmap(self): cmap_name = self.plotmethod(cmap='viridis').get_cmap().name self.assertEqual('viridis', cmap_name)