from pygeoif.geometry import mapping from shapely.geometry import shape from shapely.geometry.point import Point def merge_features(geojson, condition, aggregate={}): """Merge the geometries using shapely's union for all the geojson's features that meet the condition, condition get's passed an item of feature. Then aggregate the properties in the aggregate dict using a function that get as input the list of property values off alle matched features. Operates inplace.""" indices = [index for index, feature in enumerate(geojson['features']) if condition(feature)] if len(indices) == 0: # also if there is one index, we return geojson properties = { prop: agg([ properties_[prop] for index in indices for properties_ in [geojson['features'][index]['properties']] if prop in properties_ ]) for prop, agg in aggregate.items() } properties.update({ key: value for index in indices for key, value in geojson['features'][index]['properties'].items() if key not in aggregate }) if len(indices) == 1: geojson['features'][indices[0]]['properties'] = properties return geojson union = shape(geojson['features'][indices[0]]['geometry']) for index in indices[1:]: union = union.union(shape(geojson['features'][index]['geometry'])) for index in indices[::-1]: # reverse, such that the 'todo' indices willnot change. del geojson['features'][index] geojson['features'].append({ 'geometry': mapping(union), 'properties': properties }) return geojson def inject_geojson_regions_into_dataframe( geojson, dataframe, latitude_column='latitude', longitude_column='longitude', region_name_property='name', region_name_column='region' ): """adds a region_name_column column to the dataframe with the region name as specified in the region_name_property of the geojson, by checking which geojson feature geometrically contains the longitude and latitude of the dataframe's row. This allows for faster cross reference between the geojson and the dataframe compared to always checking shape-point containment when cross referencing. Operates in place.""" shapes = { feature['properties'][region_name_property]: shape(feature['geometry']) for feature in geojson['features'] } def get_region_name(point): nonlocal shapes for region_name, region_shape in shapes.items(): if region_shape.contains(point): return region_name point_to_region_name = { (latitude, longitude): get_region_name(point) for latitude, longitude in set(zip(dataframe[latitude_column], dataframe[longitude_column])) for point in [Point(longitude, latitude)] # alias } dataframe[region_name_column] = [ point_to_region_name[(latitude, longitude)] for latitude, longitude in zip(dataframe[latitude_column], dataframe[longitude_column]) ] return dataframe