Exemple #1
0
def checkPseudoAxis(axis, dataset=None, variable=None, ndim=(1, 2)):
    ''' detect coordinate variables and prepare for use in plotting '''
    # get coordinate variable
    if isinstance(axis, basestring):
        if isinstance(dataset, Dataset):
            axis = dataset[axis]
        else:
            raise TypeError(
                "Need a Dataset object to look up coordinate variable (pseudo-axis): {}"
                .format(dataset))
    elif not isinstance(axis, Variable):
        raise TypeError(
            "The coordinate variable (pseudo-axis) can either be a Variable object of a name: {}"
            .format(axis))
    if axis.ndim not in ndim:
        raise AxisError(
            "Coordinate variable '{:s}' does not have a compatible number of dimensions: {:d}."
            .format(axis.name, axis.ndim))
    # check against data variable
    if isinstance(variable, Variable):
        for ax in axis.axes:
            if not variable.hasAxis(ax.name):
                raise AxisError(
                    "Coordinate Variable '{}' has Axis '{}', but the Axis is not present in the data Variable '{}'"
                    .format(axis.name, ax.name, variable.name))
        if axis.ndim == 2 and axis.shape != variable.shape:
            raise AxisError(
                "Coordinate variable '{:s}' does not have a compatible shape/dimensions: {}."
                .format(axis.name, axis.shape))
    # return checked coordiante variable
    return axis
Exemple #2
0
def apply_over_arrays(fct, *arrays, **kwargs):
    ''' similar to apply_along_axis, but operates on a list of ndarray's and is not parallelized '''
    axis = kwargs.pop('axis', -1)
    lexitcode = kwargs.pop('lexitcode', False)
    lout = 'out' in kwargs  # output array (for some numpy functions)
    # pre-process input (get reshaped views)
    arrays = [
        collapseOuterDims(array, axis=axis, laddOuter=True) for array in arrays
    ]
    ie = arrays[0].shape[0]
    if not all(array.shape[0] == ie for array in arrays):
        raise AxisError("Cannot coerce input arrays into compatible shapes.")
    # special handling of output arrays
    if lout:
        out = collapseOuterDims(kwargs['out'], axis=axis, laddOuter=True)
        if out.shape[0] != ie:
            raise AxisError("Output array has incompatible shape.")
    # loop over outer dimension and apply function
    if lexitcode: ecs = []  # exit code
    for i in xrange(ie):
        arrslc = [array[i, :] for array in arrays]
        if lout: kwargs['out'] = out[i, :]
        ec = fct(*arrslc, **kwargs)
        if lexitcode: ecs.append(ec)
    #if lexitcode and not all(ecs): raise AssertionError("Some function executions were not successful!")
    # return output list (or None's if fct has no exit code)
    return ecs if lexitcode else None
Exemple #3
0
def collapseOuterDims(ndarray, axis=None, laddOuter=True):
    ''' transform an n-dim array to a 2-dim array by collapsing all but the last/innermost dimension '''
    if not isinstance(ndarray, np.ndarray): raise TypeError(ndarray)
    if ndarray.ndim < 2:
        if laddOuter: ndarray.reshape((1, ndarray.size))
        else: raise AxisError(ndarray.shape)
    if axis is not None and not (axis == -1 or axis == ndarray.ndim - 1):
        if not isinstance(axis, (int, np.integer)): raise TypeError(axis)
        ndarray = np.rollaxis(
            ndarray, axis=axis,
            start=ndarray.ndim)  # make desired axis innermost axis
    shape = (np.prod(ndarray.shape[:-1]), ndarray.shape[-1])  # new 2D shape
    ndarray = np.reshape(ndarray, shape)  # just a new view
    return ndarray  # return reshaped (and reordered) array
Exemple #4
0
def loadEnKF_StnTS(folder=None,
                   varlist='all',
                   varatts=None,
                   name='enkf',
                   title='EnKF',
                   basin=None,
                   start_date=None,
                   end_date=None,
                   sampling=None,
                   period=None,
                   date_range=None,
                   llastIncl=True,
                   WSC_station=None,
                   basin_list=None,
                   filenames=None,
                   prefix=None,
                   time_axis='datetime',
                   scalefactors=None,
                   metadata=None,
                   lkgs=False,
                   out_dir='out/',
                   yaml_file='../input_data/obs_meta.yaml',
                   lYAML=True,
                   nreal=None,
                   ntime=None,
                   **kwargs):
    ''' load EnKF ensemble data as formatted GeoPy Dataset '''
    out_folder = os.path.join(folder, 'out/')  # default output folder
    if not os.path.exists(out_folder): raise IOError(out_folder)
    # default values
    if isinstance(varlist, str) and varlist == 'hydro':
        varlist = Hydro.varlist
    elif isinstance(varlist, str) and varlist == 'obs':
        varlist = Obs.varlist
    elif isinstance(varlist, str) and varlist == 'all':
        varlist = Hydro.varlist + Obs.varlist
    elif not isinstance(varlist, (tuple, list)):
        raise TypeError(varlist)
    if varatts is None: varatts = variable_attributes.copy()
    varmap = {
        varatt['name']: enkf_name
        for enkf_name, varatt in list(varatts.items())
    }
    varlist = [varmap[var] for var in varlist]
    # load WSC station meta data
    pass
    # initialize Dataset
    dataset = Dataset(name=name,
                      title=title if title else name.title(),
                      atts=metadata)
    ensemble = None
    time = None
    observation = None
    # load observation/innovation data
    if any([var in Obs.atts for var in varlist]):
        # load data
        vardata = loadObs(varlist=[var for var in varlist if var in Obs.atts],
                          folder=out_folder,
                          lpandas=False)
        ntime, nobs, nreal = list(vardata.values())[0].shape
        # create Axes
        if time is None:
            # figure out time axis
            time = timeAxis(start_date=start_date,
                            end_date=end_date,
                            sampling=sampling,
                            date_range=date_range,
                            time_axis=time_axis,
                            llastIncl=llastIncl,
                            ntime=ntime,
                            varatts=varatts)
        elif len(time) != ntime:
            raise AxisError(time)
        if ensemble is None:
            # construct ensemble axis
            ensemble = Axis(atts=varatts['ensemble'],
                            coord=np.arange(1, nreal + 1))
        elif len(ensemble) != nreal:
            raise AxisError(ensemble)
        if observation is None:
            # construct ensemble axis
            observation = Axis(atts=varatts['observation'],
                               coord=np.arange(1, nobs + 1))
        elif len(observation) != nobs:
            raise AxisError(observation)
        # create variables
        for varname, data in list(vardata.items()):
            dataset += Variable(atts=varatts[varname],
                                data=data,
                                axes=(time, observation, ensemble))
        # load YAML data, if available
        if lYAML:
            # load YAML file
            yaml_path = os.path.join(out_folder, yaml_file)
            if not os.path.exists(yaml_path): raise IOError(yaml_path)
            with open(yaml_path, 'r') as yf:
                obs_meta = yaml.load(yf)
            if obs_meta is None: raise IOError(yaml_path)  # not a YAML file?
            # constant create variables
            for cvar, cval in list(obs_meta[0].items()):
                if isinstance(cval, str): dtype, missing = np.string_, ''
                elif isinstance(cval, (np.integer, int)):
                    dtype, missing = np.int_, 0
                elif isinstance(cval, (np.inexact, float)):
                    dtype, missing = np.float_, np.NaN
                else:
                    dtype = None  # skip
                if dtype:
                    data = np.asarray([
                        missing if obs[cvar] is None else obs[cvar]
                        for obs in obs_meta
                    ],
                                      dtype=dtype)
                    if cvar in varatts: atts = varatts[cvar]
                    else: atts = dict(name=cvar, units='')
                    dataset += Variable(atts=atts,
                                        data=data,
                                        axes=(observation, ))
    elif ntime is None:
        # try to infer time dimension from backup.info file
        backup_info = os.path.join(folder, 'backup.info')
        if os.path.exists(backup_info):
            with open(backup_info, 'r') as bf:
                ntime = int(bf.readline())
    # load discharge/hydrograph data
    if 'discharge' in varlist:
        data = loadHydro(folder=out_folder, nreal=nreal, ntime=ntime)
        ntime, nreal = data.shape
        if time is None:
            # figure out time axis
            time = timeAxis(start_date=start_date,
                            end_date=end_date,
                            sampling=sampling,
                            date_range=date_range,
                            time_axis=time_axis,
                            llastIncl=llastIncl,
                            ntime=ntime,
                            varatts=varatts)
        elif len(time) != ntime:
            raise AxisError(time)
        if ensemble is None:
            # construct ensemble axis
            ensemble = Axis(atts=varatts['ensemble'],
                            coord=np.arange(1, nreal + 1))
        elif len(ensemble) != nreal:
            raise AxisError(ensemble)
        atts = varatts['discharge']
        if lkgs:
            data *= 1000.
            if atts['units'] == 'm^3/s': atts['units'] = 'kg/s'
        dataset += Variable(atts=atts, data=data, axes=(time, ensemble))
    # return formatted Dataset
    if scalefactors is not None and scalefactors != 1:
        raise NotImplementedError
    return dataset
Exemple #5
0
def tabulate(data,
             row_idx=0,
             col_idx=1,
             header=None,
             labels=None,
             cell_str='{}',
             cell_idx=None,
             cell_fct=None,
             lflatten=False,
             mode='mylatex',
             filename=None,
             folder=None,
             lfeedback=True,
             **kwargs):
    ''' Create a nicely formatted table in the selected format ('mylatex' or call tabulate); 
      cell_str controls formatting of each cell, and also supports multiple arguments along 
      an axis. lflatten skips cell axis checking and lumps all remaining axes together. '''
    # check input
    if not isinstance(data, np.ndarray):
        try:
            data = np.asarray(data)
        except:
            raise TypeError(data)
    if cell_idx is not None:
        if not data.ndim == 3: raise AxisError(cell_idx)
    elif lflatten:
        if not data.ndim >= 2: raise AxisError(cell_idx)
    elif not data.ndim == 2: raise AxisError(cell_idx)
    if not isinstance(cell_str, basestring): raise TypeError(cell_str)
    if cell_fct:
        if not callable(cell_fct): raise TypeError(cell_fct)
        lcellfct = True
    else:
        lcellfct = False
    if cell_idx >= data.ndim: raise AxisError(cell_idx)
    collen = data.shape[col_idx]
    rowlen = data.shape[row_idx]
    if row_idx < col_idx:
        col_idx -= 1  # this is a shortcut for later (data gets sliced by row)
    llabel = False
    lheader = False
    if labels:
        if len(labels) != rowlen: raise AxisError(data.shape)
        llabel = True
    if header:
        if llabel:
            if len(header) == collen: header = ('', ) + tuple(header)
            elif not len(header) == collen + 1: raise AxisError(header)
        elif not len(header) == collen: raise AxisError(header)
        lheader = True
    ## assemble table in nested list
    table = []  # list of rows
    if lheader: table.append(header)  # first row
    # loop over rows
    for i in xrange(rowlen):
        row = [labels[i]] if labels else []
        rowdata = data.take(i, axis=row_idx)
        # loop over columns
        for j in xrange(collen):
            celldata = rowdata.take(j, axis=col_idx)
            # pass data to string of function
            if isinstance(celldata, np.ndarray):
                if lflatten: celldata = celldata.ravel()
                elif celldata.ndim > 1: raise AxisError(celldata.shape)
                cell = cell_fct(celldata) if lcellfct else cell_str.format(
                    *celldata)
            else:
                cell = cell_fct(celldata) if lcellfct else cell_str.format(
                    celldata)
            # N.B.: cell_fct also has to return a string
            row.append(cell)
        table.append(row)
    ## now make table
    if mode.lower() == 'mylatex':
        # extract settings
        lhline = kwargs.pop('lhline', True)
        lheaderhline = kwargs.pop('lheaderhline', True)
        cell_del = kwargs.pop('cell_del', '  &  ')  # regular column delimiter
        line_brk = kwargs.pop(
            'line_break',
            ' \\\\ \\hline' if lhline else ' \\\\')  # escape backslash
        tab_begin = kwargs.pop('tab_begin',
                               '')  # by default, no tab environment
        tab_end = kwargs.pop('tab_end', '')  # by default, no tab environment
        extra_hline = kwargs.pop(
            'extra_hline', [])  # row_idx or label with extra \hline command
        lpercent = kwargs.pop(
            'lpercent', True)  # escape the percent symbol (LaTeX comment)
        if lpercent:  # escape percent signs
            table = [[cell.replace('%', '\%') for cell in row]
                     for row in table]
        # align cells
        nrow = rowlen + 1 if lheader else rowlen
        ncol = collen + 1 if llabel else collen
        col_fmts = []  # column width
        for j in xrange(ncol):
            wd = 0
            for i in xrange(nrow):
                wd = max(wd, len(table[i][j]))
            col_fmts.append('{{:^{:d}s}}'.format(wd))
        # assemble table string
        string = tab_begin + '\n' if tab_begin else ''  # initialize
        for i, row in enumerate(table):
            row = [
                fmt_str.format(cell) for fmt_str, cell in zip(col_fmts, row)
            ]
            string += (' ' + row[0])  # first cell
            for cell in row[1:]:
                string += (cell_del + cell)
            string += line_brk  # add latex line break
            if i in extra_hline or (llabel and row[0] in extra_hline):
                string += ' \\hline'
            if lheaderhline and i == 0:
                string += ' \\hline'  # always put one behind the header
            string += '\n'  # add actual line break
        if tab_end: string += (tab_end + '\n')
    else:
        # use the tabulate module (it's not standard, so import only when needed)
        from tabulate import tabulate
        string = tabulate(table, tablefmt=mode, **kwargs)
        # headers, floatfmt, numalign, stralign, missingval
    ## write to file
    if filename:
        if folder: filename = folder + '/' + filename
        f = open(filename, mode='w')
        f.write(string)  # write entire string and nothing else
        f.close()
        if lfeedback: print(filename)
    # return string for printing
    return string
Exemple #6
0
def checkVarlist(varlist,
                 varname=None,
                 ndim=1,
                 bins=None,
                 support=None,
                 method='pdf',
                 lflatten=False,
                 bootstrap_axis='bootstrap',
                 lignore=False):
    ''' helper function to pre-process the variable list '''
    # N.B.: 'lignore' is currently not used
    # varlist is the list of variable objects that are to be plotted
    if isinstance(varlist, Variable): varlist = [varlist]
    elif isinstance(varlist, Dataset):
        if isinstance(varname, basestring): varlist = [varlist[varname]]
        elif isinstance(varname, (tuple, list)):
            varlist = [
                varlist[name] if name in varlist else None for name in varname
            ]
        else:
            raise TypeError
    elif isinstance(varlist, (tuple, list, Ensemble)):
        if varname is not None:
            tmplist = []
            for var in varlist:
                if isinstance(var, Variable): tmplist.append(var)
                elif isinstance(var, Dataset):
                    if var.hasVariable(varname): tmplist.append(var[varname])
                    else: tmplist.append(None)
                else: raise TypeError
            varlist = tmplist
            del tmplist
    else:
        raise TypeError
    if not all([isinstance(var, (Variable, NoneType)) for var in varlist]):
        raise TypeError
    for var in varlist:
        if var is not None and var.data_array.size > 1:
            var.squeeze()  # remove singleton dimensions
    # evaluate distribution variables on support/bins
    if bins is not None or support is not None:
        varlist = evalDistVars(varlist,
                               bins=bins,
                               support=support,
                               method=method,
                               ldatasetLink=True,
                               bootstrap_axis=bootstrap_axis)
    # check axis: they need to have only one axes, which has to be the same for all!
    for var in varlist:
        if var is None: pass
        elif isinstance(ndim, (list, tuple)):
            if var.ndim not in ndim:
                raise AxisError(
                    "Variable '{:s}' does not have compatible dimension(s): {:d}."
                    .format(var.name, var.ndim))
        elif var.ndim > ndim and not lflatten:
            raise AxisError(
                "Variable '{:s}' has more than {:d} dimension(s); consider squeezing."
                .format(var.name, ndim))
        elif var.ndim < ndim:
            raise AxisError(
                "Variable '{:s}' has less than {:d} dimension(s); consider display as a line."
                .format(var.name, ndim))
    # return cleaned-up and checkd variable list
    return varlist
Exemple #7
0
def rasterDataset(name=None,
                  title=None,
                  vardefs=None,
                  axdefs=None,
                  atts=None,
                  projection=None,
                  griddef=None,
                  lgzip=None,
                  lgdal=True,
                  lmask=True,
                  fillValue=None,
                  lskipMissing=True,
                  lgeolocator=True,
                  file_pattern=None,
                  lfeedback=True,
                  **kwargs):
    ''' function to load a set of variables that are stored in raster format in a systematic directory tree into a Dataset
        Variables and Axis are defined as follows:
          vardefs[varname] = dict(name=string, units=string, axes=tuple of strings, atts=dict, plot=dict, dtype=np.dtype, fillValue=value)
          axdefs[axname]   = dict(name=string, units=string, atts=dict, coord=array or list) or None
        The path to raster files is constructed as variable_pattern+axes_pattern, where axes_pattern is defined through the axes, 
        (as in rasterVarialbe) and variable_pattern takes the special keywords VAR, which is the variable key in vardefs.
    '''

    ## prepare input data and axes
    if griddef:
        xlon, ylat = griddef.xlon, griddef.ylat
        if projection is None:
            projection = griddef.projection
        elif projection != griddef.projection:
            raise ArgumentError("Conflicting projection and GridDef!")
        geotransform = griddef.geotransform
        isProjected = griddef.isProjected
    else:
        xlon = ylat = geotransform = None
        isProjected = False if projection is None else True
    # construct axes dict
    axes = dict()
    for axname, axdef in axdefs.items():
        assert 'coord' in axdef, axdef
        assert ('name' in axdef and 'units' in axdef) or 'atts' in axdef, axdef
        if axdef is None:
            axes[axname] = None
        else:
            ax = Axis(**axdef)
            axes[ax.name] = ax
    # check for map Axis
    if isProjected:
        if 'x' not in axes: axes['x'] = xlon
        if 'y' not in axes: axes['y'] = ylat
    else:
        if 'lon' not in axes: axes['lon'] = xlon
        if 'lat' not in axes: axes['lat'] = ylat

    ## load raster data into Variable objects
    varlist = []
    for varname, vardef in vardefs.items():
        # check definitions
        assert 'axes' in vardef and 'dtype' in vardef, vardef
        assert ('name' in vardef
                and 'units' in vardef) or 'atts' in vardef, vardef
        # determine relevant axes
        vardef = vardef.copy()
        axes_list = [
            None if ax is None else axes[ax] for ax in vardef.pop('axes')
        ]
        # define path parameters (with varname)
        path_params = vardef.pop('path_params', None)
        path_params = dict() if path_params is None else path_params.copy()
        if 'VAR' not in path_params:
            path_params['VAR'] = varname  # a special key
        # add kwargs and relevant axis indices
        relaxes = [ax.name for ax in axes_list
                   if ax is not None]  # relevant axes
        for key, value in kwargs.items():
            if key not in axes or key in relaxes:
                vardef[key] = value
        # create Variable object
        var = rasterVariable(projection=projection,
                             griddef=griddef,
                             file_pattern=file_pattern,
                             lgzip=lgzip,
                             lgdal=lgdal,
                             lmask=lmask,
                             lskipMissing=lskipMissing,
                             axes=axes_list,
                             path_params=path_params,
                             lfeedback=lfeedback,
                             **vardef)
        # vardef components: name, units, atts, plot, dtype, fillValue
        varlist.append(var)
        # check that map axes are correct
        for ax in var.xlon, var.ylat:
            if axes[ax.name] is None: axes[ax.name] = ax
            elif axes[ax.name] != ax:
                raise AxisError("{} axes are incompatible.".format(ax.name))
        if griddef is None: griddef = var.griddef
        elif griddef != var.griddef:
            raise AxisError("GridDefs are inconsistent.")
        if geotransform is None: geotransform = var.geotransform
        elif geotransform != var.geotransform:
            raise AxisError(
                "Conflicting geotransform (from Variable) and GridDef!\n {} != {}"
                .format(var.geotransform, geotransform))

    ## create Dataset
    # create dataset
    dataset = Dataset(name=name,
                      title=title,
                      varlist=varlist,
                      axes=axes,
                      atts=atts)
    # add GDAL functionality
    dataset = addGDALtoDataset(dataset,
                               griddef=griddef,
                               projection=projection,
                               geotransform=geotransform,
                               gridfolder=None,
                               lwrap360=None,
                               geolocator=lgeolocator,
                               lforce=False)
    # N.B.: for some reason we also need to pass the geotransform, otherwise it is recomputed internally and some consistency
    #       checks fail due to machine-precision differences

    # return GDAL-enabled Dataset
    return dataset
Exemple #8
0
def readRasterArray(file_pattern,
                    lgzip=None,
                    lgdal=True,
                    dtype=np.float32,
                    lmask=True,
                    fillValue=None,
                    lfeedback=False,
                    lgeotransform=True,
                    axes=None,
                    lna=False,
                    lskipMissing=False,
                    path_params=None,
                    **kwargs):
    ''' function to load a multi-dimensional numpy array from several structured ASCII raster files '''

    if axes is None: raise NotImplementedError
    #TODO: implement automatic detection of axes arguments and axes order

    ## expand path argument and figure out dimensions

    # collect axes arguments
    shape = []
    axes_kwargs = dict()
    for ax in axes:
        if ax not in kwargs: raise AxisError(ax)
        coord = kwargs.pop(ax)
        shape.append(len(coord))
        axes_kwargs[ax] = coord
    assert len(axes) == len(shape) == len(axes_kwargs)
    shape = tuple(shape)
    #TODO: add handling of embedded inner product expansion

    # argument expansion using outer product
    file_kwargs_list = expandArgumentList(outer_list=axes, **axes_kwargs)
    assert np.prod(shape) == len(file_kwargs_list)

    ## load data from raster files and assemble array
    path_params = dict() if path_params is None else path_params.copy(
    )  # will be modified

    # find first valid 2D raster to determine shape
    i0 = 0
    path_params.update(file_kwargs_list[i0])  # update axes parameters
    filepath = file_pattern.format(**path_params)  # construct file name
    if not os.path.exists(filepath):
        if lskipMissing:  # find first valid
            while not os.path.exists(filepath):
                i0 += 1  # go to next raster file
                if i0 >= len(file_kwargs_list):
                    raise IOError(
                        "No valid input raster files found!\n'{}'".format(
                            filepath))
                if lfeedback: print ' ',
                path_params.update(
                    file_kwargs_list[i0])  # update axes parameters
                filepath = file_pattern.format(**path_params)  # nest in line
        else:  # or raise error
            raise IOError(filepath)

    # read first 2D raster file
    data2D = readASCIIraster(filepath,
                             lgzip=lgzip,
                             lgdal=lgdal,
                             dtype=dtype,
                             lna=True,
                             lmask=lmask,
                             fillValue=fillValue,
                             lgeotransform=lgeotransform,
                             **kwargs)
    if lgeotransform: data2D, geotransform0, na = data2D
    else:
        data2D, na = data2D  # we might still need na, but no need to check if it is the same
    shape2D = data2D.shape  # get 2D raster shape for later use

    # allocate data array
    list_shape = (np.prod(shape),
                  ) + shape2D  # assume 3D shape to concatenate 2D rasters
    if lmask:
        data = ma.empty(list_shape, dtype=dtype)
        if fillValue is None: data._fill_value = data2D._fill_value
        else: data._fill_value = fillValue
        data.mask = True  # initialize everything as masked
    else:
        data = np.empty(list_shape, dtype=dtype)  # allocate the array
    assert data.shape[0] == len(file_kwargs_list), (data.shape,
                                                    len(file_kwargs_list))
    # insert (up to) first raster before continuing
    if lskipMissing and i0 > 0:
        data[:
             i0, :, :] = ma.masked if lmask else fillValue  # mask all invalid rasters up to first valid raster
    data[i0, :, :] = data2D  # add first (valid) raster

    # loop over remaining 2D raster files
    for i, file_kwargs in enumerate(file_kwargs_list[i0:]):

        path_params.update(file_kwargs)  # update axes parameters
        filepath = file_pattern.format(**path_params)  # construct file name
        if os.path.exists(filepath):
            if lfeedback: print '.',  # indicate data with bar/pipe
            # read 2D raster file
            data2D = readASCIIraster(filepath,
                                     lgzip=lgzip,
                                     lgdal=lgdal,
                                     dtype=dtype,
                                     lna=False,
                                     lmask=lmask,
                                     fillValue=fillValue,
                                     lgeotransform=lgeotransform,
                                     **kwargs)
            # check geotransform
            if lgeotransform:
                data2D, geotransform = data2D
                if not geotransform == geotransform0:
                    raise AxisError(
                        geotransform
                    )  # to make sure all geotransforms are identical!
            else:
                geotransform = None
            # size information
            if not shape2D == data2D.shape:
                raise AxisError(
                    data2D.shape
                )  # to make sure all geotransforms are identical!
            # insert 2D raster into 3D array
            data[i + i0, :, :] = data2D  # raster shape has to match
        elif lskipMissing:
            # fill with masked values
            data[i + i0, :, :] = ma.masked  # mask missing raster
            if lfeedback: print ' ',  # indicate missing with dot
        else:
            raise IOError(filepath)

    # complete feedback with linebreak
    if lfeedback: print ''

    # reshape and check dimensions
    assert i + i0 == data.shape[0] - 1, (i, i0)
    data = data.reshape(shape + shape2D)  # now we have the full shape
    gc.collect()  # remove duplicate data

    # return data and optional meta data
    if lgeotransform or lna:
        return_data = (data, )
        if lgeotransform: return_data += (geotransform, )
        if lna: return_data += (na, )
    else:
        return_data = data
    return return_data
Exemple #9
0
def rasterVariable(name=None,
                   units=None,
                   axes=None,
                   atts=None,
                   plot=None,
                   dtype=None,
                   projection=None,
                   griddef=None,
                   file_pattern=None,
                   lgzip=None,
                   lgdal=True,
                   lmask=True,
                   fillValue=None,
                   lskipMissing=True,
                   path_params=None,
                   offset=0,
                   scalefactor=1,
                   transform=None,
                   time_axis=None,
                   lfeedback=False,
                   **kwargs):
    ''' function to read multi-dimensional raster data and construct a GDAL-enabled Variable object '''

    # print status
    if lfeedback: print "Loading variable '{}': ".format(name),  # no newline

    ## figure out axes arguments and load data
    # figure out axes (list/tuple of axes has to be ordered correctly!)
    axes_list = [ax.name for ax in axes[:-2]]
    # N.B.: the last two axes are the two horizontal map axes (x&y); they can be None and will be inferred from raster
    # N.B.: coordinate values can be overridden with keyword arguments, but length must be consistent
    # figure out coordinates for axes
    for ax in axes[:-2]:
        if ax.name in kwargs:
            # just make sure the dimensions match, but use keyword argument
            if not len(kwargs[ax.name]) == len(ax):
                raise AxisError(
                    "Length of Variable axis and raster file dimension have to be equal."
                )
        else:
            # use Axis coordinates and add to kwargs for readRasterArray call
            kwargs[ax.name] = tuple(ax.coord)
    # load raster data
    if lfeedback: print("'{}'".format(file_pattern))
    data, geotransform = readRasterArray(file_pattern,
                                         lgzip=lgzip,
                                         lgdal=lgdal,
                                         dtype=dtype,
                                         lmask=lmask,
                                         fillValue=fillValue,
                                         lgeotransform=True,
                                         axes=axes_list,
                                         lna=False,
                                         lskipMissing=lskipMissing,
                                         path_params=path_params,
                                         lfeedback=lfeedback,
                                         **kwargs)
    # shift and rescale
    if offset != 0: data += offset
    if scalefactor != 1: data *= scalefactor
    ## create Variable object and add GDAL
    # check map axes and generate if necessary
    xlon, ylat = getAxes(
        geotransform,
        xlen=data.shape[-1],
        ylen=data.shape[-2],
        projected=griddef.isProjected if griddef else bool(projection))
    axes = list(axes)
    if axes[-1] is None: axes[-1] = xlon
    elif len(axes[-1]) != len(xlon): raise AxisError(axes[-1])
    if axes[-2] is None: axes[-2] = ylat
    elif len(axes[-2]) != len(ylat): raise AxisError(axes[-2])
    # create regular Variable with data in memory
    var = Variable(name=name,
                   units=units,
                   axes=axes,
                   data=data,
                   dtype=dtype,
                   mask=None,
                   fillValue=fillValue,
                   atts=atts,
                   plot=plot)
    # apply transform (if any), now that we have axes etc.
    if transform is not None: var = transform(var=var, time_axis=time_axis)
    # add GDAL functionality
    if griddef is not None:
        # perform some consistency checks ...
        if projection is None:
            projection = griddef.projection
        elif projection != griddef.projection:
            raise ArgumentError(
                "Conflicting projection and GridDef!\n {} != {}".format(
                    projection, griddef.projection))
        if not np.isclose(geotransform, griddef.geotransform).all():
            raise ArgumentError(
                "Conflicting geotransform (from raster) and GridDef!\n {} != {}"
                .format(geotransform, griddef.geotransform))
        # ... and use provided geotransform (due to issues with numerical precision, this is usually better)
        geotransform = griddef.geotransform  # if we don't pass the geotransform explicitly, it will be recomputed from the axes
    # add GDAL functionality
    var = addGDALtoVar(var,
                       griddef=griddef,
                       projection=projection,
                       geotransform=geotransform,
                       gridfolder=None)

    # return final, GDAL-enabled variable
    return var