map_utils

OpenStreetMap data utilities used to download, process, rotate, and persist geospatial layers for the NOMAD library.

nomad.map_utils.blocks_to_mercator(data, block_size=15.0, false_easting=-4265699.0, false_northing=4392976.0, rotation_deg=0.0, rotation_origin=None)[source]

Convert city block coordinates to Web Mercator coordinates.

This function applies an affine transformation to convert abstract city block coordinates (in units of blocks) to Web Mercator projection coordinates (EPSG:3857) in meters. The transformation is: x_mercator = block_size * x_block + false_easting

Parameters:
  • data (pd.DataFrame) – DataFrame with ‘x’, ‘y’ columns in city block coordinates

  • block_size (float, default 15.0) – Size of one city block in meters

  • false_easting (float, default -4265699.0) – False easting offset (x-origin) in Web Mercator meters

  • false_northing (float, default 4392976.0) – False northing offset (y-origin) in Web Mercator meters

  • rotation_deg (float, default 0.0) – Rotation to undo (degrees counterclockwise). If non-zero, rotates by -rotation_deg around rotation_origin after scaling and translation.

  • rotation_origin (tuple of (x, y), optional) – Rotation origin in Web Mercator coordinates. If None and rotation_deg != 0, uses (false_easting, false_northing) as origin.

Returns:

DataFrame with ‘x’, ‘y’ columns updated to Web Mercator coordinates. If ‘ha’ column exists, it is also scaled by block_size.

Return type:

pd.DataFrame

Examples

>>> import pandas as pd
>>> df = pd.DataFrame({'x': [0, 1, 2], 'y': [0, 1, 2]})
>>> result = blocks_to_mercator(df, block_size=15, false_easting=-4265699, false_northing=4392976)
>>> result['x'].tolist()
[-4265699.0, -4265684.0, -4265669.0]
nomad.map_utils.blocks_to_mercator_gdf(gdf, block_size, false_easting, false_northing, rotation_deg=0.0, drop_garden_cols=True)[source]

Transform GeoDataFrame from garden city block units to Web Mercator meters.

Parameters:
  • gdf (gpd.GeoDataFrame) – Input with geometries in garden city block units

  • block_size (float) – Block side length in meters

  • false_easting (float) – Web Mercator origin x in meters

  • false_northing (float) – Web Mercator origin y in meters

  • rotation_deg (float, default 0.0) – Rotation applied to input (will be undone by rotating -rotation_deg)

  • drop_garden_cols (bool, default True) – If True, drop coord_x, coord_y, door_cell_x, door_cell_y columns

Returns:

Transformed GeoDataFrame with CRS=’EPSG:3857’

Return type:

gpd.GeoDataFrame

Notes

Transformation sequence: 1. Scale geometries by block_size (blocks → meters) 2. Translate by false_easting, false_northing (move to Web Mercator position) 3. Rotate by -rotation_deg (undo rotation around centroid) 4. Set CRS to EPSG:3857 5. Optionally drop garden city columns

This is the GeoDataFrame equivalent of blocks_to_mercator() for DataFrames.

nomad.map_utils.download_osm_buildings(bbox_or_city, crs='EPSG:4326', schema='garden_city', clip=False, infer_building_types=False, explode=False)[source]

Download buildings + parks from OSM and categorize them.

Parameters - bbox_or_city: bbox tuple, city name, or shapely polygon - crs: output CRS - schema: category schema name - clip: retained for API parity (bbox path uses Overpass bbox) - infer_building_types: heuristics for building=”yes” - explode: explode MultiPolygons into Polygons

nomad.map_utils.download_osm_streets(bbox_or_city, crs='EPSG:4326', clip=True, clip_to_gdf=None, explode=False, graphml_path=None)[source]

Download filtered street network from OSM and return edges as GeoDataFrame.

nomad.map_utils.get_category_for_subtype(subtype, schema='garden_city')[source]

Return the category name for a subtype in the given schema.

If the subtype is not present, returns ‘unknown’ for ‘geolife_plus’ or ‘other’ for all other schemas.

nomad.map_utils.get_category_summary(gdf)[source]

Return a dict of building_type counts.

nomad.map_utils.get_city_boundary_osm(name, simplify=True, crs='EPSG:4326')[source]

Fetch a city’s boundary from OSM.

Returns a tuple of (boundary_multipolygon, center_coordinates, population). If a boundary cannot be retrieved, returns (None, None, None).

nomad.map_utils.get_subtype_summary(gdf)[source]

Return a dict of subtype counts.

nomad.map_utils.load_geodata(path: str, layer: str = None) GeoDataFrame[source]

Load a GeoDataFrame from disk based on file extension.

Supports .geojson/.json, .parquet/.geoparquet, .shp, .gpkg

nomad.map_utils.mercator_to_blocks(data, block_size=15.0, false_easting=-4265699.0, false_northing=4392976.0)[source]

Convert Web Mercator coordinates back to city block coordinates.

This function applies the inverse affine transformation to convert Web Mercator projection coordinates (EPSG:3857) in meters back to abstract city block coordinates. The transformation is: x_block = (x_mercator - false_easting) / block_size

Parameters:
  • data (pd.DataFrame) – DataFrame with ‘x’, ‘y’ columns in Web Mercator coordinates

  • block_size (float, default 15.0) – Size of one city block in meters

  • false_easting (float, default -4265699.0) – False easting offset (x-origin) in Web Mercator meters

  • false_northing (float, default 4392976.0) – False northing offset (y-origin) in Web Mercator meters

Returns:

DataFrame with ‘x’, ‘y’ columns updated to city block coordinates. If ‘ha’ column exists, it is also scaled back by dividing by block_size.

Return type:

pd.DataFrame

Examples

>>> import pandas as pd
>>> df = pd.DataFrame({'x': [-4265699.0, -4265684.0], 'y': [4392976.0, 4392991.0]})
>>> result = mercator_to_blocks(df, block_size=15, false_easting=-4265699, false_northing=4392976)
>>> result['x'].tolist()
[0.0, 1.0]
nomad.map_utils.mercator_to_blocks_gdf(gdf, block_size, false_easting, false_northing, rotation_deg=0.0)[source]

Transform GeoDataFrame from Web Mercator meters to garden city block units.

Parameters:
  • gdf (gpd.GeoDataFrame) – Input with geometries in Web Mercator (EPSG:3857)

  • block_size (float) – Block side length in meters

  • false_easting (float) – Web Mercator origin x in meters

  • false_northing (float) – Web Mercator origin y in meters

  • rotation_deg (float, default 0.0) – Rotation to apply (degrees counterclockwise)

Returns:

Transformed GeoDataFrame with CRS=None (garden city units)

Return type:

gpd.GeoDataFrame

Notes

Transformation sequence (inverse of blocks_to_mercator_gdf): 1. Rotate by rotation_deg around centroid 2. Translate by -false_easting, -false_northing (move from Web Mercator position) 3. Scale geometries by 1/block_size (meters → blocks) 4. Set CRS to None (abstract units)

This is the GeoDataFrame equivalent of mercator_to_blocks() for DataFrames.

nomad.map_utils.remove_overlaps(gdf, exclude_categories=None)[source]

Remove polygons fully contained within others, keeping one of any identical shapes.

If exclude_categories is provided and a ‘category’ column exists, rows in those categories are not considered for removal. Uses spatial indexing for efficiency.

nomad.map_utils.rotate(gdf, rotation_deg=0.0, origin='centroid')[source]

Rotate all geometries around a single origin.

Parameters - gdf: input GeoDataFrame - rotation_deg: degrees counterclockwise - origin: ‘centroid’ or a tuple of (x, y)

nomad.map_utils.rotate_streets_to_align(streets_gdf, k=200)[source]

Estimate grid alignment from street bearings and rotate the network.

Returns a tuple of (rotated_streets_gdf, rotation_degrees).

nomad.map_utils.save_geodata(gdf: GeoDataFrame, path: str, layer: str = None)[source]

Persist a GeoDataFrame to disk based on file extension.

Supported formats: - .geojson/.json -> GeoJSON - .parquet/.geoparquet -> GeoParquet - .shp -> ESRI Shapefile (multiple files created alongside) - .gpkg -> GeoPackage (layer optional, defaults to ‘data’)