Repository: pydata/xarray

Issue:
`axis` keyword ignored when applying `np.squeeze` to `DataArray`
Thank you all for creating xarray, I'm a new user and I love it! 

I believe I came across a bug. It appears the axis keyword is ignored when applying `np.squeeze` to a `DataArray`. Here is an illustration:


```
import numpy as np
import xarray as xr

test = np.random.random((1,10,1))
np.squeeze(test, axis=0).shape
# (10, 1)
np.squeeze(xr.DataArray(test), axis=0).shape
# (10,)
np.__version__
# '1.13.0'
xr.__version__
# '0.9.6'
```


Discussion:
floriankrb: Here it is. Thanks for your code reviews and your helpful comments !

Patch:
diff --git a/doc/whats-new.rst b/doc/whats-new.rst
index 42c0891f..c54c67d1 100644
--- a/doc/whats-new.rst
+++ b/doc/whats-new.rst
@@ -93,6 +93,8 @@ Enhancements
 - Speed of reindexing/alignment with dask array is orders of magnitude faster
   when inserting missing values  (:issue:`1847`).
   By `Stephan Hoyer <https://github.com/shoyer>`_.
+- Fix ``axis`` keyword ignored when applying ``np.squeeze`` to ``DataArray`` (:issue:`1487`).
+  By `Florian Pinault <https://github.com/floriankrb>`_.
 - Add ``netcdftime`` as an optional dependency of xarray. This allows for
   encoding/decoding of datetimes with non-standard calendars without the
   netCDF4 dependency (:issue:`1084`).
diff --git a/xarray/core/common.py b/xarray/core/common.py
index 1366d0ff..094e8350 100644
--- a/xarray/core/common.py
+++ b/xarray/core/common.py
@@ -211,14 +211,26 @@ class AttrAccessMixin(object):
         return list(set(item_lists))
 
 
-def get_squeeze_dims(xarray_obj, dim):
+def get_squeeze_dims(xarray_obj, dim, axis=None):
     """Get a list of dimensions to squeeze out.
     """
-    if dim is None:
+    if not dim is None and not axis is None:
+        raise ValueError('cannot use both parameters `axis` and `dim`')
+
+    if dim is None and axis is None:
         dim = [d for d, s in xarray_obj.sizes.items() if s == 1]
     else:
         if isinstance(dim, basestring):
             dim = [dim]
+        if isinstance(axis, int):
+            axis = (axis, )
+        if isinstance(axis, tuple):
+            for a in axis:
+                if not isinstance(a, int):
+                    raise ValueError(
+                        'parameter `axis` must be int or tuple of int.')
+            alldims = list(xarray_obj.sizes.keys())
+            dim = [alldims[a] for a in axis]
         if any(xarray_obj.sizes[k] > 1 for k in dim):
             raise ValueError('cannot select a dimension to squeeze out '
                              'which has length greater than one')
@@ -228,7 +240,7 @@ def get_squeeze_dims(xarray_obj, dim):
 class BaseDataObject(AttrAccessMixin):
     """Shared base class for Dataset and DataArray."""
 
-    def squeeze(self, dim=None, drop=False):
+    def squeeze(self, dim=None, drop=False, axis=None):
         """Return a new object with squeezed data.
 
         Parameters
@@ -240,6 +252,8 @@ class BaseDataObject(AttrAccessMixin):
         drop : bool, optional
             If ``drop=True``, drop squeezed coordinates instead of making them
             scalar.
+        axis : int, optional
+            Select the dimension to squeeze. Added for compatibility reasons.
 
         Returns
         -------
@@ -251,7 +265,7 @@ class BaseDataObject(AttrAccessMixin):
         --------
         numpy.squeeze
         """
-        dims = get_squeeze_dims(self, dim)
+        dims = get_squeeze_dims(self, dim, axis)
         return self.isel(drop=drop, **{d: 0 for d in dims})
 
     def get_index(self, key):


Test patch:
diff --git a/xarray/tests/test_dataarray.py b/xarray/tests/test_dataarray.py
index 0def5b68..cd8a209d 100644
--- a/xarray/tests/test_dataarray.py
+++ b/xarray/tests/test_dataarray.py
@@ -1668,6 +1668,21 @@ class TestDataArray(TestCase):
         actual = array.squeeze(drop=False)
         assert_identical(expected, actual)
 
+        array = DataArray([[[0., 1.]]], dims=['dim_0', 'dim_1', 'dim_2'])
+        expected = DataArray([[0., 1.]], dims=['dim_1', 'dim_2'])
+        actual = array.squeeze(axis=0)
+        assert_identical(expected, actual)
+
+        array = DataArray([[[[0., 1.]]]], dims=[
+                          'dim_0', 'dim_1', 'dim_2', 'dim_3'])
+        expected = DataArray([[0., 1.]], dims=['dim_1', 'dim_3'])
+        actual = array.squeeze(axis=(0, 2))
+        assert_identical(expected, actual)
+
+        array = DataArray([[[0., 1.]]], dims=['dim_0', 'dim_1', 'dim_2'])
+        with pytest.raises(ValueError):
+            array.squeeze(axis=0, dim='dim_1')
+
     def test_drop_coordinates(self):
         expected = DataArray(np.random.randn(2, 3), dims=['x', 'y'])
         arr = expected.copy()