Repository: pydata/xarray

Issue:
Test failures on master with DataArray.to_cdms2
See https://travis-ci.org/pydata/xarray/jobs/410459646

Example failure:
```
=================================== FAILURES ===================================
_________________ TestDataArray.test_to_and_from_cdms2_classic _________________
self = <xarray.tests.test_dataarray.TestDataArray testMethod=test_to_and_from_cdms2_classic>
    def test_to_and_from_cdms2_classic(self):
        """Classic with 1D axes"""
        pytest.importorskip('cdms2')
    
        original = DataArray(
            np.arange(6).reshape(2, 3),
            [('distance', [-2, 2], {'units': 'meters'}),
             ('time', pd.date_range('2000-01-01', periods=3))],
            name='foo', attrs={'baz': 123})
        expected_coords = [IndexVariable('distance', [-2, 2]),
                           IndexVariable('time', [0, 1, 2])]
        actual = original.to_cdms2()
>       assert_array_equal(actual, original)
E       ValueError: 
E       error during assertion:
E       
E       Traceback (most recent call last):
E         File "/home/travis/miniconda/envs/test_env/lib/python2.7/site-packages/numpy/testing/_private/utils.py", line 752, in assert_array_compare
E           x, y = x[~flagged], y[~flagged]
E         File "/home/travis/miniconda/envs/test_env/lib/python2.7/site-packages/cdms2/avariable.py", line 1177, in __getitem__
E           speclist = self._process_specs([key], {})
E         File "/home/travis/miniconda/envs/test_env/lib/python2.7/site-packages/cdms2/avariable.py", line 938, in _process_specs
E           if Ellipsis in specs:
E       ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
E       
E       
E       Arrays are not equal
E        x: TransientVariable([[0, 1, 2],
E                          [3, 4, 5]])
E        y: array([[0, 1, 2],
E              [3, 4, 5]])
```

Discussion:

Patch:
diff --git a/doc/whats-new.rst b/doc/whats-new.rst
index dd9eb9e4..97794125 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`.
@@ -84,7 +89,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/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/utils.py b/xarray/plot/utils.py
index 6221bfe9..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,9 +207,9 @@ 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:


Test patch:
diff --git a/xarray/tests/test_dataarray.py b/xarray/tests/test_dataarray.py
index 5d20a6cf..29ddd40c 100644
--- a/xarray/tests/test_dataarray.py
+++ b/xarray/tests/test_dataarray.py
@@ -2918,7 +2918,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')
@@ -2931,7 +2930,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):
@@ -2953,7 +2952,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
 
@@ -2971,8 +2969,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)
@@ -2980,7 +2980,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')
@@ -2992,8 +2991,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_plot.py b/xarray/tests/test_plot.py
index e7caf3d6..c38ffeff 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
@@ -472,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