Core Concepts¶
CityMetrix is built around four classes, all defined in city_metrix.metrix_model.
GeoZone and GeoExtent — the AOI¶
These two classes represent "where" you want data, and normalize the two input styles described in Defining an AOI:
- A geometry (
GeoDataFrame, bbox tuple, orGeoZone/GeoExtent) —geo_type = GEOMETRY. - A
city_id+aoi_idJSON string —geo_typeisCITY_AREAorCITY_CENTROID, and the actual boundary is resolved from the Cities Data API.
Both classes normalize the AOI to a consistent bounding box, centroid, and CRS, and provide as_utm_bbox() / as_geographic_bbox() to convert between projections — most raster processing happens in UTM (meters), since Earth Engine and zonal-statistics math need a projected CRS.
You'll mostly interact with GeoZone (when calling .groupby(...) or Metric.get_metric(...)) and GeoExtent (when calling Layer.get_data(...)).
Layer — one geospatial dataset¶
Every class in city_metrix.layers subclasses Layer and implements:
def get_data(self, bbox: GeoExtent, spatial_resolution: int = None, resampling_method: str = None):
...
get_data() returns either an xarray.DataArray (raster) or a GeoDataFrame (vector), clipped to bbox. Beyond get_data(), Layer provides:
.mask(*layers)— returns a newLayerthat excludes pixels/features not covered by the given mask layer(s)..groupby(geo_zone)— returns aLayerGroupBy, which computes zonal statistics (.mean(),.count(),.sum()) over one or more zones, automatically tiling large AOIs into a fishnet grid behind the scenes so Earth Engine requests stay within memory limits..write(bbox, target_file_path)— writes the layer's data to a local or S3 GeoTIFF/GeoJSON..retrieve_data(bbox, ...)— same asget_data(), but reads from the S3 cache first if a cached result already exists for this layer + AOI + parameters.
Metric — one computed indicator¶
Every class in city_metrix.metrics subclasses Metric and implements:
def get_metric(self, geo_zone: GeoZone, spatial_resolution: int = None):
...
get_metric() composes one or more Layer objects (usually via .mask() and .groupby()) and returns a pandas.Series or pandas.DataFrame of computed values — one per zone in geo_zone. Metric mirrors Layer's caching/writing API: .write(), .write_as_geojson(), .retrieve_metric().
Caching¶
Both Layer and Metric results for city AOIs are automatically cached to S3, keyed by class name and non-default constructor parameters (see Caching). Custom polygon AOIs are not cached. This is why every layer/metric class declares OUTPUT_FILE_FORMAT, MAJOR_NAMING_ATTS, and MINOR_NAMING_ATTS class attributes — they control the cache key.
Putting it together¶
GeoZone / GeoExtent → "where"
+
Layer (chained via .mask()) → "what raw/derived data"
+
.groupby(...).mean()/.count()/.sum() → "zonal statistics"
=
Metric.get_metric() → the same pattern, pre-packaged as a named indicator