Skip to content

geeutils module

hydrafloods.geeutils

add_indices(img, indices=['mndwi'])

Function to calculate multiple band indices and add to image as bands

Parameters:

Name Type Description Default
img ee.Image

image to calculate indices from

required
indices list[str]

list of strings of index names to calculate. can use any named index function in geeutils. default = ["mndwi"]

['mndwi']

Returns:

Type Description
ee.Image

image object with added indices

Source code in hydrafloods/geeutils.py
@decorators.keep_attrs
def add_indices(img, indices=["mndwi"]):
    """Function to calculate multiple band indices and add to image as bands

    args:
        img (ee.Image): image to calculate indices from
        indices (list[str], optional): list of strings of index names to calculate.
            can use any named index function in geeutils. default = ["mndwi"]

    returns:
        ee.Image: image object with added indices
    """

    # loop through each index and append to images list
    cat_bands = [img]
    for index in indices:
        index_func = getattr(all_indices, index)
        cat_bands.append(index_func(img))

    # return images as concatenated bands
    return ee.Image.cat(cat_bands)

admin_bbox(admin_name, level=0, max_error=1000)

Function to get a bounding box geometry of an administrative area

Parameters:

Name Type Description Default
admin_name str

US-recognized country name

required
max_error float,optional

The maximum amount of error tolerated when performing any necessary reprojection. default = 100

1000

Returns:

Type Description
ee.Geometry

geometry of country bounding box

Source code in hydrafloods/geeutils.py
def admin_bbox(admin_name, level=0, max_error=1000):
    """Function to get a bounding box geometry of an administrative area
    args:
        admin_name (str): US-recognized country name
        max_error (float,optional): The maximum amount of error tolerated when
            performing any necessary reprojection. default = 100

    returns:
        ee.Geometry: geometry of country bounding box
    """

    if level not in range(0,3):
        raise ValueError(f"Administrative level is 0-2, provided level {level} is outside of range")

    admin_bounds = ee.FeatureCollection("FAO/GAUL/2015/level2")
    return (
        admin_bounds.filter(ee.Filter.eq(f"ADM{level}_NAME", admin_name))
        .geometry(max_error)
        .bounds(max_error)
    )

batch_export(collection, collection_asset, region=None, prefix=None, suffix=None, scale=1000, crs='EPSG:4326', pyramiding=None, export_type='toAsset', folder=None, metadata=None, verbose=False)

Function to export each image in a collection Wraps export_image will set YYYYMMdd formatted time in file name

Parameters:

Name Type Description Default
collection ee.ImageCollection

image collection to export

required
collection_asset str

image collection asset ID to export to

required
region ee.Geometry

region to export image

None
prefix str

prefix string to add before time info in name

None
suffix str

suffix string to add after time info in name

None
scale int

resolution in meters to export image to. default = 1000

1000
crs str

epsg code to export image to. default = "EPSG:4326"

'EPSG:4326'
pyramiding dict | None

dictionary defining band pyramiding scheme. if None then "mean" will be used as default for all bands. default = None

None
export_type str, optional)

method by which to export the image. Default is 'toAsset', can also be 'toDrive'.

'toAsset'
folder str | None

target folder to export for 'toDrive'/ if None then export should go to root of Drive

None
metadata dict | None None
verbose bool False
Source code in hydrafloods/geeutils.py
def batch_export(
    collection,
    collection_asset,
    region=None,
    prefix=None,
    suffix=None,
    scale=1000,
    crs="EPSG:4326",
    pyramiding=None,
    export_type="toAsset",
    folder=None,
    metadata=None,
    verbose=False,
):
    """Function to export each image in a collection
    Wraps `export_image` will set YYYYMMdd formatted time in file name

    args:
        collection (ee.ImageCollection): image collection to export
        collection_asset (str): image collection asset ID to export to
        region (ee.Geometry): region to export image
        prefix (str): prefix string to add before time info in name
        suffix (str): suffix string to add after time info in name
        scale (int, optional): resolution in meters to export image to. default = 1000
        crs (str, optional): epsg code to export image to. default = "EPSG:4326"
        pyramiding (dict | None, optional): dictionary defining band pyramiding scheme.
            if None then "mean" will be used as default for all bands. default = None
        export_type (str, optional) : method by which to export the image.
            Default is 'toAsset', can also be 'toDrive'.
        folder (str | None, optional): target folder to export for 'toDrive'/
                if None then export should go to root of Drive
        metadata (dict | None, optional):
        verbose (bool, optional):

    """
    if type(collection) is not ee.imagecollection.ImageCollection:
        try:
            collection = getattr(collection, "collection")
        except Exception as e:
            raise TypeError(
                "argument collection needs to be either of type ee.ImageCollection "
                "or hydrafloods.hfCollection"
            )

    n = collection.size()
    exportImages = collection.sort("system:time_start", False).toList(n)
    nIter = n.getInfo()

    for i in range(nIter):
        img = ee.Image(exportImages.get(i))
        if metadata is not None:
            img = img.set(metadata)

        t = img.get("system:time_start").getInfo()
        date = datetime.datetime.utcfromtimestamp(t / 1e3).strftime("%Y%m%d%H%M%S")

        if region is None:
            region = img.geometry()

        exportName = date
        if prefix is not None:
            exportName = f"{prefix}_" + exportName
        if suffix is not None:
            exportName = exportName + f"_{suffix}"

        description = exportName
        if verbose:
            print(f"running export for {description}")

        if not collection_asset.endswith("/"):
            collection_asset += "/"

        exportName = collection_asset + description

        export_image(
            img,
            region,
            asset_id=exportName,
            description=description,
            scale=scale,
            crs=crs,
            pyramiding=pyramiding,
            export_type=export_type,
            folder=folder,
        )

    return

country_bbox(country_name, max_error=1000)

Function to get a bounding box geometry of a country

Parameters:

Name Type Description Default
country_name str

US-recognized country name

required
max_error float,optional

The maximum amount of error tolerated when performing any necessary reprojection. default = 100

1000

Returns:

Type Description
ee.Geometry

geometry of country bounding box

Source code in hydrafloods/geeutils.py
def country_bbox(country_name, max_error=1000):
    """Function to get a bounding box geometry of a country

    args:
        country_name (str): US-recognized country name
        max_error (float,optional): The maximum amount of error tolerated when
            performing any necessary reprojection. default = 100

    returns:
        ee.Geometry: geometry of country bounding box
    """

    all_countries = ee.FeatureCollection("USDOS/LSIB_SIMPLE/2017")
    return (
        all_countries.filter(ee.Filter.eq("country_na", country_name))
        .geometry(max_error)
        .bounds(max_error)
    )

db_to_power(img)

Function to convert SAR units from dB to power

Parameters:

Name Type Description Default
img ee.Image

SAR dB image to convert to power

required

Returns:

Type Description
ee.Image

power SAR image

Source code in hydrafloods/geeutils.py
@decorators.keep_names
@decorators.keep_attrs
def db_to_power(img):
    """Function to convert SAR units from dB to power

    args:
        img (ee.Image): SAR dB image to convert to power

    returns:
        ee.Image: power SAR image
    """
    return ee.Image(10).pow(img.divide(10))

export_image(image, region, asset_id=None, description=None, scale=1000, crs='EPSG:4326', pyramiding=None, export_type='toAsset', folder=None)

Function to wrap image export with EE Python API

Parameters:

Name Type Description Default
image ee.Image

image to export

required
region ee.Geometry

region to export image

required
asset_id str | None

asset ID to export image to if None then asset_id will be a random string. default = None

None
description str | None

description to identify image export/ if None then description will be random string. default = None

None
scale int

resolution in meters to export image to. default = 1000

1000
crs str

epsg code to export image to. default = "EPSG:4326"

'EPSG:4326'
pyramiding dict | None

dictionary defining band pyramiding scheme. if None then "mean" will be used as default for all bands. default = None

None
export_type str, optional)

method by which to export the image. Default is 'toAsset', can also be 'toDrive'.

'toAsset'
folder str | None

target folder to export for 'toDrive'/ if None then export should go to root of Drive

None
Source code in hydrafloods/geeutils.py
def export_image(
    image,
    region,
    asset_id=None,
    description=None,
    scale=1000,
    crs="EPSG:4326",
    pyramiding=None,
    export_type="toAsset",
    folder=None,
):
    """Function to wrap image export with EE Python API

    args:
        image (ee.Image): image to export
        region (ee.Geometry): region to export image
        asset_id (str | None, optional): asset ID to export image to\
            if None then asset_id will be a random string. default = None
        description (str | None, optional): description to identify image export/
            if None then description will be random string. default = None
        scale (int, optional): resolution in meters to export image to. default = 1000
        crs (str, optional): epsg code to export image to. default = "EPSG:4326"
        pyramiding (dict | None, optional): dictionary defining band pyramiding scheme.
            if None then "mean" will be used as default for all bands. default = None
        export_type (str, optional) : method by which to export the image.
            Default is 'toAsset', can also be 'toDrive'.
        folder (str | None, optional): target folder to export for 'toDrive'/
            if None then export should go to root of Drive

    """
    if (asset_id is None) or (type(asset_id) != str):
        asset_id = "".join(
            random.SystemRandom().choice(string.ascii_letters) for _ in range(8)
        ).lower()
    if (description is None) or (type(description) != str):
        description = "".join(
            random.SystemRandom().choice(string.ascii_letters) for _ in range(8)
        ).lower()
    if type(export_type) != str:
        raise TypeError(
            f"Input for export_type not a string, was a " f"{type(export_type)}."
        )
    elif (export_type != "toAsset") and (export_type != "toDrive"):
        raise ValueError(
            "Invalid input for export_type, must be " '"toAsset" or "toDrive".'
        )
    if (folder is not None) and (type(folder) != str):
        raise TypeError(f"Input for folder was not a string, was a " f"{type(folder)}")
    # get serializable geometry for export
    export_region = region.bounds(maxError=10).getInfo()["coordinates"]

    if pyramiding is None:
        pyramiding = {".default": "mean"}

    # set export process
    if export_type == "toAsset":
        export = ee.batch.Export.image.toAsset(
            image,
            description=description,
            assetId=asset_id,
            scale=scale,
            region=export_region,
            maxPixels=1e13,
            crs=crs,
            pyramidingPolicy=pyramiding,
        )
    elif export_type == "toDrive":
        export = ee.batch.Export.image.toDrive(
            image,
            description=description,
            folder=folder,
            scale=scale,
            region=export_region,
            maxPixels=1e13,
            crs=crs,
        )
    # start export process
    export.start()

    return

extract_bits(image, start, end=None, new_name=None)

Function to conver qa bits to binary flag image

Parameters:

Name Type Description Default
image ee.Image

qa image to extract bit from

required
start int

starting bit for flag

required
end int | None

ending bit for flag, if None then will only use start bit. default = None

None
new_name str | None

output name of resulting image, if None name will be {start}Bits. default = None

None

Returns:

Type Description
ee.Image

image with extract bits

Source code in hydrafloods/geeutils.py
def extract_bits(image, start, end=None, new_name=None):
    """Function to conver qa bits to binary flag image

    args:
        image (ee.Image): qa image to extract bit from
        start (int): starting bit for flag
        end (int | None, optional): ending bit for flag, if None then will only use start bit. default = None
        new_name (str | None, optional): output name of resulting image, if None name will be {start}Bits. default = None

    returns:
        ee.Image: image with extract bits
    """

    newname = new_name if new_name is not None else f"{start}Bits"

    if (start == end) or (end is None):
        # perform a bit shift with bitwiseAnd
        return image.select([0], [newname]).bitwiseAnd(1 << start)
    else:
        # Compute the bits we need to extract.
        pattern = 0
        for i in range(start, end):
            pattern += int(math.pow(2, i))

        # Return a single band image of the extracted QA bits, giving the band
        # a new name.
        return image.select([0], [newname]).bitwiseAnd(pattern).rightShift(start)

get_geoms(img)

Helper function to get geometry from image

Parameters:

Name Type Description Default
img ee.Image

image to get geometry from

required

Returns:

Type Description
ee.Geometry

geometry of image

Source code in hydrafloods/geeutils.py
def get_geoms(img):
    """Helper function to get geometry from image

    args:
        img (ee.Image): image to get geometry from

    returns:
        ee.Geometry: geometry of image
    """
    return img.geometry()

power_to_db(img)

Function to convert SAR units from power to dB

Parameters:

Name Type Description Default
img ee.Image

SAR power image to convert to dB

required

Returns:

Type Description
ee.Image

dB SAR image

Source code in hydrafloods/geeutils.py
@decorators.keep_names
@decorators.keep_attrs
def power_to_db(img):
    """Function to convert SAR units from power to dB

    args:
        img (ee.Image): SAR power image to convert to dB

    returns:
        ee.Image: dB SAR image
    """
    return ee.Image(10).multiply(img.log10())

rescale(img, scale=0.0001, offset=0)

Function to linearly rescale units using user defined scale and offset

Parameters:

Name Type Description Default
img ee.Image

image to rescale

required
scale float,optional

scale value (i.e. slope of linear equation). default = 0.0001

0.0001
offset float

offset value (i.e. y-intercept). default = 0

0

Returns:

Type Description
ee.Image

rescaled image

Source code in hydrafloods/geeutils.py
@decorators.keep_names
@decorators.keep_attrs
def rescale(img, scale=0.0001, offset=0):
    """Function to linearly rescale units using user defined scale and offset

    args:
        img (ee.Image): image to rescale
        scale (float,optional): scale value (i.e. slope of linear equation). default = 0.0001
        offset (float, optional): offset value (i.e. y-intercept). default = 0

    returns:
        ee.Image: rescaled image
    """
    return img.multiply(scale).add(offset)

tile_region(region, grid_size=0.1, intersect_geom=None, contain_geom=None, centroid_within=None)

Function to create a feature collection of tiles covering a region

Parameters:

Name Type Description Default
region ee.Geometry

region to create tile grid over

required
grid_size float

resolution in decimal degrees to create tiles. default = 0.1

0.1
intersect_geom ee.Geometry | None

geometry object to filter tiles that intesect with geometry useful for filtering tiles that are created over oceans with no data. default = None

None
contain_geom ee.Geometry | None

geometry object to filter tiles that are contained within geometry useful for filtering tiles that are only in an area. default = None

None

Returns:

Type Description
ee.FeatureCollection

collection of feature tiles at a given grid_size over a region

Source code in hydrafloods/geeutils.py
def tile_region(
    region, grid_size=0.1, intersect_geom=None, contain_geom=None, centroid_within=None
):
    """Function to create a feature collection of tiles covering a region

    args:
        region (ee.Geometry): region to create tile grid over
        grid_size (float, optional): resolution in decimal degrees to create tiles. default = 0.1
        intersect_geom (ee.Geometry | None, optional): geometry object to filter tiles that intesect with
            geometry useful for filtering tiles that are created over oceans with no data. default = None
        contain_geom (ee.Geometry | None, optional): geometry object to filter tiles that are contained within
            geometry useful for filtering tiles that are only in an area. default = None

    returns:
        ee.FeatureCollection: collection of feature tiles at a given grid_size over a region
    """
    # nesting grid construction along y and then x coordinates
    def constuctGrid(i):
        """Closure function to contruct grid"""

        def contructXGrid(j):
            j = ee.Number(j)
            box = (
                ee.Geometry.Rectangle(
                    [j, i, j.add(grid_res), i.add(grid_res)],
                    "epsg:4326",
                    geodesic=False,
                )
            )
            if contain_geom is not None:
                keep = contain_geom.contains(box, maxError=500)

            elif intersect_geom is not None:
                keep = box.intersects(intersect_geom, maxError=500)

            elif centroid_within is not None:
                keep = box.centroid().intersects(centroid_within, maxError=500)

            return ee.Feature(box,{"ul_lat":i.add(grid_res), "ul_lon":j, "keep":keep} )

        i = ee.Number(i)
        out = ee.List.sequence(west, east.subtract(grid_res), grid_res).map(
            contructXGrid, True
        )
        return out

    if (contain_geom is not None) and (intersect_geom is not None):
        raise ValueError(
            "contains and intersection keywords are mutually exclusive, please define only one"
        )

    bounds = region.bounds(maxError=1000)
    coords = ee.List(bounds.coordinates().get(0))
    grid_res = ee.Number(grid_size)

    west = ee.Number(ee.List(coords.get(0)).get(0))
    south = ee.Number(ee.List(coords.get(0)).get(1))
    east = ee.Number(ee.List(coords.get(2)).get(0))
    north = ee.Number(ee.List(coords.get(2)).get(1))

    west = ee.Algorithms.If(
        west.lt(0),
        west.subtract(west.mod(grid_res).add(grid_res)),
        west.subtract(west.mod(grid_res)),
    )
    south = ee.Algorithms.If(
        south.lt(0),
        south.subtract(south.mod(grid_res).add(grid_res)),
        south.subtract(south.mod(grid_res)),
    )
    east = east.add(grid_res.subtract(east.mod(grid_res)))
    north = north.add(grid_res.subtract(north.mod(grid_res)))

    grid = ee.FeatureCollection(
        ee.List.sequence(south, north.subtract(grid_res), grid_res)
        .map(constuctGrid)
        .flatten()
    ).filter(ee.Filter.eq("keep",True))

    return grid