city_gen

class nomad.city_gen.City(dimensions: tuple = (0, 0), manual_streets: bool = False, name: str = 'Garden City', block_side_length: float = 15.0, web_mercator_origin_x: float = -4265699.0, web_mercator_origin_y: float = 4392976.0, rotation_deg: float = 0.0, offset_x: int = 0, offset_y: int = 0)[source]

Bases: object

Class for representing a city containing buildings, streets, and methods for city management.

buildings

A dictionary of Building objects with their IDs as keys.

Type:

dict

streets

A dictionary of Street objects with their coordinates as keys.

Type:

dict

buildings_outline

A polygon representing the combined geometry of all buildings in the city.

Type:

shapely.geometry.polygon.Polygon

city_boundary

A polygon representing the boundary of the city.

Type:

shapely.geometry.polygon.Polygon

dimensions

A tuple representing the dimensions of the city (width, height).

Type:

tuple

street_graph

A dictionary representing the graph of streets with their neighbors.

Type:

dict

shortest_paths

A dictionary containing the shortest paths between all pairs of streets.

Type:

dict

gravity

A DataFrame containing the gravity values between all pairs of streets.

Type:

pandas.DataFrame

add_building(building_type, door, geom=None, blocks=None, gdf_row=None)[source]

Adds a building to the city with the specified type, door location, and geometry.

Parameters:
  • building_type (str) – The type of the building (‘home’, ‘workplace’, ‘retail’, ‘park’).

  • door (tuple) – A tuple representing the (x, y) coordinates of the door of the building.

  • geom (shapely.geometry.polygon.Polygon, optional) – The geometry of the building (can be a box or MultiPolygon).

  • blocks (list of tuples, optional) – A list of (x, y) coordinates representing the blocks occupied by the building.

  • gdf_row (geopandas.GeoDataFrame or pandas.Series, optional) – A single row GeoDataFrame or Series containing building information.

Raises:

ValueError – If the door is not on an existing street, if the building overlaps with existing buildings, or if the geometry/blocks do not align with the grid.

add_buildings_from_gdf(buildings_gdf)[source]

Initialize or add multiple buildings from a GeoDataFrame.

Parameters:

buildings_gdf (geopandas.GeoDataFrame) – A GeoDataFrame containing building information with columns for type, door coordinates, and geometry.

Raises:

ValueError – If the GeoDataFrame lacks required columns or contains invalid data.

add_street(coords)[source]

Adds a street to the city at the specified (x, y) coordinates.

property buildings_df
check_adjacent(geom1, geom2, graph=None)[source]

Adjacency on a grid of 1x1 blocks. Returns list[bool].

compute_gravity(exponent=2.0, callable_only=False, n_chunks=10, use_proxy_hub_distance=True)[source]

Precompute building-to-building gravity from door-to-door distances.

Parameters:
  • exponent (float) – The gravity decay exponent (default 2.0)

  • callable_only (bool) – If True, store callable function instead of dense matrix (default False)

  • n_chunks (int) – Number of chunks for computing nearby doors in hub mode (default 10)

  • use_proxy_hub_distance (bool) – If True, use hub-based distance approximation (fast, scales to large cities). If False, compute true graph distances between all door pairs (slow but exact, suitable for small cities with <200 buildings). Default True.

Notes

Hub mode approximates dist(i, j) as the distance from door_i to hub_i, plus the graph distance from hub_i to hub_j, plus the distance from hub_j to door_j. True mode computes shortest_path_length(door_i, door_j) on the street graph.

Stores result in self.grav as DataFrame (callable_only=False) or callable (callable_only=True)

Persistence:

  • Hub mode (use_proxy_hub_distance=True): Gravity infrastructure is saved by save_geopackage() and restored by from_geopackage(load_gravity=True). The city.grav callable works immediately after loading.

  • True distance mode (use_proxy_hub_distance=False): Not persisted. Must call compute_gravity(…, use_proxy_hub_distance=False) after loading. This is fast for small cities (<200 buildings) where this mode is intended.

compute_shortest_paths(callable_only=False)[source]

Compute shortest paths between street blocks.

Parameters:

callable_only (bool, default False) – If False, precompute all-pairs shortest paths (only for small cities) If True, store on-demand callable (placeholder for hub-based routing)

Notes

Callable mode currently uses nx.shortest_path() on demand—this is a PLACEHOLDER. Production use with _sample_step requires hub-based routing for scalability (billions of calls). Current implementation too slow for large-scale trajectory generation.

Stores result in self.shortest_paths as dict or callable

classmethod from_geodataframes(buildings_gdf, streets_gdf, blocks_gdf=None, edges_df=None, city_boundary=None)[source]

Construct a City from buildings and streets GeoDataFrames.

classmethod from_geopackage(gpkg_path, edges_path=None, poi_cols=None, load_gravity=True)[source]
from_mercator(data)[source]

Convert Web Mercator coordinates back to city block coordinates using city’s parameters.

Parameters:

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

Returns:

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

Return type:

pd.DataFrame

get_block(coordinates)[source]

Returns information about the block at the given coordinates.

Parameters:

coordinates (tuple) – A tuple representing the (x, y) coordinates of the block.

Returns:

A dictionary containing the kind of block (‘street’ or ‘building’), the ID of the building if applicable, the type of building if applicable, and the geometry of the block.

Return type:

dict

get_building(identifier=None, door_coords=None, any_coords=None)[source]

Retrieve a building by string ID, door coordinates, or any coordinates within the city’s bounds.

Parameters:

identifierstr, optional

The string ID of the building (e.g., ‘h-x8-y8’).

door_coordstuple, optional

The (x, y) coordinates of the building’s door.

any_coordstuple, optional

Any (x, y) coordinates within the city’s bounds to find a building that contains this point.

Returns:

geopandas.GeoDataFrame or None

A GeoDataFrame with a single row containing building details if found, None otherwise.

get_building_coordinates()[source]

Get building coordinates as a DataFrame with building_id, x, y, building_type, size columns.

Returns:

DataFrame with columns: building_id, x, y, building_type, size

Return type:

pd.DataFrame

get_distance_fast(start_coord: tuple, end_coord: tuple)[source]

Return shortest path distance (number of edges) between two street cells.

Parameters:
  • start_coord (tuple[int, int]) – Starting street block (x, y).

  • end_coord (tuple[int, int]) – Ending street block (x, y).

Returns:

Number of edges in the shortest path from start to end.

Return type:

int

Notes

Uses the same shortest_paths mechanism as get_shortest_path(), but returns only the distance (len(path) - 1) for efficiency.

get_paths_fast(start_coord: tuple, end_coord: tuple)[source]

DEPRECATED: Return shortest path with LRU-style caching.

This method wraps get_shortest_path() with a simple cache. May be useful for future optimizations but currently not sufficient for large-scale trajectory generation needs.

Parameters:
  • start_coord (tuple[int, int]) – Starting street block (x, y).

  • end_coord (tuple[int, int]) – Ending street block (x, y).

Returns:

Sequence of street blocks from start to end, or empty list if no path.

Return type:

list[tuple[int, int]]

get_shortest_path(start_coord: tuple, end_coord: tuple, plot: bool = False, ax=None)[source]

Return a block path between two street cells.

Parameters:
  • start_coord (tuple[int, int]) – Starting street block (x, y).

  • end_coord (tuple[int, int]) – Ending street block (x, y).

  • plot (bool, optional) – Plot the resulting path on the city map when True.

  • ax (matplotlib.axes.Axes, optional) – Target axis used when plot=True.

Returns:

Sequence of street blocks from start to end.

Return type:

list[tuple[int, int]]

Raises:

ValueError – If either coordinate is not a valid street block or if shortest_paths has not been computed.

Notes

Requires compute_shortest_paths() to be called first. Uses precomputed paths (dict) or on-demand callable depending on mode.

get_street_graph()[source]

Build the street graph needed for routing.

plot_city(ax, doors=True, address=True, zorder=1, heatmap_agent=None, colors=None, alpha=1, legend=False)[source]

Plots the city on a given matplotlib axis.

Parameters:
  • ax (matplotlib.axes.Axes) – The axis on which to plot the city.

  • doors (bool) – Whether to plot doors of buildings.

  • address (bool) – Whether to plot the address of buildings.

  • zorder (int) – The z-order of the plot.

  • heatmap_agent (Agent) – The agent for which to plot a heatmap of time spent in each building.

  • colors (dict) – A dictionary mapping building types to colors for plotting.

  • legend (bool) – Whether to display a legend for building types.

save(filename)[source]

Saves the city object to a file.

Parameters:

filename (str) – The name of the file to save the city object to.

save_geopackage(gpkg_path, persist_blocks=True, persist_city_properties=True, persist_gravity_data=True, reverse_affine=False, edges_path=None, street_graphml_path=None)[source]

Save city to GeoPackage with all spatial objects for simulation continuity.

Parameters:
  • gpkg_path (str) – Path to GeoPackage (.gpkg) for buildings, streets, and auxiliary layers

  • persist_blocks (bool, default False) – If True, save blocks_gdf layer

  • persist_city_properties (bool, default True) – If True, save city properties (name, block_side_length, origins, etc.)

  • persist_gravity_data (bool, default True) – If True, save gravity infrastructure (hubs, distances, nearby doors)

  • reverse_affine (bool, default False) – If True, transform geometries from garden city units to Web Mercator meters

  • edges_path (str, optional) – Path to save edges parquet (ox, oy, dx, dy, distance, gravity)

  • street_graphml_path (str, optional) – Path to save street graph as GraphML

Notes

This method saves everything needed to reload and continue a simulation. Use from_geopackage() to reload.

property streets_df
to_file(buildings_path=None, streets_path=None, street_graphml_path=None, driver='GeoJSON', to_crs=None, reverse_affine=False)[source]

Export city layers to file with optional coordinate transformations.

Parameters:
  • buildings_path (str, optional) – Path to save buildings layer

  • streets_path (str, optional) – Path to save streets layer

  • street_graphml_path (str, optional) – Path to save street graph as GraphML

  • driver (str, default 'GeoJSON') – Output format: ‘GeoJSON’, ‘GPKG’, ‘Parquet’, ‘ESRI Shapefile’

  • to_crs (str or CRS, optional) – Target CRS for reprojection (e.g., ‘EPSG:4326’)

  • reverse_affine (bool, default False) – If True, transform from garden city units to Web Mercator meters using self.block_side_length, offset_x, offset_y, rotation_deg

Notes

For GeoJSON output, to_crs=’EPSG:4326’ is required if reverse_affine=True.

to_mercator(data)[source]

Convert city block coordinates to Web Mercator coordinates using city’s parameters.

Parameters:

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

Returns:

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

Return type:

pd.DataFrame

class nomad.city_gen.RandomCityGenerator(width, height, street_spacing=5, park_ratio=0.1, home_ratio=0.4, work_ratio=0.3, retail_ratio=0.2, seed=42, verbose=False)[source]

Bases: object

fill_block(block_x, block_y, block_type)[source]

Fills a block with multiple buildings of the specified type.

generate_city()[source]

Generates a systematically structured city where blocks are fully occupied with buildings.

generate_streets()[source]

Predefine streets in a systematic grid pattern using a NumPy mask.

get_adjacent_street(location)[source]

Finds the closest predefined street to assign as the door, ensuring it is within bounds.

get_block_type(x, y)[source]

Dynamically assigns a block type instead of storing all in memory.

place_buildings_in_blocks()[source]

Fills each block completely with buildings using proportional distribution.

class nomad.city_gen.RasterCity(boundary_polygon, streets_gdf, buildings_gdf, block_side_length=15.0, crs='EPSG:3857', building_type_col='building_type', name='Rasterized City', resolve_overlaps=False, other_building_behavior='keep', rotation_deg=0.0, rotation_origin=None, verbose=True)[source]

Bases: City

class nomad.city_gen.Street(coordinates: tuple = None, geometry: Polygon = None)[source]

Bases: object

Class for street block in the city through which individuals move from building to building.

coordinates

A tuple representing the (x, y) coordinates of the street block.

Type:

tuple

geometry

A polygon representing the geometry of the street block.

Type:

shapely.geometry.polygon.Polygon

id

A unique identifier for the street block, formatted as ‘s-x{coordinates[0]}-y{coordinates[1]}’.

Type:

str

(none)
nomad.city_gen.assign_block_types(blocks_gdf, streets_gdf, buildings_gdf_input)[source]
nomad.city_gen.assign_door_to_building(building_blocks, available_blocks, graph=None)[source]

Find adjacent block that can serve as door (not occupied by buildings).

nomad.city_gen.find_connected_components(block_coords: List[Tuple[int, int]], connectivity: str = '4-connected') List[Set[Tuple[int, int]]][source]
nomad.city_gen.find_intersecting_blocks(geometries_gdf: GeoDataFrame, blocks_gdf: GeoDataFrame, predicate: str = 'intersects') DataFrame[source]
nomad.city_gen.generate_canvas_blocks(boundary_polygon, block_size, crs='EPSG:3857', verbose=True, with_block_groups=False)[source]
nomad.city_gen.load(filename)[source]

Load a city object from a file.

nomad.city_gen.save(city, filename)[source]

Save the city object to a file.

nomad.city_gen.verify_street_connectivity(streets_gdf)[source]