# Buggy code
def sel(self, method=None, tolerance=None, drop=False, **indexers):
    """Returns a new dataset with each array indexed by tick labels
    along the specified dimension(s).

    In contrast to `Dataset.isel`, indexers for this method should use
    labels instead of integers.

    Under the hood, this method is powered by using pandas's powerful Index
    objects. This makes label based indexing essentially just as fast as
    using integer indexing.

    It also means this method uses pandas's (well documented) logic for
    indexing. This means you can use string shortcuts for datetime indexes
    (e.g., '2000-01' to select all values in January 2000). It also means
    that slices are treated as inclusive of both the start and stop values,
    unlike normal Python indexing.

    Parameters
    ----------
    method : {None, 'nearest', 'pad'/'ffill', 'backfill'/'bfill'}, optional
        Method to use for inexact matches (requires pandas>=0.16):

        * None (default): only exact matches
        * pad / ffill: propagate last valid index value forward
        * backfill / bfill: propagate next valid index value backward
        * nearest: use nearest valid index value
    tolerance : optional
        Maximum distance between original and new labels for inexact
        matches. The values of the index at the matching locations most
        satisfy the equation ``abs(index[indexer] - target) <= tolerance``.
        Requires pandas>=0.17.
    drop : bool, optional
        If ``drop=True``, drop coordinates variables in `indexers` instead
        of making them scalar.
    **indexers : {dim: indexer, ...}
        Keyword arguments with names matching dimensions and values given
        by scalars, slices or arrays of tick labels. For dimensions with
        multi-index, the indexer may also be a dict-like object with keys
        matching index level names.
        If DataArrays are passed as indexers, xarray-style indexing will be
        carried out. See :ref:`indexing` for the details.

    Returns
    -------
    obj : Dataset
        A new Dataset with the same contents as this dataset, except each
        variable and dimension is indexed by the appropriate indexers.
        If indexer DataArrays have coordinates that do not conflict with
        this object, then these coordinates will be attached.
        In general, each array's data will be a view of the array's data
        in this dataset, unless vectorized indexing was triggered by using
        an array indexer, in which case the data will be a copy.


    See Also
    --------
    Dataset.isel
    DataArray.sel
    """
    from .dataarray import DataArray

    v_indexers = {
        k: v.variable.data if isinstance(v, DataArray) else v
        for k, v in indexers.items()
    }

    pos_indexers, new_indexes = indexing.remap_label_indexers(
        self, v_indexers, method=method, tolerance=tolerance
    )
    # attach indexer's coordinate to pos_indexers
    for k, v in indexers.items():
        if isinstance(v, Variable):
            pos_indexers[k] = Variable(v.dims, pos_indexers[k])
        elif isinstance(v, DataArray):
            # drop coordinates found in indexers since .sel() already
            # ensures alignments
            coords = OrderedDict(
                (k, v) for k, v in v._coords.items() if k not in indexers
            )
            pos_indexers[k] = DataArray(pos_indexers[k], coords=coords, dims=v.dims)
    result = self.isel(drop=drop, **pos_indexers)
    return result._replace_indexes(new_indexes)


# Traceback (AxisError)
In [8]: xarr.variable[l_indices.variable, c_indices.variable] = 2
---------------------------------------------------------------------------
AxisError                                 Traceback (most recent call last)
<ipython-input-8-75558576dcaf> in <module>()
----> 1 xarr.variable[l_indices.variable, c_indices.variable] = 2

~/dev/xarray/xarray/core/variable.py in __setitem__(self, key, value)
653             value = np.moveaxis(value, new_order, range(len(new_order)))
654
--> 655         self._indexable_data[index_tuple] = value
656
657     @property

~/dev/xarray/xarray/core/indexing.py in __setitem__(self, key, value)
660     def __setitem__(self, key, value):
661         array, key = self._indexing_array_and_key(key)
--> 662         array[key] = value
663
664

~/dev/xarray/xarray/core/nputils.py in __setitem__(self, key, value)
132         mixed_positions, vindex_positions = _advanced_indexer_subspaces(key)
133         self._array[key] = np.moveaxis(value, vindex_positions,
--> 134                                        mixed_positions)

~/conda/envs/xarray-dev/lib/python3.5/site-packages/numpy/core/numeric.py in moveaxis(a, source, destination)
1599         transpose = a.transpose
1600
-> 1601     source = normalize_axis_tuple(source, a.ndim, 'source')
1602     destination = normalize_axis_tuple(destination, a.ndim, 'destination')
1603     if len(source) != len(destination):

~/conda/envs/xarray-dev/lib/python3.5/site-packages/numpy/core/numeric.py in normalize_axis_tuple(axis, ndim, argname, allow_duplicate)
1534     except TypeError:
1535         axis = tuple(axis)
-> 1536     axis = tuple(normalize_axis_index(ax, ndim, argname) for ax in axis)
1537     if not allow_duplicate and len(set(axis)) != len(axis):
1538         if argname:

~/conda/envs/xarray-dev/lib/python3.5/site-packages/numpy/core/numeric.py in <genexpr>(.0)
1534     except TypeError:
1535         axis = tuple(axis)
-> 1536     axis = tuple(normalize_axis_index(ax, ndim, argname) for ax in axis)
1537     if not allow_duplicate and len(set(axis)) != len(axis):
1538         if argname:

AxisError: source: axis 0 is out of bounds for array of dimension 0

# Fixed code
def sel(self, method=None, tolerance=None, drop=False, **indexers):
    """Returns a new dataset with each array indexed by tick labels
    along the specified dimension(s).

    In contrast to `Dataset.isel`, indexers for this method should use
    labels instead of integers.

    Under the hood, this method is powered by using pandas's powerful Index
    objects. This makes label based indexing essentially just as fast as
    using integer indexing.

    It also means this method uses pandas's (well documented) logic for
    indexing. This means you can use string shortcuts for datetime indexes
    (e.g., '2000-01' to select all values in January 2000). It also means
    that slices are treated as inclusive of both the start and stop values,
    unlike normal Python indexing.

    Parameters
    ----------
    method : {None, 'nearest', 'pad'/'ffill', 'backfill'/'bfill'}, optional
        Method to use for inexact matches (requires pandas>=0.16):

        * None (default): only exact matches
        * pad / ffill: propagate last valid index value forward
        * backfill / bfill: propagate next valid index value backward
        * nearest: use nearest valid index value
    tolerance : optional
        Maximum distance between original and new labels for inexact
        matches. The values of the index at the matching locations most
        satisfy the equation ``abs(index[indexer] - target) <= tolerance``.
        Requires pandas>=0.17.
    drop : bool, optional
        If ``drop=True``, drop coordinates variables in `indexers` instead
        of making them scalar.
    **indexers : {dim: indexer, ...}
        Keyword arguments with names matching dimensions and values given
        by scalars, slices or arrays of tick labels. For dimensions with
        multi-index, the indexer may also be a dict-like object with keys
        matching index level names.
        If DataArrays are passed as indexers, xarray-style indexing will be
        carried out. See :ref:`indexing` for the details.

    Returns
    -------
    obj : Dataset
        A new Dataset with the same contents as this dataset, except each
        variable and dimension is indexed by the appropriate indexers.
        If indexer DataArrays have coordinates that do not conflict with
        this object, then these coordinates will be attached.
        In general, each array's data will be a view of the array's data
        in this dataset, unless vectorized indexing was triggered by using
        an array indexer, in which case the data will be a copy.


    See Also
    --------
    Dataset.isel
    DataArray.sel
    """
    pos_indexers, new_indexes = remap_label_indexers(
        self, method, tolerance, **indexers
    )
    result = self.isel(drop=drop, **pos_indexers)
    return result._replace_indexes(new_indexes)