Repository: pandas-dev/pandas

Issue:
MultiIndex xs failure on axis=1
``` python
In [40]: columns = pd.MultiIndex.from_tuples([('a', 'foo'), ('a', 'bar'), ('b', 'hello'), ('b', 'world')], names=['lvl0', 'lvl1'])

In [41]: df = pd.DataFrame(np.random.randn(4, 4), columns=columns)

In [42]: df
Out[42]:
lvl0         a                   b
lvl1       foo       bar     hello     world
0     2.560515  1.579242  0.727753  2.207781
1    -0.599632  0.254395  0.784745  0.340575
2     1.262004  0.409085 -0.229616  1.096679
3     1.637929 -0.694670 -0.356355  0.410580

In [43]: df.xs('a', level='lvl0', axis=1)
---------------------------------------------------------------------------
Exception                                 Traceback (most recent call last)

<...>

<...>/lib/python2.7/site-packages/pandas-0.11.0.dev_14a04dd-py2.7-linux-x86_64.egg/pandas/core/internals.pyc in set_axis(self, axis, value)
    831         if len(value) != len(cur_axis):
    832             raise Exception('Length mismatch (%d vs %d)'
--> 833                             % (len(value), len(cur_axis)))
    834         self.axes[axis] = value
    835

Exception: Length mismatch (2 vs 4)

In [44]: df.xs('a', axis=1)
Out[44]:
lvl1       foo       bar
0     2.560515  1.579242
1    -0.599632  0.254395
2     1.262004  0.409085
3     1.637929 -0.694670

In [45]: pd.__version__
Out[45]: '0.11.0.dev-14a04dd'
```

```
[1227][i] uname -a
Linux xl-mec-03 2.6.18-308.11.1.el5 #1 SMP Fri Jun 15 15:41:53 EDT 2012 x86_64 x86_64 x86_64 GNU/Linux
```



Discussion:
@lodagro 

this was a bug, fixed in (ref was wrong before) #3125
pls verify that this is the correct results
FYI this does not actually need to be sorted

```
In [4]: columns = MultiIndex.from_tuples([('a', 'foo'), ('a', 'bar'),
                              ('b', 'hello'), ('b', 'world')], 
                          names=['lvl0', 'lvl1'])

In [5]: df = DataFrame(np.random.randn(4, 4), columns=columns)

In [6]: df.sortlevel(axis=1,inplace=True)
Out[6]: 
lvl0         a                   b          
lvl1       bar       foo     hello     world
0     1.114395 -0.886457  0.982989  0.136733
1     1.660381  0.976088 -2.599046 -1.747203
2     0.274841  0.063242  0.445300  1.188482
3    -0.647010  1.042165  0.283118  0.462133

In [7]: df.xs('a', level='lvl0', axis=1)
Out[7]: 
lvl1       bar       foo
0     1.114395 -0.886457
1     1.660381  0.976088
2     0.274841  0.063242
3    -0.647010  1.042165
```

Equivalent, but longer

```
In [8]: df.iloc[:,0:2].loc[:,'a']
Out[8]: 
lvl1       bar       foo
0     1.114395 -0.886457
1     1.660381  0.976088
2     0.274841  0.063242
3    -0.647010  1.042165
```

@y-p pls verify this as well....always a little fuzzy on the semantics

Perfect, thanks!


Resolving patch:
diff --git a/pandas/core/frame.py b/pandas/core/frame.py
--- a/pandas/core/frame.py
+++ b/pandas/core/frame.py
@@ -2226,8 +2226,9 @@ def xs(self, key, axis=0, level=None, copy=True):
                 raise ValueError('Cannot retrieve view (copy=False)')
 
             # level = 0
-            if not isinstance(loc, slice):
-                indexer = [slice(None, None)] * 2
+            loc_is_slice = isinstance(loc, slice)
+            if not loc_is_slice:
+                indexer = [slice(None)] * 2
                 indexer[axis] = loc
                 indexer = tuple(indexer)
             else:
@@ -2237,10 +2238,9 @@ def xs(self, key, axis=0, level=None, copy=True):
                     indexer = self.index[loc]
 
             # select on the correct axis
-            if axis == 1:
-                result = self.ix[:, indexer]
-            else:
-                result = self.ix[indexer]
+            if axis == 1 and loc_is_slice:
+                indexer = slice(None), indexer
+            result = self.ix[indexer]
             setattr(result, result._get_axis_name(axis), new_ax)
             return result
 


Test patch:
diff --git a/pandas/tests/test_indexing.py b/pandas/tests/test_indexing.py
--- a/pandas/tests/test_indexing.py
+++ b/pandas/tests/test_indexing.py
@@ -724,6 +724,11 @@ def test_xs_multiindex(self):
         expected = df.iloc[:,0:2].loc[:,'a']
         assert_frame_equal(result,expected)
 
+        result = df.xs('foo', level='lvl1', axis=1)
+        expected = df.iloc[:, 1:2].copy()
+        expected.columns = expected.columns.droplevel('lvl1')
+        assert_frame_equal(result, expected)
+
     def test_setitem_dtype_upcast(self):
  
         # GH3216