Пример #1
0
def get_map_points():
    """
    Get map point data for the given place type enclosed within the given dcid
    """
    place_dcid = request.args.get("placeDcid")
    if not place_dcid:
        return Response(json.dumps("error: must provide a placeDcid field"),
                        400,
                        mimetype='application/json')
    place_type = request.args.get("placeType")
    if not place_type:
        return Response(json.dumps("error: must provide a placeType field"),
                        400,
                        mimetype='application/json')
    geos = []
    geos = dc_service.get_places_in([place_dcid],
                                    place_type).get(place_dcid, [])
    if not geos:
        return Response(json.dumps({}), 200, mimetype='application/json')
    names_by_geo = place_api.get_display_name('^'.join(geos), g.locale)
    # For some places, lat long is attached to the place node, but for other
    # places, the lat long is attached to the location value of the place node.
    # If a place has location, we will use the location value to find the lat
    # and long.
    # eg. epaGhgrpFacilityId/1003010 has latitude and longitude but no location
    # epa/120814013 which is an AirQualitySite has a location, but no latitude
    # or longitude
    location_by_geo = dc_service.get_property_values(geos, "location")
    # dict of <dcid used to get latlon>: <dcid of the place>
    geo_by_latlon_subject = {}
    for geo_dcid in geos:
        if geo_dcid in location_by_geo and len(
                location_by_geo.get(geo_dcid)) > 0:
            location_dcid = location_by_geo[geo_dcid][0]
            geo_by_latlon_subject[location_dcid] = geo_dcid
        else:
            geo_by_latlon_subject[geo_dcid] = geo_dcid
    lat_by_subject = dc_service.get_property_values(
        list(geo_by_latlon_subject.keys()), "latitude")
    lon_by_subject = dc_service.get_property_values(
        list(geo_by_latlon_subject.keys()), "longitude")

    map_points_list = []
    for subject_dcid, latitude in lat_by_subject.items():
        longitude = lon_by_subject.get(subject_dcid, [])
        if len(latitude) == 0 or len(longitude) == 0:
            continue
        if not is_float(latitude[0]) or not is_float(longitude[0]):
            continue
        geo_id = geo_by_latlon_subject.get(subject_dcid, "")
        map_point = {
            "placeDcid": geo_id,
            "placeName": names_by_geo.get(geo_id, "Unnamed Place"),
            "latitude": float(latitude[0]),
            "longitude": float(longitude[0])
        }
        map_points_list.append(map_point)
    return Response(json.dumps(map_points_list),
                    200,
                    mimetype='application/json')
Пример #2
0
def get_state_code(dcids):
    """Get state codes for a list of places that are state equivalents

    Args:
        dcids: ^ separated string of dcids of places that are state equivalents

    Returns:
        A dictionary of state codes, keyed by dcid
    """
    result = {}
    if not dcids:
        return result
    dcids = dcids.split('^')
    iso_codes = dc.get_property_values(dcids, 'isoCode', True)

    for dcid in dcids:
        state_code = None
        iso_code = iso_codes[dcid]
        if iso_code:
            split_iso_code = iso_code[0].split("-")
            if len(split_iso_code
                  ) > 1 and split_iso_code[0] == US_ISO_CODE_PREFIX:
                state_code = split_iso_code[1]
        result[dcid] = state_code

    return result
Пример #3
0
def geojson():
    """
    Get geoJson data for places enclosed within the given dcid
    """
    place_dcid = request.args.get("placeDcid")
    if not place_dcid:
        return Response(json.dumps("error: must provide a placeDcid field"),
                        400,
                        mimetype='application/json')
    place_type = request.args.get("placeType")
    if not place_type:
        place_dcid, place_type = get_choropleth_display_level(place_dcid)
    geos = []
    if place_dcid and place_type:
        geos = dc_service.get_places_in([place_dcid],
                                        place_type).get(place_dcid, [])
    if not geos:
        return Response(json.dumps({}), 200, mimetype='application/json')
    geojson_prop = CHOROPLETH_GEOJSON_PROPERTY_MAP.get(place_type, "")
    # geoId/72 needs higher resolution geojson because otherwise, the map looks
    # too fragmented
    if place_dcid == 'geoId/72':
        geojson_prop = 'geoJsonCoordinatesDP1'
    names_by_geo = place_api.get_display_name('^'.join(geos), g.locale)
    geojson_by_geo = dc_service.get_property_values(geos, geojson_prop)
    features = []
    for geo_id, json_text in geojson_by_geo.items():
        if json_text and geo_id in names_by_geo:
            geo_feature = {
                "type": "Feature",
                "geometry": {
                    "type": "MultiPolygon",
                },
                "id": geo_id,
                "properties": {
                    "name": names_by_geo.get(geo_id, "Unnamed Area"),
                    "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']))
            features.append(geo_feature)
    return Response(json.dumps({
        "type": "FeatureCollection",
        "features": features,
        "properties": {
            "current_geo": place_dcid
        }
    }),
                    200,
                    mimetype='application/json')
Пример #4
0
def get_map_points():
    """
    Get map point data for the given place type enclosed within the given dcid
    """
    place_dcid = request.args.get("placeDcid")
    if not place_dcid:
        return Response(json.dumps("error: must provide a placeDcid field"),
                        400,
                        mimetype='application/json')
    place_type = request.args.get("placeType")
    if not place_type:
        return Response(json.dumps("error: must provide a placeType field"),
                        400,
                        mimetype='application/json')
    geos = []
    geos = dc_service.get_places_in([place_dcid],
                                    place_type).get(place_dcid, [])
    if not geos:
        return Response(json.dumps({}), 200, mimetype='application/json')
    names_by_geo = place_api.get_display_name('^'.join(geos), g.locale)
    latitude_by_geo = dc_service.get_property_values(geos, "latitude")
    longitude_by_geo = dc_service.get_property_values(geos, "longitude")

    map_points_list = []
    for geo_id, latitude in latitude_by_geo.items():
        longitude = longitude_by_geo.get(geo_id, [])
        if len(latitude_by_geo) == 0 or len(longitude) == 0:
            continue
        map_point = {
            "placeDcid": geo_id,
            "placeName": names_by_geo.get(geo_id, "Unnamed Place"),
            "latitude": float(latitude[0]),
            "longitude": float(longitude[0])
        }
        map_points_list.append(map_point)
    return Response(json.dumps(map_points_list),
                    200,
                    mimetype='application/json')
Пример #5
0
def get_sublevel(requested_geoDcid, display_level):
    """Returns the best sublevel display for a geoDcid.

    Args:
        requested_geoDcid: The parent geo DCID to find children.
        display_level: Display level provided or None. Valid display_levels
            are [AdministrativeLevel1, AdministrativeLevel2]
    Returns:
       Directly returns display_level argument if it is not none.
        Otherwise the next sublevel below the parent is returned.
    """
    if not display_level:
        requested_geoDcid_type = dc.get_property_values([requested_geoDcid],
                                                        "typeOf")
        for level in requested_geoDcid_type.get(requested_geoDcid, []):
            if level in LEVEL_MAP:
                return LEVEL_MAP[level]
    return display_level
Пример #6
0
def geojson(dcid):
    """
    Get geoJson data for a given place
    """
    geos, geojson_prop = get_choropleth_places(dcid)
    if not geos:
        return Response(json.dumps({}), 200, mimetype='application/json')

    names_by_geo = place_api.get_display_name('^'.join(geos), g.locale)
    geojson_by_geo = dc_service.get_property_values(geos, geojson_prop)
    features = []
    for geo_id, json_text in geojson_by_geo.items():
        if json_text and geo_id in names_by_geo:
            geo_feature = {
                "type": "Feature",
                "geometry": {
                    "type": "MultiPolygon",
                },
                "id": geo_id,
                "properties": {
                    "name": names_by_geo.get(geo_id, "Unnamed Area"),
                    "hasSublevel": False,
                    "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'] = (
                choropleth_api.coerce_geojson_to_righthand_rule(
                    geojson['coordinates'], geojson['type']))
            features.append(geo_feature)
    return Response(json.dumps({
        "type": "FeatureCollection",
        "features": features,
        "properties": {
            "current_geo": dcid
        }
    }),
                    200,
                    mimetype='application/json')
Пример #7
0
def get_sublevel(requested_geoDcid, display_level):
    """Returns the best sublevel display for a geoDcid.

    Args:
        requested_geoDcid: The parent geo DCID to find children.
        display_level: Display level provided or None. Valid display_levels
            are [AdministrativeLevel1, AdministrativeLevel2, City]
    Returns:
       Directly returns display_level argument if it is not none.
        Otherwise the next sublevel below the parent is returned.
    """
    if not display_level:
        requested_geoDcid_type = dc.get_property_values(
            [requested_geoDcid], "typeOf")[requested_geoDcid]
        # TODO(iancostello): Handle a failed function call, e.g., returns None.
        # TODO(iancostello): Handle the case where display_level is None.
        for level in requested_geoDcid_type:
            if level in LEVEL_MAP:
                return LEVEL_MAP[level]
    return display_level
Пример #8
0
def api_nearby_places(dcid):
    """
    Get the nearby places for a given place.
    """
    req_json = {
        'dcids': [dcid],
        'property': 'nearbyPlaces',
        'direction': 'out'
    }
    url = dc.API_ROOT + dc.API_ENDPOINTS['get_property_values']
    payload = dc.send_request(url, req_json=req_json)
    prop_values = payload[dcid].get('out')
    if not prop_values:
        return json.dumps([])
    places = []
    for prop_value in prop_values:
        places.append(prop_value['value'].split('@'))
    places.sort(key=lambda x: x[1])
    dcids = [place[0] for place in places]
    data = dc.get_property_values(dcids, 'typeOf', True)
    return json.dumps(data)
Пример #9
0
    def get_data(self):
        gr = self.get_params.get('gr') is not None  # Growth Rate
        dcids = self.get_params.getlist('mid')
        place_args = {'': (dcids, ch.parse_pop_obs_args(self.get_params, ''))}
        place_dcid = dcids[0]
        pc = self.get_params.get('pc')
        num_to_include = self.get_params.get('n')
        num_to_include = int(
            num_to_include if num_to_include else ch.DEFAULT_NUM_BARS)
        po_args = ch.parse_pop_obs_args(self.get_params)

        chart_type = self.get_params.get('t')
        logging.info('chart type %s', chart_type)
        if chart_type == 'mp':
            plot_data, dcid_name = self.get_plot_data(place_args, pc, gr)
            return self.render_chart_mp(plot_data, dcid_name, dcids,
                                        po_args['observationDate'])

        elif chart_type == 'op':
            place_type = self.get_params.get('placet')
            order = self.get_params.get('order')
            is_top = (order if order else '').lower() == 'highest'
            is_comp = self.get_params.get('comp') is not None

            if po_args['popType'] == 'AcademicAssessmentEvent':
                if po_args['constraints']['schoolSubject'] == 'Mathematics':
                    place_vals = [(u'nces/260110307481', 1503.7),
                                  (u'nces/260023201202', 1500.1),
                                  (u'nces/260110307754', 1497.0),
                                  ('nces/260027801484', 1495.2)]
                    place_names = {
                        'nces/260110307481': 'Bates Academy',
                        'nces/260023201202':
                        'Detroit Edison Public School Academy',
                        'nces/260110307754': 'Clippert Academy',
                        'nces/260027801484': 'Detroit Merit Charter Academy'
                    }
                else:
                    place_vals = [(u'nces/260110307481', 1496.6),
                                  (u'nces/260110304675', 1490.1),
                                  (u'nces/260023201202', 1486.9),
                                  ('nces/260013908078', 1484.7)]
                    place_names = {
                        'nces/260110307481': 'Bates Academy',
                        'nces/260110304675': 'Chrysler Elementary School',
                        'nces/260023201202':
                        'Detroit Edison Public School Academy',
                        'nces/260013908078':
                        'Cesar Chavez Academy Intermediate'
                    }

            else:
                # Handle errors better
                places = ch.get_and_filter_places_in(place_dcid, place_type)
                place_obs = datacommons.get_place_obs(
                    place_type, po_args['observationDate'], po_args['popType'],
                    po_args['constraints'])
                place_vals, place_names = ch.filter_place_obs_vals(
                    places, place_obs, po_args)
                place_pop = None
                if pc:
                    dcids = place_vals
                    place_population = ch.get_place_population(dcids)
                    od = po_args['observationDate']
                    place_pop = {
                        dcid: place_population[(dcid, od)]
                        for dcid in place_vals
                    }
                    place_vals = per_capita(place_vals, place_pop)
                place_vals = top_values(place_vals, num_to_include, is_top,
                                        is_comp)
            return self.render_chart_op(place_vals, place_names,
                                        num_to_include, is_comp)
        elif chart_type == 'rp':
            if pc:
                try:
                    pc = int(pc)
                    assert pc >= 1
                except:
                    raise ValueError(
                        'pc option must be a positive integer: %r' % pc)
            place_ranks = {
                'geoId/2603000':
                (999, 'USA Cities'),  # Ann Arbor, among all cities
                'geoId/0649670': (999, 'USA Cities'),  # MTV, among all cities
                'geoId/26': (999, 'USA States'),  # Michigan, among all States
                'geoId/2622000': (999, 'USA Cities')  # Detroit
            }
            DETROIT_5G_MATH_CPV = {
                'assessmentType': 'MichiganStudentTestOfEducationalProgress',
                'schoolGradeLevel': 'SchoolGrade5',
                'schoolSubject': 'Mathematics'
            }
            DETROIT_5G_ELA_CPV = {
                'assessmentType': 'MichiganStudentTestOfEducationalProgress',
                'schoolGradeLevel': 'SchoolGrade5',
                'schoolSubject': 'EnglishLanguageArts'
            }

            if (place_dcid == 'geoId/2622000'
                    and po_args['popType'] == 'AcademicAssessmentEvent'
                    and po_args['measuredProp'] == 'scaledScore'
                    and po_args['statType'] == 'meanValue'
                    and po_args['observationDate']
                    == "2019"):  # make sure our hardcoding doesn't overtrigger
                places = ['geoId/2622000', 'geoId/26163', 'geoId/26']

                if po_args['constraints'] == DETROIT_5G_MATH_CPV:
                    place_vals = {
                        'geoId/2622000': 1463.2,
                        'geoId/26163': 1480.1,
                        'geoId/26': 1487.6
                    }
                elif po_args['constraints'] == DETROIT_5G_ELA_CPV:
                    place_vals = {
                        'geoId/2622000': 1471.9,
                        'geoId/26163': 1488.9,
                        'geoId/26': 1496.0
                    }
            else:
                places = [place_dcid] + ch.get_ancestor_places(place_dcid)

                # pl_dcid: pop_dcid
                place_pops = datacommons.get_populations(
                    places, po_args['popType'], po_args['constraints'])
                # pop_dcid: obs_val
                pop_obs = datacommons.get_observations(
                    place_pops.values(), po_args['measuredProp'],
                    po_args['statType'], po_args['observationDate'],
                    po_args['observationPeriod'], po_args['measurementMethod'])
                # pl_dcid: obs_val
                place_vals = {
                    pl_dcid: pop_obs[pop_dcid]
                    for pl_dcid, pop_dcid in place_pops.items()
                }
                # Hardcoding, but ultimately changed again in render_chart_rp due to pc
                place_vals['geoId/26'] = -999
                place_vals['country/USA'] = -999

            place_names = {
                k: v[0]
                for k, v in datacommons.get_property_values(places,
                                                            'name').items()
            }

            if pc:
                place_population = ch.get_place_population(places)
                population_od = po_args['observationDate'][:4]
                # TODO(b/149601841): URGENT--replace this with reading latest_obs_date
                if population_od > '2018':
                    population_od = '2018'

                place_pop = {
                    dcid: place_population[(dcid, population_od)]
                    for dcid in places
                }
                place_vals = per_capita(place_vals, place_pop, factor=pc)
            # Order by place type
            ordered_place_data = collections.OrderedDict()
            for p in places:
                ordered_place_data[p] = {
                    'val': place_vals.get(p),
                    'rank': place_ranks.get(p),
                    'name': place_names.get(p)
                }
            return self.render_chart_rp(ordered_place_data)
        elif chart_type == 'av':
            pop_obs = datacommons.get_pop_obs(place_dcid)
            pops = pop_obs['populations']
            kept_pop_ids, cp = filter_pops_obs(pops, po_args)
            kept_obs = {}
            for pop_id in kept_pop_ids:
                obs = filter_obs(pops[pop_id], po_args)
                if obs:
                    v = pops[pop_id]['propertyValues'][cp]
                    kept_obs[v] = obs
            if pc:
                place_population = ch.get_place_population([place_dcid])
                od = po_args['observationDate']
                scale = place_population[(place_dcid, od)]
            else:
                scale = 1
            return self.render_chart_av(kept_obs, num_to_include,
                                        po_args['statType'], cp, scale)
Пример #10
0
def get_property_value(dcid, prop, out=True):
    return dc.get_property_values([dcid], prop, out)[dcid]
Пример #11
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)
Пример #12
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)
Пример #13
0
def get_property_value(dcids, prop):
    """Returns the property values for given node dcids and property label."""
    response = dc.get_property_values(dcids.split('^'), prop)
    return Response(json.dumps(response), 200, mimetype='application/json')