Example #1
0
def get_stats_wrapper(dcid_str, stats_var):
    """Wrapper function to get stats for multiple places and give statsvar.

    This wrapper takes concatenated place dcids as a string argument so the
    flask cache can work.

    Args:
        dcid_str: place dcids concatenated by "^".
        stats_var: the dcid of the statistical variable.
    Returns:
        An serialized json str. The json is an object keyed by the place dcid
        with value to be the observation time series.
    """
    dcids = dcid_str.split('^')
    return json.dumps(dc.get_stats(dcids, stats_var))
Example #2
0
def choropleth_values():
    """Returns data for geographic subregions for a certain statistical
            variable.

    API Params:
        geoDcid: The currently viewed geography to render, as a string.
        level: The subgeographic level to pull and display information for,
                as a string. Choices: Country, AdministrativeLevel[1/2], City.
        statVar: The statistical variable to pull data about.

    API Returns:
        values: dictionary of geo to statistical variable values (as a float)
            for all subgeos.
    """
    # Get required request parameters.
    requested_geoDcid = flask.request.args.get("geoDcid")
    if not requested_geoDcid:
        return flask.jsonify({"error": "Must provide a 'geoDcid' field!"}, 400)
    stat_var = flask.request.args.get("statVar")
    if not stat_var:
        return flask.jsonify({"error": "Must provide a 'statVar' field!"}, 400)
    display_level = get_sublevel(requested_geoDcid,
                                 flask.request.args.get("level"))
    if not display_level:
        return flask.jsonify(
            {
                "error":
                f"Failed to automatically resolve geographic subdivision level for"
                +
                f"{requested_geoDcid}. Please provide a 'level' field manually."
            }, 400)

    # Get all subgeos.
    geos_contained_in_place = dc.get_places_in([requested_geoDcid],
                                               display_level).get(
                                                   requested_geoDcid, [])
    values_by_geo = dc.get_stats(geos_contained_in_place, stat_var)

    # Add to dictionary for response.
    populations_by_geo = {}
    for geo_id, payload in values_by_geo.items():
        if payload and "data" in payload:
            latest_data = get_latest_data(payload)
            if latest_data:
                populations_by_geo[geo_id] = latest_data

    # Return as json payload.
    return flask.jsonify(populations_by_geo, 200)
Example #3
0
def get_stats_wrapper(dcid_str, stats_var):
    """Wrapper function to get stats for multiple places and give statsvar.

    This wrapper takes concatenated place dcids as a string argument so the
    flask cache can work.

    Args:
        dcid_str: place dcids concatenated by "^".
        stats_var: the dcid of the statistical variable.
    Returns:
        An serialized json str. The json is an object keyed by the place dcid
        with value to be the observation time series.
    """
    dcids = dcid_str.split('^')
    result = dc.get_stats(dcids, stats_var)
    for dcid in result:
        if not result[dcid]:
            # Convert {} to None so client side sees null instead of {}
            result[dcid] = None
    return json.dumps(result)
Example #4
0
def choropleth_geo():
    """Returns data for geographic subregions for a certain statistical
            variable.

    API Params:
        geoDcid: The currently viewed geography to render, as a string.
        level: The subgeographic level to pull and display information for,
                as a string. Choices: Country, AdministrativeLevel[1/2], City.
        mdom: The measurement denominator to use as a string.
            Defaults to "Count_Person".


    API Returns:
        geoJson: geoJson format that includes statistical variables info,
            geoDcid, and name for all subregions.
    """
    # Get required request parameters.
    requested_geoDcid = flask.request.args.get("geoDcid")
    if not requested_geoDcid:
        return flask.jsonify({"error": "Must provide a 'geoDcid' field!"}, 400)
    display_level = get_sublevel(requested_geoDcid,
                                 flask.request.args.get("level"))
    geo_json_prop = GEOJSON_PROPERTY_MAP.get(display_level, None)
    if not display_level:
        return flask.jsonify(
            {
                "error":
                f"Failed to automatically resolve geographic subdivision level for"
                +
                f"{requested_geoDcid}. Please provide a 'level' field manually."
            }, 400)
    if not geo_json_prop:
        return flask.jsonify(
            {
                "error":
                f"Geojson data is not available for the geographic subdivision"
                + f"level needed for {requested_geoDcid}."
            }, 400)
    # Get optional fields.
    measurement_denominator = flask.request.args.get("mdom",
                                                     default="Count_Person")

    # Get list of all contained places.
    geos_contained_in_place = dc.get_places_in([requested_geoDcid],
                                               display_level).get(
                                                   requested_geoDcid, [])

    # Download statistical variable, names, and geojson for subgeos.
    # Also, handle the case where only a fraction of values are returned.
    names_by_geo = dc.get_property_values(
        geos_contained_in_place + [requested_geoDcid], "name")
    geojson_by_geo = dc.get_property_values(geos_contained_in_place,
                                            geo_json_prop)

    # Download population data if per capita.
    # TODO(iancostello): Determine how to handle populations
    # and statistical values from different times.
    population_by_geo = dc.get_stats(geos_contained_in_place,
                                     measurement_denominator)

    # Process into a combined json object.
    features = []
    for geo_id, json_text in geojson_by_geo.items():
        # Valid response needs at least geometry and a name.
        if not json_text:
            continue
        if geo_id not in names_by_geo:
            continue
        geo_feature = {
            "type": "Feature",
            "geometry": {
                "type": "MultiPolygon",
            },
            "id": geo_id,
            "properties": {
                # Choose the first name when multiple are present.
                "name": names_by_geo.get(geo_id, ["Unnamed Area"])[0],
                "hasSublevel": (display_level in LEVEL_MAP),
                "geoDcid": geo_id,
            }
        }

        # Load, simplify, and add geoJSON coordinates.
        # Exclude geo if no or multiple renderings are present.
        if len(json_text) != 1:
            continue

        geojson = json.loads(json_text[0])
        geo_feature['geometry']['coordinates'] = (
            coerce_geojson_to_righthand_rule(geojson['coordinates'],
                                             geojson['type']))

        if geo_id not in population_by_geo:
            continue

        population_payload = population_by_geo[geo_id]
        data = get_data(population_payload)

        # TODO(edumorales): return the population
        # for N date that all places have in common.
        if data:
            max_date = max(data)
            geo_feature["properties"]["pop"] = data[max_date]

        # Add to main dataframe.
        features.append(geo_feature)

    # Return as json payload.
    return flask.jsonify(
        {
            "type": "FeatureCollection",
            "features": features,
            "properties": {
                "current_geo":
                names_by_geo.get(requested_geoDcid, ["Unnamed Area"])[0]
            }
        }, 200)
Example #5
0
def choropleth_geo():
    """Returns data for geographic subregions for a certain statistical 
            variable.

    API Params:
        geoDcid: The currently viewed geography to render, as a string.
        level: The subgeographic level to pull and display information for,
                as a string. Choices: Country, AdministrativeLevel[1/2], City.
        mdom: The measurement denominator to use as a string.
            Defaults to "Count_Person".


    API Returns:
        geoJson: geoJson format that includes statistical variables info,
            geoDcid, and name for all subregions.
    """
    # Get required request parameters.
    requested_geoDcid = flask.request.args.get("geoDcid")
    if not requested_geoDcid:
        return flask.jsonify({"error": "Must provide a 'geoDcid' field!"}, 400)
    display_level = get_sublevel(requested_geoDcid,
                                 flask.request.args.get("level"))

    # Get optional fields.
    measurement_denominator = flask.request.args.get("mdom",
                                                     default="Count_Person")

    # Get list of all contained places.
    # TODO(iancostello): Handle a failing function call.
    geos_contained_in_place = dc.get_places_in(
        [requested_geoDcid], display_level)[requested_geoDcid]

    # Download statistical variable, names, and geojson for subgeos.
    # TODO(iancostello): Handle failing function calls.
    # Also, handle the case where only a fraction of values are returned.
    names_by_geo = dc.get_property_values(
        geos_contained_in_place + [requested_geoDcid], "name")
    geojson_by_geo = dc.get_property_values(geos_contained_in_place,
                                            "geoJsonCoordinates")

    # Download population data if per capita.
    # TODO(iancostello): Determine how to handle populations
    # and statistical values from different times.
    population_by_geo = dc.get_stats(geos_contained_in_place,
                                     measurement_denominator)

    # Process into a combined json object.
    features, values = [], []
    for geo_id, json_text in geojson_by_geo.items():
        # Valid response needs at least geometry and a name.
        if json_text and geo_id in names_by_geo:
            geo_feature = {
                "type": "Feature",
                "geometry": {
                    "type": "MultiPolygon",
                },
                "id": geo_id,
                "properties": {
                    # Choose the first name when multiple are present.
                    # TODO(iancostello): Implement a better approach.
                    "name": names_by_geo[geo_id][0],
                    "hasSublevel": (display_level in LEVEL_MAP),
                    "geoDcid": geo_id,
                }
            }
            # Load, simplify, and add geoJSON coordinates.
            # First returned value is chosen always.
            # TODO(iancostello): Implement a better approach.
            geojson = json.loads(json_text[0])
            geo_feature['geometry']['coordinates'] = (
                coerce_geojson_to_righthand_rule(geojson['coordinates'],
                                                 geojson['type']))
            # Process Statistical Observation if valid.
            if ('data' in population_by_geo.get(geo_id, [])):
                # Grab the latest available data.
                geo_feature["properties"]["pop"] = next(
                    iter(reversed(population_by_geo[geo_id]['data'].values())))

            # Add to main dataframe.
            features.append(geo_feature)

    # Return as json payload.
    return flask.jsonify(
        {
            "type": "FeatureCollection",
            "features": features,
            "properties": {
                # TODO(iancostello): Don't just pick the first and check.
                "current_geo": names_by_geo[requested_geoDcid][0]
            }
        },
        200)
Example #6
0
def get_stats_wrapper(dcid_str, stats_var):
    dcids = dcid_str.split('^')
    return json.dumps(dc.get_stats(dcids, stats_var))