crs-l1-paris-lambert93
Map (reference ← swipe → agent)
0:00
Our heat-loss model won't accept the `paris_buildings` file in lat/lon. It needs the coordinates in metres using the standard official projection for the Paris region. Can you convert the buildings over so the model can ingest them? Please leave the attributes alone, and keep every geometry as a plain Polygon rather than turning it into a MultiPolygon. Write the result as a GeoPackage to `paris_buildings_lambert93.gpkg`, and use `id` as the key.
0:00
System info
{
"adapter": "openrouter",
"model": "google/gemma-4-26b-a4b-it",
"base_url": "https://openrouter.ai/api/v1"
}
0:00
Bash
ls -F
ls -F
paris_buildings_wgs84.geojson
0:12
Write
/work/solve.py
content · 45 lines · py
import geopandas as gpd
def convert_buildings():
# Load the buildings file
input_file = 'paris_buildings_wgs84.geojson'
output_file = 'paris_buildings_lambert93.gpkg'
print(f"Reading {input_file}...")
gdf = gpd.read_file(input_file)
# Check current CRS
print(f"Current CRS: {gdf.crs}")
# The official projection for France is RGF93 / Lambert-93 (EPSG:2154)
target_crs = "EPSG:2154"
print(f"Projecting to {target_crs}...")
# Project the GeoDataFrame
gdf_projected = gdf.to_crs(target_crs)
# Requirement: Keep every geometry as a plain Polygon rather than a MultiPolygon.
# If a geometry is a MultiPolygon, we explode it into individual Polygons.
print("Exploding MultiPolygons into Polygons...")
gdf_projected = gdf_projected.explode(index_parts=False)
# The explode method might create new indices, but we need to keep the original attributes.
# gdf.explode(index_parts=False) preserves columns.
# However, if 'id' was used as index in the original, it should be preserved.
# Let's check if 'id' is a column or an index.
# Requirement: Write the result as a GeoPackage to 'paris_buildings_lambert93.gpkg',
# and use 'id' as the key.
# In GeoPackage/SQL context, 'id' as a key usually means the primary key.
# In geopandas write_file, we don't explicitly set the PK in the same way as SQL,
# but we can ensure 'id' exists as a column.
# Let's ensure the output format is correct.
print(f"Writing to {output_file}...")
gdf_projected.to_file(output_file, driver="GPKG")
print("Conversion complete.")
if __name__ == "__main__":
convert_buildings()
Wrote /work/solve.py (1713 chars).
0:13
Bash
python solve.py
python solve.py
Reading paris_buildings_wgs84.geojson... Current CRS: EPSG:4326 Projecting to EPSG:2154... Exploding MultiPolygons into Polygons... Writing to paris_buildings_lambert93.gpkg... Conversion complete.
0:25
Write
/work/solve.py
content · 43 lines · py
import geopandas as gpd
def convert_buildings():
input_file = 'paris_buildings_wgs84.geojson'
output_file = 'paris_buildings_lambert93.gpkg'
target_crs = "EPSG:2154"
gdf = gpd.read_file(input_file)
# Project
gdf_projected = gdf.to_crs(target_crs)
# Explode MultiPolygons to Polygons
# explode() will create new rows for each part of a MultiPolygon.
# We must ensure the 'id' column is preserved and used correctly.
gdf_exploded = gdf_projected.explode(index_parts=False)
# The user wants 'id' as the key. In a GeoPackage, the primary key is typically a column named 'fid' or 'id'.
# Let's verify the columns in the original file.
print("Columns in original:", gdf.columns.tolist())
# If 'id' exists, it's already a column.
# If 'id' is the index, we should reset it to make it a column.
if 'id' not in gdf_exploded.columns:
# If 'id' was the index of the original GDF, explode might have messed with it
# or it might be in the index.
print("Warning: 'id' not found in columns. Checking index...")
# Reset index to ensure all attributes (including index) become columns
gdf_exploded = gdf_exploded.reset_index()
# If 'id' was the index, it will now be a column named 'index' or similar.
# But usually, 'id' is a column in GeoJSON.
# Let's ensure the column name is exactly 'id' if it's meant to be the key
# But we don't want to overwrite if 'id' already exists.
print(f"Writing to {output_file}...")
gdf_exploded.to_file(output_file, driver="GPKG")
print("Conversion complete.")
if __name__ == "__main__":
convert_buildings()
Wrote /work/solve.py (1713 chars).
0:26
Bash
# Let's see what the original file looks like
# Let's see what the original file looks like head -n 20 paris_buildings_wgs84.geojson
{
"type": "FeatureCollection",
"name": "paris_buildings_wgs84",
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } },
"features": [
{ "type": "Feature", "properties": { "id": "007591b9-c632-4d57-8bd2-144f82cfdd73", "class": "apartments", "subtype": "residential", "name": "", "height": null, "num_floors": 4 }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 2.3597498, 48.8570399 ], [ 2.3597608, 48.8570499 ], [ 2.3598145, 48.8571068 ], [ 2.3598435, 48.8571291 ], [ 2.359806, 48.8571492 ], [ 2.3597163, 48.8570555 ], [ 2.3597328, 48.8570478 ], [ 2.3597498, 48.8570399 ] ] ] } },
{ "type": "Feature", "properties": { "id": "00fac4fe-168a-4116-b287-6a28f34c87df", "class": "hotel", "subtype": "commercial", "name": "Hôtel de Nice", "height": null, "num_floors": 7 }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 2.3558066, 48.8565792 ], [ 2.3558201, 48.8565761 ], [ 2.355847, 48.8566201 ], [ 2.3558588, 48.8566176 ], [ 2.3559027, 48.8566953 ], [ 2.3558801, 48.8567021 ], [ 2.3557818, 48.856724 ], [ 2.3557422, 48.8566535 ], [ 2.3557293, 48.8566307 ], [ 2.355756, 48.856591 ], [ 2.3558066, 48.8565792 ] ] ] } },
{ "type": "Feature", "properties": { "id": "020eefa5-5685-4f26-bd27-5b2bbd276bec", "class": "apartments", "subtype": "residential", "name": "", "height": null, "num_floors": 7 }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 2.3572011, 48.8572525 ], [ 2.3572582, 48.8572755 ], [ 2.3572304, 48.8572879 ], [ 2.3571022, 48.8573444 ], [ 2.3570724, 48.8573171 ], [ 2.3570455, 48.8572899 ], [ 2.3570759, 48.8572763 ], [ 2.3570906, 48.857296 ], [ 2.3571193, 48.8572856 ], [ 2.3571116, 48.8572727 ], [ 2.3570988, 48.857277 ], [ 2.3570899, 48.8572701 ], [ 2.3571344, 48.8572517 ], [ 2.3570889, 48.8571907 ], [ 2.3571324, 48.8571707 ], [ 2.3571965, 48.8572473 ], [ 2.3572011, 48.8572525 ] ] ] } },
{ "type": "Feature", "properties": { "id": "030e5772-d9af-4df1-9d7c-75d629eeca2d", "class": "apartments", "subtype": "residential", "name": "", "height": null, "num_floors": 5 }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 2.3576144, 48.8554387 ], [ 2.3575176, 48.8554725 ], [ 2.3574425, 48.8553782 ], [ 2.3575422, 48.8553435 ], [ 2.3576734, 48.8554183 ], [ 2.3576144, 48.8554387 ] ] ] } },
{ "type": "Feature", "properties": { "id": "0468c0c0-8ee9-4000-a0c1-514c803c86ee", "class": "apartments", "subtype": "residential", "name": "", "height": null, "num_floors": null }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 2.3563341, 48.858202 ], [ 2.3563562, 48.8581947 ], [ 2.3565055, 48.8583418 ], [ 2.3562074, 48.8584452 ], [ 2.3561355, 48.8583597 ], [ 2.3560759, 48.8582882 ], [ 2.3561163, 48.8582744 ], [ 2.3563341, 48.858202 ] ] ] } },
{ "type": "Feature", "properties": { "id": "04eec0bf-2cf3-436b-be28-5a17310179a4", "class": "apartments", "subtype": "residential", "name": "", "height": null, "num_floors": null }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 2.3593621, 48.8570356 ], [ 2.3593057, 48.8570501 ], [ 2.3593865, 48.8571298 ], [ 2.3592946, 48.8571673 ], [ 2.3592538, 48.8571923 ], [ 2.3591646, 48.8571264 ], [ 2.3591789, 48.8571161 ], [ 2.3591532, 48.8571066 ], [ 2.3591395, 48.8571171 ], [ 2.3591133, 48.8571072 ], [ 2.3591417, 48.8570895 ], [ 2.3591806, 48.8570624 ], [ 2.3591223, 48.8569857 ], [ 2.3591185, 48.8569791 ], [ 2.3592878, 48.8569268 ], [ 2.3593217, 48.8569787 ], [ 2.3593126, 48.8569826 ], [ 2.3593621, 48.8570356 ] ], [ [ 2.3592979, 48.8570841 ], [ 2.359273, 48.8570541 ], [ 2.3592526, 48.8570618 ], [ 2.3592822, 48.8570911 ], [ 2.3592979, 48.8570841 ] ] ] } },
{ "type": "Feature", "properties": { "id": "051dfb19-9a71-4127-8522-63bf20232528", "class": "apartments", "subtype": "residential", "name": "", "height": null, "num_floors": null }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 2.3581223, 48.8581081 ], [ 2.3580964, 48.8580772 ], [ 2.3584975, 48.857856 ], [ 2.3585364, 48.8578936 ], [ 2.3584542, 48.8579474 ], [ 2.3583045, 48.8580455 ], [ 2.3581774, 48.8581295 ], [ 2.3581578, 48.8581275 ], [ 2.3581367, 48.8581253 ], [ 2.3581223, 48.8581081 ] ] ] } },
{ "type": "Feature", "properties": { "id": "0707091a-10c6-4669-b6ed-55166847839e", "class": "apartments", "subtype": "residential", "name": "", "height": null, "num_floors": null }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 2.3573039, 48.8571135 ], [ 2.3572826, 48.8571208 ], [ 2.3572282, 48.8570585 ], [ 2.357222, 48.8570514 ], [ 2.3571732, 48.8569955 ], [ 2.3573448, 48.8569306 ], [ 2.3573136, 48.856893 ], [ 2.3574243, 48.8568539 ], [ 2.3575378, 48.8568138 ], [ 2.3575632, 48.8568051 ], [ 2.3576794, 48.8567629 ], [ 2.3578134, 48.8567165 ], [ 2.3578419, 48.8567066 ], [ 2.3579102, 48.8566833 ], [ 2.3580018, 48.8567988 ], [ 2.3579785, 48.8568061 ], [ 2.3578495, 48.8568467 ], [ 2.3578249, 48.8568547 ], [ 2.3577854, 48.8568662 ], [ 2.3576943, 48.8569005 ], [ 2.357741, 48.8569661 ], [ 2.3577062, 48.8569778 ], [ 2.3576648, 48.8569913 ], [ 2.3575549, 48.8570275 ], [ 2.3573039, 48.8571135 ] ], [ [ 2.3575937, 48.8568607 ], [ 2.3575442, 48.8568789 ], [ 2.3573572, 48.8569455 ], [ 2.3573748, 48.8569681 ], [ 2.3573225, 48.8569871 ], [ 2.3573677, 48.8570433 ], [ 2.3574221, 48.8570234 ], [ 2.3574185, 48.8570203 ], [ 2.3575226, 48.8569831 ], [ 2.3575195, 48.8569766 ], [ 2.3575983, 48.8569478 ], [ 2.3576068, 48.8569586 ], [ 2.3576598, 48.8569415 ], [ 2.3575937, 48.8568607 ] ] ] } },
{ "type": "Feature", "properties": { "id": "07142702-50fc-4469-9fec-687e5719d2e5", "class": "", "subtype": "", "name": "", "height": null, "num_floors": 5 }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 2.3573095, 48.8587292 ], [ 2.3572626, 48.8586874 ], [ 2.3573894, 48.8586176 ], [ 2.3574152, 48.85864 ], [ 2.3574534, 48.858621 ], [ 2.3574255, 48.8585971 ], [ 2.3574634, 48.8585761 ], [ 2.3575101, 48.8586154 ], [ 2.3574314, 48.8586636 ], [ 2.3574052, 48.8586809 ], [ 2.3573095, 48.8587292 ] ] ] } },
{ "type": "Feature", "properties": { "id": "071f77d5-75e3-4a98-89de-44f9a945aa44", "class": "apartments", "subtype": "residential", "name": "", "height": null, "num_floors": 6 }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 2.3565534, 48.8564198 ], [ 2.3565814, 48.8564286 ], [ 2.3566114, 48.8564826 ], [ 2.3564514, 48.8565169 ], [ 2.3564064, 48.8564365 ], [ 2.3564507, 48.8564258 ], [ 2.3565194, 48.8564091 ], [ 2.3565534, 48.8564198 ] ] ] } },
{ "type": "Feature", "properties": { "id": "07949552-5a76-4fe6-ba80-efa54e8b0688", "class": "apartments", "subtype": "residential", "name": "", "height": null, "num_floors": 6 }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 2.3563841, 48.8579286 ], [ 2.3564188, 48.8579083 ], [ 2.3564408, 48.8578943 ], [ 2.3564942, 48.8579492 ], [ 2.3564604, 48.857966 ], [ 2.3564275, 48.8579796 ], [ 2.3563841, 48.8579286 ] ] ] } },
{ "type": "Feature", "properties": { "id": "07ae479c-aa1a-4096-8c0d-4aa3d77d6c68", "class": "apartments", "subtype": "residential", "name": "", "height": null, "num_floors": null }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 2.3558582, 48.8583412 ], [ 2.3558805, 48.8583346 ], [ 2.3559207, 48.8583788 ], [ 2.3559434, 48.8584057 ], [ 2.3559652, 48.8583978 ], [ 2.3559826, 48.858419 ], [ 2.3559799, 48.8584201 ], [ 2.3559791, 48.8584223 ], [ 2.3559256, 48.8584407 ], [ 2.3559394, 48.8584582 ], [ 2.355925, 48.8584647 ], [ 2.3559556, 48.8585025 ], [ 2.3559606, 48.8585011 ], [ 2.3559961, 48.8585458 ], [ 2.3560893, 48.8585128 ], [ 2.3562946, 48.8587651 ], [ 2.3562546, 48.8587793 ], [ 2.3562817, 48.8588068 ], [ 2.3561865, 48.8588431 ], [ 2.3561537, 48.8588004 ], [ 2.3561489, 48.8588015 ], [ 2.3560707, 48.8587033 ], [ 2.3559915, 48.8586048 ], [ 2.3557874, 48.8583621 ], [ 2.3558582, 48.8583412 ] ] ] } },
{ "type": "Feature", "properties": { "id": "085195c0-034d-4763-994a-37cf71a53f1b", "class": "apartments", "subtype": "residential", "name": "", "height": null, "num_floors": 3 }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 2.3570164, 48.8568157 ], [ 2.3570464, 48.8568041 ], [ 2.3571038, 48.8567839 ], [ 2.3571104, 48.8567891 ], [ 2.3571663, 48.8567698 ], [ 2.3572235, 48.8567482 ], [ 2.357284, 48.8567257 ], [ 2.3573256, 48.8567861 ], [ 2.357207, 48.8568283 ], [ 2.3570701, 48.8568769 ], [ 2.3570214, 48.8568214 ], [ 2.3570164, 48.8568157 ] ] ] } },
{ "type": "Feature", "properties": { "id": "08e6b740-11e7-434c-8387-97797166f85a", "class": "apartments", "subtype": "residential", "name": "", "height": null, "num_floors": 5 }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 2.3573754, 48.8587838 ], [ 2.3573095, 48.8587292 ], [ 2.3574052, 48.8586809 ], [ 2.3574314, 48.8586636 ], [ 2.3574943, 48.8587156 ], [ 2.35745, 48.858741 ], [ 2.3574313, 48.8587518 ], [ 2.3573786, 48.858782 ], [ 2.3573754, 48.8587838 ] ] ] } },
{ "type": "Feature", "properties": { "id": "0955376b-191f-4230-85e0-7c79b20a94ba", "class": "apartments", "subtype": "residential", "name": "", "height": null, "num_floors": null }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 2.3576954, 48.8575906 ], [ 2.3576496, 48.857536 ], [ 2.3578871, 48.8574519 ], [ 2.3579379, 48.8574355 ], [ 2.3579755, 48.8574873 ], [ 2.3579546, 48.8574944 ], [ 2.3579672, 48.8575123 ], [ 2.3578471, 48.8575511 ], [ 2.3577027, 48.8575994 ], [ 2.3576954, 48.8575906 ] ] ] } },
0:34
Write
/work/solve.py
content · 37 lines · py
import geopandas as gpd
def convert_buildings():
input_file = 'paris_buildings_wgs84.geojson'
output_file = 'paris_buildings_lambert93.gpkg'
target_crs = "EPSG:2154"
print(f"Reading {input_file}...")
gdf = gpd.read_file(input_file)
print(f"Current CRS: {gdf.crs}")
print(f"Projecting to {target_crs}...")
gdf_projected = gdf.to_crs(target_crs)
print("Exploding MultiPolygons into Polygons...")
# We use explode() to turn MultiPolygons into separate Polygon rows.
# index_parts=False ensures we don't get a MultiIndex if not needed,
# but we want to keep the original attributes.
gdf_exploded = gdf_projected.explode(index_parts=False)
# The explode method in recent geopandas versions preserves all columns.
# Since 'id' is a column in the GeoJSON (as seen in the head output),
# it will be preserved.
print(f"Writing to {output_file}...")
# We'll write it to GeoPackage.
# GeoPackage's primary key is usually handled by the driver,
# but having 'id' in the attributes is what the user requested.
gdf_exploded.to_file(output_file, driver="GPKG")
print(f"Conversion complete. Saved to {output_file}")
print(f"Final geometry type: {gdf_exploded.geom_type.unique()}")
if __name__ == "__main__":
convert_buildings()
Wrote /work/solve.py (1349 chars).
0:35
Bash
python solve.py
python solve.py
Reading paris_buildings_wgs84.geojson... Current CRS: EPSG:4326 Projecting to EPSG:2154... Exploding MultiPolygons into Polygons... Writing to paris_buildings_lambert93.gpkg... Conversion complete. Saved to paris_buildings_lambert93.gpkg Final geometry type: <ArrowStringArray> ['Polygon'] Length: 1, dtype: str
0:39
Bash
# Check if the output file is actually a valid GeoPackage and contains the 'id' ...
# Check if the output file is actually a valid GeoPackage and contains the 'id' column
python -c "import geopandas as gpd; gdf = gpd.read_file('paris_buildings_lambert93.gpkg'); print(gdf.head()); print(gdf.columns); print(gdf.geom_type.unique())"
id ... geometry 0 007591b9-c632-4d57-8bd2-144f82cfdd73 ... POLYGON ((653023.358 6862079.654, 653024.174 6... 1 00fac4fe-168a-4116-b287-6a28f34c87df ... POLYGON ((652733.625 6862030.782, 652734.612 6... 2 020eefa5-5685-4f26-bd27-5b2bbd276bec ... POLYGON ((652836.551 6862104.813, 652840.761 6... 3 030e5772-d9af-4df1-9d7c-75d629eeca2d ... POLYGON ((652865.234 6861902.887, 652858.162 6... 4 0468c0c0-8ee9-4000-a0c1-514c803c86ee ... POLYGON ((652773.799 6862210.907, 652775.414 6... [5 rows x 7 columns] Index(['id', 'class', 'subtype', 'name', 'height', 'num_floors', 'geometry'], dtype='str') <ArrowStringArray> ['Polygon'] Length: 1, dtype: str
0:46