fio-l2-cairo-mixedgeom-split
Map (reference ← swipe → agent)
0:00
Heritage analyst here. I've put together `heritage_sites.geojson` from my own field work, and every site in it is several features sharing a `site_id`. I need to load the data into our desktop tool, which only ingests typed GPKG layers, no mixed-geometry files, and every feature has to be single-part. Can you give me back `heritage.gpkg` with three layers named `points`, `lines`, and `polygons`, keeping the `site_id` on every feature so I don't lose the cross-layer link? Use Egypt's national grid.
0:00
System info
{
"adapter": "openrouter",
"model": "google/gemma-4-26b-a4b-it",
"base_url": "https://openrouter.ai/api/v1"
}
0:05
Bash
ls -F
ls -F
heritage_sites.geojson
0:09
Write
/work/check_data.py
content · 13 lines · py
import geopandas as gpd
# Load the data
gdf = gpd.read_file('heritage_sites.geojson')
# Print info to understand the structure
print("Original GeoDataFrame info:")
print(gdf.info())
print("\nFirst few rows:")
print(gdf.head())
print("\nGeometry types present:")
print(gdf.geometry.type.unique())
Wrote /work/check_data.py (298 chars).
0:13
Bash
python /work/check_data.py
python /work/check_data.py
Original GeoDataFrame info:
<class 'geopandas.geodataframe.GeoDataFrame'>
RangeIndex: 50 entries, 0 to 49
Data columns (total 5 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 site_id 50 non-null str
1 feature_kind 50 non-null str
2 name_en 50 non-null str
3 name_ar 50 non-null str
4 geometry 50 non-null geometry
dtypes: geometry(1), str(4)
memory usage: 5.4 KB
None
First few rows:
site_id ... geometry
0 EG-CAI-001 ... POLYGON ((31.256 30.0316, 31.2572 30.0316, 31....
1 EG-CAI-001 ... LINESTRING (31.2556 30.0321, 31.2566 30.0322, ...
2 EG-CAI-001 ... LINESTRING (31.2567 30.0312, 31.2566 30.0322, ...
3 EG-CAI-001 ... POINT (31.2566 30.0326)
4 EG-CAI-001 ... POINT (31.257 30.0322)
[5 rows x 5 columns]
Geometry types present:
<ArrowStringArray>
['Polygon', 'LineString', 'Point', 'MultiPolygon']
Length: 4, dtype: str
0:42
Write
/work/solve.py
content · 65 lines · py
import geopandas as gpd
def process_heritage_data(input_file, output_file):
# Load the data
gdf = gpd.read_file(input_file)
# Egypt's national grid: EPSG:22992 (Egypt Red Belt)
# or EPSG:32636 (WGS 84 / UTM zone 36N) is commonly used.
# Since the prompt mentions "Egypt's national grid",
# let's try to find a standard one. EPSG:22992 is a common choice for Egypt.
# However, if the input is WGS84, we'll transform it.
target_crs = "EPSG:22992" # Egypt Red Belt
# Ensure we are working with a CRS
if gdf.crs is None:
# Assuming WGS84 if not specified
gdf.set_crs("EPSG:4326", inplace=True)
# Transform to target CRS
gdf = gdf.to_crs(target_crs)
# Separate geometries and ensure they are single-part
# We create three separate DataFrames: points, lines, polygons
# 1. Polygons (including MultiPolygons, but exploded to single part)
# We explode multi-geometries to ensure single-part
gdf_exploded = gdf.explode(index_parts=False)
polygons = gdf_exploded[gdf_exploded.geometry.type.isin(['Polygon'])]
lines = gdf_exploded[gdf_exploded.geometry.type.isin(['LineString'])]
points = gdf_exploded[gdf_exploded.geometry.type.isin(['Point'])]
# If there are MultiLineStrings or MultiPoints, explode them too if they weren't caught
# But explode(index_parts=False) usually handles that.
# Let's double check the types after explode
# Sometimes LineString becomes MultiLineString if not careful, but explode handles it.
# Create the GeoPackage
# We need to write them to different layers
# First, clear/create the file? gpd.to_file with mode='w' creates/overwrites.
# To write multiple layers, we use mode='a' for subsequent layers or just write one by one.
# Write Polygons
if not polygons.empty:
polygons.to_file(output_file, layer='polygons', driver="GPKG")
# Write Lines (append to existing GPKG)
if not lines.empty:
lines.to_file(output_file, layer='lines', driver="GPKG", mode='a')
# Write Points (append to existing GPKG)
if not points.empty:
points.to_file(output_file, layer='points', driver="GPKG", mode='a')
print(f"Successfully created {output_file}")
print(f"Polygons: {len(polygons)} features")
print(f"Lines: {len(lines)} features")
print(f"Points: {len(points)} features")
if __name__ == "__main__":
process_heritage_data('heritage_sites.geojson', 'heritage.gpkg')
Wrote /work/solve.py (2546 chars).
0:45
Bash
python /work/solve.py
python /work/solve.py
Successfully created heritage.gpkg Polygons: 15 features Lines: 15 features Points: 25 features
1:02
Write
/work/verify.py
content · 23 lines · py
import geopandas as gpd
def verify_output(output_file):
import fiona
print(f"Verifying {output_file}:")
layers = fiona.listlayers(output_file)
print(f"Layers found: {layers}")
for layer in layers:
gdf = gpd.read_file(output_file, layer=layer)
print(f"\nLayer: {layer}")
print(f"CRS: {gdf.crs}")
print(f"Count: {len(gdf)}")
print(f"Geometry types: {gdf.geometry.type.unique()}")
print(f"Sample site_id: {gdf['site_id'].head().tolist()}")
# Check if any are multi-part
multi_types = gdf.geometry.type.value_counts()
print(f"Geometry type distribution:\n{multi_types}")
if __name__ == "__main__":
verify_output('heritage.gpkg')
Wrote /work/verify.py (733 chars).
1:04
Bash
python /work/verify.py
python /work/verify.py
Verifying heritage.gpkg: Layers found: ['polygons', 'lines', 'points'] Layer: polygons CRS: EPSG:22992 Count: 15 Geometry types: <ArrowStringArray> ['Polygon'] Length: 1, dtype: str Sample site_id: ['EG-CAI-001', 'EG-CAI-002', 'EG-CAI-002', 'EG-CAI-003', 'EG-CAI-003'] Geometry type distribution: Polygon 15 Name: count, dtype: int64 Layer: lines CRS: EPSG:22992 Count: 15 Geometry types: <ArrowStringArray> ['LineString'] Length: 1, dtype: str Sample site_id: ['EG-CAI-001', 'EG-CAI-001', 'EG-CAI-002', 'EG-CAI-003', 'EG-CAI-003'] Geometry type distribution: LineString 15 Name: count, dtype: int64 Layer: points CRS: EPSG:22992 Count: 25 Geometry types: <ArrowStringArray> ['Point'] Length: 1, dtype: str Sample site_id: ['EG-CAI-001', 'EG-CAI-001', 'EG-CAI-001', 'EG-CAI-002', 'EG-CAI-002'] Geometry type distribution: Point 25 Name: count, dtype: int64
1:30