def from_dataset(cls, base, method='isel', default_slice=None,
                     decoder=None, auto_update=None, prefer_list=False,
                     squeeze=True, attrs=None, load=False, **kwargs):
        """
        Construct an ArrayList instance from an existing base dataset

        Parameters
        ----------
        base: xarray.Dataset
            Dataset instance that is used as reference
        %(InteractiveArray.update.parameters.method)s
        %(InteractiveBase.parameters.auto_update)s
        prefer_list: bool
            If True and multiple variable names pher array are found, the
            :class:`InteractiveList` class is used. Otherwise the arrays are
            put together into one :class:`InteractiveArray`.
        default_slice: indexer
            Index (e.g. 0 if `method` is 'isel') that shall be used for
            dimensions not covered by `dims` and `furtherdims`. If None, the
            whole slice will be used.
        decoder: CFDecoder
            The decoder that shall be used to decoder the `base` dataset
        squeeze: bool, optional
            Default True. If True, and the created arrays have a an axes with
            length 1, it is removed from the dimension list (e.g. an array
            with shape (3, 4, 1, 5) will be squeezed to shape (3, 4, 5))
        attrs: dict, optional
            Meta attributes that shall be assigned to the selected data arrays
            (additional to those stored in the `base` dataset)
        load: bool or dict
            If True, load the data from the dataset using the
            :meth:`xarray.DataArray.load` method. If :class:`dict`, those will
            be given to the above mentioned ``load`` method

        Other Parameters
        ----------------
        %(setup_coords.parameters)s

        Returns
        -------
        ArrayList
            The list with the specified :class:`InteractiveArray` instances
            that hold a reference to the given `base`"""
        try:
            load = dict(load)
        except (TypeError, ValueError):
            def maybe_load(arr):
                return arr.load() if load else arr
        else:
            def maybe_load(arr):
                return arr.load(**load)

        def iter_dims(dims):
            """Split the given dictionary into multiples and iterate over it"""
            if not dims:
                while 1:
                    yield {}
            else:
                dims = OrderedDict(dims)
                keys = dims.keys()
                for vals in zip(*map(cycle, map(safe_list, dims.values()))):
                    yield dict(zip(keys, vals))

        def recursive_selection(key, dims, names):
            names = safe_list(names)
            if len(names) > 1 and prefer_list:
                keys = ('arr%i' % i for i in range(len(names)))
                return InteractiveList(
                    starmap(sel_method, zip(keys, iter_dims(dims), names)),
                    auto_update=auto_update, arr_name=key)
            elif len(names) > 1:
                return sel_method(key, dims, tuple(names))
            else:
                return sel_method(key, dims, names[0])

        def ds2arr(arr):
            base_var = next(var for key, var in arr.variables.items()
                            if key not in arr.coords)
            attrs = base_var.attrs
            arr = arr.to_array()
            if 'coordinates' in base_var.encoding:
                arr.encoding['coordinates'] = base_var.encoding[
                    'coordinates']
            arr.attrs.update(attrs)
            return arr

        if decoder is not None:
            def get_decoder(arr):
                return decoder
        else:
            def get_decoder(arr):
                return CFDecoder.get_decoder(base, arr)

        def add_missing_dimensions(arr):
            # add the missing dimensions to the dataset. This is not anymore
            # done by default from xarray >= 0.9 but we need it to ensure the
            # interactive treatment of DataArrays
            missing = set(arr.dims).difference(base.coords) - {'variable'}
            for dim in missing:
                base[dim] = arr.coords[dim] = np.arange(base.dims[dim])

        if squeeze:
            def squeeze_array(arr):
                return arr.isel(**{dim: 0 for i, dim in enumerate(arr.dims)
                                   if arr.shape[i] == 1})
        else:
            def squeeze_array(arr):
                return arr
        if method == 'isel':
            def sel_method(key, dims, name=None):
                if name is None:
                    return recursive_selection(key, dims, dims.pop('name'))
                elif (isinstance(name, six.string_types) or
                      not utils.is_iterable(name)):
                    arr = base[name]
                else:
                    arr = base[list(name)]
                add_missing_dimensions(arr)
                if not isinstance(arr, xr.DataArray):
                    arr = ds2arr(arr)
                def_slice = slice(None) if default_slice is None else \
                    default_slice
                decoder = get_decoder(arr)
                dims = decoder.correct_dims(arr, dims)
                dims.update({
                    dim: def_slice for dim in set(arr.dims).difference(
                        dims) if dim != 'variable'})
                ret = squeeze_array(arr.isel(**dims))
                # delete the variable dimension for the idims
                dims.pop('variable', None)
                ret.psy.init_accessor(arr_name=key, base=base, idims=dims)
                return maybe_load(ret)
        else:
            def sel_method(key, dims, name=None):
                if name is None:
                    return recursive_selection(key, dims, dims.pop('name'))
                elif (isinstance(name, six.string_types) or
                      not utils.is_iterable(name)):
                    arr = base[name]
                else:
                    arr = base[list(name)]
                add_missing_dimensions(arr)
                if not isinstance(arr, xr.DataArray):
                    arr = ds2arr(arr)
                # idims will be calculated by the array (maybe not the most
                # efficient way...)
                decoder = get_decoder(arr)
                dims = decoder.correct_dims(arr, dims)
                if default_slice is not None:
                    dims.update({
                        key: default_slice for key in set(arr.dims).difference(
                            dims) if key != 'variable'})
                # the sel method does not work with slice objects
                if any(isinstance(idx, slice) for idx in dims.values()):
                    # ignore method argument
                    ret = squeeze_array(arr.sel(**dims))
                else:
                    ret = squeeze_array(arr.sel(method=method, **dims))
                ret.psy.init_accessor(arr_name=key, base=base)
                return maybe_load(ret)
        if 'name' not in kwargs:
            default_names = list(
                key for key in base.variables if key not in base.coords)
            try:
                default_names.sort()
            except TypeError:
                pass
            kwargs['name'] = default_names
        names = setup_coords(**kwargs)
        # check coordinates
        possible_keys = ['t', 'x', 'y', 'z', 'name'] + list(base.dims)
        for key in set(chain(*six.itervalues(names))):
            utils.check_key(key, possible_keys, name='dimension')
        instance = cls(starmap(sel_method, six.iteritems(names)),
                       attrs=base.attrs, auto_update=auto_update)
        # convert to interactive lists if an instance is not
        if prefer_list and any(
                not isinstance(arr, InteractiveList) for arr in instance):
            # if any instance is an interactive list, than convert the others
            if any(isinstance(arr, InteractiveList) for arr in instance):
                for i, arr in enumerate(instance):
                    if not isinstance(arr, InteractiveList):
                        instance[i] = InteractiveList([arr])
            else:  # put everything into one single interactive list
                instance = cls([InteractiveList(instance, attrs=base.attrs,
                                                auto_update=auto_update)])
                instance[0].psy.arr_name = instance[0][0].psy.arr_name
        if attrs is not None:
            for arr in instance:
                arr.attrs.update(attrs)
        return instance
def from_dataset ( cls , base , method = 'isel' , default_slice = None , decoder = None , auto_update = None , prefer_list = False , squeeze = True , attrs = None , load = False , ** kwargs ) : try : load = dict ( load ) except ( TypeError , ValueError ) : def maybe_load ( arr ) : return arr . load ( ) if load else arr else : def maybe_load ( arr ) : return arr . load ( ** load ) def iter_dims ( dims ) : if not dims : while 1 : yield { } else : dims = OrderedDict ( dims ) keys = dims . keys ( ) for vals in zip ( * map ( cycle , map ( safe_list , dims . values ( ) ) ) ) : yield dict ( zip ( keys , vals ) ) def recursive_selection ( key , dims , names ) : names = safe_list ( names ) if len ( names ) > 1 and prefer_list : keys = ( 'arr%i' % i for i in range ( len ( names ) ) ) return InteractiveList ( starmap ( sel_method , zip ( keys , iter_dims ( dims ) , names ) ) , auto_update = auto_update , arr_name = key ) elif len ( names ) > 1 : return sel_method ( key , dims , tuple ( names ) ) else : return sel_method ( key , dims , names [ 0 ] ) def ds2arr ( arr ) : base_var = next ( var for key , var in arr . variables . items ( ) if key not in arr . coords ) attrs = base_var . attrs arr = arr . to_array ( ) if 'coordinates' in base_var . encoding : arr . encoding [ 'coordinates' ] = base_var . encoding [ 'coordinates' ] arr . attrs . update ( attrs ) return arr if decoder is not None : def get_decoder ( arr ) : return decoder else : def get_decoder ( arr ) : return CFDecoder . get_decoder ( base , arr ) def add_missing_dimensions ( arr ) : missing = set ( arr . dims ) . difference ( base . coords ) - { 'variable' } for dim in missing : base [ dim ] = arr . coords [ dim ] = np . arange ( base . dims [ dim ] ) if squeeze : def squeeze_array ( arr ) : return arr . isel ( ** { dim : 0 for i , dim in enumerate ( arr . dims ) if arr . shape [ i ] == 1 } ) else : def squeeze_array ( arr ) : return arr if method == 'isel' : def sel_method ( key , dims , name = None ) : if name is None : return recursive_selection ( key , dims , dims . pop ( 'name' ) ) elif ( isinstance ( name , six . string_types ) or not utils . is_iterable ( name ) ) : arr = base [ name ] else : arr = base [ list ( name ) ] add_missing_dimensions ( arr ) if not isinstance ( arr , xr . DataArray ) : arr = ds2arr ( arr ) def_slice = slice ( None ) if default_slice is None else default_slice decoder = get_decoder ( arr ) dims = decoder . correct_dims ( arr , dims ) dims . update ( { dim : def_slice for dim in set ( arr . dims ) . difference ( dims ) if dim != 'variable' } ) ret = squeeze_array ( arr . isel ( ** dims ) ) dims . pop ( 'variable' , None ) ret . psy . init_accessor ( arr_name = key , base = base , idims = dims ) return maybe_load ( ret ) else : def sel_method ( key , dims , name = None ) : if name is None : return recursive_selection ( key , dims , dims . pop ( 'name' ) ) elif ( isinstance ( name , six . string_types ) or not utils . is_iterable ( name ) ) : arr = base [ name ] else : arr = base [ list ( name ) ] add_missing_dimensions ( arr ) if not isinstance ( arr , xr . DataArray ) : arr = ds2arr ( arr ) decoder = get_decoder ( arr ) dims = decoder . correct_dims ( arr , dims ) if default_slice is not None : dims . update ( { key : default_slice for key in set ( arr . dims ) . difference ( dims ) if key != 'variable' } ) if any ( isinstance ( idx , slice ) for idx in dims . values ( ) ) : ret = squeeze_array ( arr . sel ( ** dims ) ) else : ret = squeeze_array ( arr . sel ( method = method , ** dims ) ) ret . psy . init_accessor ( arr_name = key , base = base ) return maybe_load ( ret ) if 'name' not in kwargs : default_names = list ( key for key in base . variables if key not in base . coords ) try : default_names . sort ( ) except TypeError : pass kwargs [ 'name' ] = default_names names = setup_coords ( ** kwargs ) possible_keys = [ 't' , 'x' , 'y' , 'z' , 'name' ] + list ( base . dims ) for key in set ( chain ( * six . itervalues ( names ) ) ) : utils . check_key ( key , possible_keys , name = 'dimension' ) instance = cls ( starmap ( sel_method , six . iteritems ( names ) ) , attrs = base . attrs , auto_update = auto_update ) if prefer_list and any ( not isinstance ( arr , InteractiveList ) for arr in instance ) : if any ( isinstance ( arr , InteractiveList ) for arr in instance ) : for i , arr in enumerate ( instance ) : if not isinstance ( arr , InteractiveList ) : instance [ i ] = InteractiveList ( [ arr ] ) else : instance = cls ( [ InteractiveList ( instance , attrs = base . attrs , auto_update = auto_update ) ] ) instance [ 0 ] . psy . arr_name = instance [ 0 ] [ 0 ] . psy . arr_name if attrs is not None : for arr in instance : arr . attrs . update ( attrs ) return instance
Construct an ArrayList instance from an existing base dataset

        Parameters
        ----------
        base: xarray.Dataset
            Dataset instance that is used as reference
        %(InteractiveArray.update.parameters.method)s
        %(InteractiveBase.parameters.auto_update)s
        prefer_list: bool
            If True and multiple variable names pher array are found, the
            :class:`InteractiveList` class is used. Otherwise the arrays are
            put together into one :class:`InteractiveArray`.
        default_slice: indexer
            Index (e.g. 0 if `method` is 'isel') that shall be used for
            dimensions not covered by `dims` and `furtherdims`. If None, the
            whole slice will be used.
        decoder: CFDecoder
            The decoder that shall be used to decoder the `base` dataset
        squeeze: bool, optional
            Default True. If True, and the created arrays have a an axes with
            length 1, it is removed from the dimension list (e.g. an array
            with shape (3, 4, 1, 5) will be squeezed to shape (3, 4, 5))
        attrs: dict, optional
            Meta attributes that shall be assigned to the selected data arrays
            (additional to those stored in the `base` dataset)
        load: bool or dict
            If True, load the data from the dataset using the
            :meth:`xarray.DataArray.load` method. If :class:`dict`, those will
            be given to the above mentioned ``load`` method

        Other Parameters
        ----------------
        %(setup_coords.parameters)s

        Returns
        -------
        ArrayList
            The list with the specified :class:`InteractiveArray` instances
            that hold a reference to the given `base`