Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add indicator percentpop euclidean proximity to openspace #83

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
5 changes: 5 additions & 0 deletions city_metrix/layers/layer.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ def mean(self):

def count(self):
return self._zonal_stats("count")

def sum(self):
return self._zonal_stats("sum")

def _zonal_stats(self, stats_func):
if box(*self.zones.total_bounds).area <= MAX_TILE_SIZE_DEGREES**2:
Expand Down Expand Up @@ -315,6 +318,8 @@ def _aggregate_stats(df, stats_func):
elif stats_func == "mean":
# mean must weight by number of pixels used for each tile
return (df["mean"] * df["count"]).sum() / df["count"].sum()
elif stats_func == "sum":
return df["sum"].sum()


def get_stats_funcs(stats_func):
Expand Down
12 changes: 11 additions & 1 deletion city_metrix/layers/open_street_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,16 @@ class OpenStreetMapClass(Enum):


class OpenStreetMap(Layer):
def __init__(self, osm_class=None, **kwargs):
"""
Attributes:
osm_class: Enum value from OpenStreetMapClass
buffer_distance: meters distance for buffer around osm features
"""

def __init__(self, osm_class=None, buffer_distance=None, **kwargs):
super().__init__(**kwargs)
self.osm_class = osm_class
self.buffer_distance = buffer_distance # meters

def get_data(self, bbox):
north, south, east, west = bbox[3], bbox[1], bbox[0], bbox[2]
Expand Down Expand Up @@ -74,4 +81,7 @@ def get_data(self, bbox):
crs = get_utm_zone_epsg(bbox)
osm_feature = osm_feature.to_crs(crs)

if self.buffer_distance:
osm_feature['geometry'] = osm_feature.geometry.buffer(self.buffer_distance)

return osm_feature
5 changes: 3 additions & 2 deletions city_metrix/metrics/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from .built_land_without_tree_cover import built_land_without_tree_cover
from .built_land_with_low_surface_reflectivity import built_land_with_low_surface_reflectivity
from .built_land_with_high_land_surface_temperature import built_land_with_high_land_surface_temperature
from .era_5_met_preprocessing import era_5_met_preprocessing
from .mean_tree_cover import mean_tree_cover
from .urban_open_space import urban_open_space
from .natural_areas import natural_areas
from .era_5_met_preprocessing import era_5_met_preprocessing
from .pop_open_space import pop_open_space
from .urban_open_space import urban_open_space
13 changes: 13 additions & 0 deletions city_metrix/metrics/pop_open_space.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from geopandas import GeoDataFrame, GeoSeries
from city_metrix.layers import OpenStreetMap, OpenStreetMapClass, WorldPop


def pop_open_space(zones: GeoDataFrame, buffer_distance=400) -> GeoSeries:
# (Later add agesex_classes)
pop = WorldPop()
open_space = OpenStreetMap(osm_class=OpenStreetMapClass.OPEN_SPACE, buffer_distance=buffer_distance)

pop_open_space_sum = pop.mask(open_space).groupby(zones).sum()
pop_sum = pop.groupby(zones).sum()

return pop_open_space_sum / pop_sum
7 changes: 7 additions & 0 deletions tests/test_metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,13 @@ def test_natural_areas():
assert expected_zone_size == actual_indicator_size


def test_pop_open_space():
indicator = pop_open_space(ZONES)
expected_zone_size = ZONES.geometry.size
actual_indicator_size = indicator.size
assert expected_zone_size == actual_indicator_size


def test_urban_open_space():
indicator = urban_open_space(ZONES)
expected_zone_size = ZONES.geometry.size
Expand Down
Loading