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:03
Bash
ls -F
ls -F
heritage_sites.geojson
0:13
Write
/work/check_data.py
content · 12 lines · py
import geopandas as gpd
# Load the data
gdf = gpd.read_file('heritage_sites.geojson')
print("Initial Data Info:")
print(gdf.info())
print("\nGeometry Types found:")
print(gdf.geom_type.unique())
print("\nFirst few rows:")
print(gdf.head())
Wrote /work/check_data.py (242 chars).
0:16
Bash
python /work/check_data.py
python /work/check_data.py
Initial Data 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
Geometry Types found:
<ArrowStringArray>
['Polygon', 'LineString', 'Point', 'MultiPolygon']
Length: 4, dtype: str
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]
0:40
Write
/work/solve.py
content · 69 lines · py
import geopandas as gpd
# Load the data
gdf = gpd.read_file('heritage_sites.geojson')
# Egypt National Grid (Egypt Red Belt / Egypt TM)
# EPSG:22992 is Egypt Red Belt
# However, usually, standard is EPSG:32636 (WGS 84 / UTM zone 36N)
# or WGS 84 / UTM zone 35N depending on location.
# Let's search for a more standard Egypt National Grid or just use a common one.
# According to some sources EPSG:22992 is Egypt Red Belt.
# Let's try to find the most common one if not specified.
# Given the prompt says "Egypt's national grid", I will use EPSG:22992.
# If it's not available, I'll fall back to a standard UTM for Egypt.
target_crs = "EPSG:22992"
# To be safe, check if EPSG:22992 is available or just use UTM 36N (32636) which is widely used.
# Actually, I'll just try 22992.
# 1. Ensure all geometries are single-part
gdf['geometry'] = gdf.geometry.apply(lambda x: x if x.geom_type in ['Point', 'LineString', 'Polygon'] else x.explode(index_parts=True))
# Note: explode() might return a GeoSeries, need to make sure it stays as a GeoDataFrame or handle it.
# Let's refine the explosion process.
def ensure_single_part(gdf):
exploded_list = []
for _, row in gdf.iterrows():
geom = row.geometry
if geom.geom_type in ['Point', 'LineString', 'Polygon']:
exploded_list.append(row)
else:
# Explode Multi-part
exploded_geom = geom.explode(index_parts=False)
for part in exploded_geom:
new_row = row.copy()
new_row.geometry = part
exploded_list.append(new_row)
return gpd.GeoDataFrame(exploded_list, crs=gdf.crs)
gdf_single = ensure_single_part(gdf)
# Re-project to Egypt's national grid
gdf_single = gdf_single.to_crs(target_crs)
# 2. Split into three layers
points = gdf_single[gdf_single.geometry.geom_type == 'Point']
lines = gdf_single[gdf_single.geometry.geom_type == 'LineString']
polygons = gdf_single[gdf_single.geometry.geom_type == 'Polygon']
# 3. Save to GPKG
output_file = 'heritage.gpkg'
with pd.io.gpd.GPDFile() as driver: # This is not how geopandas works for multiple layers
pass
# Use the correct way to write multiple layers in geopandas
import pandas as pd # just in case
# We use the engine='pyogrio' if available or just standard driver
# Geopandas write_to_file supports 'layer' argument
points.to_file(output_file, layer='points', driver='GPKG')
lines.to_file(output_file, layer='lines', driver='GPKG')
polygons.to_file(output_file, layer='polygons', driver='GPKG')
print(f"Successfully created {output_file} with layers: points, lines, polygons")
print(f"Projected CRS: {gdf_single.crs}")
Wrote /work/solve.py (2661 chars).
0:52
Bash
python /work/solve.py
python /work/solve.py
Traceback (most recent call last):
File "/work/solve.py", line 22, in <module>
gdf['geometry'] = gdf.geometry.apply(lambda x: x if x.geom_type in ['Point', 'LineString', 'Polygon'] else x.explode(index_parts=True))
~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.14/site-packages/geopandas/geoseries.py", line 800, in apply
result = super().apply(func, args=args, **kwargs)
File "/usr/local/lib/python3.14/site-packages/pandas/core/series.py", line 5084, in apply
).apply()
~~~~~^^
File "/usr/local/lib/python3.14/site-packages/pandas/core/apply.py", line 1520, in apply
return self.apply_standard()
~~~~~~~~~~~~~~~~~~~^^
File "/usr/local/lib/python3.14/site-packages/pandas/core/apply.py", line 1578, in apply_standard
mapped = obj._map_values(mapper=curried)
File "/usr/local/lib/python3.14/site-packages/pandas/core/base.py", line 1020, in _map_values
return arr.map(mapper, na_action=na_action)
~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.14/site-packages/pandas/core/arrays/base.py", line 2745, in map
return map_array(self, mapper, na_action=na_action)
File "/usr/local/lib/python3.14/site-packages/pandas/core/algorithms.py", line 1715, in map_array
return lib.map_infer(values, mapper)
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^
File "pandas/_libs/lib.pyx", line 3071, in pandas._libs.lib.map_infer
File "/work/solve.py", line 22, in <lambda>
gdf['geometry'] = gdf.geometry.apply(lambda x: x if x.geom_type in ['Point', 'LineString', 'Polygon'] else x.explode(index_parts=True))
^^^^^^^^^
AttributeError: 'MultiPolygon' object has no attribute 'explode'
1:10
Write
/work/solve.py
content · 41 lines · py
import geopandas as gpd
# Load the data
gdf = gpd.read_file('heritage_sites.geojson')
# Egypt National Grid (Egypt Red Belt / Egypt TM)
# EPSG:22992 is Egypt Red Belt.
target_crs = "EPSG:22992"
def ensure_single_part(gdf):
# explode() on a GeoDataFrame is the easiest way to turn Multi-geometries into single-part
# It handles all geom types and preserves columns.
# index_parts=False means it doesn't create a multi-index.
exploded_gdf = gdf.explode(index_parts=False)
return exploded_gdf
# 1. Ensure all geometries are single-part
gdf_single = ensure_single_part(gdf)
# 2. Re-project to Egypt's national grid
gdf_single = gdf_single.to_crs(target_crs)
# 3. Split into three layers based on geometry type
# Note: explode() might leave us with Point, LineString, Polygon
# We need to make sure we categorize them correctly.
points = gdf_single[gdf_single.geometry.geom_type == 'Point']
lines = gdf_single[gdf_single.geometry.geom_type == 'LineString']
polygons = gdf_single[gdf_single.geometry.geom_type == 'Polygon']
# 4. Save to GPKG
output_file = 'heritage.gpkg'
# Writing layers
points.to_file(output_file, layer='points', driver='GPKG')
lines.to_file(output_file, layer='lines', driver='GPKG')
polygons.to_file(output_file, layer='polygons', driver='GPKG')
print(f"Successfully created {output_file} with layers: points, lines, polygons")
print(f"Projected CRS: {gdf_single.crs}")
print(f"Counts - Points: {len(points)}, Lines: {len(lines)}, Polygons: {len(polygons)}")
Wrote /work/solve.py (1504 chars).
1:13
Bash
python /work/solve.py
python /work/solve.py
Successfully created heritage.gpkg with layers: points, lines, polygons Projected CRS: EPSG:22992 Counts - Points: 25, Lines: 15, Polygons: 15
1:26
Bash
# Check the content of the gpkg using ogrinfo if available,
# Check the content of the gpkg using ogrinfo if available,
# but let's use a quick python script to verify layers and schema.
python -c "import geopandas as gpd; layers = ['points', 'lines', 'polygons']; [print(f'Layer {l}:', gpd.read_file('heritage.gpkg', layer=l).head(1)) for l in layers]"
Layer points: site_id ... geometry 0 EG-CAI-001 ... POINT (639589.453 813622.922) [1 rows x 5 columns] Layer lines: site_id ... geometry 0 EG-CAI-001 ... LINESTRING (639493.121 813567.28, 639589.552 8... [1 rows x 5 columns] Layer polygons: site_id ... geometry 0 EG-CAI-001 ... POLYGON ((639531.827 813511.939, 639647.574 81... [1 rows x 5 columns]
2:01