Repository: pydata/xarray

Issue:
Passing origin keyword to DataArray.plot.imshow does not behave as expected
#### Code Sample
```python
from numpy import arange
from xarray import DataArray
import matplotlib.pyplot as plt

a = DataArray(arange(100).reshape((10,10)), dims=('x', 'y'))

print('a[0, 0] ==', a.loc[0, 0])

for origin in ('upper', 'lower'):
    a.plot.imshow(size=2, origin=origin)
    plt.title('origin=%s' % origin)
plt.show()
```
#### Problem description

The 'upper' case should plot the [0,0] block in the top left, and 'lower' should plot it in the bottom left, but the actual behavior is opposite. Passing origin='lower' also fails to flip the y-axis labels.

![upper](https://user-images.githubusercontent.com/10374429/44538938-c39c2a00-a6d0-11e8-9f52-7135c0e66c3c.png)

![lower](https://user-images.githubusercontent.com/10374429/44538941-c72fb100-a6d0-11e8-8a71-3f446cc84a89.png)

#### Output of ``xr.show_versions()``

<details>

INSTALLED VERSIONS
------------------
commit: None
python: 3.6.5.final.0
python-bits: 64
OS: Linux
OS-release: 4.18.3-arch1-1-ARCH
machine: x86_64
processor: 
byteorder: little
LC_ALL: en_US.UTF-8
LANG: en_US.UTF-8
LOCALE: en_US.UTF-8

xarray: 0.10.7
pandas: 0.23.1
numpy: 1.13.3
scipy: 1.0.0
netCDF4: 1.3.1
h5netcdf: None
h5py: 2.7.1
Nio: None
zarr: None
bottleneck: 1.2.1
cyordereddict: None
dask: 0.18.1
distributed: 1.22.0
matplotlib: 2.2.2
cartopy: None
seaborn: 0.8.1
setuptools: 39.2.0
pip: 10.0.1
conda: 4.5.10
pytest: 3.6.2
IPython: 6.4.0
sphinx: 1.7.5

</details>


Discussion:

Patch:
diff --git a/doc/whats-new.rst b/doc/whats-new.rst
index dd9eb9e4..881ae52c 100644
--- a/doc/whats-new.rst
+++ b/doc/whats-new.rst
@@ -36,6 +36,11 @@ Documentation
 Enhancements
 ~~~~~~~~~~~~
 
+- Default colormap for sequential and divergent data can now be set via
+  :py:func:`~xarray.set_options()`
+  (:issue:`2394`)
+  By `Julius Busecke <https://github.com/jbusecke>`_.
+
 - min_count option is newly supported in :py:meth:`~xarray.DataArray.sum`,
   :py:meth:`~xarray.DataArray.prod` and :py:meth:`~xarray.Dataset.sum`, and
   :py:meth:`~xarray.Dataset.prod`.
@@ -68,9 +73,16 @@ Enhancements
   (:issue:`1875`)
   By `Andrew Huang <https://github.com/ahuang11>`_.
 
+- You can now call ``unstack`` without arguments to unstack every MultiIndex in a DataArray or Dataset.
+  By `Julia Signell <https://github.com/jsignell>`_.
+
 Bug fixes
 ~~~~~~~~~
 
+- ``xarray.plot.imshow()`` correctly uses the ``origin`` argument.
+  (:issue:`2379`)
+  By `Deepak Cherian <https://github.com/dcherian>`_.
+
 - Fixed ``DataArray.to_iris()`` failure while creating ``DimCoord`` by
   falling back to creating ``AuxCoord``. Fixed dependency on ``var_name``
   attribute being set.
@@ -84,7 +96,7 @@ Bug fixes
 - Tests can be run in parallel with pytest-xdist
   By `Tony Tung <https://github.com/ttung>`_.
 
-- Follow up the renamings in dask; from dask.ghost to dask.overlap 
+- Follow up the renamings in dask; from dask.ghost to dask.overlap
   By `Keisuke Fujii <https://github.com/fujiisoup>`_.
 
 - Now raises a ValueError when there is a conflict between dimension names and
diff --git a/xarray/coding/times.py b/xarray/coding/times.py
index d946e2ed..6edbedce 100644
--- a/xarray/coding/times.py
+++ b/xarray/coding/times.py
@@ -183,8 +183,11 @@ def decode_cf_datetime(num_dates, units, calendar=None,
         # fixes: https://github.com/pydata/pandas/issues/14068
         # these lines check if the the lowest or the highest value in dates
         # cause an OutOfBoundsDatetime (Overflow) error
-        pd.to_timedelta(flat_num_dates.min(), delta) + ref_date
-        pd.to_timedelta(flat_num_dates.max(), delta) + ref_date
+        with warnings.catch_warnings():
+            warnings.filterwarnings('ignore', 'invalid value encountered',
+                                    RuntimeWarning)
+            pd.to_timedelta(flat_num_dates.min(), delta) + ref_date
+            pd.to_timedelta(flat_num_dates.max(), delta) + ref_date
 
         # Cast input dates to integers of nanoseconds because `pd.to_datetime`
         # works much faster when dealing with integers
diff --git a/xarray/core/dataarray.py b/xarray/core/dataarray.py
index 373a6a4c..ae3758f0 100644
--- a/xarray/core/dataarray.py
+++ b/xarray/core/dataarray.py
@@ -1247,23 +1247,45 @@ class DataArray(AbstractArray, DataWithCoords):
         ds = self._to_temp_dataset().stack(dimensions, **dimensions_kwargs)
         return self._from_temp_dataset(ds)
 
-    def unstack(self, dim):
+    def unstack(self, dim=None):
         """
-        Unstack an existing dimension corresponding to a MultiIndex into
+        Unstack existing dimensions corresponding to MultiIndexes into
         multiple new dimensions.
 
         New dimensions will be added at the end.
 
         Parameters
         ----------
-        dim : str
-            Name of the existing dimension to unstack.
+        dim : str or sequence of str, optional
+            Dimension(s) over which to unstack. By default unstacks all
+            MultiIndexes.
 
         Returns
         -------
         unstacked : DataArray
             Array with unstacked data.
 
+        Examples
+        --------
+
+        >>> arr = DataArray(np.arange(6).reshape(2, 3),
+        ...                 coords=[('x', ['a', 'b']), ('y', [0, 1, 2])])
+        >>> arr
+        <xarray.DataArray (x: 2, y: 3)>
+        array([[0, 1, 2],
+               [3, 4, 5]])
+        Coordinates:
+          * x        (x) |S1 'a' 'b'
+          * y        (y) int64 0 1 2
+        >>> stacked = arr.stack(z=('x', 'y'))
+        >>> stacked.indexes['z']
+        MultiIndex(levels=[[u'a', u'b'], [0, 1, 2]],
+                   labels=[[0, 0, 0, 1, 1, 1], [0, 1, 2, 0, 1, 2]],
+                   names=[u'x', u'y'])
+        >>> roundtripped = stacked.unstack()
+        >>> arr.identical(roundtripped)
+        True
+
         See also
         --------
         DataArray.stack
diff --git a/xarray/core/dataset.py b/xarray/core/dataset.py
index 06b258ae..e98495e7 100644
--- a/xarray/core/dataset.py
+++ b/xarray/core/dataset.py
@@ -2310,35 +2310,8 @@ class Dataset(Mapping, ImplementsDatasetReduce, DataWithCoords,
             result = result._stack_once(dims, new_dim)
         return result
 
-    def unstack(self, dim):
-        """
-        Unstack an existing dimension corresponding to a MultiIndex into
-        multiple new dimensions.
-
-        New dimensions will be added at the end.
-
-        Parameters
-        ----------
-        dim : str
-            Name of the existing dimension to unstack.
-
-        Returns
-        -------
-        unstacked : Dataset
-            Dataset with unstacked data.
-
-        See also
-        --------
-        Dataset.stack
-        """
-        if dim not in self.dims:
-            raise ValueError('invalid dimension: %s' % dim)
-
+    def _unstack_once(self, dim):
         index = self.get_index(dim)
-        if not isinstance(index, pd.MultiIndex):
-            raise ValueError('cannot unstack a dimension that does not have '
-                             'a MultiIndex')
-
         full_idx = pd.MultiIndex.from_product(index.levels, names=index.names)
 
         # take a shortcut in case the MultiIndex was not modified.
@@ -2366,6 +2339,51 @@ class Dataset(Mapping, ImplementsDatasetReduce, DataWithCoords,
 
         return self._replace_vars_and_dims(variables, coord_names)
 
+    def unstack(self, dim=None):
+        """
+        Unstack existing dimensions corresponding to MultiIndexes into
+        multiple new dimensions.
+
+        New dimensions will be added at the end.
+
+        Parameters
+        ----------
+        dim : str or sequence of str, optional
+            Dimension(s) over which to unstack. By default unstacks all
+            MultiIndexes.
+
+        Returns
+        -------
+        unstacked : Dataset
+            Dataset with unstacked data.
+
+        See also
+        --------
+        Dataset.stack
+        """
+
+        if dim is None:
+            dims = [d for d in self.dims if isinstance(self.get_index(d),
+                                                       pd.MultiIndex)]
+        else:
+            dims = [dim] if isinstance(dim, basestring) else dim
+
+            missing_dims = [d for d in dims if d not in self.dims]
+            if missing_dims:
+                raise ValueError('Dataset does not contain the dimensions: %s'
+                                 % missing_dims)
+
+            non_multi_dims = [d for d in dims if not
+                              isinstance(self.get_index(d), pd.MultiIndex)]
+            if non_multi_dims:
+                raise ValueError('cannot unstack dimensions that do not '
+                                 'have a MultiIndex: %s' % non_multi_dims)
+
+        result = self.copy(deep=False)
+        for dim in dims:
+            result = result._unstack_once(dim)
+        return result
+
     def update(self, other, inplace=True):
         """Update this dataset's variables with those from another dataset.
 
diff --git a/xarray/core/formatting.py b/xarray/core/formatting.py
index 65f3c91c..042c8c53 100644
--- a/xarray/core/formatting.py
+++ b/xarray/core/formatting.py
@@ -183,7 +183,7 @@ def format_items(x):
         day_part = (x[~pd.isnull(x)]
                     .astype('timedelta64[D]')
                     .astype('timedelta64[ns]'))
-        time_needed = x != day_part
+        time_needed = x[~pd.isnull(x)] != day_part
         day_needed = day_part != np.timedelta64(0, 'ns')
         if np.logical_not(day_needed).all():
             timedelta_format = 'time'
diff --git a/xarray/core/missing.py b/xarray/core/missing.py
index 232fa185..90aa4ffa 100644
--- a/xarray/core/missing.py
+++ b/xarray/core/missing.py
@@ -3,6 +3,8 @@ from __future__ import absolute_import, division, print_function
 from collections import Iterable
 from functools import partial
 
+import warnings
+
 import numpy as np
 import pandas as pd
 
@@ -207,13 +209,16 @@ def interp_na(self, dim=None, use_coordinate=True, method='linear', limit=None,
     interp_class, kwargs = _get_interpolator(method, **kwargs)
     interpolator = partial(func_interpolate_na, interp_class, **kwargs)
 
-    arr = apply_ufunc(interpolator, index, self,
-                      input_core_dims=[[dim], [dim]],
-                      output_core_dims=[[dim]],
-                      output_dtypes=[self.dtype],
-                      dask='parallelized',
-                      vectorize=True,
-                      keep_attrs=True).transpose(*self.dims)
+    with warnings.catch_warnings():
+        warnings.filterwarnings('ignore', 'overflow', RuntimeWarning)
+        warnings.filterwarnings('ignore', 'invalid value', RuntimeWarning)
+        arr = apply_ufunc(interpolator, index, self,
+                          input_core_dims=[[dim], [dim]],
+                          output_core_dims=[[dim]],
+                          output_dtypes=[self.dtype],
+                          dask='parallelized',
+                          vectorize=True,
+                          keep_attrs=True).transpose(*self.dims)
 
     if limit is not None:
         arr = arr.where(valids)
diff --git a/xarray/core/options.py b/xarray/core/options.py
index 48d4567f..a6118f02 100644
--- a/xarray/core/options.py
+++ b/xarray/core/options.py
@@ -3,7 +3,9 @@ from __future__ import absolute_import, division, print_function
 OPTIONS = {
     'display_width': 80,
     'arithmetic_join': 'inner',
-    'enable_cftimeindex': False
+    'enable_cftimeindex': False,
+    'cmap_sequential': 'viridis',
+    'cmap_divergent': 'RdBu_r',
 }
 
 
@@ -19,6 +21,13 @@ class set_options(object):
     - ``enable_cftimeindex``: flag to enable using a ``CFTimeIndex``
       for time indexes with non-standard calendars or dates outside the
       Timestamp-valid range. Default: ``False``.
+    - ``cmap_sequential``: colormap to use for nondivergent data plots.
+      Default: ``viridis``. If string, must be matplotlib built-in colormap.
+      Can also be a Colormap object (e.g. mpl.cm.magma)
+    - ``cmap_divergent``: colormap to use for divergent data plots.
+      Default: ``RdBu_r``. If string, must be matplotlib built-in colormap.
+      Can also be a Colormap object (e.g. mpl.cm.magma)
+
 
     You can use ``set_options`` either as a context manager:
 
diff --git a/xarray/plot/plot.py b/xarray/plot/plot.py
index 179f41e9..10fca44b 100644
--- a/xarray/plot/plot.py
+++ b/xarray/plot/plot.py
@@ -479,9 +479,11 @@ class _PlotMethods(object):
 
 def _rescale_imshow_rgb(darray, vmin, vmax, robust):
     assert robust or vmin is not None or vmax is not None
+    # TODO: remove when min numpy version is bumped to 1.13
     # There's a cyclic dependency via DataArray, so we can't import from
     # xarray.ufuncs in global scope.
     from xarray.ufuncs import maximum, minimum
+
     # Calculate vmin and vmax automatically for `robust=True`
     if robust:
         if vmax is None:
@@ -507,7 +509,10 @@ def _rescale_imshow_rgb(darray, vmin, vmax, robust):
     # After scaling, downcast to 32-bit float.  This substantially reduces
     # memory usage after we hand `darray` off to matplotlib.
     darray = ((darray.astype('f8') - vmin) / (vmax - vmin)).astype('f4')
-    return minimum(maximum(darray, 0), 1)
+    with warnings.catch_warnings():
+        warnings.filterwarnings('ignore', 'xarray.ufuncs',
+                                PendingDeprecationWarning)
+        return minimum(maximum(darray, 0), 1)
 
 
 def _plot2d(plotfunc):
@@ -619,7 +624,7 @@ def _plot2d(plotfunc):
     @functools.wraps(plotfunc)
     def newplotfunc(darray, x=None, y=None, figsize=None, size=None,
                     aspect=None, ax=None, row=None, col=None,
-                    col_wrap=None, xincrease=True, yincrease=True,
+                    col_wrap=None, xincrease=None, yincrease=None,
                     add_colorbar=None, add_labels=True, vmin=None, vmax=None,
                     cmap=None, center=None, robust=False, extend=None,
                     levels=None, infer_intervals=None, colors=None,
@@ -789,7 +794,7 @@ def _plot2d(plotfunc):
     @functools.wraps(newplotfunc)
     def plotmethod(_PlotMethods_obj, x=None, y=None, figsize=None, size=None,
                    aspect=None, ax=None, row=None, col=None, col_wrap=None,
-                   xincrease=True, yincrease=True, add_colorbar=None,
+                   xincrease=None, yincrease=None, add_colorbar=None,
                    add_labels=True, vmin=None, vmax=None, cmap=None,
                    colors=None, center=None, robust=False, extend=None,
                    levels=None, infer_intervals=None, subplot_kws=None,
@@ -857,10 +862,8 @@ def imshow(x, y, z, ax, **kwargs):
     left, right = x[0] - xstep, x[-1] + xstep
     bottom, top = y[-1] + ystep, y[0] - ystep
 
-    defaults = {'extent': [left, right, bottom, top],
-                'origin': 'upper',
-                'interpolation': 'nearest',
-                }
+    defaults = {'origin': 'upper',
+                'interpolation': 'nearest'}
 
     if not hasattr(ax, 'projection'):
         # not for cartopy geoaxes
@@ -869,6 +872,11 @@ def imshow(x, y, z, ax, **kwargs):
     # Allow user to override these defaults
     defaults.update(kwargs)
 
+    if defaults['origin'] == 'upper':
+        defaults['extent'] = [left, right, bottom, top]
+    else:
+        defaults['extent'] = [left, right, top, bottom]
+
     if z.ndim == 3:
         # matplotlib imshow uses black for missing data, but Xarray makes
         # missing data transparent.  We therefore add an alpha channel if
diff --git a/xarray/plot/utils.py b/xarray/plot/utils.py
index 1ddb0235..9af0624d 100644
--- a/xarray/plot/utils.py
+++ b/xarray/plot/utils.py
@@ -7,6 +7,7 @@ import textwrap
 
 from ..core.pycompat import basestring
 from ..core.utils import is_scalar
+from ..core.options import OPTIONS
 
 ROBUST_PERCENTILE = 2.0
 
@@ -206,15 +207,17 @@ def _determine_cmap_params(plot_data, vmin=None, vmax=None, cmap=None,
     # Choose default colormaps if not provided
     if cmap is None:
         if divergent:
-            cmap = "RdBu_r"
+            cmap = OPTIONS['cmap_divergent']
         else:
-            cmap = "viridis"
+            cmap = OPTIONS['cmap_sequential']
 
     # Handle discrete levels
     if levels is not None:
         if is_scalar(levels):
-            if user_minmax or levels == 1:
+            if user_minmax:
                 levels = np.linspace(vmin, vmax, levels)
+            elif levels == 1:
+                levels = np.asarray([(vmin + vmax) / 2])
             else:
                 # N in MaxNLocator refers to bins, not ticks
                 ticker = mpl.ticker.MaxNLocator(levels - 1)


Test patch:
diff --git a/xarray/tests/test_backends.py b/xarray/tests/test_backends.py
index 38012252..8b469761 100644
--- a/xarray/tests/test_backends.py
+++ b/xarray/tests/test_backends.py
@@ -1789,6 +1789,7 @@ class H5NetCDFDataTest(BaseNetCDF4Test, TestCase):
         with create_tmp_file() as tmp_file:
             yield backends.H5NetCDFStore(tmp_file, 'w')
 
+    @pytest.mark.filterwarnings('ignore:complex dtypes are supported by h5py')
     def test_complex(self):
         expected = Dataset({'x': ('y', np.ones(5) + 1j * np.ones(5))})
         with self.roundtrip(expected) as actual:
@@ -2527,6 +2528,7 @@ class PyNioTestAutocloseTrue(PyNioTest):
 
 
 @requires_pseudonetcdf
+@pytest.mark.filterwarnings('ignore:IOAPI_ISPH is assumed to be 6370000')
 class PseudoNetCDFFormatTest(TestCase):
     autoclose = True
 
@@ -2658,14 +2660,11 @@ class PseudoNetCDFFormatTest(TestCase):
         """
         Open a CAMx file and test data variables
         """
-        with warnings.catch_warnings():
-            warnings.filterwarnings('ignore', category=UserWarning,
-                                    message=('IOAPI_ISPH is assumed to be ' +
-                                             '6370000.; consistent with WRF'))
-            camxfile = open_example_dataset('example.uamiv',
-                                            engine='pseudonetcdf',
-                                            autoclose=True,
-                                            backend_kwargs={'format': 'uamiv'})
+
+        camxfile = open_example_dataset('example.uamiv',
+                                        engine='pseudonetcdf',
+                                        autoclose=True,
+                                        backend_kwargs={'format': 'uamiv'})
         data = np.arange(20, dtype='f').reshape(1, 1, 4, 5)
         expected = xr.Variable(('TSTEP', 'LAY', 'ROW', 'COL'), data,
                                dict(units='ppm', long_name='O3'.ljust(16),
@@ -2687,17 +2686,14 @@ class PseudoNetCDFFormatTest(TestCase):
         """
         Open a CAMx file and test data variables
         """
-        with warnings.catch_warnings():
-            warnings.filterwarnings('ignore', category=UserWarning,
-                                    message=('IOAPI_ISPH is assumed to be ' +
-                                             '6370000.; consistent with WRF'))
-            camxfile = open_example_mfdataset(
-                ['example.uamiv',
-                 'example.uamiv'],
-                engine='pseudonetcdf',
-                autoclose=True,
-                concat_dim='TSTEP',
-                backend_kwargs={'format': 'uamiv'})
+
+        camxfile = open_example_mfdataset(
+            ['example.uamiv',
+             'example.uamiv'],
+            engine='pseudonetcdf',
+            autoclose=True,
+            concat_dim='TSTEP',
+            backend_kwargs={'format': 'uamiv'})
 
         data1 = np.arange(20, dtype='f').reshape(1, 1, 4, 5)
         data = np.concatenate([data1] * 2, axis=0)
@@ -2720,19 +2716,18 @@ class PseudoNetCDFFormatTest(TestCase):
 
     def test_uamiv_format_write(self):
         fmtkw = {'format': 'uamiv'}
-        with warnings.catch_warnings():
-            warnings.filterwarnings('ignore', category=UserWarning,
-                                    message=('IOAPI_ISPH is assumed to be ' +
-                                             '6370000.; consistent with WRF'))
-            expected = open_example_dataset('example.uamiv',
-                                            engine='pseudonetcdf',
-                                            autoclose=False,
-                                            backend_kwargs=fmtkw)
+
+        expected = open_example_dataset('example.uamiv',
+                                        engine='pseudonetcdf',
+                                        autoclose=False,
+                                        backend_kwargs=fmtkw)
         with self.roundtrip(expected,
                             save_kwargs=fmtkw,
                             open_kwargs={'backend_kwargs': fmtkw}) as actual:
             assert_identical(expected, actual)
 
+        expected.close()
+
     def save(self, dataset, path, **save_kwargs):
         import PseudoNetCDF as pnc
         pncf = pnc.PseudoNetCDFFile()
diff --git a/xarray/tests/test_coding_times.py b/xarray/tests/test_coding_times.py
index e763af49..7d3a4930 100644
--- a/xarray/tests/test_coding_times.py
+++ b/xarray/tests/test_coding_times.py
@@ -538,7 +538,8 @@ def test_cf_datetime_nan(num_dates, units, expected_list):
     with warnings.catch_warnings():
         warnings.filterwarnings('ignore', 'All-NaN')
         actual = coding.times.decode_cf_datetime(num_dates, units)
-    expected = np.array(expected_list, dtype='datetime64[ns]')
+    # use pandas because numpy will deprecate timezone-aware conversions
+    expected = pd.to_datetime(expected_list)
     assert_array_equal(expected, actual)
 
 
diff --git a/xarray/tests/test_dask.py b/xarray/tests/test_dask.py
index f6c47cce..6ca83ab7 100644
--- a/xarray/tests/test_dask.py
+++ b/xarray/tests/test_dask.py
@@ -2,6 +2,7 @@ from __future__ import absolute_import, division, print_function
 
 import pickle
 from textwrap import dedent
+from distutils.version import LooseVersion
 
 import numpy as np
 import pandas as pd
@@ -24,8 +25,12 @@ dd = pytest.importorskip('dask.dataframe')
 
 class DaskTestCase(TestCase):
     def assertLazyAnd(self, expected, actual, test):
-        with dask.set_options(get=dask.get):
+
+        with (dask.config.set(get=dask.get)
+              if LooseVersion(dask.__version__) >= LooseVersion('0.18.0')
+              else dask.set_options(get=dask.get)):
             test(actual, expected)
+
         if isinstance(actual, Dataset):
             for k, v in actual.variables.items():
                 if k in actual.dims:
@@ -196,11 +201,13 @@ class TestVariable(DaskTestCase):
         except NotImplementedError as err:
             assert 'dask' in str(err)
 
+    @pytest.mark.filterwarnings('ignore::PendingDeprecationWarning')
     def test_univariate_ufunc(self):
         u = self.eager_var
         v = self.lazy_var
         self.assertLazyAndAllClose(np.sin(u), xu.sin(v))
 
+    @pytest.mark.filterwarnings('ignore::PendingDeprecationWarning')
     def test_bivariate_ufunc(self):
         u = self.eager_var
         v = self.lazy_var
@@ -421,6 +428,7 @@ class TestDataArrayAndDataset(DaskTestCase):
         actual = duplicate_and_merge(self.lazy_array)
         self.assertLazyAndEqual(expected, actual)
 
+    @pytest.mark.filterwarnings('ignore::PendingDeprecationWarning')
     def test_ufuncs(self):
         u = self.eager_array
         v = self.lazy_array
@@ -821,7 +829,9 @@ def test_basic_compute():
                 dask.multiprocessing.get,
                 dask.local.get_sync,
                 None]:
-        with dask.set_options(get=get):
+        with (dask.config.set(get=get)
+              if LooseVersion(dask.__version__) >= LooseVersion('0.18.0')
+              else dask.set_options(get=get)):
             ds.compute()
             ds.foo.compute()
             ds.foo.variable.compute()
diff --git a/xarray/tests/test_dataarray.py b/xarray/tests/test_dataarray.py
index 3619688d..a4562894 100644
--- a/xarray/tests/test_dataarray.py
+++ b/xarray/tests/test_dataarray.py
@@ -672,6 +672,7 @@ class TestDataArray(TestCase):
         assert_identical(da.isel(x=np.array([0], dtype="int64")),
                          da.isel(x=np.array([0])))
 
+    @pytest.mark.filterwarnings('ignore::DeprecationWarning')
     def test_isel_fancy(self):
         shape = (10, 7, 6)
         np_array = np.random.random(shape)
@@ -845,6 +846,7 @@ class TestDataArray(TestCase):
         selected = data.isel(x=0, drop=False)
         assert_identical(expected, selected)
 
+    @pytest.mark.filterwarnings("ignore:Dataset.isel_points")
     def test_isel_points(self):
         shape = (10, 5, 6)
         np_array = np.random.random(shape)
@@ -1237,6 +1239,7 @@ class TestDataArray(TestCase):
                 ValueError, 'different size for unlabeled'):
             foo.reindex_like(bar)
 
+    @pytest.mark.filterwarnings('ignore:Indexer has dimensions')
     def test_reindex_regressions(self):
         # regression test for #279
         expected = DataArray(np.random.randn(5), coords=[("time", range(5))])
@@ -1286,7 +1289,7 @@ class TestDataArray(TestCase):
 
     def test_expand_dims_error(self):
         array = DataArray(np.random.randn(3, 4), dims=['x', 'dim_0'],
-                          coords={'x': np.linspace(0.0, 1.0, 3.0)},
+                          coords={'x': np.linspace(0.0, 1.0, 3)},
                           attrs={'key': 'entry'})
 
         with raises_regex(ValueError, 'dim should be str or'):
@@ -1660,9 +1663,23 @@ class TestDataArray(TestCase):
 
     def test_stack_unstack(self):
         orig = DataArray([[0, 1], [2, 3]], dims=['x', 'y'], attrs={'foo': 2})
+        assert_identical(orig, orig.unstack())
+
         actual = orig.stack(z=['x', 'y']).unstack('z').drop(['x', 'y'])
         assert_identical(orig, actual)
 
+        dims = ['a', 'b', 'c', 'd', 'e']
+        orig = xr.DataArray(np.random.rand(1, 2, 3, 2, 1), dims=dims)
+        stacked = orig.stack(ab=['a', 'b'], cd=['c', 'd'])
+
+        unstacked = stacked.unstack(['ab', 'cd'])
+        roundtripped = unstacked.drop(['a', 'b', 'c', 'd']).transpose(*dims)
+        assert_identical(orig, roundtripped)
+
+        unstacked = stacked.unstack()
+        roundtripped = unstacked.drop(['a', 'b', 'c', 'd']).transpose(*dims)
+        assert_identical(orig, roundtripped)
+
     def test_stack_unstack_decreasing_coordinate(self):
         # regression test for GH980
         orig = DataArray(np.random.rand(3, 4), dims=('y', 'x'),
@@ -2915,7 +2932,6 @@ class TestDataArray(TestCase):
         ma = da.to_masked_array()
         assert len(ma.mask) == N
 
-    @pytest.mark.xfail  # GH:2332 TODO fix this in upstream?
     def test_to_and_from_cdms2_classic(self):
         """Classic with 1D axes"""
         pytest.importorskip('cdms2')
@@ -2928,7 +2944,7 @@ class TestDataArray(TestCase):
         expected_coords = [IndexVariable('distance', [-2, 2]),
                            IndexVariable('time', [0, 1, 2])]
         actual = original.to_cdms2()
-        assert_array_equal(actual, original)
+        assert_array_equal(actual.asma(), original)
         assert actual.id == original.name
         self.assertItemsEqual(actual.getAxisIds(), original.dims)
         for axis, coord in zip(actual.getAxisList(), expected_coords):
@@ -2950,7 +2966,6 @@ class TestDataArray(TestCase):
             assert_array_equal(original.coords[coord_name],
                                back.coords[coord_name])
 
-    @pytest.mark.xfail  # GH:2332 TODO fix this in upstream?
     def test_to_and_from_cdms2_sgrid(self):
         """Curvilinear (structured) grid
 
@@ -2968,8 +2983,10 @@ class TestDataArray(TestCase):
                              name='sst')
         actual = original.to_cdms2()
         self.assertItemsEqual(actual.getAxisIds(), original.dims)
-        assert_array_equal(original.coords['lon'], actual.getLongitude())
-        assert_array_equal(original.coords['lat'], actual.getLatitude())
+        assert_array_equal(original.coords['lon'],
+                           actual.getLongitude().asma())
+        assert_array_equal(original.coords['lat'],
+                           actual.getLatitude().asma())
 
         back = from_cdms2(actual)
         self.assertItemsEqual(original.dims, back.dims)
@@ -2977,7 +2994,6 @@ class TestDataArray(TestCase):
         assert_array_equal(original.coords['lat'], back.coords['lat'])
         assert_array_equal(original.coords['lon'], back.coords['lon'])
 
-    @pytest.mark.xfail  # GH:2332 TODO fix this in upstream?
     def test_to_and_from_cdms2_ugrid(self):
         """Unstructured grid"""
         pytest.importorskip('cdms2')
@@ -2989,8 +3005,10 @@ class TestDataArray(TestCase):
                              coords={'lon': lon, 'lat': lat, 'cell': cell})
         actual = original.to_cdms2()
         self.assertItemsEqual(actual.getAxisIds(), original.dims)
-        assert_array_equal(original.coords['lon'], actual.getLongitude())
-        assert_array_equal(original.coords['lat'], actual.getLatitude())
+        assert_array_equal(original.coords['lon'],
+                           actual.getLongitude().getValue())
+        assert_array_equal(original.coords['lat'],
+                           actual.getLatitude().getValue())
 
         back = from_cdms2(actual)
         self.assertItemsEqual(original.dims, back.dims)
diff --git a/xarray/tests/test_dataset.py b/xarray/tests/test_dataset.py
index 101de9fe..d22d8470 100644
--- a/xarray/tests/test_dataset.py
+++ b/xarray/tests/test_dataset.py
@@ -1240,6 +1240,7 @@ class TestDataset(TestCase):
         selected = data.isel(x=0, drop=False)
         assert_identical(expected, selected)
 
+    @pytest.mark.filterwarnings("ignore:Dataset.isel_points")
     def test_isel_points(self):
         data = create_test_data()
 
@@ -1317,6 +1318,8 @@ class TestDataset(TestCase):
                          dim2=stations['dim2s'],
                          dim=np.array([4, 5, 6]))
 
+    @pytest.mark.filterwarnings("ignore:Dataset.sel_points")
+    @pytest.mark.filterwarnings("ignore:Dataset.isel_points")
     def test_sel_points(self):
         data = create_test_data()
 
@@ -1347,6 +1350,7 @@ class TestDataset(TestCase):
         with pytest.raises(KeyError):
             data.sel_points(x=[2.5], y=[2.0], method='pad', tolerance=1e-3)
 
+    @pytest.mark.filterwarnings('ignore::DeprecationWarning')
     def test_sel_fancy(self):
         data = create_test_data()
 
@@ -2103,14 +2107,15 @@ class TestDataset(TestCase):
         expected = Dataset({'b': (('x', 'y'), [[0, 1], [2, 3]]),
                             'x': [0, 1],
                             'y': ['a', 'b']})
-        actual = ds.unstack('z')
-        assert_identical(actual, expected)
+        for dim in ['z', ['z'], None]:
+            actual = ds.unstack(dim)
+            assert_identical(actual, expected)
 
     def test_unstack_errors(self):
         ds = Dataset({'x': [1, 2, 3]})
-        with raises_regex(ValueError, 'invalid dimension'):
+        with raises_regex(ValueError, 'does not contain the dimensions'):
             ds.unstack('foo')
-        with raises_regex(ValueError, 'does not have a MultiIndex'):
+        with raises_regex(ValueError, 'do not have a MultiIndex'):
             ds.unstack('x')
 
     def test_stack_unstack_fast(self):
diff --git a/xarray/tests/test_missing.py b/xarray/tests/test_missing.py
index 5c7e384c..47224e55 100644
--- a/xarray/tests/test_missing.py
+++ b/xarray/tests/test_missing.py
@@ -93,14 +93,14 @@ def test_interpolate_pd_compat():
 
 
 @requires_scipy
-def test_scipy_methods_function():
-    for method in ['barycentric', 'krog', 'pchip', 'spline', 'akima']:
-        kwargs = {}
-        # Note: Pandas does some wacky things with these methods and the full
-        # integration tests wont work.
-        da, _ = make_interpolate_example_data((25, 25), 0.4, non_uniform=True)
-        actual = da.interpolate_na(method=method, dim='time', **kwargs)
-        assert (da.count('time') <= actual.count('time')).all()
+@pytest.mark.parametrize('method', ['barycentric', 'krog',
+                                    'pchip', 'spline', 'akima'])
+def test_scipy_methods_function(method):
+    # Note: Pandas does some wacky things with these methods and the full
+    # integration tests wont work.
+    da, _ = make_interpolate_example_data((25, 25), 0.4, non_uniform=True)
+    actual = da.interpolate_na(method=method, dim='time')
+    assert (da.count('time') <= actual.count('time')).all()
 
 
 @requires_scipy
diff --git a/xarray/tests/test_plot.py b/xarray/tests/test_plot.py
index 4e5ea8fc..15cb6af5 100644
--- a/xarray/tests/test_plot.py
+++ b/xarray/tests/test_plot.py
@@ -5,6 +5,7 @@ from datetime import datetime
 
 import numpy as np
 import pandas as pd
+import xarray as xr
 import pytest
 
 import xarray.plot as xplt
@@ -267,6 +268,7 @@ class TestPlot(PlotTestCase):
         assert ax.has_data()
 
     @pytest.mark.slow
+    @pytest.mark.filterwarnings('ignore:tight_layout cannot')
     def test_convenient_facetgrid(self):
         a = easy_array((10, 15, 4))
         d = DataArray(a, dims=['y', 'x', 'z'])
@@ -328,6 +330,7 @@ class TestPlot(PlotTestCase):
             self.darray.plot(aspect=1)
 
     @pytest.mark.slow
+    @pytest.mark.filterwarnings('ignore:tight_layout cannot')
     def test_convenient_facetgrid_4d(self):
         a = easy_array((10, 15, 2, 3))
         d = DataArray(a, dims=['y', 'x', 'columns', 'rows'])
@@ -470,6 +473,21 @@ class TestDetermineCmapParams(TestCase):
         assert cmap_params['levels'] is None
         assert cmap_params['norm'] is None
 
+    def test_cmap_sequential_option(self):
+        with xr.set_options(cmap_sequential='magma'):
+            cmap_params = _determine_cmap_params(self.data)
+            assert cmap_params['cmap'] == 'magma'
+
+    def test_cmap_sequential_explicit_option(self):
+        with xr.set_options(cmap_sequential=mpl.cm.magma):
+            cmap_params = _determine_cmap_params(self.data)
+            assert cmap_params['cmap'] == mpl.cm.magma
+
+    def test_cmap_divergent_option(self):
+        with xr.set_options(cmap_divergent='magma'):
+            cmap_params = _determine_cmap_params(self.data, center=0.5)
+            assert cmap_params['cmap'] == 'magma'
+
     def test_nan_inf_are_ignored(self):
         cmap_params1 = _determine_cmap_params(self.data)
         data = self.data
@@ -775,10 +793,13 @@ class Common2dMixin:
         clim2 = self.plotfunc(x2).get_clim()
         assert clim1 == clim2
 
+    @pytest.mark.filterwarnings('ignore::UserWarning')
+    @pytest.mark.filterwarnings('ignore:invalid value encountered')
     def test_can_plot_all_nans(self):
         # regression test for issue #1780
         self.plotfunc(DataArray(np.full((2, 2), np.nan)))
 
+    @pytest.mark.filterwarnings('ignore: Attempting to set')
     def test_can_plot_axis_size_one(self):
         if self.plotfunc.__name__ not in ('contour', 'contourf'):
             self.plotfunc(DataArray(np.ones((1, 1))))
@@ -970,6 +991,7 @@ class Common2dMixin:
         del func_sig['darray']
         assert func_sig == method_sig
 
+    @pytest.mark.filterwarnings('ignore:tight_layout cannot')
     def test_convenient_facetgrid(self):
         a = easy_array((10, 15, 4))
         d = DataArray(a, dims=['y', 'x', 'z'])
@@ -1001,6 +1023,7 @@ class Common2dMixin:
             else:
                 assert '' == ax.get_xlabel()
 
+    @pytest.mark.filterwarnings('ignore:tight_layout cannot')
     def test_convenient_facetgrid_4d(self):
         a = easy_array((10, 15, 2, 3))
         d = DataArray(a, dims=['y', 'x', 'columns', 'rows'])
@@ -1279,11 +1302,23 @@ class TestImshow(Common2dMixin, PlotTestCase):
         assert out.dtype == np.uint8
         assert (out[..., :3] == da.values).all()  # Compare without added alpha
 
+    @pytest.mark.filterwarnings('ignore:Several dimensions of this array')
     def test_regression_rgb_imshow_dim_size_one(self):
         # Regression: https://github.com/pydata/xarray/issues/1966
         da = DataArray(easy_array((1, 3, 3), start=0.0, stop=1.0))
         da.plot.imshow()
 
+    def test_imshow_origin_kwarg(self):
+        da = DataArray(easy_array((5, 5, 3), start=-0.6, stop=1.4))
+        da.plot.imshow(origin='upper')
+        assert plt.xlim()[0] < 0
+        assert plt.ylim()[1] < 0
+
+        plt.clf()
+        da.plot.imshow(origin='lower')
+        assert plt.xlim()[0] < 0
+        assert plt.ylim()[0] < 0
+
 
 class TestFacetGrid(PlotTestCase):
     def setUp(self):
@@ -1511,6 +1546,7 @@ class TestFacetGrid(PlotTestCase):
             sharey=False)
 
 
+@pytest.mark.filterwarnings('ignore:tight_layout cannot')
 class TestFacetGrid4d(PlotTestCase):
     def setUp(self):
         a = easy_array((10, 15, 3, 2))
@@ -1538,6 +1574,7 @@ class TestFacetGrid4d(PlotTestCase):
             assert substring_in_axes(label, ax)
 
 
+@pytest.mark.filterwarnings('ignore:tight_layout cannot')
 class TestFacetedLinePlots(PlotTestCase):
     def setUp(self):
         self.darray = DataArray(np.random.randn(10, 6, 3, 4),