def validate_min_lt_max(min, max):
    try:
        min = float(min)
        max = float(max)
    except ValueError:
        raise error_handler.InvalidUsage(
            "Specified min and max values must be numbers.")
    if not min < max:
        raise error_handler.InvalidUsage(
            "Specified min must be less than max.")
示例#2
0
def get_msfd_data():
    """
    Get Crucial data. Either groundwater_declining_trend, or evaporation_deficit dataset must be provided.
    See datasets_visualization_parameters.json for possible bands to request as band
    :return:
    """
    r = request.get_json()
    dataset = r.get("dataset", None)
    image_id = r.get("imageId", None)
    band = r.get("band", None)

    function = r.get("function", None)
    start_date = r.get("startDate", None)
    end_date = r.get("endDate", None)
    image_num_limit = r.get("limit", None)
    min = r.get("min", None)
    max = r.get("max", None)

    if not band:
        msg = f"band is a required parameter"
        logger.error(msg)
        raise error_handler.InvalidUsage(msg)
    if dataset:
        source = "projects/dgds-gee/msfd/" + dataset
    elif image_id:
        source = image_id
    else:
        msg = f"dataset or image_id is a required parameter"
        logger.error(msg)
        raise error_handler.InvalidUsage(msg)

    image_info = dgds_functions.get_dgds_data(
        source=source,
        dataset=dataset,
        image_id=image_id,
        band=band,
        function=function,
        start_date=start_date,
        end_date=end_date,
        image_num_limit=image_num_limit,
        min=min,
        max=max,
    )
    if not image_info:
        raise error_handler.InvalidUsage("No images returned.")

    return Response(json.dumps(image_info),
                    status=200,
                    mimetype="application/json")
示例#3
0
def get_chasm_data():
    """
    Get metocean data. dataset must be provided.
    :return:
    """
    r = request.get_json()
    dataset = r.get("dataset", None)
    band = r["band"]
    image_id = r.get("imageId", None)

    function = r.get("function", None)
    start_date = r.get("startDate", None)
    end_date = r.get("endDate", None)
    image_num_limit = r.get("limit", None)
    min = r.get("min", None)
    max = r.get("max", None)

    source = None
    # Can provide either dataset and/or image_id
    if not (dataset or image_id):
        msg = f"dataset or imageId required."
        logger.error(msg)
        raise error_handler.InvalidUsage(msg)

    if dataset:
        source = "projects/dgds-gee/chasm/" + dataset
    elif image_id:
        image_location_parameters = image_id.split("/")
        source = ("/").join(image_location_parameters[:-1])

    image_info = dgds_functions.get_dgds_data(
        source=source,
        dataset=dataset,
        image_id=image_id,
        band=band,
        function=function,
        start_date=start_date,
        end_date=end_date,
        image_num_limit=image_num_limit,
        min=min,
        max=max,
    )
    if not image_info:
        raise error_handler.InvalidUsage("No images returned.")

    return Response(json.dumps(image_info),
                    status=200,
                    mimetype="application/json")
示例#4
0
def get_gebco_data():
    r = request.get_json()
    dataset = r.get("dataset", "gebco")
    band = r.get("band", "elevation")
    image_id = r.get("imageId", None)

    start_date = r.get("startDate", None)
    end_date = r.get("endDate", None)
    image_num_limit = r.get("limit", None)
    min = r.get("min", None)
    max = r.get("max", None)

    if dataset:
        source = "projects/dgds-gee/bathymetry/" + dataset + "/2019"
    if image_id:
        source = image_id

    image_info = dgds_functions.get_dgds_data(
        source=source,
        dataset=dataset,
        image_id=image_id,
        band=band,
        start_date=start_date,
        end_date=end_date,
        image_num_limit=image_num_limit,
        min=min,
        max=max,
    )
    if not image_info:
        raise error_handler.InvalidUsage("No images returned.")

    return Response(json.dumps(image_info),
                    status=200,
                    mimetype="application/json")
示例#5
0
def get_glossis_data():
    """
    Get GLOSSIS data. Either currents, wind, or waterlevel dataset must be provided.
    If waterlevel dataset is requested, must specify if band water_level_surge, water_level,
    or astronomical_tide is requested
    :return:
    """
    r = request.get_json()
    dataset = r.get("dataset", None)
    image_id = r.get("imageId", None)
    band = r.get("band", None)

    function = r.get("function", None)
    start_date = r.get("startDate", None)
    end_date = r.get("endDate", None)
    image_num_limit = r.get("limit", None)
    min = r.get("min", None)
    max = r.get("max", None)

    if not (dataset or image_id):
        msg = f"dataset or imageId required."
        logger.error(msg)
        raise error_handler.InvalidUsage(msg)
    if dataset:
        source = "projects/dgds-gee/glossis/" + dataset
    if image_id:
        image_location_parameters = image_id.split("/")
        source = ("/").join(image_location_parameters[:-1])

    image_info = dgds_functions.get_dgds_data(
        source=source,
        dataset=dataset,
        image_id=image_id,
        band=band,
        function=function,
        start_date=start_date,
        end_date=end_date,
        image_num_limit=image_num_limit,
        min=min,
        max=max,
    )
    if not image_info:
        raise error_handler.InvalidUsage("No images returned.")

    return Response(json.dumps(image_info),
                    status=200,
                    mimetype="application/json")
示例#6
0
def get_image_collection_info():
    r = request.get_json()
    source = r['source']
    start_date = r.get('startDate', None)
    end_date = r.get('endDate', None)
    image_num_limit = r.get('limit', None)

    info = dgds_functions.get_image_collection_info(source, start_date,
                                                    end_date, image_num_limit)
    if not info:
        raise error_handler.InvalidUsage('No images returned.')

    return Response(json.dumps(info), status=200, mimetype='application/json')
示例#7
0
def get_gll_dtm_data():
    r = request.get_json()
    band = r.get("band", "elevation")

    imageid = "users/maartenpronk/gll_dtm/gll_dtm_v1"
    image_info = dgds_functions.get_dgds_data(
        source=None,
        image_id=imageid,
        band=band,
    )
    if not image_info:
        raise error_handler.InvalidUsage("No images returned.")

    return Response(json.dumps(image_info),
                    status=200,
                    mimetype="application/json")
def filter_liwo_collection_v1(collection_path, id_key, liwo_ids, band,
                              reducer):
    """
    Create combined max image from collection. Version 1 based on unnamed single
    and multi band images.
    :param collection_path: Path to Earth Engine Image Collection
    :param id_key: Metadata key name for unique ids
    :param scenario_ids: List of scenario ids to combine
    :param band: band of image to select
    :param reducer: reducer operation by which to combine images
    :return: combined image
    """
    # Filter based on breach location
    collection = ee.ImageCollection(collection_path)

    # TODO: how to make this generic, consider GraphQL
    collection = collection.filter(ee.Filter.inList(id_key, liwo_ids))

    collection = collection.map(lambda im: im.set('bandNames', im.bandNames()))

    n_selected = collection.size().getInfo()

    if band != 'waterdepth':
        collection = collection.filterMetadata('bandNames', 'equals',
                                               ['b1', 'b2', 'b3', 'b4', 'b5'])

    n_filtered = collection.size().getInfo()

    if n_selected != n_filtered:
        logging.warning('missing images, selected %s, filtered %s', n_selected,
                        n_filtered)

    # Filter based on band name (characteristic to display)
    collection = collection.select(band)
    n_images = collection.size().getInfo()
    msg = 'No images available for breach locations: %s' % (liwo_ids, )
    logger.debug(msg)

    if not n_images:
        raise error_handler.InvalidUsage(msg)

    # get max image
    reduce_func = getattr(ee.Reducer, reducer)()
    image = ee.Image(collection.reduce(reduce_func))
    # clip image to region and show only values greater than 0 (no-data value given in images) .clip(region)
    image = image.mask(image.gt(0))
    return image
示例#9
0
def filter_liwo_collection_v2(collection_path, id_key, scenario_ids, band,
                              reducer):
    """
    Create combined max image from collection. Version 2 based on named image bands
    :param collection_path: Path to Earth Engine Image Collection
    :param id_key: Metadata key name for unique ids
    :param scenario_ids: List of scenario ids to combine
    :param band: band of image to select
    :param reducer: reducer operation by which to combine images
    :return: combined image
    """
    # Filter based on scenario id, band
    scenarios = ee.ImageCollection(collection_path)
    scenarios = scenarios.filter(ee.Filter.inList(id_key, scenario_ids))
    scenarios = scenarios.filter(
        ee.Filter.listContains("system:band_names", band))
    scenarios = scenarios.select(band)
    n_selected = scenarios.size().getInfo()

    if n_selected == 0:
        msg = 'No images available for breach locations: %s' % (scenario_ids, )
        logger.debug(msg)
        raise error_handler.InvalidUsage(msg)
        # raise ValueError("No images with band {} in scenario_ids {}".format(band, scenario_ids))

    if len(scenario_ids) != n_selected:
        logging.info("collection {}, missing {} scenarios for band {}".format(
            collection_path,
            len(scenario_ids) - n_selected, band))

    bounds = scenarios.geometry().bounds()

    # reduce image
    reduce_func = getattr(ee.Reducer, reducer)()
    if reducer == 'min':
        # Aankomstijden <= 0 should not be included in the aggregated minimum
        scenarios = scenarios.map(lambda i: i.mask(i.gt(0)))

    image = ee.Image(scenarios.reduce(reduce_func))
    if reducer == 'max':
        # Do not display any values <= 0 (Some no data values assigned as 0 and not -9999).
        image = image.mask(image.gt(0))

    # reclip by bounds
    image = image.clip(bounds)
    return image
示例#10
0
def validate_min_lt_max(min, max):
    if not min < max:
        raise error_handler.InvalidUsage(
            'Specified min must be less than max.')
示例#11
0
def get_feature_info():
    """
    Get image value at point
    :return:
    """
    r = request.get_json()
    image_id = r['imageId']
    bbox = r['bbox']
    datasets = r.get('datasets', None)
    band = r.get('band', None)
    function = r.get('function', None)
    info_format = r.get('info_format', 'JSON')
    if function == 'mosaic_elevation_datasets':
        if not datasets:
            msg = f'datsets list expected for function {function}'
            raise error_handler.InvalidUsage(msg)
        image = ee.Image(
            dgds_functions.mosaic_elevation_datasets(datasets).select(
                'elevation'))
    else:
        image = ee.Image(image_id)
        image_location_parameters = image_id.split('/')
        source = ('/').join(image_location_parameters[:-1])

        data_params = dgds_functions.get_dgds_source_vis_params(
            source, image_id)

        if band:
            band_name = data_params['bandNames'][band]
            image = image.select(band_name)
        if function:
            assert (function in data_params.get('function', None)) or \
                   (function == data_params['function'].get(band, None)), \
                f'{function} not an option.'

        image = dgds_functions.apply_image_operation(image, function,
                                                     data_params, band)

    image = image.rename('value')
    # TODO: get scale of image, or load default scale from parameters
    value = (image.sample(**{
        'region': ee.Geometry(bbox),
        'geometries': True,
        'scale': 10
    }).first().getInfo())

    # if no data at point, value will be None.
    if not value:
        # return Feature with value None (standard return format from GEE)
        value = {
            "geometry": bbox,
            "id": "0",
            "properties": {
                "value": None
            },
            "type": "Feature"
        }
    else:
        value['properties']['value'] = round(value['properties']['value'], 2)

    if info_format == 'JSON':
        value = value['properties']

    return Response(json.dumps(value), status=200, mimetype='application/json')
示例#12
0
def get_liwo_scenarios():
    r = request.get_json()

    # Currently 'liwo' only option
    variable = 'liwo'
    # name of breach location as string
    liwo_ids = r['liwo_ids']
    # band name as string
    band = r['band']

    raster_assets = {
        'liwo': 'users/rogersckw9/liwo/liwo-scenarios-03-2019'
    }
    bands = {
        'waterdepth': 'b1',
        'velocity': 'b2',
        'riserate': 'b3',
        'damage': 'b4',
        'fatalities': 'b5'
    }

    reducers = {
        'waterdepth': 'max',
        'velocity': 'max',
        'riserate': 'max',
        'damage': 'max',
        'fatalities': 'max'
    }
    # for now use max as a reducer
    assert band in reducers
    assert band in bands
    reducer = reducers[band]


    styles  = {
        'waterdepth': {
            'sld_style': '\
                <RasterSymbolizer>\
                    <ColorMap type="intervals">\
                        <ColorMapEntry color="#FFFFFF" opacity="0.01" quantity="0.01999"/>\
                        <ColorMapEntry color="#CEFEFE" opacity="1.0" quantity="0.5" label="&lt; 0.5"/>\
                        <ColorMapEntry color="#94bff7" opacity="1.0" quantity="1" label="0.5 - 1.0"/>\
                        <ColorMapEntry color="#278ef4" opacity="1.0" quantity="1.5" label="1.0 - 1.5"/>\
                        <ColorMapEntry color="#0000cc" opacity="1.0" quantity="2.0" label="1.5 - 2.0"/>\
                        <ColorMapEntry color="#4A0177" opacity="1.0" quantity="5" label="2.0 - 5.0"/>\
                        <ColorMapEntry color="#73004c" opacity="1.0" quantity="9999" label="&gt; 5.0"/>\
                    </ColorMap>\
                </RasterSymbolizer>'
        },
        'velocity': {
            'sld_style': '\
                <RasterSymbolizer>\
                    <ColorMap type="intervals">\
                        <ColorMapEntry color="#FFFFFF" opacity="0.01" quantity="0.01"/>\
                        <ColorMapEntry color="#FAD7FE" opacity="1.0" quantity="0.5" label="&lt; 0.5"/>\
                        <ColorMapEntry color="#E95CF5" opacity="1.0" quantity="1" label="0.5 - 1.0"/>\
                        <ColorMapEntry color="#CB00DB" opacity="1.0" quantity="2" label="1.0 - 2.0"/>\
                        <ColorMapEntry color="#8100B1" opacity="1.0" quantity="4" label="2.0 - 4.0"/>\
                        <ColorMapEntry color="#8100D2" opacity="1.0" quantity="1000" label="&gt; 4.0"/>\
                    </ColorMap>\
                </RasterSymbolizer>'
        },
        'riserate': {
            'sld_style': '\
                <RasterSymbolizer>\
                    <ColorMap type="intervals">\
                        <ColorMapEntry color="#FFFFFF" opacity="0.01" quantity="0.01"/>\
                        <ColorMapEntry color="#FFF5E6" opacity="1.0" quantity="0.25" label="&lt; 0.25"/>\
                        <ColorMapEntry color="#FFD2A8" opacity="1.0" quantity="0.5" label="0.25 - 0.5"/>\
                        <ColorMapEntry color="#FFAD66" opacity="1.0" quantity="1" label="0.5 - 1.0"/>\
                        <ColorMapEntry color="#EB7515" opacity="1.0" quantity="2" label="1.0 - 2.0"/>\
                        <ColorMapEntry color="#B05500" opacity="1.0" quantity="1000000" label="&gt; 2.0"/>\
                    </ColorMap>\
                </RasterSymbolizer>'
        },
        'damage': {
            'sld_style': '\
                <RasterSymbolizer>\
                    <ColorMap type="intervals">\
                        <ColorMapEntry color="#FFFFFF" opacity="0.01" quantity="0.01"/>\
                        <ColorMapEntry color="#499b1b" opacity="1.0" quantity="10000" label="&lt; 10.000"/>\
                        <ColorMapEntry color="#61f033" opacity="1.0" quantity="100000" label="10.000 - 100.000"/>\
                        <ColorMapEntry color="#ffbb33" opacity="1.0" quantity="1000000" label="100.000 - 1.000.000"/>\
                        <ColorMapEntry color="#ff3333" opacity="1.0" quantity="5000000" label="1.000.000 - 5.000.000"/>\
                        <ColorMapEntry color="#8f3333" opacity="1.0" quantity="1000000000000000" label="&gt; 5.000.000"/>\
                    </ColorMap>\
                </RasterSymbolizer>'
        },
        'fatalities': {
            'sld_style': '\
                <RasterSymbolizer>\
                    <ColorMap type="intervals">\
                        <ColorMapEntry color="#FFFFFF" opacity="0.01" quantity="0.0001"/>\
                        <ColorMapEntry color="#499b1b" opacity="1.0" quantity="0.1" label="&lt; 0.1"/>\
                        <ColorMapEntry color="#61f033" opacity="1.0" quantity="0.3" label="0.1 - 0.3"/>\
                        <ColorMapEntry color="#ffbb33" opacity="1.0" quantity="1" label="0.3 - 1"/>\
                        <ColorMapEntry color="#ff3333" opacity="1.0" quantity="3" label="1 - 3"/>\
                        <ColorMapEntry color="#8f3333" opacity="1.0" quantity="10000" label="&gt; 3"/>\
                    </ColorMap>\
                </RasterSymbolizer>'
}
    }

    # Filter based on breach location
    collection = ee.ImageCollection(raster_assets[variable])

    # TODO: how to make this generic, consider GraphQL
    collection = collection.filter(
        ee.Filter.inList('LIWO_ID', liwo_ids)
    )

    collection = collection.map(
        lambda im: im.set('bandNames', im.bandNames())
    )

    n_selected = collection.size().getInfo()

    collection = collection.filterMetadata('bandNames', 'equals', ['b1', 'b2', 'b3', 'b4', 'b5'])

    n_filtered = collection.size().getInfo()

    if n_selected != n_filtered:
        logging.warning('missing images, selected %s, filtered %s', n_selected, n_filtered)


    # Filter based on band name (characteristic to display)
    collection = collection.select(bands[band])
    n_images = collection.size().getInfo()
    msg = 'No images available for breach locations: %s' % (liwo_ids, )
    logger.debug(msg)

    if not n_images:
        raise error_handler.InvalidUsage(msg)

    # get max image
    reduce_func = getattr(ee.Reducer, reducer)()
    image = ee.Image(collection.reduce(reduce_func))
    # clip image to region and mask all 0 values (no-data value given in images) .clip(region)
    image = image.mask(image.neq(0))

    def generate_image_info(im, params):
        """generate url and tokens for image"""
        im = ee.Image(im)

        # some images are scaled to a factor of 10.
        if params.get('scale') == 'log':
            im = im.log10()

        im = im.sldStyle(params.get('sld_style'))

        m = im.getMapId()

        mapid = m.get('mapid')
        token = m.get('token')

        url = 'https://earthengine.googleapis.com/map/{mapid}/{{z}}/{{x}}/{{y}}?token={token}'.format(
            mapid=mapid,
            token=token
        )

        result = {
            'mapid': mapid,
            'token': token,
            'url': url
        }
        return result

    def export_image_response(image, region, info):
        """create export response for image"""
        url = image.getDownloadURL({
            'name': 'export',
            'format': 'tif',
            'crs': info['crs'],
            'scale': info['scale'],
            'region': json.dumps(region.bounds(info['scale']).getInfo())
        })
        result = {'export_url': url}
        return result

    # TODO: generate visualization params for map ids
    params = styles[band]

    info = generate_image_info(image, params)
    info['variable'] = variable
    info['liwo_ids'] = liwo_ids
    info['band'] = band

    # # Following needed for export:
    # # Specify region over which to compute
    # export  is True or None/False
    if r.get('export'):
        region = ee.Geometry(r['region'])
        # scale of pixels for export, in meters
        info['scale'] = float(r['scale'])
        # coordinate system for export projection
        info['crs'] = r['crs']
        extra_info = export_image_response(image, region, info)
        info.update(extra_info)

    return Response(
        json.dumps(info),
        status=200,
        mimetype='application/json'
    )