def storeRasterInArray(rasters):
    """Store list of raster or multi-band raster in a ndarray

    Parameters
    ----------

    rasters : list
        list of rasters to analyse

    Return
    ----------
    ndarray

    """

    # get raster size with first raster file
    data = fut.readRaster(rasters[0], False)

    # get rasters or bands number
    if len(rasters) == 1:
        nbbands = fut.getRasterNbands(rasters[0])

    elif len(rasters) > 1:
        nbbands = len(rasters)

    # Set a empty ndarrays with same dimension as input rasters
    outdata = np.zeros([data[1], data[0], nbbands])

    # Populate output ndarrays
    if len(rasters) == 1:
        for nbband in range(nbbands):
            outdata[:, :, nbband] = fut.readRaster(rasters[0], True,
                                                   nbband + 1)[0]

    elif len(rasters) > 1:
        for idx, raster in enumerate(rasters):
            outdata[:, :, idx] = fut.readRaster(raster, True)[0]
    else:
        raise Exception("No input raster provided to store in Numpy array")

    return outdata
def zonalstats(path,
               rasters,
               params,
               output,
               paramstats,
               classes="",
               bufferDist=None,
               nodata=0,
               gdalpath="",
               systemcall=True,
               gdalcachemax="9000"):
    """Compute zonal statistitics (descriptive and categorical)
       on multi-band raster or multi-rasters
       based on Point (buffered or not) or Polygon zonal vector

    Parameters
    ----------
    path : string
        working directory

    rasters : list
        list of rasters to analyse

    params : list
        list of fid list and vector file

    output : vector file (sqlite, shapefile and geojson)
        vector file to store statistitics

    paramstats : list
        list of statistics to compute (e.g. {1:'stats', 2:'rate'})

            - paramstats = {1:"rate", 2:"statsmaj", 3:"statsmaj", 4:"stats", 2:stats_cl}
            - stats : mean_b, std_b, max_b, min_b
            - statsmaj : meanmaj, stdmaj, maxmaj, minmaj of majority class
            - rate : rate of each pixel value (classe names)
            - stats_cl : mean_cl, std_cl, max_cl, min_cl of one class
            - val : value of corresponding pixel (only for Point geometry and without other stats)

    classes : nomenclature file
        nomenclature

    bufferDist : int
        in case of point zonal vector : buffer size

    gdalpath : string
        path of gdal binaries (for system execution)

    systemcall : boolean
        if True, wrapped raster are stored in working dir

    gdalcachemax : string
        gdal cache for wrapping operation (in Mb)

    """
    if os.path.exists(output):
        return

    # Get bands or raster number
    if len(rasters) != 1:
        nbbands = len(rasters)
    else:
        nbbands = fut.getRasterNbands(rasters[0])

    # Prepare and check validity of statistics methods and input raster
    paramstats = checkmethodstats(rasters, paramstats, nbbands)

    # Get vector file and FID list
    vector, idvals = params

    # if no vector subsetting (all features)
    if not idvals:
        idvals = getFidList(vector)

    # vector open and iterate features and/or buffer geom
    vectorname = os.path.splitext(os.path.basename(vector))[0]
    vectorgeomtype = vf.getGeomType(vector)
    vectorbuff = None

    # Prepare schema of output geopandas dataframe (geometry type and columns formatting)
    schema = setPandasSchema(paramstats, vectorgeomtype, bufferDist)

    # Buffer Point vector file
    if bufferDist and vectorgeomtype in (1, 4, 1001, 1004):
        vectorbuff = os.path.join(path, vectorname + "buff.shp")
        _ = bfo.bufferPoly(vector, vectorbuff, bufferDist=bufferDist)

    # Store input vector in output geopandas dataframe
    vectgpad = gpad.read_file(vector)

    # Prepare statistics columns of output geopandas dataframe
    stats = definePandasDf(vectgpad, idvals, paramstats, classes)

    # Iterate FID list
    dataset = vf.openToRead(vector)
    lyr = dataset.GetLayer()

    for idval in idvals:
        if vectorgeomtype in (1, 4, 1001, 1004):
            if 'val' in list(paramstats.values()):
                lyr.SetAttributeFilter("FID=" + str(idval))
                for feat in lyr:
                    geom = feat.GetGeometryRef()
                    if geom:
                        xpt, ypt, _ = geom.GetPoint()

            # Switch to buffered vector (Point and bufferDist)
            if bufferDist:
                if vectorbuff:
                    vector = vectorbuff

        # creation of wrapped rasters
        success, bands = extractRasterArray(rasters, paramstats, vector,
                                            vectorgeomtype, idval, gdalpath,
                                            gdalcachemax, systemcall, path)

        if success:
            if 'val' in list(paramstats.values()):
                stats = extractPixelValue(rasters, bands, paramstats, xpt, ypt,
                                          stats, idval)
            else:
                stats = computeStats(bands, paramstats, stats, idval, nodata)

        else:
            print(
                "gdalwarp problem for feature %s (geometry error, too small area, etc.)"
                % (idval))

    # Prepare columns name and format of output dataframe
    if "rate" in list(paramstats.values()) and classes != "":
        stats, schema = formatDataFrame(stats, schema, True, classes)
    else:
        stats, schema = formatDataFrame(stats, schema)

    # exportation
    dataframeExport(stats, output, schema)