Source code for modelly.space.geo.export
"""GeoDataFrames of a ``GeoSpace`` and writing them as GeoParquet or GeoJSON."""
from __future__ import annotations
from collections.abc import Sequence
from pathlib import Path
from typing import TYPE_CHECKING
import geopandas as gpd
import shapely
from modelly.space.geo.regions import NO_REGION
if TYPE_CHECKING:
from modelly.space.geo.space import GeoSpace
PARQUET_SUFFIXES = (".parquet", ".geoparquet")
GEOJSON_SUFFIXES = (".geojson", ".json")
[docs]
def agents_frame(space: GeoSpace, attributes: Sequence[str] = ()) -> gpd.GeoDataFrame:
"""One row per agent: ``unique_id``, ``region``, the named attributes and a point."""
agents = space.active_agents
rows = space.agent_regions()
labels = list(space.regions.index)
data = {
"unique_id": [agent.unique_id for agent in agents],
"region": [None if r == NO_REGION else labels[r] for r in rows],
}
for name in attributes:
data[name] = [getattr(agent, name) for agent in agents]
positions = space.agent_positions
geometry = shapely.points(positions[:, 0], positions[:, 1])
return gpd.GeoDataFrame(data, geometry=geometry, crs=space.crs)
[docs]
def regions_frame(space: GeoSpace) -> gpd.GeoDataFrame:
"""The regions with an ``n_agents`` column counting the agents in each."""
frame = space.regions.copy()
frame["n_agents"] = space.region_counts().to_numpy()
return frame
[docs]
def write_frame(frame: gpd.GeoDataFrame, path: Path) -> Path:
"""Write ``frame`` to ``path``: GeoParquet or GeoJSON, chosen by the suffix."""
suffix = path.suffix.lower()
if suffix in PARQUET_SUFFIXES:
frame.to_parquet(path)
elif suffix in GEOJSON_SUFFIXES:
text = frame.to_json(to_wgs84=frame.crs is not None)
path.write_text(text, encoding="utf-8", newline="\n")
else:
raise ValueError(
f"Unknown suffix {path.suffix!r}: use one of "
f"{PARQUET_SUFFIXES + GEOJSON_SUFFIXES}."
)
return path