diff --git a/INTERFACE.yaml b/INTERFACE.yaml
index ee35e7c..b4b9ace 100644
--- a/INTERFACE.yaml
+++ b/INTERFACE.yaml
@@ -12,6 +12,8 @@ pathvars:
description: "location of module results."
results:
shapes:
- default: "/shapes.parquet"
+ default: "/{scenario}/shapes.parquet"
description: |
- Harmonised geoparquet dataset with all the configured countries, including non-contested exclusive economic zones.
+ Harmonised geoparquet dataset for a configured scenario, including land and maritime non-contested EEZs.
+wildcards:
+ scenario: Scenario name from the module configuration.
diff --git a/README.md b/README.md
index 96c2c40..03bbeb7 100644
--- a/README.md
+++ b/README.md
@@ -26,21 +26,30 @@ Data processing steps:
-1. The configuration file is read to identify the datasets to use as well as the specific countries and regional aggregation (`subtype` in the configuration) to process.
+1. The configuration file is read to identify which requested geopolitical combination (`scenarios`) was requested. These can be any number of nations (`countries`), each coming from a distinct dataset (`source`) and with its own subnational aggregation (`subtype`).
- Country landmass data: [eurostat NUTS](https://ec.europa.eu/eurostat/web/gisco/geodata/statistical-units/territorial-units-statistics), [GADM](https://gadm.org/), [geoBoundaries](https://www.geoboundaries.org/), and [Overture Maps](https://overturemaps.org/) are supported.
- Exclusive Economic Zone (EEZ) data: [MarineRegions.org](https://www.marineregions.org/).
2. Individual country files are downloaded and harmonised to fit a standardised schema.
- If identified, contested regions are removed at this stage.
- Land is clipped using maritime Exclusive Economic Zones (EEZ).
- Optionally, a Voronoi algorithm is run to separate EEZ areas to fit subnational regions.
-3. Each country file is combined and then clipped using its neighbours to minimise overlapping polygons.
+3. The country files requested in the scenario are combined and then clipped using their neighbours to minimise overlapping polygons.
> [!TIP]
-> The `subtype` naming matches that of the source database. For example, NUTS uses 0, 1, 2 and 3 (NUTS0, NUTS1, NUTS2, etc.).
-> Use the references at the bottom of this page for more details.
+> Keep in mind the following
+>
+> - All downloaded data is kept locally for future reuse across scenarios to minimise stress on the data sources the module relies on.
+> - Data source availability can vary.
+> Always consult the data source website to identify if a country is available at the desired resolution.
> [!CAUTION]
-> To increase the replicability of your workflow, we recommend using NUTS and geoBoundaries as sources whenever possible as they have more stable hosting methods than Overture Maps and GADM.
+> Be aware of the following known issues.
+>
+>- Overture Maps replicability: this data source [does not retain versions](https://github.com/orgs/OvertureMaps/discussions/422) for long.
+> If replicability is important to you, we suggest configuring other sources.
+>- Anti-meridian distortions: regions near the 180/-180 line (e.g., Fiji, Hawaii, New Zealand, Alaska) might be distorted during processing.
+> This is a known issue in the libraries we rely on (`geopandas`, `GDAL`) and something that is being actively [worked on at the moment](https://geopandas.org/en/v1.1.3/about/roadmap.html#s2-geometry-engine).
+> For now, we advice to use global projections (EPSG:3857, EPSG:8857) as a way to mitigate it.
## Configuration
@@ -50,7 +59,7 @@ Please consult the configuration [README](./config/README.md) and the [configura
## Input / output structure
-This module only has one output: a geoparquet file with your requested geo-boundary "shapes".
+This module only has one output: a geoparquet file with your requested geo-boundary "shapes" for each of the the configured `scenarios`.
Please consult the [interface file](./INTERFACE.yaml) for more information.
diff --git a/config/china_example.yaml b/config/china_example.yaml
deleted file mode 100644
index fd19204..0000000
--- a/config/china_example.yaml
+++ /dev/null
@@ -1,9 +0,0 @@
-# Example of regional disaggregation of a large country
-# China has contested borders, which will be removed by the module
-crs:
- projected: "epsg:3857"
- geographic: "epsg:4326"
-countries:
- "CHN":
- subtype: "country"
- source: "overture"
diff --git a/config/config.yaml b/config/config.yaml
index 31116a0..70bcd68 100644
--- a/config/config.yaml
+++ b/config/config.yaml
@@ -1,33 +1,215 @@
# A minimal example of how to configure this module
+
+# Default global settings across scenarios
voronoi_eez:
enabled: True
sample_spacing: 10000 # sample every 10 km
crs:
projected: "epsg:3857"
geographic: "epsg:4326"
-countries:
- DNK:
- subtype: "1"
- source: "nuts"
- resolution: 01M
- year: 2024
- GBR:
- subtype: "country"
- source: "overture"
- NLD:
- subtype: 0
- source: "geoboundaries"
- release_type: "gbOpen"
- BEL:
- subtype: 1
- source: "geoboundaries"
- release_type: "gbOpen"
- CHE:
- subtype: "country"
- source: "overture"
- ESP:
- subtype: "2"
- source: "nuts"
- resolution: 01M
- year: 2024
- extra_eez: 8364
+
+# At least one scenario.
+# We include four cases as examples.
+scenarios:
+ mixed_example:
+ # Assorted countries
+ countries:
+ DNK:
+ subtype: "1"
+ source: "nuts"
+ resolution: 01M
+ year: 2024
+ GBR:
+ subtype: "country"
+ source: "overture"
+ NLD:
+ subtype: 0
+ source: "geoboundaries"
+ release_type: "gbOpen"
+ BEL:
+ subtype: 1
+ source: "geoboundaries"
+ release_type: "gbOpen"
+ CHE:
+ subtype: "country"
+ source: "overture"
+ ESP:
+ subtype: "2"
+ source: "nuts"
+ resolution: 01M
+ year: 2024
+ extra_eez: 8364
+ china_national:
+ # Large country at national level
+ # China has contested borders, which will be removed by the module
+ voronoi_eez:
+ enabled: False
+ sample_spacing: 10000
+ countries:
+ "CHN":
+ subtype: "country"
+ source: "overture"
+ USA_states:
+ # Example of regional disaggregation of a large country crossing the antimeridean.
+ # USA has multiple marine zones, which can be appended as extras
+ countries:
+ "USA":
+ subtype: "1"
+ source: "gadm"
+ extra_eez: [8463, 8453]
+ europe_regions:
+ # A large continental example.
+ # Europe at regional resolution.
+ crs:
+ projected: "epsg:3035"
+ geographic: "epsg:4326"
+ countries:
+ "ALB":
+ subtype: "1"
+ source: "geoboundaries"
+ release_type: "gbOpen"
+ "AUT":
+ subtype: "1"
+ source: "geoboundaries"
+ release_type: "gbOpen"
+ "BEL":
+ subtype: "1"
+ source: "geoboundaries"
+ release_type: "gbOpen"
+ "BGR":
+ subtype: "1"
+ source: "geoboundaries"
+ release_type: "gbOpen"
+ "BIH":
+ subtype: "1"
+ source: "geoboundaries"
+ release_type: "gbOpen"
+ "CHE":
+ subtype: "1"
+ source: "geoboundaries"
+ release_type: "gbOpen"
+ "CYP":
+ subtype: "1"
+ source: "geoboundaries"
+ release_type: "gbOpen"
+ "CZE":
+ subtype: "1"
+ source: "geoboundaries"
+ release_type: "gbOpen"
+ "DEU":
+ subtype: "1"
+ source: "geoboundaries"
+ release_type: "gbOpen"
+ "DNK":
+ subtype: "1"
+ source: "nuts"
+ resolution: 01M
+ year: 2024
+ "ESP":
+ subtype: "1"
+ source: "geoboundaries"
+ release_type: "gbOpen"
+ extra_eez: 8364
+ "EST":
+ subtype: "1"
+ source: "geoboundaries"
+ release_type: "gbOpen"
+ "FIN":
+ subtype: "1"
+ source: "geoboundaries"
+ release_type: "gbOpen"
+ "FRA":
+ subtype: "1"
+ source: "geoboundaries"
+ release_type: "gbOpen"
+ "GBR":
+ subtype: "region"
+ source: "overture"
+ "GGY":
+ subtype: "0"
+ source: "geoboundaries"
+ release_type: "gbOpen"
+ "GRC":
+ subtype: "1"
+ source: "geoboundaries"
+ release_type: "gbOpen"
+ "HRV":
+ subtype: "1"
+ source: "geoboundaries"
+ release_type: "gbOpen"
+ "HUN":
+ subtype: "1"
+ source: "geoboundaries"
+ release_type: "gbOpen"
+ "IMN":
+ subtype: "0"
+ source: "geoboundaries"
+ release_type: "gbOpen"
+ "IRL":
+ subtype: "region"
+ source: "overture"
+ "ITA":
+ subtype: "1"
+ source: "geoboundaries"
+ release_type: "gbOpen"
+ "LTU":
+ subtype: "1"
+ source: "geoboundaries"
+ release_type: "gbOpen"
+ "LUX":
+ subtype: "1"
+ source: "geoboundaries"
+ release_type: "gbOpen"
+ "LVA":
+ subtype: "1"
+ source: "geoboundaries"
+ release_type: "gbOpen"
+ "MKD":
+ subtype: "1"
+ source: "geoboundaries"
+ release_type: "gbOpen"
+ "MNE":
+ subtype: "1"
+ source: "geoboundaries"
+ release_type: "gbOpen"
+ "NLD":
+ subtype: "region"
+ source: "overture"
+ "NOR":
+ subtype: "1"
+ source: "geoboundaries"
+ release_type: "gbOpen"
+ "POL":
+ subtype: "1"
+ source: "geoboundaries"
+ release_type: "gbOpen"
+ "PRT":
+ subtype: "1"
+ source: "nuts"
+ resolution: 01M
+ year: 2024
+ extra_eez: [8361, 8363]
+ "ROU":
+ subtype: "1"
+ source: "geoboundaries"
+ release_type: "gbOpen"
+ "SRB":
+ subtype: "1"
+ source: "geoboundaries"
+ release_type: "gbOpen"
+ "SVK":
+ subtype: "1"
+ source: "geoboundaries"
+ release_type: "gbOpen"
+ "SVN":
+ subtype: "1"
+ source: "geoboundaries"
+ release_type: "gbOpen"
+ "SWE":
+ subtype: "1"
+ source: "geoboundaries"
+ release_type: "gbOpen"
+ "XKX":
+ subtype: "1"
+ source: "geoboundaries"
+ release_type: "gbOpen"
diff --git a/config/europe_example.yaml b/config/europe_example.yaml
deleted file mode 100644
index bfa1eb5..0000000
--- a/config/europe_example.yaml
+++ /dev/null
@@ -1,157 +0,0 @@
-# A minimal example of how to configure this module
-voronoi_eez:
- enabled: True
- sample_spacing: 10000
-crs:
- projected: "epsg:3035"
- geographic: "epsg:4326"
-countries:
- "ALB":
- subtype: "1"
- source: "geoboundaries"
- release_type: "gbOpen"
- "AUT":
- subtype: "1"
- source: "geoboundaries"
- release_type: "gbOpen"
- "BEL":
- subtype: "1"
- source: "geoboundaries"
- release_type: "gbOpen"
- "BGR":
- subtype: "1"
- source: "geoboundaries"
- release_type: "gbOpen"
- "BIH":
- subtype: "1"
- source: "geoboundaries"
- release_type: "gbOpen"
- "CHE":
- subtype: "1"
- source: "geoboundaries"
- release_type: "gbOpen"
- "CYP":
- subtype: "1"
- source: "geoboundaries"
- release_type: "gbOpen"
- "CZE":
- subtype: "1"
- source: "geoboundaries"
- release_type: "gbOpen"
- "DEU":
- subtype: "1"
- source: "geoboundaries"
- release_type: "gbOpen"
- "DNK":
- subtype: "1"
- source: "nuts"
- resolution: 01M
- year: 2024
- "ESP":
- subtype: "1"
- source: "geoboundaries"
- release_type: "gbOpen"
- extra_eez: 8364
- "EST":
- subtype: "1"
- source: "geoboundaries"
- release_type: "gbOpen"
- "FIN":
- subtype: "1"
- source: "geoboundaries"
- release_type: "gbOpen"
- "FRA":
- subtype: "1"
- source: "geoboundaries"
- release_type: "gbOpen"
- "GBR":
- subtype: "region"
- source: "overture"
- "GGY":
- subtype: "0"
- source: "geoboundaries"
- release_type: "gbOpen"
- "GRC":
- subtype: "1"
- source: "geoboundaries"
- release_type: "gbOpen"
- "HRV":
- subtype: "1"
- source: "geoboundaries"
- release_type: "gbOpen"
- "HUN":
- subtype: "1"
- source: "geoboundaries"
- release_type: "gbOpen"
- "IMN":
- subtype: "0"
- source: "geoboundaries"
- release_type: "gbOpen"
- "IRL":
- subtype: "region"
- source: "overture"
- "ITA":
- subtype: "1"
- source: "geoboundaries"
- release_type: "gbOpen"
- "LTU":
- subtype: "1"
- source: "geoboundaries"
- release_type: "gbOpen"
- "LUX":
- subtype: "1"
- source: "geoboundaries"
- release_type: "gbOpen"
- "LVA":
- subtype: "1"
- source: "geoboundaries"
- release_type: "gbOpen"
- "MKD":
- subtype: "1"
- source: "geoboundaries"
- release_type: "gbOpen"
- "MNE":
- subtype: "1"
- source: "geoboundaries"
- release_type: "gbOpen"
- "NLD":
- subtype: "region"
- source: "overture"
- "NOR":
- subtype: "1"
- source: "geoboundaries"
- release_type: "gbOpen"
- "POL":
- subtype: "1"
- source: "geoboundaries"
- release_type: "gbOpen"
- "PRT":
- subtype: "1"
- source: "nuts"
- resolution: 01M
- year: 2024
- extra_eez: [8361, 8363]
- "ROU":
- subtype: "1"
- source: "geoboundaries"
- release_type: "gbOpen"
- "SRB":
- subtype: "1"
- source: "geoboundaries"
- release_type: "gbOpen"
- "SVK":
- subtype: "1"
- source: "geoboundaries"
- release_type: "gbOpen"
- "SVN":
- subtype: "1"
- source: "geoboundaries"
- release_type: "gbOpen"
- "SWE":
- subtype: "1"
- source: "geoboundaries"
- release_type: "gbOpen"
- "XKX":
- subtype: "1"
- source: "geoboundaries"
- release_type: "gbOpen"
diff --git a/config/usa_example.yaml b/config/usa_example.yaml
deleted file mode 100644
index 2d7fe8d..0000000
--- a/config/usa_example.yaml
+++ /dev/null
@@ -1,13 +0,0 @@
-# Example of regional disaggregation of a large country
-# USA has multiple marine zones, which can be appended as extras
-voronoi_eez:
- enabled: True
- sample_spacing: 10000 # sample every 10 km
-crs:
- projected: "epsg:3857"
- geographic: "epsg:4326"
-countries:
- "USA":
- subtype: "1"
- source: "gadm"
- extra_eez: [8463, 8453]
diff --git a/pixi.lock b/pixi.lock
index e34830e..6dc220e 100644
--- a/pixi.lock
+++ b/pixi.lock
@@ -803,6 +803,7 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/linux-64/freetype-2.14.3-ha770c72_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/freexl-2.0.0-h9dce30a_2.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/geos-3.14.0-h480dda7_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/geotiff-1.7.4-h1000f5c_4.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/gflags-2.2.2-h5888daf_1005.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/giflib-5.2.2-hd590300_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/glog-0.7.1-hbabe93e_0.conda
@@ -837,17 +838,15 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype6-2.14.3-h73754d4_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_19.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_19.conda
- - conda: https://conda.anaconda.org/conda-forge/linux-64/libgdal-core-3.11.4-h6c36cd4_6.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libgdal-core-3.10.3-h05c3bbc_24.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_19.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_19.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_19.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libgoogle-cloud-2.39.0-h9d11ab5_1.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libgoogle-cloud-storage-2.39.0-hdbdcf42_1.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libgrpc-1.78.1-h1d1128b_0.conda
- - conda: https://conda.anaconda.org/conda-forge/linux-64/libhwy-1.4.0-h10be129_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h3b78370_2.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.1.4.1-hb03c661_0.conda
- - conda: https://conda.anaconda.org/conda-forge/linux-64/libjxl-0.11.2-h174a0a3_1.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libkml-1.3.0-haa4a5bd_1023.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-6_h47877c9_openblas.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_0.conda
@@ -882,7 +881,6 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.3-py312h8a5da7c_1.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.10.9-py312he3d6523_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/minizip-4.2.1-hb71707f_0.conda
- - conda: https://conda.anaconda.org/conda-forge/linux-64/muparser-2.3.5-h5888daf_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.12.0-h54a6638_1.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.3.5-py312h33ff503_1.conda
@@ -899,13 +897,14 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/linux-64/pyarrow-19.0.1-py312h7900ff3_2.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/pyarrow-core-19.0.1-py312hc195796_2_cpu.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.46.4-py312h868fb18_0.conda
- - conda: https://conda.anaconda.org/conda-forge/linux-64/pyogrio-0.11.1-py312h6e8b602_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/pyogrio-0.11.0-py312h02b19dd_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/pyproj-3.7.2-py312he675c61_3.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.13-hd63d673_0_cpython.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/python-duckdb-1.2.0-py312h2ec8cdc_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/pytokens-0.4.1-py312h5253ce2_1.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.3-py312h8a5da7c_1.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/qhull-2020.2-h434a139_5.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/rasterio-1.4.4-py312h762fea3_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/re2-2025.11.05-h5301d42_1.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/rpds-py-0.30.0-py312h868fb18_0.conda
@@ -925,8 +924,10 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/linux-64/zlib-1.3.2-h25fd6f3_2.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/zlib-ng-2.3.3-hceb46e0_1.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/affine-2.4.0-pyhd8ed1ab_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/annotated-doc-0.0.4-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/annotated-types-0.7.0-pyhd8ed1ab_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/antimeridian-0.4.7-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/asttokens-3.0.1-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/attrs-26.1.0-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/black-26.3.1-pyh866005b_0.conda
@@ -938,14 +939,16 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/noarch/chardet-7.4.3-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.7-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/click-8.3.3-pyhc90fa1f_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/click-plugins-1.1.1.2-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/cligj-0.7.2-pyhd8ed1ab_2.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhcf101f3_2.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/decorator-5.2.1-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/duckdb-1.2.0-h6c4a22f_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/executing-2.2.1-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/folium-0.20.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/frictionless-4.40.8-pyh6c4a22f_0.tar.bz2
- - conda: https://conda.anaconda.org/conda-forge/noarch/geopandas-1.0.1-pyhd8ed1ab_3.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/geopandas-base-1.0.1-pyha770c72_3.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/geopandas-1.1.3-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/geopandas-base-1.1.3-pyha770c72_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda
@@ -1000,6 +1003,7 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/noarch/shellingham-1.5.4-pyhd8ed1ab_2.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/simpleeval-1.0.7-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/snuggs-1.4.7-pyhd8ed1ab_2.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/stack_data-0.6.3-pyhd8ed1ab_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/stringcase-1.2.0-pyhd8ed1ab_2.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/tabulate-0.10.0-pyhcf101f3_0.conda
@@ -1020,8 +1024,10 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/noarch/xyzservices-2026.3.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.23.1-pyhcf101f3_0.conda
osx-arm64:
+ - conda: https://conda.anaconda.org/conda-forge/noarch/affine-2.4.0-pyhd8ed1ab_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/annotated-doc-0.0.4-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/annotated-types-0.7.0-pyhd8ed1ab_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/antimeridian-0.4.7-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/asttokens-3.0.1-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/attrs-26.1.0-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/black-26.3.1-pyh866005b_0.conda
@@ -1033,14 +1039,16 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/noarch/chardet-7.4.3-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.7-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/click-8.3.3-pyhc90fa1f_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/click-plugins-1.1.1.2-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/cligj-0.7.2-pyhd8ed1ab_2.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhcf101f3_2.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/decorator-5.2.1-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/duckdb-1.2.0-h6c4a22f_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/executing-2.2.1-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/folium-0.20.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/frictionless-4.40.8-pyh6c4a22f_0.tar.bz2
- - conda: https://conda.anaconda.org/conda-forge/noarch/geopandas-1.0.1-pyhd8ed1ab_3.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/geopandas-base-1.0.1-pyha770c72_3.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/geopandas-1.1.3-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/geopandas-base-1.1.3-pyha770c72_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda
@@ -1095,6 +1103,7 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/noarch/shellingham-1.5.4-pyhd8ed1ab_2.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/simpleeval-1.0.7-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/snuggs-1.4.7-pyhd8ed1ab_2.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/stack_data-0.6.3-pyhd8ed1ab_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/stringcase-1.2.0-pyhd8ed1ab_2.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/tabulate-0.10.0-pyhcf101f3_0.conda
@@ -1145,6 +1154,7 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/freetype-2.14.3-hce30654_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/freexl-2.0.0-h3ab3353_2.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/geos-3.14.0-h4bcf65f_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/geotiff-1.7.4-hf862be1_4.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/gflags-2.2.2-hf9b8971_1005.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/giflib-5.2.2-h93a5062_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/glog-0.7.1-heb240a5_0.conda
@@ -1177,16 +1187,14 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libfreetype-2.14.3-hce30654_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libfreetype6-2.14.3-hdfa99f5_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgcc-15.2.0-hcbb3090_19.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgdal-core-3.11.4-h693e041_6.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgdal-core-3.10.3-h694df76_24.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran-15.2.0-h07b0088_19.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran5-15.2.0-hdae7583_19.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgoogle-cloud-2.39.0-h2f60c08_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgoogle-cloud-storage-2.39.0-ha114238_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgrpc-1.78.1-h3e3f78d_0.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libhwy-1.4.0-ha332bbd_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libiconv-1.18-h23cfdf5_2.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libjpeg-turbo-3.1.4.1-h84a0fba_0.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libjxl-0.11.2-h934fa54_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libkml-1.3.0-hb833057_1023.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblapack-3.11.0-6_hd9741b5_openblas.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblzma-5.8.3-h8088a28_0.conda
@@ -1218,7 +1226,6 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/markupsafe-3.0.3-py313h65a2061_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/matplotlib-base-3.10.9-py313h36cb854_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/minizip-4.2.1-hdb7fadc_0.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-arm64/muparser-2.3.5-h11e0b38_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.6-h1d4f5a5_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/nlohmann_json-3.12.0-h784d473_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.3.5-py313h16eae64_1.conda
@@ -1235,13 +1242,14 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyarrow-19.0.1-py313h39782a4_2.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyarrow-core-19.0.1-py313hcc89289_2_cpu.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pydantic-core-2.46.4-py313h212e517_0.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyogrio-0.11.1-py313hd8ca31c_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyogrio-0.11.0-py313h4ad91d6_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyproj-3.7.2-py313h6de5794_3.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.13.13-h20e6be0_100_cp313.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-duckdb-1.2.0-py313h928ef07_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pytokens-0.4.1-py313h6688731_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyyaml-6.0.3-py313h65a2061_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/qhull-2020.2-h420ef59_5.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/rasterio-1.4.4-py313hb3bd904_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/re2-2025.11.05-ha480c28_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.3-h46df422_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/rpds-py-0.30.0-py313h2c089d5_0.conda
@@ -1260,8 +1268,10 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/zlib-ng-2.3.3-hed4e4f5_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstd-1.5.7-hbf9d68e_6.conda
win-64:
+ - conda: https://conda.anaconda.org/conda-forge/noarch/affine-2.4.0-pyhd8ed1ab_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/annotated-doc-0.0.4-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/annotated-types-0.7.0-pyhd8ed1ab_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/antimeridian-0.4.7-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/asttokens-3.0.1-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/attrs-26.1.0-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/black-26.3.1-pyh866005b_0.conda
@@ -1273,6 +1283,8 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/noarch/chardet-7.4.3-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.7-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/click-8.3.3-pyh6dadd2b_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/click-plugins-1.1.1.2-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/cligj-0.7.2-pyhd8ed1ab_2.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhcf101f3_2.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/decorator-5.2.1-pyhd8ed1ab_0.conda
@@ -1280,8 +1292,8 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/noarch/executing-2.2.1-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/folium-0.20.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/frictionless-4.40.8-pyh6c4a22f_0.tar.bz2
- - conda: https://conda.anaconda.org/conda-forge/noarch/geopandas-1.0.1-pyhd8ed1ab_3.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/geopandas-base-1.0.1-pyha770c72_3.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/geopandas-1.1.3-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/geopandas-base-1.1.3-pyha770c72_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda
@@ -1335,6 +1347,7 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/noarch/shellingham-1.5.4-pyhd8ed1ab_2.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/simpleeval-1.0.7-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/snuggs-1.4.7-pyhd8ed1ab_2.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/stack_data-0.6.3-pyhd8ed1ab_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/stringcase-1.2.0-pyhd8ed1ab_2.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/tabulate-0.10.0-pyhcf101f3_0.conda
@@ -1381,6 +1394,7 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/win-64/freetype-2.14.3-h57928b3_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/freexl-2.0.0-hf297d47_2.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/geos-3.14.0-hdade9fe_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/geotiff-1.7.4-h73469f5_4.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/kiwisolver-1.5.0-py313h1a38498_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/krb5-1.22.2-h0ea6238_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/lcms2-2.19.1-hf2c6c5f_0.conda
@@ -1405,16 +1419,14 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/win-64/libfreetype-2.14.3-h57928b3_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/libfreetype6-2.14.3-hdbac1cb_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/libgcc-15.2.0-h8ee18e1_19.conda
- - conda: https://conda.anaconda.org/conda-forge/win-64/libgdal-core-3.11.4-h8a8bf46_6.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libgdal-core-3.10.3-h2f24e33_24.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/libgomp-15.2.0-h8ee18e1_19.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/libgoogle-cloud-2.39.0-h01c467a_1.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/libgoogle-cloud-storage-2.39.0-he04ea4c_1.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/libgrpc-1.78.1-h9ff2b3e_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/libhwloc-2.12.2-default_h4379cf1_1000.conda
- - conda: https://conda.anaconda.org/conda-forge/win-64/libhwy-1.4.0-h172a326_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/libiconv-1.18-hc1393d2_2.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/libjpeg-turbo-3.1.4.1-hfd05255_0.conda
- - conda: https://conda.anaconda.org/conda-forge/win-64/libjxl-0.11.2-h932607e_1.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/libkml-1.3.0-h68a222c_1023.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/liblapack-3.11.0-6_hf9ab0e9_mkl.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/liblzma-5.8.3-hfd05255_0.conda
@@ -1444,7 +1456,6 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/win-64/matplotlib-base-3.10.9-py313he1ded55_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/minizip-4.2.1-h0ffbb96_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/mkl-2025.3.1-hac47afa_13.conda
- - conda: https://conda.anaconda.org/conda-forge/win-64/muparser-2.3.5-he0c23c2_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/numpy-2.3.5-py313hce7ae62_1.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/onemkl-license-2025.3.1-h57928b3_13.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/openjpeg-2.5.4-h0e57b4f_0.conda
@@ -1459,13 +1470,14 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/win-64/pyarrow-19.0.1-py313hfa70ccb_2.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/pyarrow-core-19.0.1-py313h5921983_2_cpu.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/pydantic-core-2.46.4-py313hfbe8231_0.conda
- - conda: https://conda.anaconda.org/conda-forge/win-64/pyogrio-0.11.1-py313h0dbd5a6_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/pyogrio-0.11.0-py313h75b81ac_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/pyproj-3.7.2-py313hbf73894_3.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/python-3.13.13-h09917c8_100_cp313.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/python-duckdb-1.2.0-py313h5813708_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/pytokens-0.4.1-py313h5fd188c_1.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/pyyaml-6.0.3-py313hd650c13_1.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/qhull-2020.2-hc790b64_5.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/rasterio-1.4.4-py313ha5c5119_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/re2-2025.11.05-ha104f34_1.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/rpds-py-0.30.0-py313hfbe8231_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/scikit-learn-1.8.0-np2py313h4ce4a18_1.conda
@@ -2419,6 +2431,25 @@ packages:
license: LGPL-2.1-only
size: 1977241
timestamp: 1755851798617
+- conda: https://conda.anaconda.org/conda-forge/linux-64/geotiff-1.7.4-h1000f5c_4.conda
+ sha256: d17e2f34fe5c61eb620e8679368d8ee90be36379cd6023f8690bdcba1c60761c
+ md5: ff1966654a6cd1cf06a6e44c13e60b8a
+ depends:
+ - proj
+ - zlib
+ - libjpeg-turbo
+ - libtiff
+ - __glibc >=2.17,<3.0.a0
+ - libstdcxx >=14
+ - libgcc >=14
+ - libzlib >=1.3.1,<2.0a0
+ - proj >=9.7.0,<9.8.0a0
+ - libjpeg-turbo >=3.1.0,<4.0a0
+ - libtiff >=4.7.0,<4.8.0a0
+ license: MIT
+ license_family: MIT
+ size: 144495
+ timestamp: 1757965550923
- conda: https://conda.anaconda.org/conda-forge/linux-64/gflags-2.2.2-h5888daf_1005.conda
sha256: 6c33bf0c4d8f418546ba9c250db4e4221040936aef8956353bc764d4877bc39a
md5: d411fc29e338efb48c5fd4576d71d881
@@ -3234,13 +3265,14 @@ packages:
license_family: BSD
size: 177306
timestamp: 1766331805898
-- conda: https://conda.anaconda.org/conda-forge/linux-64/libgdal-core-3.11.4-h6c36cd4_6.conda
- sha256: 5bcca9be1cd9c3e0e7c7bbc1b4d2ebefbb5b1004e21f5bdbd993a0e5b9c0872c
- md5: c6c5d093e8a60acdd93f731cc3593c97
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libgdal-core-3.10.3-h05c3bbc_24.conda
+ sha256: 1a1aebbc173afbb90602c93b6cdff31bd781998c228717797f941caef6434a74
+ md5: a69445ccff7ec3d60fe14110bd4d86ae
depends:
- __glibc >=2.17,<3.0.a0
- blosc >=1.21.6,<2.0a0
- geos >=3.14.0,<3.14.1.0a0
+ - geotiff >=1.7.4,<1.8.0a0
- giflib >=5.2.2,<5.3.0a0
- json-c >=0.18,<0.19.0a0
- lerc >=4.0.0,<5.0a0
@@ -3251,30 +3283,29 @@ packages:
- libgcc >=14
- libiconv >=1.18,<2.0a0
- libjpeg-turbo >=3.1.0,<4.0a0
- - libjxl >=0.11,<0.12.0a0
- libkml >=1.3.0,<1.4.0a0
- liblzma >=5.8.1,<6.0a0
- libpng >=1.6.50,<1.7.0a0
- libspatialite >=5.1.0,<5.2.0a0
- libsqlite >=3.50.4,<4.0a0
- libstdcxx >=14
+ - libtiff >=4.7.1,<4.8.0a0
- libwebp-base >=1.6.0,<2.0a0
- libxml2
- libxml2-16 >=2.14.6
- libzlib >=1.3.1,<2.0a0
- lz4-c >=1.10.0,<1.11.0a0
- - muparser >=2.3.5,<2.4.0a0
- openssl >=3.5.4,<4.0a0
- pcre2 >=10.46,<10.47.0a0
- proj >=9.7.0,<9.8.0a0
- xerces-c >=3.3.0,<3.4.0a0
- zstd >=1.5.7,<1.6.0a0
constrains:
- - libgdal 3.11.4.*
+ - libgdal 3.10.3.*
license: MIT
license_family: MIT
- size: 12131233
- timestamp: 1761259370721
+ size: 11051744
+ timestamp: 1761690729608
- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_16.conda
sha256: 8a7b01e1ee1c462ad243524d76099e7174ebdd94ff045fe3e9b1e58db196463b
md5: 40d9b534410403c821ff64f00d0adc22
@@ -3460,16 +3491,6 @@ packages:
license_family: APACHE
size: 7021360
timestamp: 1774020290672
-- conda: https://conda.anaconda.org/conda-forge/linux-64/libhwy-1.4.0-h10be129_0.conda
- sha256: 8b70955d5e9a49d08945d4f8e2eab855b2efa5fce9cb9bc5e75d86764e6f2f38
- md5: 3a9428b74c403c71048104d38437b48c
- depends:
- - __glibc >=2.17,<3.0.a0
- - libgcc >=14
- - libstdcxx >=14
- license: Apache-2.0 OR BSD-3-Clause
- size: 1435782
- timestamp: 1776989559668
- conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h3b78370_2.conda
sha256: c467851a7312765447155e071752d7bf9bf44d610a5687e32706f480aad2833f
md5: 915f5995e94f60e9a4826e0b0920ee88
@@ -3501,20 +3522,6 @@ packages:
license: IJG AND BSD-3-Clause AND Zlib
size: 633831
timestamp: 1775962768273
-- conda: https://conda.anaconda.org/conda-forge/linux-64/libjxl-0.11.2-h174a0a3_1.conda
- sha256: 0c8a78c6a42a6e4c6de3a5e82d692f60400d43f4cc80591745f28b37daad9c70
- md5: 850f48943d6b4589800a303f0de6a816
- depends:
- - __glibc >=2.17,<3.0.a0
- - libgcc >=14
- - libstdcxx >=14
- - libhwy >=1.4.0,<1.5.0a0
- - libbrotlienc >=1.2.0,<1.3.0a0
- - libbrotlidec >=1.2.0,<1.3.0a0
- license: BSD-3-Clause
- license_family: BSD
- size: 1846962
- timestamp: 1777065125966
- conda: https://conda.anaconda.org/conda-forge/linux-64/libkml-1.3.0-haa4a5bd_1023.conda
sha256: f6348ac9cebbc03f765ea6d2da88d57d19531585c8f3a963b98635b208e8bef1
md5: 953b7cca897e21215302dbfe2af5cd0c
@@ -4279,17 +4286,6 @@ packages:
license_family: Apache
size: 102525
timestamp: 1762504116832
-- conda: https://conda.anaconda.org/conda-forge/linux-64/muparser-2.3.5-h5888daf_0.conda
- sha256: 320dfc59a94cb9e3635bda71b9e62278b34aa2fdaea0caa6832ddb9b37e9ccd5
- md5: ab3e3db511033340e75e7002e80ce8c0
- depends:
- - __glibc >=2.17,<3.0.a0
- - libgcc >=13
- - libstdcxx >=13
- license: MIT
- license_family: MIT
- size: 203174
- timestamp: 1747116762269
- conda: https://conda.anaconda.org/conda-forge/linux-64/mypy-1.19.1-py312h4c3975b_0.conda
sha256: d0e0765e5ec08141b10da9e03ef620d2e3e571d81cc2bc14025c52a48bb01856
md5: c3ad8cc29400fe5ca1b6a6e5ae46538e
@@ -4760,22 +4756,22 @@ packages:
license_family: MIT
size: 1895409
timestamp: 1778084226169
-- conda: https://conda.anaconda.org/conda-forge/linux-64/pyogrio-0.11.1-py312h6e8b602_1.conda
- sha256: 0c44f249204ca6886abcc8a03cf8c8c8681d18cc533ede3697a3f00ac99e4740
- md5: 71e2dd5aa884ab062c2d41fe10f9cefe
+- conda: https://conda.anaconda.org/conda-forge/linux-64/pyogrio-0.11.0-py312h02b19dd_0.conda
+ sha256: 28ad34f1e1ddad99bbbd7d2609fe46855e920f6985644f52852adf9ecfddc868
+ md5: b4e4e057ab327b7a1270612587a75523
depends:
- __glibc >=2.17,<3.0.a0
- - libgcc >=14
- - libgdal-core >=3.11.3,<3.12.0a0
- - libstdcxx >=14
+ - libgcc >=13
+ - libgdal-core >=3.10.3,<3.11.0a0
+ - libstdcxx >=13
- numpy
- packaging
- python >=3.12,<3.13.0a0
- python_abi 3.12.* *_cp312
license: MIT
license_family: MIT
- size: 638127
- timestamp: 1756824422270
+ size: 665062
+ timestamp: 1746734790035
- conda: https://conda.anaconda.org/conda-forge/linux-64/pyproj-3.7.2-py312he675c61_3.conda
sha256: ea0299f9699547531e81dd685f7ff0e50f7bc6dad932d8005ef24c3393cc07c1
md5: c3258c31e507a81f0b52156bcca81e73
@@ -4933,6 +4929,31 @@ packages:
license: LicenseRef-Qhull
size: 552937
timestamp: 1720813982144
+- conda: https://conda.anaconda.org/conda-forge/linux-64/rasterio-1.4.4-py312h762fea3_0.conda
+ sha256: 23ffbe589064e224b3ac69d05454062836971f57c4c734261c58dfb7b9d14f37
+ md5: df884dc5a76b2e2b2d13901f0d5d1668
+ depends:
+ - __glibc >=2.17,<3.0.a0
+ - affine
+ - attrs
+ - certifi
+ - click >=4,!=8.2.*
+ - click-plugins
+ - cligj >=0.5
+ - libgcc >=14
+ - libgdal-core <3.11
+ - libgdal-core >=3.10.3,<3.11.0a0
+ - libstdcxx >=14
+ - numpy >=1.23,<3
+ - proj >=9.7.1,<9.8.0a0
+ - python >=3.12,<3.13.0a0
+ - python_abi 3.12.* *_cp312
+ - setuptools >=0.9.8
+ - snuggs >=1.4.1
+ license: BSD-3-Clause
+ license_family: BSD
+ size: 7835544
+ timestamp: 1765553234963
- conda: https://conda.anaconda.org/conda-forge/linux-64/re2-2025.11.05-h5301d42_1.conda
sha256: 3fc684b81631348540e9a42f6768b871dfeab532d3f47d5c341f1f83e2a2b2b2
md5: 66a715bc01c77d43aca1f9fcb13dde3c
@@ -5552,6 +5573,15 @@ packages:
license_family: LGPL
size: 631452
timestamp: 1758743294412
+- conda: https://conda.anaconda.org/conda-forge/noarch/affine-2.4.0-pyhd8ed1ab_1.conda
+ sha256: 0deeaf0c001d5543719db9b2686bc1920c86c7e142f9bec74f35e1ce611b1fc2
+ md5: 8c4061f499edec6b8ac7000f6d586829
+ depends:
+ - python >=3.9
+ license: BSD-3-Clause
+ license_family: BSD
+ size: 19164
+ timestamp: 1733762153202
- conda: https://conda.anaconda.org/conda-forge/noarch/amply-0.1.6-pyhd8ed1ab_1.conda
sha256: e8d87cb66bcc62bc8d8168037b776de962ebf659e45acb1a813debde558f7339
md5: 5a81866192811f3a0827f5f93e589f02
@@ -5582,6 +5612,18 @@ packages:
license_family: MIT
size: 18074
timestamp: 1733247158254
+- conda: https://conda.anaconda.org/conda-forge/noarch/antimeridian-0.4.7-pyhd8ed1ab_0.conda
+ sha256: 56d4aa5e64b00989dd5b31d2e41af5ba2869775a1df7eb4e4155729c6bc1b9fa
+ md5: 56e9ab4ca5ec150ad52ca420f2cec646
+ depends:
+ - click >=8.1,=8.*
+ - numpy >=1.22.4
+ - python >=3.10
+ - shapely >=2.0
+ license: Apache-2.0
+ license_family: APACHE
+ size: 21300
+ timestamp: 1775308729010
- conda: https://conda.anaconda.org/conda-forge/noarch/appdirs-1.4.4-pyhd8ed1ab_1.conda
sha256: 5b9ef6d338525b332e17c3ed089ca2f53a5d74b7a7b432747d29c6466e39346d
md5: f4e90937bbfc3a4a92539545a37bb448
@@ -5827,6 +5869,26 @@ packages:
license_family: BSD
size: 100048
timestamp: 1777219902525
+- conda: https://conda.anaconda.org/conda-forge/noarch/click-plugins-1.1.1.2-pyhd8ed1ab_0.conda
+ sha256: ba1ee6e2b2be3da41d70d0d51d1159010de900aa3f33fceaea8c52e9bd30a26e
+ md5: e9b05deb91c013e5224672a4ba9cf8d1
+ depends:
+ - click >=4.0
+ - python >=3.9
+ license: BSD-3-Clause
+ license_family: BSD
+ size: 12683
+ timestamp: 1750848314962
+- conda: https://conda.anaconda.org/conda-forge/noarch/cligj-0.7.2-pyhd8ed1ab_2.conda
+ sha256: 1a52ae1febfcfb8f56211d1483a1ac4419b0028b7c3e9e61960a298978a42396
+ md5: 55c7804f428719241a90b152016085a1
+ depends:
+ - click >=4.0
+ - python >=3.9,<4.0
+ license: BSD-3-Clause
+ license_family: BSD
+ size: 12521
+ timestamp: 1733750069604
- conda: https://conda.anaconda.org/conda-forge/noarch/clio-tools-2026.03.30-pyhd8ed1ab_0.conda
sha256: a8b34e4bb8854ad899e461430fbabad81fa694805e45421bfe3e56da031d44ad
md5: 169bb144044321bb1cec1bfa4ea82a5b
@@ -6108,35 +6170,35 @@ packages:
license_family: MIT
size: 152965
timestamp: 1661419601518
-- conda: https://conda.anaconda.org/conda-forge/noarch/geopandas-1.0.1-pyhd8ed1ab_3.conda
- sha256: 04f7e616ebbf6352ff852b53c57901e43f14e2b3c92411f99b5547f106bc192e
- md5: 1baca589eb35814a392eaad6d152447e
+- conda: https://conda.anaconda.org/conda-forge/noarch/geopandas-1.1.3-pyhd8ed1ab_0.conda
+ sha256: c9ed18fb6270202299671f8075dd4f2fdff42220e4fd958e84629375769747f0
+ md5: 4eb8b870142ca06d2a1d2c74662eac7d
depends:
- folium
- - geopandas-base 1.0.1 pyha770c72_3
- - mapclassify >=2.4.0
+ - geopandas-base 1.1.3 pyha770c72_0
+ - mapclassify >=2.5.0
- matplotlib-base
- pyogrio >=0.7.2
- - pyproj >=3.3.0
- - python >=3.9
+ - pyproj >=3.5.0
+ - python >=3.10
- xyzservices
license: BSD-3-Clause
license_family: BSD
- size: 7583
- timestamp: 1734346218849
-- conda: https://conda.anaconda.org/conda-forge/noarch/geopandas-base-1.0.1-pyha770c72_3.conda
- sha256: 2d031871b57c6d4e5e2d6cc23bd6d4e0084bb52ebca5c1b20bf06d03749e0f24
- md5: e8343d1b635bf09dafdd362d7357f395
+ size: 8761
+ timestamp: 1773131235020
+- conda: https://conda.anaconda.org/conda-forge/noarch/geopandas-base-1.1.3-pyha770c72_0.conda
+ sha256: b07fc3edb5cb86df52081e5cb120a03a178767ed079b5d2cd313212351460620
+ md5: 18789a85c307970ae1786dfc6dfd234f
depends:
- - numpy >=1.22
+ - numpy >=1.24
- packaging
- - pandas >=1.4.0
- - python >=3.9
+ - pandas >=2.0.0
+ - python >=3.10
- shapely >=2.0.0
license: BSD-3-Clause
license_family: BSD
- size: 239261
- timestamp: 1734346217454
+ size: 254983
+ timestamp: 1773131233972
- conda: https://conda.anaconda.org/conda-forge/noarch/gitdb-4.0.12-pyhd8ed1ab_0.conda
sha256: dbbec21a369872c8ebe23cb9a3b9d63638479ee30face165aa0fccc96e93eec3
md5: 7c14f3706e099f8fcd47af2d494616cc
@@ -7338,6 +7400,17 @@ packages:
license_family: BSD
size: 26051
timestamp: 1739781801801
+- conda: https://conda.anaconda.org/conda-forge/noarch/snuggs-1.4.7-pyhd8ed1ab_2.conda
+ sha256: 61f9373709e7d9009e3a062b135dbe44b16e684a4fcfe2dd624143bc0f80d402
+ md5: 9aa358575bbd4be126eaa5e0039f835c
+ depends:
+ - numpy
+ - pyparsing >=2.1.6
+ - python >=3.9
+ license: MIT
+ license_family: MIT
+ size: 11313
+ timestamp: 1733818738919
- conda: https://conda.anaconda.org/conda-forge/noarch/sqlmodel-0.0.37-pyhcf101f3_0.conda
sha256: 9cbf4805021fd817fde2654ccc1a1bd0352647614819a28381e81098efe4da20
md5: 00e6147bef9a85139099c9861c3b976b
@@ -8387,6 +8460,24 @@ packages:
license: LGPL-2.1-only
size: 1536680
timestamp: 1755851888781
+- conda: https://conda.anaconda.org/conda-forge/osx-arm64/geotiff-1.7.4-hf862be1_4.conda
+ sha256: 139909705857801b2cf4ff738a70c035365248a35583ba6ecab7c981ac5356da
+ md5: 111fe25c7b56f8e8f10322b4d99abe69
+ depends:
+ - proj
+ - zlib
+ - libjpeg-turbo
+ - libtiff
+ - __osx >=11.0
+ - libcxx >=19
+ - libzlib >=1.3.1,<2.0a0
+ - libjpeg-turbo >=3.1.0,<4.0a0
+ - libtiff >=4.7.0,<4.8.0a0
+ - proj >=9.7.0,<9.8.0a0
+ license: MIT
+ license_family: MIT
+ size: 128471
+ timestamp: 1757965588361
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/gflags-2.2.2-hf9b8971_1005.conda
sha256: fd56ed8a1dab72ab90d8a8929b6f916a6d9220ca297ff077f8f04c5ed3408e20
md5: 57a511a5905caa37540eb914dfcbf1fb
@@ -9075,13 +9166,14 @@ packages:
license_family: BSD
size: 159247
timestamp: 1766331953491
-- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgdal-core-3.11.4-h693e041_6.conda
- sha256: b10496eac3bfc9509009ea9e9ffd2fd4aea4409d780b0fc2c763c63e1656b14d
- md5: dbc028bb7adefb044f57a3d1ef7d5577
+- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgdal-core-3.10.3-h694df76_24.conda
+ sha256: 30c224f677f1d2779b955434fef8c16b3b391e7461e18f4855053ffeb7a9d6f2
+ md5: 021a4f4c798ede069f985f6bbeb2bb88
depends:
- __osx >=11.0
- blosc >=1.21.6,<2.0a0
- geos >=3.14.0,<3.14.1.0a0
+ - geotiff >=1.7.4,<1.8.0a0
- giflib >=5.2.2,<5.3.0a0
- json-c >=0.18,<0.19.0a0
- lerc >=4.0.0,<5.0a0
@@ -9092,29 +9184,28 @@ packages:
- libexpat >=2.7.1,<3.0a0
- libiconv >=1.18,<2.0a0
- libjpeg-turbo >=3.1.0,<4.0a0
- - libjxl >=0.11,<0.12.0a0
- libkml >=1.3.0,<1.4.0a0
- liblzma >=5.8.1,<6.0a0
- libpng >=1.6.50,<1.7.0a0
- libspatialite >=5.1.0,<5.2.0a0
- libsqlite >=3.50.4,<4.0a0
+ - libtiff >=4.7.1,<4.8.0a0
- libwebp-base >=1.6.0,<2.0a0
- libxml2
- libxml2-16 >=2.14.6
- libzlib >=1.3.1,<2.0a0
- lz4-c >=1.10.0,<1.11.0a0
- - muparser >=2.3.5,<2.4.0a0
- openssl >=3.5.4,<4.0a0
- pcre2 >=10.46,<10.47.0a0
- proj >=9.7.0,<9.8.0a0
- xerces-c >=3.3.0,<3.4.0a0
- zstd >=1.5.7,<1.6.0a0
constrains:
- - libgdal 3.11.4.*
+ - libgdal 3.10.3.*
license: MIT
license_family: MIT
- size: 9273075
- timestamp: 1761262580865
+ size: 8497903
+ timestamp: 1761693365540
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran-15.2.0-h07b0088_16.conda
sha256: 68a6c1384d209f8654112c4c57c68c540540dd8e09e17dd1facf6cf3467798b5
md5: 11e09edf0dde4c288508501fe621bab4
@@ -9228,15 +9319,6 @@ packages:
license_family: APACHE
size: 4820402
timestamp: 1774012715207
-- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libhwy-1.4.0-ha332bbd_0.conda
- sha256: 4fcad3cbec60da940312e883b7866816517acc5f9baecfe9a778de57327a1b1b
- md5: 7394850583ca88325244b68b532c7a39
- depends:
- - __osx >=11.0
- - libcxx >=19
- license: Apache-2.0 OR BSD-3-Clause
- size: 609931
- timestamp: 1776990524407
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libiconv-1.18-h23cfdf5_2.conda
sha256: de0336e800b2af9a40bdd694b03870ac4a848161b35c8a2325704f123f185f03
md5: 4d5a7445f0b25b6a3ddbb56e790f5251
@@ -9274,19 +9356,6 @@ packages:
license: IJG AND BSD-3-Clause AND Zlib
size: 555681
timestamp: 1775962975624
-- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libjxl-0.11.2-h934fa54_1.conda
- sha256: 948cf1370abb58e06a7c9554838c68672ef1d78e01c3fc4e62ccfc3072579645
- md5: 05bead8980f5ae6a070117dacec38b5b
- depends:
- - libcxx >=19
- - __osx >=11.0
- - libhwy >=1.4.0,<1.5.0a0
- - libbrotlienc >=1.2.0,<1.3.0a0
- - libbrotlidec >=1.2.0,<1.3.0a0
- license: BSD-3-Clause
- license_family: BSD
- size: 1032419
- timestamp: 1777065264956
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libkml-1.3.0-hb833057_1023.conda
sha256: bfc6c0b1f30de524e3270eed2171d87e6b96552ff90cf2a5eb34c00d6bcb3dfa
md5: 3d8eeedb8e541d1cb593e8204fcc397d
@@ -9957,17 +10026,6 @@ packages:
license_family: Apache
size: 91725
timestamp: 1762504404391
-- conda: https://conda.anaconda.org/conda-forge/osx-arm64/muparser-2.3.5-h11e0b38_0.conda
- sha256: 5533e7e3d4b0819b4426f8a1b3f680e6b9c922cdae2b7fabcd0e8c59df22772a
- md5: 1cdbe54881794ee356d3cba7e3ed6668
- depends:
- - __osx >=11.0
- - libcxx >=18
- - llvm-openmp >=18.1.8
- license: MIT
- license_family: MIT
- size: 154087
- timestamp: 1747117056226
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/mypy-1.19.1-py313hd3e6d80_0.conda
sha256: 7f52c1ede45433ae03b1ea4a45e1e6ed3fdf4f6e9e54d9ac05718205f49856e7
md5: dd6f5c085908e1945002e50d60c5c4d8
@@ -10425,13 +10483,13 @@ packages:
license_family: MIT
size: 1720475
timestamp: 1778084300413
-- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyogrio-0.11.1-py313hd8ca31c_1.conda
- sha256: a028079ee0884dd778a94840733f864e7336c12ca2182b46a33592242b3a59cc
- md5: d617721ce482cbba8c40f4a9872a2c4f
+- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyogrio-0.11.0-py313h4ad91d6_0.conda
+ sha256: 8fbeefdb9f67cd188c38cb50a9c1ffa360fd4c987666060e2cf7773eb38c54f6
+ md5: dafffca1d5d08b8966815eed08aece8a
depends:
- __osx >=11.0
- - libcxx >=19
- - libgdal-core >=3.11.3,<3.12.0a0
+ - libcxx >=18
+ - libgdal-core >=3.10.3,<3.11.0a0
- numpy
- packaging
- python >=3.13,<3.14.0a0
@@ -10439,8 +10497,8 @@ packages:
- python_abi 3.13.* *_cp313
license: MIT
license_family: MIT
- size: 570550
- timestamp: 1756824596862
+ size: 601750
+ timestamp: 1746734883266
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pyproj-3.7.2-py313h6de5794_3.conda
sha256: 7a65aa08a4dd6060289a73d461a379ee8e6c183f1b6dd78e0c01332acec8f651
md5: 1f2ae983e8f36a664dbe220b8d1f7e97
@@ -10589,6 +10647,31 @@ packages:
license: LicenseRef-Qhull
size: 516376
timestamp: 1720814307311
+- conda: https://conda.anaconda.org/conda-forge/osx-arm64/rasterio-1.4.4-py313hb3bd904_0.conda
+ sha256: fbbaf8378343197c30aea6d796847ac792e5f38e263383d6360d49122a33d611
+ md5: 699df60947da770aa55348cccfa4f082
+ depends:
+ - __osx >=11.0
+ - affine
+ - attrs
+ - certifi
+ - click >=4,!=8.2.*
+ - click-plugins
+ - cligj >=0.5
+ - libcxx >=19
+ - libgdal-core <3.11
+ - libgdal-core >=3.10.3,<3.11.0a0
+ - numpy >=1.23,<3
+ - proj >=9.7.1,<9.8.0a0
+ - python >=3.13,<3.14.0a0
+ - python >=3.13,<3.14.0a0 *_cp313
+ - python_abi 3.13.* *_cp313
+ - setuptools >=0.9.8
+ - snuggs >=1.4.1
+ license: BSD-3-Clause
+ license_family: BSD
+ size: 7141339
+ timestamp: 1765553472902
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/re2-2025.11.05-ha480c28_1.conda
sha256: 5bab972e8f2bff1b5b3574ffec8ecb89f7937578bd107584ed3fde507ff132f9
md5: a1ff22f664b0affa3de712749ccfbf04
@@ -11584,6 +11667,28 @@ packages:
license: LGPL-2.1-only
size: 1728594
timestamp: 1755852570331
+- conda: https://conda.anaconda.org/conda-forge/win-64/geotiff-1.7.4-h73469f5_4.conda
+ sha256: 5f01f23fc4447b130238668a40d1c7baa916f3ad175e5772c8482fc1f8c9e2e7
+ md5: 2a62961eeffe28d84c166600e4bf6e25
+ depends:
+ - proj
+ - zlib
+ - libjpeg-turbo
+ - libtiff
+ - vc >=14.3,<15
+ - vc14_runtime >=14.44.35208
+ - ucrt >=10.0.20348.0
+ - vc >=14.3,<15
+ - vc14_runtime >=14.44.35208
+ - ucrt >=10.0.20348.0
+ - libzlib >=1.3.1,<2.0a0
+ - libtiff >=4.7.0,<4.8.0a0
+ - proj >=9.7.0,<9.8.0a0
+ - libjpeg-turbo >=3.1.0,<4.0a0
+ license: MIT
+ license_family: MIT
+ size: 137535
+ timestamp: 1757965585058
- conda: https://conda.anaconda.org/conda-forge/win-64/getopt-win32-0.1-h6a83c73_3.conda
sha256: d04c4a6c11daa72c4a0242602e1d00c03291ef66ca2d7cd0e171088411d57710
md5: 49c36fcad2e9af6b91e91f2ce5be8ebd
@@ -12190,12 +12295,13 @@ packages:
license_family: BSD
size: 166711
timestamp: 1766331770351
-- conda: https://conda.anaconda.org/conda-forge/win-64/libgdal-core-3.11.4-h8a8bf46_6.conda
- sha256: 2602a1e0503dc2083524d8428d89ccc66e73ed09e706334c62e1fd85c9375eb2
- md5: fd3141a9ef5384b6ecad819ffe429378
+- conda: https://conda.anaconda.org/conda-forge/win-64/libgdal-core-3.10.3-h2f24e33_24.conda
+ sha256: e23a12478480266f7ac6bffbc22082f534c23e251dfec2923edfff9f60947b70
+ md5: 0489c36d03b99d3f71d9d0b4742f1620
depends:
- blosc >=1.21.6,<2.0a0
- geos >=3.14.0,<3.14.1.0a0
+ - geotiff >=1.7.4,<1.8.0a0
- lerc >=4.0.0,<5.0a0
- libarchive >=3.8.2,<3.9.0a0
- libcurl >=8.16.0,<9.0a0
@@ -12203,18 +12309,17 @@ packages:
- libexpat >=2.7.1,<3.0a0
- libiconv >=1.18,<2.0a0
- libjpeg-turbo >=3.1.0,<4.0a0
- - libjxl >=0.11,<0.12.0a0
- libkml >=1.3.0,<1.4.0a0
- liblzma >=5.8.1,<6.0a0
- libpng >=1.6.50,<1.7.0a0
- libspatialite >=5.1.0,<5.2.0a0
- libsqlite >=3.50.4,<4.0a0
+ - libtiff >=4.7.1,<4.8.0a0
- libwebp-base >=1.6.0,<2.0a0
- libxml2
- libxml2-16 >=2.14.6
- libzlib >=1.3.1,<2.0a0
- lz4-c >=1.10.0,<1.11.0a0
- - muparser >=2.3.5,<2.4.0a0
- openssl >=3.5.4,<4.0a0
- pcre2 >=10.46,<10.47.0a0
- proj >=9.7.0,<9.8.0a0
@@ -12224,11 +12329,11 @@ packages:
- xerces-c >=3.3.0,<3.4.0a0
- zstd >=1.5.7,<1.6.0a0
constrains:
- - libgdal 3.11.4.*
+ - libgdal 3.10.3.*
license: MIT
license_family: MIT
- size: 9195264
- timestamp: 1761261707518
+ size: 8467648
+ timestamp: 1761692955596
- conda: https://conda.anaconda.org/conda-forge/win-64/libglib-2.86.3-h0c9aed9_0.conda
sha256: 84b74fc81fff745f3d21a26c317ace44269a563a42ead3500034c27e407e1021
md5: c2d5b6b790ef21abac0b5331094ccb56
@@ -12351,16 +12456,6 @@ packages:
license_family: BSD
size: 2411241
timestamp: 1765104337762
-- conda: https://conda.anaconda.org/conda-forge/win-64/libhwy-1.4.0-h172a326_0.conda
- sha256: 4b45bf59ee46d3c746272c27651da9ce709fda4eee8536c7424acea60d0e2ad0
- md5: aeca1cb6665f19e560c1fbd20b5bcf34
- depends:
- - ucrt >=10.0.20348.0
- - vc >=14.3,<15
- - vc14_runtime >=14.44.35208
- license: Apache-2.0 OR BSD-3-Clause
- size: 562583
- timestamp: 1776989522919
- conda: https://conda.anaconda.org/conda-forge/win-64/libiconv-1.18-hc1393d2_2.conda
sha256: 0dcdb1a5f01863ac4e8ba006a8b0dc1a02d2221ec3319b5915a1863254d7efa7
md5: 64571d1dd6cdcfa25d0664a5950fdaa2
@@ -12403,20 +12498,6 @@ packages:
license: IJG AND BSD-3-Clause AND Zlib
size: 842806
timestamp: 1775962811457
-- conda: https://conda.anaconda.org/conda-forge/win-64/libjxl-0.11.2-h932607e_1.conda
- sha256: 4715e22c602526c85da09f73865676add67e0995a944b821fbff84547a9db533
- md5: 327bce3eb1ef1875c7145e915d25bcd3
- depends:
- - vc >=14.3,<15
- - vc14_runtime >=14.44.35208
- - ucrt >=10.0.20348.0
- - libhwy >=1.4.0,<1.5.0a0
- - libbrotlienc >=1.2.0,<1.3.0a0
- - libbrotlidec >=1.2.0,<1.3.0a0
- license: BSD-3-Clause
- license_family: BSD
- size: 1194926
- timestamp: 1777065171989
- conda: https://conda.anaconda.org/conda-forge/win-64/libkml-1.3.0-h68a222c_1023.conda
sha256: 6b2c6506dc7d7bb3bc4128d575e4ae6c2cf18d3f9828a4be331e0b5e49edf108
md5: b44e0d9eb84c6c086d809787aab0a1da
@@ -13073,17 +13154,6 @@ packages:
license_family: Apache
size: 88214
timestamp: 1762504204957
-- conda: https://conda.anaconda.org/conda-forge/win-64/muparser-2.3.5-he0c23c2_0.conda
- sha256: 57f78d8cd9a282d03cd7a7ffb1f42d570e1bbfb42d606e99de5c16e089067185
- md5: 013aabb169d59009bdf7d70319360e9b
- depends:
- - ucrt >=10.0.20348.0
- - vc >=14.2,<15
- - vc14_runtime >=14.29.30139
- license: MIT
- license_family: MIT
- size: 148557
- timestamp: 1747117340968
- conda: https://conda.anaconda.org/conda-forge/win-64/mypy-1.19.1-py313h5ea7bf4_0.conda
sha256: cd7b84c381f42944de2deabe98e3f79f39f9fe5eeb9d5a9d071b3476e686a3ac
md5: 1a933205527bdbc6ada5dab36347c993
@@ -13535,22 +13605,22 @@ packages:
license_family: MIT
size: 1888029
timestamp: 1778084253466
-- conda: https://conda.anaconda.org/conda-forge/win-64/pyogrio-0.11.1-py313h0dbd5a6_1.conda
- sha256: 0c37a6adf7f04180911bf46e676ca8ee0eefb5b3be76e872fd6854b953467e15
- md5: 7d1eaf4ed949aeb268394cf2857e20b5
+- conda: https://conda.anaconda.org/conda-forge/win-64/pyogrio-0.11.0-py313h75b81ac_0.conda
+ sha256: a3294855e5682b79a5921d3749fa45286249f2c22782885c14903e6bae8cb507
+ md5: 7a3d31c8db0ac99557cb2faf51fc42b5
depends:
- - libgdal-core >=3.11.3,<3.12.0a0
+ - libgdal-core >=3.10.3,<3.11.0a0
- numpy
- packaging
- python >=3.13,<3.14.0a0
- python_abi 3.13.* *_cp313
- ucrt >=10.0.20348.0
- - vc >=14.3,<15
- - vc14_runtime >=14.44.35208
+ - vc >=14.2,<15
+ - vc14_runtime >=14.29.30139
license: MIT
license_family: MIT
- size: 817932
- timestamp: 1756824550436
+ size: 834342
+ timestamp: 1746735042949
- conda: https://conda.anaconda.org/conda-forge/win-64/pyproj-3.7.2-py313hbf73894_3.conda
sha256: fa38aae6747307dd46747052988b54e2cd340c98b3b969065f52460d9e66b50c
md5: 779b40a8eb5e2aa5ffc5eddd3b136fb7
@@ -13735,6 +13805,31 @@ packages:
license: LicenseRef-Qhull
size: 1377020
timestamp: 1720814433486
+- conda: https://conda.anaconda.org/conda-forge/win-64/rasterio-1.4.4-py313ha5c5119_0.conda
+ sha256: 6891f73e7272ce530d36a5e01ade4c93b5e62133439a0b21bda9b431298f6a1a
+ md5: c094475643548d60959967b5be3638bb
+ depends:
+ - affine
+ - attrs
+ - certifi
+ - click >=4,!=8.2.*
+ - click-plugins
+ - cligj >=0.5
+ - libgdal-core <3.11
+ - libgdal-core >=3.10.3,<3.11.0a0
+ - numpy >=1.23,<3
+ - proj >=9.7.1,<9.8.0a0
+ - python >=3.13,<3.14.0a0
+ - python_abi 3.13.* *_cp313
+ - setuptools >=0.9.8
+ - snuggs >=1.4.1
+ - ucrt >=10.0.20348.0
+ - vc >=14.3,<15
+ - vc14_runtime >=14.44.35208
+ license: BSD-3-Clause
+ license_family: BSD
+ size: 7468329
+ timestamp: 1765553619782
- conda: https://conda.anaconda.org/conda-forge/win-64/re2-2025.11.05-ha104f34_1.conda
sha256: 345b1ed8288d81510101f886aaf547e3294370e5dab340c4c3fcb0b25e5d99e0
md5: 6807f05dcf3f1736ad6cc9525b8b8725
diff --git a/pixi.toml b/pixi.toml
index fc18afa..c423cd1 100644
--- a/pixi.toml
+++ b/pixi.toml
@@ -59,7 +59,7 @@ channels = ["conda-forge"]
[feature.shape.dependencies]
boto3 = "1.40.46.*"
duckdb = "1.2.0.*"
-geopandas = "1.0.1.*"
+geopandas = "1.1.3.*"
ipdb = "0.13.13.*"
pandera-geopandas = "0.24.*"
pandera-io = "0.24.*"
@@ -70,6 +70,8 @@ numpy = "2.3.5.*"
pandas = "3.0.2.*"
pytz = "2026.2.*"
requests = "2.33.1.*"
+antimeridian = "0.4.7.*"
+rasterio = "1.4.4.*"
[environments]
shape = { features = ["shape"], no-default-feature = true }
diff --git a/tests/conftest.py b/tests/conftest.py
new file mode 100644
index 0000000..fef1d4d
--- /dev/null
+++ b/tests/conftest.py
@@ -0,0 +1,11 @@
+"""Shared pytest fixtures."""
+
+from pathlib import Path
+
+import pytest
+
+
+@pytest.fixture(scope="module")
+def module_path():
+ """Parent directory of the project."""
+ return Path(__file__).parent.parent
diff --git a/tests/integration/Snakefile b/tests/integration/Snakefile
index ad71d73..564b3e4 100644
--- a/tests/integration/Snakefile
+++ b/tests/integration/Snakefile
@@ -9,7 +9,7 @@ configfile: workflow.source_path("./test_config.yaml")
module module_geo_boundaries:
pathvars:
# Redirect specific module results (outputs)
- shapes="results/outputs/shapes.parquet",
+ shapes="results/outputs/{scenario}/shapes.parquet",
# Redirect module intermediate files
logs="resources/module/logs",
resources="resources/module/resources",
@@ -28,6 +28,6 @@ use rule * from module_geo_boundaries as geo_boundaries_module_*
rule all:
default_target: True
input:
- "results/outputs/shapes.parquet",
+ "results/outputs/integration/shapes.parquet",
message:
"A generic test case for this module."
diff --git a/tests/integration/test_config.yaml b/tests/integration/test_config.yaml
index ea3ad94..25d8bd0 100644
--- a/tests/integration/test_config.yaml
+++ b/tests/integration/test_config.yaml
@@ -2,16 +2,18 @@ module_geo_boundaries:
crs:
projected: "epsg:3857"
geographic: "epsg:4326"
- countries:
- "MNE":
- subtype: "0"
- source: "geoboundaries"
- release_type: "gbOpen"
- "SVK":
- subtype: "country"
- source: "overture"
- "MKD":
- subtype: "0"
- source: "nuts"
- resolution: 03M
- year: 2024
+ scenarios:
+ integration:
+ countries:
+ "MNE":
+ subtype: "0"
+ source: "geoboundaries"
+ release_type: "gbOpen"
+ "SVK":
+ subtype: "country"
+ source: "overture"
+ "MKD":
+ subtype: "0"
+ source: "nuts"
+ resolution: 03M
+ year: 2024
diff --git a/tests/integration_test.py b/tests/integration_test.py
index 009e87f..7210a3a 100644
--- a/tests/integration_test.py
+++ b/tests/integration_test.py
@@ -11,12 +11,6 @@
from clio_tools.data_module import ModuleInterface
-@pytest.fixture(scope="module")
-def module_path():
- """Parent directory of the project."""
- return Path(__file__).parent.parent
-
-
def test_interface_file(module_path):
"""The interfacing file should be correct."""
assert ModuleInterface.from_yaml(module_path / "INTERFACE.yaml")
diff --git a/tests/local_test.py b/tests/local_test.py
index 8c1fe56..d8b5ce3 100644
--- a/tests/local_test.py
+++ b/tests/local_test.py
@@ -4,7 +4,7 @@
You'll likely run out of memory.
Instead, run a relevant case:
-pytest tests/local_test.py::test_config_example["europe_example"]
+pytest tests/local_test.py::test_config_example
"""
import subprocess
@@ -13,29 +13,22 @@
import pytest
-@pytest.fixture(scope="module")
-def module_path():
- """Parent directory of the project."""
- return Path(__file__).parent.parent
-
-
@pytest.mark.parametrize(
- "scenario", ["config", "china_example", "europe_example", "usa_example"]
+ "scenario", ["mixed_example", "china_national", "USA_states", "europe_regions"]
)
-def test_config_example(module_path, scenario):
+def test_scenario(module_path: Path, scenario: str):
"""Example files should result in a successful run."""
- result_file = "results/shapes.parquet"
- config_file = Path(module_path / f"config/{scenario}.yaml")
- smk_command = f"snakemake --cores 4 --replace-workflow-config --configfile={config_file} {result_file}"
+ result_file = f"results/{scenario}/shapes.parquet"
+ smk_command = f"snakemake --cores 4 {result_file}"
subprocess.run(smk_command + " --forceall", shell=True, check=True, cwd=module_path)
subprocess.run(
- smk_command + " --report results/report.html",
+ smk_command + f" --report results/{scenario}/report.html",
shell=True,
check=True,
cwd=module_path,
)
subprocess.run(
- smk_command + " --rulegraph | dot -Tpng > results/rulegraph.png",
+ smk_command + f" --rulegraph | dot -Tpng > results/{scenario}/rulegraph.png",
shell=True,
check=True,
cwd=module_path,
diff --git a/workflow/Snakefile b/workflow/Snakefile
index a546796..6ff7a30 100644
--- a/workflow/Snakefile
+++ b/workflow/Snakefile
@@ -10,7 +10,12 @@ min_version("9.19")
# This allows users to re-wire how the module is used in their workflow with ease.
pathvars:
# Module results
- shapes="/shapes.parquet",
+ shapes="/{scenario}/shapes.parquet",
+
+
+wildcard_constraints:
+ country="[A-Z]{3}",
+ eez_key="[0-9_]+",
# Load the example configuration. This will be overridden by users.
@@ -33,6 +38,7 @@ include: "rules/build.smk"
# Add all files to be delivered alongside the workflow here
+workflow.source_path("scripts/_geo.py")
workflow.source_path("scripts/_schemas.py")
workflow.source_path("scripts/_utils.py")
diff --git a/workflow/envs/shape.linux-64.pin.txt b/workflow/envs/shape.linux-64.pin.txt
index a434d88..cdcaf4b 100644
--- a/workflow/envs/shape.linux-64.pin.txt
+++ b/workflow/envs/shape.linux-64.pin.txt
@@ -23,20 +23,24 @@ https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda#4a13
https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda#18335a698559cdbcd86150a48bf54ba6
https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda#d2ffd7602c02f2b316fd921d39876885
https://conda.anaconda.org/conda-forge/linux-64/python-3.12.13-hd63d673_0_cpython.conda#7eccb41177e15cc672e1babe9056018e
-https://conda.anaconda.org/conda-forge/noarch/pytz-2026.2-pyhcf101f3_0.conda#03cb60f505ad3ada0a95277af5faeb1a
-https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda#8e194e7b992f99a5015edbd4ebd38efd
-https://conda.anaconda.org/conda-forge/noarch/pycountry-24.6.1-pyhd8ed1ab_0.conda#62ed8c560f1b5b8d74ed11e68e9ae223
+https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda#3687cc0b82a8b4c17e1f0eb7e47163d5
https://conda.anaconda.org/conda-forge/noarch/python_abi-3.12-8_cp312.conda#c3efd25ac4d74b1584d2f7a57195ddf1
https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_19.conda#5794b3bdc38177caf969dabd3af08549
-https://conda.anaconda.org/conda-forge/linux-64/snappy-1.2.2-h03e3b7b_1.conda#98b6c9dc80eb87b2519b97bcf7e578dd
-https://conda.anaconda.org/conda-forge/linux-64/libabseil-20260107.1-cxx17_h7b12aa8_0.conda#6f7b4302263347698fd24565fbf11310
-https://conda.anaconda.org/conda-forge/linux-64/libre2-11-2025.11.05-h0dc7533_1.conda#ced7f10b6cfb4389385556f47c0ad949
-https://conda.anaconda.org/conda-forge/linux-64/re2-2025.11.05-h5301d42_1.conda#66a715bc01c77d43aca1f9fcb13dde3c
-https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.10.0-h5888daf_1.conda#9de5350a85c4a20c685259b889aa6393
-https://conda.anaconda.org/conda-forge/linux-64/libprotobuf-6.33.5-h2b00c02_0.conda#11ac478fa72cf12c214199b8a96523f4
-https://conda.anaconda.org/conda-forge/linux-64/orc-2.2.2-hbb90d81_1.conda#9269175175f18091b8844c8e9f213205
-https://conda.anaconda.org/conda-forge/linux-64/libutf8proc-2.11.3-hfe17d71_0.conda#1247168fe4a0b8912e3336bccdbf98a5
-https://conda.anaconda.org/conda-forge/linux-64/zlib-1.3.2-h25fd6f3_2.conda#c2a01a08fc991620a74b32420e97868a
+https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_19.conda#85072b0ad177c966294f129b7c04a2d5
+https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_19.conda#42bf7eca1a951735fa06c0e3c0d5c8e6
+https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.32-pthreads_h94d23a6_0.conda#89d61bc91d3f39fda0ca10fcd3c68594
+https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-6_h4a7cf45_openblas.conda#6d6d225559bfa6e2f3c90ee9c03d4e2e
+https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-6_h47877c9_openblas.conda#881d801569b201c2e753f03c84b85e15
+https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-6_h0358290_openblas.conda#36ae340a916635b97ac8a0655ace2a35
+https://conda.anaconda.org/conda-forge/linux-64/numpy-2.3.5-py312h33ff503_1.conda#03baecffb72fa96fe234fd505908065f
+https://conda.anaconda.org/conda-forge/noarch/snuggs-1.4.7-pyhd8ed1ab_2.conda#9aa358575bbd4be126eaa5e0039f835c
+https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda#8e194e7b992f99a5015edbd4ebd38efd
+https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.53.1-hbc0de68_0.conda#8e0b8654ead18e50af552e54b5a08a61
+https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.6.0-hd42ef1d_0.conda#aea31d2e5b1091feca96fcfe945c3cf9
+https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.1.4.1-hb03c661_0.conda#6178c6f2fb254558238ef4e6c56fb782
+https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.25-h17f619e_0.conda#6c77a605a7a689d17d4819c0f8ac9a00
+https://conda.anaconda.org/conda-forge/linux-64/lerc-4.1.0-hdb68285_0.conda#a752488c68f2e7c456bcbd8f16eec275
+https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.1-h9d88235_1.conda#cd5a90476766d53e901500df9215e927
https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.1-hcf80075_0.conda#eecce068c7e4eddeb169591baac20ac4
https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-hd590300_2.conda#172bf1cd1ff8629f2b1179945ed45055
https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.6-hb03c661_0.conda#920bb03579f15389b9e512095ad995b7
@@ -45,13 +49,54 @@ https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949
https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.3-hb9d3cd8_0.conda#b38117a3c920364aff79f870c984b4a3
https://conda.anaconda.org/conda-forge/linux-64/krb5-1.22.2-ha1258a1_0.conda#fb53fb07ce46a575c5d004bbc96032c2
https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.20.0-hcf29cc6_0.conda#c3cc2864f82a944bc90a7beb4d3b0e88
+https://conda.anaconda.org/conda-forge/linux-64/proj-9.7.1-he0df7b0_3.conda#031e33ae075b336c0ce92b14efa886c5
+https://conda.anaconda.org/conda-forge/linux-64/icu-78.3-h33c6efd_0.conda#c80d8a3b84358cb967fa81e7075fbc8a
+https://conda.anaconda.org/conda-forge/linux-64/xerces-c-3.3.0-hd9031aa_1.conda#66a1db55ecdb7377d2b91f54cd56eafa
+https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.46-h1321c63_0.conda#7fa07cb0fb1b625a089ccc01218ee5b1
+https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.10.0-h5888daf_1.conda#9de5350a85c4a20c685259b889aa6393
+https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h3b78370_2.conda#915f5995e94f60e9a4826e0b0920ee88
+https://conda.anaconda.org/conda-forge/linux-64/libxml2-16-2.15.3-hca6bf5a_0.conda#e79d2c2f24b027aa8d5ab1b1ba3061e7
+https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.15.3-h49c6c72_0.conda#995d8c8bad2a3cc8db14675a153dec2b
+https://conda.anaconda.org/conda-forge/linux-64/zlib-1.3.2-h25fd6f3_2.conda#c2a01a08fc991620a74b32420e97868a
+https://conda.anaconda.org/conda-forge/linux-64/libxml2-devel-2.15.3-h49c6c72_0.conda#be70cb50dd0ecc1531c58034d38f72e0
+https://conda.anaconda.org/conda-forge/linux-64/geos-3.14.0-h480dda7_0.conda#5dc479effdabf54a0ff240d565287495
+https://conda.anaconda.org/conda-forge/linux-64/librttopo-1.1.0-h96cd706_19.conda#212a9378a85ad020b8dc94853fdbeb6c
+https://conda.anaconda.org/conda-forge/linux-64/minizip-4.2.1-hb71707f_0.conda#fe7b4ff5792fee512aad843294ea809a
+https://conda.anaconda.org/conda-forge/linux-64/freexl-2.0.0-h9dce30a_2.conda#ecb5d11305b8ba1801543002e69d2f2f
+https://conda.anaconda.org/conda-forge/linux-64/libspatialite-5.1.0-gpl_hcb59c51_118.conda#ce07b32efdf860ed996fdedcff3ea96e
+https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.58-h421ea60_0.conda#eba48a68a1a2b9d3c0d9511548db85db
+https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-15.2.0-hdf11a46_19.conda#e5ce228e579726c07255dbf90dc62101
+https://conda.anaconda.org/conda-forge/linux-64/uriparser-0.9.8-hac33072_0.conda#d71d3a66528853c0a1ac2c02d79a0284
+https://conda.anaconda.org/conda-forge/linux-64/libkml-1.3.0-haa4a5bd_1023.conda#953b7cca897e21215302dbfe2af5cd0c
+https://conda.anaconda.org/conda-forge/linux-64/lzo-2.10-h280c20c_1002.conda#45161d96307e3a447cc3eb5896cf6f8c
+https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.8.7-gpl_hc2c16d8_100.conda#dbeb5c8321cb2408d406a3da16a0ff0d
+https://conda.anaconda.org/conda-forge/linux-64/json-c-0.18-h6688a6e_0.conda#38f5dbc9ac808e31c00650f7be1db93f
+https://conda.anaconda.org/conda-forge/linux-64/giflib-5.2.2-hd590300_0.conda#3bf7b9fd5a7136126e0234db4b87c8b6
+https://conda.anaconda.org/conda-forge/linux-64/geotiff-1.7.4-h1000f5c_4.conda#ff1966654a6cd1cf06a6e44c13e60b8a
+https://conda.anaconda.org/conda-forge/linux-64/snappy-1.2.2-h03e3b7b_1.conda#98b6c9dc80eb87b2519b97bcf7e578dd
+https://conda.anaconda.org/conda-forge/linux-64/blosc-1.21.6-he440d0b_1.conda#2c2fae981fd2afd00812c92ac47d023d
+https://conda.anaconda.org/conda-forge/linux-64/libgdal-core-3.10.3-h05c3bbc_24.conda#a69445ccff7ec3d60fe14110bd4d86ae
+https://conda.anaconda.org/conda-forge/noarch/click-8.3.3-pyhc90fa1f_0.conda#2266262ce8a425ecb6523d765f79b303
+https://conda.anaconda.org/conda-forge/noarch/cligj-0.7.2-pyhd8ed1ab_2.conda#55c7804f428719241a90b152016085a1
+https://conda.anaconda.org/conda-forge/noarch/click-plugins-1.1.1.2-pyhd8ed1ab_0.conda#e9b05deb91c013e5224672a4ba9cf8d1
+https://conda.anaconda.org/conda-forge/noarch/certifi-2026.4.22-pyhd8ed1ab_0.conda#929471569c93acefb30282a22060dcd5
+https://conda.anaconda.org/conda-forge/noarch/attrs-26.1.0-pyhcf101f3_0.conda#c6b0543676ecb1fb2d7643941fe375f2
+https://conda.anaconda.org/conda-forge/noarch/affine-2.4.0-pyhd8ed1ab_1.conda#8c4061f499edec6b8ac7000f6d586829
+https://conda.anaconda.org/conda-forge/linux-64/rasterio-1.4.4-py312h762fea3_0.conda#df884dc5a76b2e2b2d13901f0d5d1668
+https://conda.anaconda.org/conda-forge/noarch/pytz-2026.2-pyhcf101f3_0.conda#03cb60f505ad3ada0a95277af5faeb1a
+https://conda.anaconda.org/conda-forge/noarch/pycountry-24.6.1-pyhd8ed1ab_0.conda#62ed8c560f1b5b8d74ed11e68e9ae223
+https://conda.anaconda.org/conda-forge/linux-64/libabseil-20260107.1-cxx17_h7b12aa8_0.conda#6f7b4302263347698fd24565fbf11310
+https://conda.anaconda.org/conda-forge/linux-64/libre2-11-2025.11.05-h0dc7533_1.conda#ced7f10b6cfb4389385556f47c0ad949
+https://conda.anaconda.org/conda-forge/linux-64/re2-2025.11.05-h5301d42_1.conda#66a715bc01c77d43aca1f9fcb13dde3c
+https://conda.anaconda.org/conda-forge/linux-64/libprotobuf-6.33.5-h2b00c02_0.conda#11ac478fa72cf12c214199b8a96523f4
+https://conda.anaconda.org/conda-forge/linux-64/orc-2.2.2-hbb90d81_1.conda#9269175175f18091b8844c8e9f213205
+https://conda.anaconda.org/conda-forge/linux-64/libutf8proc-2.11.3-hfe17d71_0.conda#1247168fe4a0b8912e3336bccdbf98a5
https://conda.anaconda.org/conda-forge/linux-64/prometheus-cpp-1.3.0-ha5d0236_0.conda#a83f6a2fdc079e643237887a37460668
https://conda.anaconda.org/conda-forge/linux-64/nlohmann_json-3.12.0-h54a6638_1.conda#16c2a0e9c4a166e53632cfca4f68d020
https://conda.anaconda.org/conda-forge/linux-64/libopentelemetry-cpp-headers-1.21.0-ha770c72_2.conda#253e70376a8ae74f9d99d44712b3e087
https://conda.anaconda.org/conda-forge/linux-64/libgrpc-1.78.1-h1d1128b_0.conda#b5fb6d6c83f63d83ef2721dca6ff7091
https://conda.anaconda.org/conda-forge/linux-64/libopentelemetry-cpp-1.21.0-h9692893_2.conda#c3de1cc30bc11edbc98aed352381449d
https://conda.anaconda.org/conda-forge/linux-64/libgoogle-cloud-2.39.0-h9d11ab5_1.conda#cd398eb8374fb626a710b7a35b7ffa98
-https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-15.2.0-hdf11a46_19.conda#e5ce228e579726c07255dbf90dc62101
https://conda.anaconda.org/conda-forge/linux-64/libcrc32c-1.1.2-h9c3ff4c_0.tar.bz2#c965a5aa0d5c1c37ffc62dff36e28400
https://conda.anaconda.org/conda-forge/linux-64/libgoogle-cloud-storage-2.39.0-hdbdcf42_1.conda#384a1730ea66a72692e377cb45996d61
https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.2.0-hb03c661_1.conda#72c8fd1af66bd67bf580645b426513ed
@@ -59,10 +104,6 @@ https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.2.0-hb03c661_1.co
https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.2.0-hb03c661_1.conda#366b40a69f0ad6072561c1d09301c886
https://conda.anaconda.org/conda-forge/linux-64/gflags-2.2.2-h5888daf_1005.conda#d411fc29e338efb48c5fd4576d71d881
https://conda.anaconda.org/conda-forge/linux-64/glog-0.7.1-hbabe93e_0.conda#ff862eebdfeb2fd048ae9dc92510baca
-https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h3b78370_2.conda#915f5995e94f60e9a4826e0b0920ee88
-https://conda.anaconda.org/conda-forge/linux-64/icu-78.3-h33c6efd_0.conda#c80d8a3b84358cb967fa81e7075fbc8a
-https://conda.anaconda.org/conda-forge/linux-64/libxml2-16-2.15.3-hca6bf5a_0.conda#e79d2c2f24b027aa8d5ab1b1ba3061e7
-https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.15.3-h49c6c72_0.conda#995d8c8bad2a3cc8db14675a153dec2b
https://conda.anaconda.org/conda-forge/linux-64/azure-core-cpp-1.16.2-h206d751_0.conda#5492abf806c45298ae642831c670bba0
https://conda.anaconda.org/conda-forge/linux-64/azure-storage-common-cpp-12.12.0-ha7a2c86_1.conda#6400f73fe5ebe19fe7aca3616f1f1de7
https://conda.anaconda.org/conda-forge/linux-64/azure-storage-blobs-cpp-12.16.0-hdd73cc9_1.conda#939d9ce324e51961c7c4c0046733dbb7
@@ -108,13 +149,6 @@ https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda#
https://conda.anaconda.org/conda-forge/noarch/pandera-base-0.24.0-pyhd8ed1ab_2.conda#e1c50e117a98e39d297d9290132f032b
https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda#3339e3b65d58accf4ca4fb8748ab16b3
https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda#5b8d21249ff20967101ffa321cab24e8
-https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_19.conda#85072b0ad177c966294f129b7c04a2d5
-https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_19.conda#42bf7eca1a951735fa06c0e3c0d5c8e6
-https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.32-pthreads_h94d23a6_0.conda#89d61bc91d3f39fda0ca10fcd3c68594
-https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-6_h4a7cf45_openblas.conda#6d6d225559bfa6e2f3c90ee9c03d4e2e
-https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-6_h47877c9_openblas.conda#881d801569b201c2e753f03c84b85e15
-https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-6_h0358290_openblas.conda#36ae340a916635b97ac8a0655ace2a35
-https://conda.anaconda.org/conda-forge/linux-64/numpy-2.3.5-py312h33ff503_1.conda#03baecffb72fa96fe234fd505908065f
https://conda.anaconda.org/conda-forge/linux-64/pandas-3.0.2-py312h8ecdadd_0.conda#42050f82a0c0f6fa23eda3d93b251c18
https://conda.anaconda.org/conda-forge/noarch/pandera-0.24.0-hd8ed1ab_2.conda#a12a21a89519f0cc224e44da86f5be2c
https://conda.anaconda.org/conda-forge/noarch/validators-0.35.0-pyhd8ed1ab_0.conda#3449ef730c7d483adde81993994092b9
@@ -123,7 +157,6 @@ https://conda.anaconda.org/conda-forge/noarch/pygments-2.20.0-pyhd8ed1ab_0.conda
https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda#592132998493b3ff25fd7479396e8351
https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.2.0-pyhd8ed1ab_0.conda#6d03368f2b2b0a5fb6839df53b2eb5e0
https://conda.anaconda.org/conda-forge/noarch/rich-15.0.0-pyhcf101f3_0.conda#0242025a3c804966bf71aa04eee82f66
-https://conda.anaconda.org/conda-forge/noarch/click-8.3.3-pyhc90fa1f_0.conda#2266262ce8a425ecb6523d765f79b303
https://conda.anaconda.org/conda-forge/noarch/annotated-doc-0.0.4-pyhcf101f3_0.conda#52be5139047efadaeeb19c6a5103f92a
https://conda.anaconda.org/conda-forge/noarch/typer-0.25.1-pyhcf101f3_0.conda#ef114c2eb2ff19f6bf616c81f4710841
https://conda.anaconda.org/conda-forge/noarch/tabulate-0.10.0-pyhcf101f3_0.conda#3b887b7b3468b0f494b4fad40178b043
@@ -139,14 +172,12 @@ https://conda.anaconda.org/conda-forge/linux-64/backports.zstd-1.4.0-py312h90b7f
https://conda.anaconda.org/conda-forge/noarch/urllib3-2.7.0-pyhd8ed1ab_0.conda#cbb88288f74dbe6ada1c6c7d0a97223e
https://conda.anaconda.org/conda-forge/noarch/idna-3.13-pyhcf101f3_0.conda#fb7130c190f9b4ec91219840a05ba3ac
https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.7-pyhd8ed1ab_0.conda#a9167b9571f3baa9d448faa2139d1089
-https://conda.anaconda.org/conda-forge/noarch/certifi-2026.4.22-pyhd8ed1ab_0.conda#929471569c93acefb30282a22060dcd5
https://conda.anaconda.org/conda-forge/noarch/requests-2.33.1-pyhcf101f3_1.conda#9659f587a8ceacc21864260acd02fc67
https://conda.anaconda.org/conda-forge/noarch/text-unidecode-1.3-pyhd8ed1ab_2.conda#23b4ba5619c4752976eb7ba1f5acb7e8
https://conda.anaconda.org/conda-forge/noarch/python-slugify-8.0.4-pyhd8ed1ab_1.conda#a4059bc12930bddeb41aef71537ffaed
https://conda.anaconda.org/conda-forge/noarch/petl-1.7.17-pyhd8ed1ab_0.conda#4c2498dcda0d58cf25466e82f7287b32
https://conda.anaconda.org/conda-forge/noarch/marko-2.2.2-pyhd8ed1ab_0.conda#3c3e9339e46fffba5920be28d9233860
https://conda.anaconda.org/conda-forge/linux-64/rpds-py-0.30.0-py312h868fb18_0.conda#3ffc5a3572db8751c2f15bacf6a0e937
-https://conda.anaconda.org/conda-forge/noarch/attrs-26.1.0-pyhcf101f3_0.conda#c6b0543676ecb1fb2d7643941fe375f2
https://conda.anaconda.org/conda-forge/noarch/referencing-0.37.0-pyhcf101f3_0.conda#870293df500ca7e18bedefa5838a22ab
https://conda.anaconda.org/conda-forge/noarch/jsonschema-specifications-2025.9.1-pyhcf101f3_0.conda#439cd0f567d697b20a8f45cb70a1005a
https://conda.anaconda.org/conda-forge/noarch/jsonschema-4.26.0-pyhcf101f3_0.conda#ada41c863af263cc4c5fcbaff7c3e4dc
@@ -160,39 +191,11 @@ https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.6-pyhcf101f3_0.co
https://conda.anaconda.org/conda-forge/noarch/pathspec-1.1.1-pyhd8ed1ab_0.conda#11adc78451c998c0fd162584abfa3559
https://conda.anaconda.org/conda-forge/noarch/black-26.3.1-pyh866005b_0.conda#c7e43448266209d766a229cada982884
https://conda.anaconda.org/conda-forge/noarch/pandera-io-0.24.0-hd8ed1ab_2.conda#d456360daad56c802e27504979ef1e19
-https://conda.anaconda.org/conda-forge/linux-64/geos-3.14.0-h480dda7_0.conda#5dc479effdabf54a0ff240d565287495
https://conda.anaconda.org/conda-forge/linux-64/shapely-2.1.1-py312h950be2a_2.conda#6333340e60402c7456811a14e4e12b26
https://conda.anaconda.org/conda-forge/noarch/xyzservices-2026.3.0-pyhd8ed1ab_0.conda#4487b9c371d0161d54b5c7bbd890c0fc
-https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.53.1-hbc0de68_0.conda#8e0b8654ead18e50af552e54b5a08a61
-https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.6.0-hd42ef1d_0.conda#aea31d2e5b1091feca96fcfe945c3cf9
-https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.1.4.1-hb03c661_0.conda#6178c6f2fb254558238ef4e6c56fb782
-https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.25-h17f619e_0.conda#6c77a605a7a689d17d4819c0f8ac9a00
-https://conda.anaconda.org/conda-forge/linux-64/lerc-4.1.0-hdb68285_0.conda#a752488c68f2e7c456bcbd8f16eec275
-https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.1-h9d88235_1.conda#cd5a90476766d53e901500df9215e927
-https://conda.anaconda.org/conda-forge/linux-64/proj-9.7.1-he0df7b0_3.conda#031e33ae075b336c0ce92b14efa886c5
https://conda.anaconda.org/conda-forge/linux-64/pyproj-3.7.2-py312he675c61_3.conda#c3258c31e507a81f0b52156bcca81e73
-https://conda.anaconda.org/conda-forge/linux-64/xerces-c-3.3.0-hd9031aa_1.conda#66a1db55ecdb7377d2b91f54cd56eafa
-https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.46-h1321c63_0.conda#7fa07cb0fb1b625a089ccc01218ee5b1
-https://conda.anaconda.org/conda-forge/linux-64/muparser-2.3.5-h5888daf_0.conda#ab3e3db511033340e75e7002e80ce8c0
-https://conda.anaconda.org/conda-forge/linux-64/libxml2-devel-2.15.3-h49c6c72_0.conda#be70cb50dd0ecc1531c58034d38f72e0
-https://conda.anaconda.org/conda-forge/linux-64/librttopo-1.1.0-h96cd706_19.conda#212a9378a85ad020b8dc94853fdbeb6c
-https://conda.anaconda.org/conda-forge/linux-64/minizip-4.2.1-hb71707f_0.conda#fe7b4ff5792fee512aad843294ea809a
-https://conda.anaconda.org/conda-forge/linux-64/freexl-2.0.0-h9dce30a_2.conda#ecb5d11305b8ba1801543002e69d2f2f
-https://conda.anaconda.org/conda-forge/linux-64/libspatialite-5.1.0-gpl_hcb59c51_118.conda#ce07b32efdf860ed996fdedcff3ea96e
-https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.58-h421ea60_0.conda#eba48a68a1a2b9d3c0d9511548db85db
-https://conda.anaconda.org/conda-forge/linux-64/uriparser-0.9.8-hac33072_0.conda#d71d3a66528853c0a1ac2c02d79a0284
-https://conda.anaconda.org/conda-forge/linux-64/libkml-1.3.0-haa4a5bd_1023.conda#953b7cca897e21215302dbfe2af5cd0c
-https://conda.anaconda.org/conda-forge/linux-64/libhwy-1.4.0-h10be129_0.conda#3a9428b74c403c71048104d38437b48c
-https://conda.anaconda.org/conda-forge/linux-64/libjxl-0.11.2-h174a0a3_1.conda#850f48943d6b4589800a303f0de6a816
-https://conda.anaconda.org/conda-forge/linux-64/lzo-2.10-h280c20c_1002.conda#45161d96307e3a447cc3eb5896cf6f8c
-https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.8.7-gpl_hc2c16d8_100.conda#dbeb5c8321cb2408d406a3da16a0ff0d
-https://conda.anaconda.org/conda-forge/linux-64/json-c-0.18-h6688a6e_0.conda#38f5dbc9ac808e31c00650f7be1db93f
-https://conda.anaconda.org/conda-forge/linux-64/giflib-5.2.2-hd590300_0.conda#3bf7b9fd5a7136126e0234db4b87c8b6
-https://conda.anaconda.org/conda-forge/linux-64/blosc-1.21.6-he440d0b_1.conda#2c2fae981fd2afd00812c92ac47d023d
-https://conda.anaconda.org/conda-forge/linux-64/libgdal-core-3.11.4-h6c36cd4_6.conda#c6c5d093e8a60acdd93f731cc3593c97
-https://conda.anaconda.org/conda-forge/linux-64/pyogrio-0.11.1-py312h6e8b602_1.conda#71e2dd5aa884ab062c2d41fe10f9cefe
+https://conda.anaconda.org/conda-forge/linux-64/pyogrio-0.11.0-py312h02b19dd_0.conda#b4e4e057ab327b7a1270612587a75523
https://conda.anaconda.org/conda-forge/linux-64/qhull-2020.2-h434a139_5.conda#353823361b1d27eb3960efb076dfcaf6
-https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda#3687cc0b82a8b4c17e1f0eb7e47163d5
https://conda.anaconda.org/conda-forge/linux-64/zlib-ng-2.3.3-hceb46e0_1.conda#2aadb0d17215603a82a2a6b0afd9a4cb
https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.4-h55fea9a_0.conda#11b3379b191f63139e29c0d19dee24cd
https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.5-hb03c661_1.conda#1dafce8548e38671bea82e3f5c6ce22f
@@ -219,10 +222,10 @@ https://conda.anaconda.org/conda-forge/noarch/joblib-1.5.3-pyhd8ed1ab_0.conda#61
https://conda.anaconda.org/conda-forge/linux-64/scikit-learn-1.8.0-np2py312h3226591_1.conda#38decbeae260892040709cafc0514162
https://conda.anaconda.org/conda-forge/noarch/networkx-3.6.1-pyhcf101f3_0.conda#a2c1eeadae7a309daed9d62c96012a2b
https://conda.anaconda.org/conda-forge/noarch/mapclassify-2.10.0-pyhd8ed1ab_1.conda#cc293b4cad9909bf66ca117ea90d4631
-https://conda.anaconda.org/conda-forge/noarch/geopandas-base-1.0.1-pyha770c72_3.conda#e8343d1b635bf09dafdd362d7357f395
+https://conda.anaconda.org/conda-forge/noarch/geopandas-base-1.1.3-pyha770c72_0.conda#18789a85c307970ae1786dfc6dfd234f
https://conda.anaconda.org/conda-forge/noarch/branca-0.8.2-pyhd8ed1ab_0.conda#1fcdf88e7a8c296d3df8409bf0690db4
https://conda.anaconda.org/conda-forge/noarch/folium-0.20.0-pyhd8ed1ab_0.conda#a6997a7dcd6673c0692c61dfeaea14ab
-https://conda.anaconda.org/conda-forge/noarch/geopandas-1.0.1-pyhd8ed1ab_3.conda#1baca589eb35814a392eaad6d152447e
+https://conda.anaconda.org/conda-forge/noarch/geopandas-1.1.3-pyhd8ed1ab_0.conda#4eb8b870142ca06d2a1d2c74662eac7d
https://conda.anaconda.org/conda-forge/noarch/pandera-geopandas-0.24.0-hd8ed1ab_2.conda#fb21509f073465506ea994dc4667bf66
https://conda.anaconda.org/conda-forge/noarch/toml-0.10.2-pyhcf101f3_3.conda#d0fc809fa4c4d85e959ce4ab6e1de800
https://conda.anaconda.org/conda-forge/noarch/traitlets-5.15.0-pyhcf101f3_0.conda#4bada6a6d908a27262af8ebddf4f7492
@@ -248,3 +251,4 @@ https://conda.anaconda.org/conda-forge/noarch/jmespath-1.1.0-pyhcf101f3_1.conda#
https://conda.anaconda.org/conda-forge/noarch/botocore-1.40.76-pyhd8ed1ab_0.conda#4babebd5361bc44503358a519a81a465
https://conda.anaconda.org/conda-forge/noarch/s3transfer-0.14.0-pyhd8ed1ab_0.conda#4e3089ce93822a25408c480dd53561b6
https://conda.anaconda.org/conda-forge/noarch/boto3-1.40.46-pyhd8ed1ab_0.conda#a93057bba32eef7b217733734642bfea
+https://conda.anaconda.org/conda-forge/noarch/antimeridian-0.4.7-pyhd8ed1ab_0.conda#56e9ab4ca5ec150ad52ca420f2cec646
diff --git a/workflow/envs/shape.osx-arm64.pin.txt b/workflow/envs/shape.osx-arm64.pin.txt
index eff4525..b2dc58f 100644
--- a/workflow/envs/shape.osx-arm64.pin.txt
+++ b/workflow/envs/shape.osx-arm64.pin.txt
@@ -16,20 +16,27 @@ https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.5.2-hcf2aa1b_0.conda#4
https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.8.0-hf6b4638_0.conda#65466e82c09e888ca7560c11a97d5450
https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-hd037594_9.conda#620b85a3f45526a8bc4d23fd78fc22f0
https://conda.anaconda.org/conda-forge/osx-arm64/python-3.13.13-h20e6be0_100_cp313.conda#9991a930e81d3873eba7a299ba783ec4
-https://conda.anaconda.org/conda-forge/noarch/pytz-2026.2-pyhcf101f3_0.conda#03cb60f505ad3ada0a95277af5faeb1a
-https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda#8e194e7b992f99a5015edbd4ebd38efd
-https://conda.anaconda.org/conda-forge/noarch/pycountry-24.6.1-pyhd8ed1ab_0.conda#62ed8c560f1b5b8d74ed11e68e9ae223
+https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda#3687cc0b82a8b4c17e1f0eb7e47163d5
+https://conda.anaconda.org/conda-forge/osx-arm64/llvm-openmp-22.1.4-hc7d1edf_0.conda#46d04a647df7a4525e487d88068d19ef
+https://conda.anaconda.org/conda-forge/osx-arm64/_openmp_mutex-4.5-7_kmp_llvm.conda#a44032f282e7d2acdeb1c240308052dd
+https://conda.anaconda.org/conda-forge/osx-arm64/libgcc-15.2.0-hcbb3090_19.conda#644058123986582db33aebd4ae2ca184
+https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran5-15.2.0-hdae7583_19.conda#ba36d8c606a6a53fe0b8c12d47267b3d
+https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran-15.2.0-h07b0088_19.conda#1ea03f87cdb1078fbc0e2b2deb63752c
+https://conda.anaconda.org/conda-forge/osx-arm64/libopenblas-0.3.32-openmp_he657e61_0.conda#3a1111a4b6626abebe8b978bb5a323bf
+https://conda.anaconda.org/conda-forge/osx-arm64/libblas-3.11.0-6_h51639a9_openblas.conda#e551103471911260488a02155cef9c94
+https://conda.anaconda.org/conda-forge/osx-arm64/liblapack-3.11.0-6_hd9741b5_openblas.conda#ee33d2d05a7c5ea1f67653b37eb74db1
https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-22.1.5-h55c6f16_1.conda#ff484b683fecf1e875dfc7aa01d19796
+https://conda.anaconda.org/conda-forge/osx-arm64/libcblas-3.11.0-6_hb0561ab_openblas.conda#805c6d31c5621fd75e53dfcf21fb243a
+https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.3.5-py313h16eae64_1.conda#c72599556b49dc853839f4439c1eea32
+https://conda.anaconda.org/conda-forge/noarch/snuggs-1.4.7-pyhd8ed1ab_2.conda#9aa358575bbd4be126eaa5e0039f835c
+https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda#8e194e7b992f99a5015edbd4ebd38efd
+https://conda.anaconda.org/conda-forge/osx-arm64/sqlite-3.53.1-h85ec8f2_0.conda#f7a7a885f173730179da53e02b98ca93
https://conda.anaconda.org/conda-forge/osx-arm64/zstd-1.5.7-hbf9d68e_6.conda#ab136e4c34e97f34fb621d2592a393d8
-https://conda.anaconda.org/conda-forge/osx-arm64/snappy-1.2.2-hada39a4_1.conda#fca4a2222994acd7f691e57f94b750c5
-https://conda.anaconda.org/conda-forge/osx-arm64/libabseil-20260107.1-cxx17_h2062a1b_0.conda#bb65152e0d7c7178c0f1ee25692c9fd1
-https://conda.anaconda.org/conda-forge/osx-arm64/libre2-11-2025.11.05-h4c27e2a_1.conda#40d8ad21be4ccfff83a314076c3563f4
-https://conda.anaconda.org/conda-forge/osx-arm64/re2-2025.11.05-ha480c28_1.conda#a1ff22f664b0affa3de712749ccfbf04
-https://conda.anaconda.org/conda-forge/osx-arm64/lz4-c-1.10.0-h286801f_1.conda#01511afc6cc1909c5303cf31be17b44f
-https://conda.anaconda.org/conda-forge/osx-arm64/libprotobuf-6.33.5-h4a5acfd_0.conda#b839e3295b66434f20969c8b940f056a
-https://conda.anaconda.org/conda-forge/osx-arm64/orc-2.2.2-h578b684_1.conda#5ed1fedefe1098670f8d8e8189dcda7c
-https://conda.anaconda.org/conda-forge/osx-arm64/libutf8proc-2.11.3-h2431656_0.conda#2255add2f6ae77d0a96624a5cbde6d45
-https://conda.anaconda.org/conda-forge/osx-arm64/zlib-1.3.2-h8088a28_2.conda#f1c0bce276210bed45a04949cfe8dc20
+https://conda.anaconda.org/conda-forge/osx-arm64/libwebp-base-1.6.0-h07db88b_0.conda#e5e7d467f80da752be17796b87fe6385
+https://conda.anaconda.org/conda-forge/osx-arm64/libjpeg-turbo-3.1.4.1-h84a0fba_0.conda#b8a7544c83a67258b0e8592ec6a5d322
+https://conda.anaconda.org/conda-forge/osx-arm64/libdeflate-1.25-hc11a715_0.conda#a6130c709305cd9828b4e1bd9ba0000c
+https://conda.anaconda.org/conda-forge/osx-arm64/lerc-4.1.0-h1eee2c3_0.conda#095e5749868adab9cae42d4b460e5443
+https://conda.anaconda.org/conda-forge/osx-arm64/libtiff-4.7.1-h4030677_1.conda#e2a72ab2fa54ecb6abab2b26cde93500
https://conda.anaconda.org/conda-forge/osx-arm64/libssh2-1.11.1-h1590b86_0.conda#b68e8f66b94b44aaa8de4583d3d4cc40
https://conda.anaconda.org/conda-forge/osx-arm64/libev-4.33-h93a5062_2.conda#36d33e440c31857372a72137f78bacf5
https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.34.6-hc919400_0.conda#bcb3cba70cf1eec964a03b4ba7775f01
@@ -37,6 +44,47 @@ https://conda.anaconda.org/conda-forge/osx-arm64/libnghttp2-1.68.1-h8f3e76b_0.co
https://conda.anaconda.org/conda-forge/osx-arm64/libedit-3.1.20250104-pl5321hafb1f1b_0.conda#44083d2d2c2025afca315c7a172eab2b
https://conda.anaconda.org/conda-forge/osx-arm64/krb5-1.22.2-h385eeb1_0.conda#e446e1822f4da8e5080a9de93474184d
https://conda.anaconda.org/conda-forge/osx-arm64/libcurl-8.20.0-hd5a2499_0.conda#2f57b7d0c6adda88957586b7afd78438
+https://conda.anaconda.org/conda-forge/osx-arm64/proj-9.7.1-hfb14a63_3.conda#8f33a4a2b856de0e8f006c489beca62a
+https://conda.anaconda.org/conda-forge/osx-arm64/icu-78.3-hef89b57_0.conda#f1182c91c0de31a7abd40cedf6a5ebef
+https://conda.anaconda.org/conda-forge/osx-arm64/xerces-c-3.3.0-h25f632f_1.conda#0b886d06130b774f086d3b2ce0b7277a
+https://conda.anaconda.org/conda-forge/osx-arm64/pcre2-10.46-h7125dd6_0.conda#0e6e82c3cc3835f4692022e9b9cd5df8
+https://conda.anaconda.org/conda-forge/osx-arm64/lz4-c-1.10.0-h286801f_1.conda#01511afc6cc1909c5303cf31be17b44f
+https://conda.anaconda.org/conda-forge/osx-arm64/libiconv-1.18-h23cfdf5_2.conda#4d5a7445f0b25b6a3ddbb56e790f5251
+https://conda.anaconda.org/conda-forge/osx-arm64/libxml2-16-2.15.3-h5ef1a60_0.conda#19edaa53885fc8205614b03da2482282
+https://conda.anaconda.org/conda-forge/osx-arm64/libxml2-2.15.3-h5654f7c_0.conda#8e037d73747d6fe34e12d7bcac10cf21
+https://conda.anaconda.org/conda-forge/osx-arm64/zlib-1.3.2-h8088a28_2.conda#f1c0bce276210bed45a04949cfe8dc20
+https://conda.anaconda.org/conda-forge/osx-arm64/libxml2-devel-2.15.3-h5654f7c_0.conda#469f4af737803bf7deda25d41c557593
+https://conda.anaconda.org/conda-forge/osx-arm64/geos-3.14.0-h4bcf65f_0.conda#adc2b527bb017db48415a1b243abcb68
+https://conda.anaconda.org/conda-forge/osx-arm64/librttopo-1.1.0-hf7cb3ef_19.conda#093cc30c0744bf29a51209fd50543186
+https://conda.anaconda.org/conda-forge/osx-arm64/minizip-4.2.1-hdb7fadc_0.conda#fcd860469a8fa003e25d472b40b0ff81
+https://conda.anaconda.org/conda-forge/osx-arm64/freexl-2.0.0-h3ab3353_2.conda#dd655a29b40fe0d1bf95c64cf3cb348d
+https://conda.anaconda.org/conda-forge/osx-arm64/libspatialite-5.1.0-gpl_he9e465b_118.conda#2f7972081a15d940ee21708828773a72
+https://conda.anaconda.org/conda-forge/osx-arm64/libpng-1.6.58-h132b30e_0.conda#2259ae0949dbe20c0665850365109b27
+https://conda.anaconda.org/conda-forge/osx-arm64/uriparser-0.9.8-h00cdb27_0.conda#e8ff9e11babbc8cd77af5a4258dc2802
+https://conda.anaconda.org/conda-forge/osx-arm64/libkml-1.3.0-hb833057_1023.conda#3d8eeedb8e541d1cb593e8204fcc397d
+https://conda.anaconda.org/conda-forge/osx-arm64/lzo-2.10-h925e9cb_1002.conda#e56eaa1beab0e7fed559ae9c0264dd88
+https://conda.anaconda.org/conda-forge/osx-arm64/libarchive-3.8.7-gpl_h6fbacd7_100.conda#014dc9c74fef186581342c4844591ac6
+https://conda.anaconda.org/conda-forge/osx-arm64/json-c-0.18-he4178ee_0.conda#94f14ef6157687c30feb44e1abecd577
+https://conda.anaconda.org/conda-forge/osx-arm64/giflib-5.2.2-h93a5062_0.conda#95fa1486c77505330c20f7202492b913
+https://conda.anaconda.org/conda-forge/osx-arm64/geotiff-1.7.4-hf862be1_4.conda#111fe25c7b56f8e8f10322b4d99abe69
+https://conda.anaconda.org/conda-forge/osx-arm64/snappy-1.2.2-hada39a4_1.conda#fca4a2222994acd7f691e57f94b750c5
+https://conda.anaconda.org/conda-forge/osx-arm64/blosc-1.21.6-h7dd00d9_1.conda#925acfb50a750aa178f7a0aced77f351
+https://conda.anaconda.org/conda-forge/osx-arm64/libgdal-core-3.10.3-h694df76_24.conda#021a4f4c798ede069f985f6bbeb2bb88
+https://conda.anaconda.org/conda-forge/noarch/click-8.3.3-pyhc90fa1f_0.conda#2266262ce8a425ecb6523d765f79b303
+https://conda.anaconda.org/conda-forge/noarch/cligj-0.7.2-pyhd8ed1ab_2.conda#55c7804f428719241a90b152016085a1
+https://conda.anaconda.org/conda-forge/noarch/click-plugins-1.1.1.2-pyhd8ed1ab_0.conda#e9b05deb91c013e5224672a4ba9cf8d1
+https://conda.anaconda.org/conda-forge/noarch/certifi-2026.4.22-pyhd8ed1ab_0.conda#929471569c93acefb30282a22060dcd5
+https://conda.anaconda.org/conda-forge/noarch/attrs-26.1.0-pyhcf101f3_0.conda#c6b0543676ecb1fb2d7643941fe375f2
+https://conda.anaconda.org/conda-forge/noarch/affine-2.4.0-pyhd8ed1ab_1.conda#8c4061f499edec6b8ac7000f6d586829
+https://conda.anaconda.org/conda-forge/osx-arm64/rasterio-1.4.4-py313hb3bd904_0.conda#699df60947da770aa55348cccfa4f082
+https://conda.anaconda.org/conda-forge/noarch/pytz-2026.2-pyhcf101f3_0.conda#03cb60f505ad3ada0a95277af5faeb1a
+https://conda.anaconda.org/conda-forge/noarch/pycountry-24.6.1-pyhd8ed1ab_0.conda#62ed8c560f1b5b8d74ed11e68e9ae223
+https://conda.anaconda.org/conda-forge/osx-arm64/libabseil-20260107.1-cxx17_h2062a1b_0.conda#bb65152e0d7c7178c0f1ee25692c9fd1
+https://conda.anaconda.org/conda-forge/osx-arm64/libre2-11-2025.11.05-h4c27e2a_1.conda#40d8ad21be4ccfff83a314076c3563f4
+https://conda.anaconda.org/conda-forge/osx-arm64/re2-2025.11.05-ha480c28_1.conda#a1ff22f664b0affa3de712749ccfbf04
+https://conda.anaconda.org/conda-forge/osx-arm64/libprotobuf-6.33.5-h4a5acfd_0.conda#b839e3295b66434f20969c8b940f056a
+https://conda.anaconda.org/conda-forge/osx-arm64/orc-2.2.2-h578b684_1.conda#5ed1fedefe1098670f8d8e8189dcda7c
+https://conda.anaconda.org/conda-forge/osx-arm64/libutf8proc-2.11.3-h2431656_0.conda#2255add2f6ae77d0a96624a5cbde6d45
https://conda.anaconda.org/conda-forge/osx-arm64/prometheus-cpp-1.3.0-h0967b3e_0.conda#7172339b49c94275ba42fec3eaeda34f
https://conda.anaconda.org/conda-forge/osx-arm64/nlohmann_json-3.12.0-h784d473_1.conda#755cfa6c08ed7b7acbee20ccbf15a47c
https://conda.anaconda.org/conda-forge/osx-arm64/libopentelemetry-cpp-headers-1.21.0-hce30654_2.conda#d1adb8f085e35aa6335c2a4e6f025fb6
@@ -50,10 +98,6 @@ https://conda.anaconda.org/conda-forge/osx-arm64/libbrotlienc-1.2.0-hc919400_1.c
https://conda.anaconda.org/conda-forge/osx-arm64/libbrotlidec-1.2.0-hc919400_1.conda#079e88933963f3f149054eec2c487bc2
https://conda.anaconda.org/conda-forge/osx-arm64/gflags-2.2.2-hf9b8971_1005.conda#57a511a5905caa37540eb914dfcbf1fb
https://conda.anaconda.org/conda-forge/osx-arm64/glog-0.7.1-heb240a5_0.conda#fef68d0a95aa5b84b5c1a4f6f3bf40e1
-https://conda.anaconda.org/conda-forge/osx-arm64/libiconv-1.18-h23cfdf5_2.conda#4d5a7445f0b25b6a3ddbb56e790f5251
-https://conda.anaconda.org/conda-forge/osx-arm64/icu-78.3-hef89b57_0.conda#f1182c91c0de31a7abd40cedf6a5ebef
-https://conda.anaconda.org/conda-forge/osx-arm64/libxml2-16-2.15.3-h5ef1a60_0.conda#19edaa53885fc8205614b03da2482282
-https://conda.anaconda.org/conda-forge/osx-arm64/libxml2-2.15.3-h5654f7c_0.conda#8e037d73747d6fe34e12d7bcac10cf21
https://conda.anaconda.org/conda-forge/osx-arm64/azure-core-cpp-1.16.2-he5ae378_0.conda#7efe92d28599c224a24de11bb14d395e
https://conda.anaconda.org/conda-forge/osx-arm64/azure-storage-common-cpp-12.12.0-he467506_1.conda#b658a3fb0fc412b2a4d30da3fcec036f
https://conda.anaconda.org/conda-forge/osx-arm64/azure-storage-blobs-cpp-12.16.0-hc57151b_1.conda#f08b3b9d7333dc427b79897e6e3e7f29
@@ -98,16 +142,6 @@ https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda#
https://conda.anaconda.org/conda-forge/noarch/pandera-base-0.24.0-pyhd8ed1ab_2.conda#e1c50e117a98e39d297d9290132f032b
https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda#3339e3b65d58accf4ca4fb8748ab16b3
https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda#5b8d21249ff20967101ffa321cab24e8
-https://conda.anaconda.org/conda-forge/osx-arm64/llvm-openmp-22.1.4-hc7d1edf_0.conda#46d04a647df7a4525e487d88068d19ef
-https://conda.anaconda.org/conda-forge/osx-arm64/_openmp_mutex-4.5-7_kmp_llvm.conda#a44032f282e7d2acdeb1c240308052dd
-https://conda.anaconda.org/conda-forge/osx-arm64/libgcc-15.2.0-hcbb3090_19.conda#644058123986582db33aebd4ae2ca184
-https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran5-15.2.0-hdae7583_19.conda#ba36d8c606a6a53fe0b8c12d47267b3d
-https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran-15.2.0-h07b0088_19.conda#1ea03f87cdb1078fbc0e2b2deb63752c
-https://conda.anaconda.org/conda-forge/osx-arm64/libopenblas-0.3.32-openmp_he657e61_0.conda#3a1111a4b6626abebe8b978bb5a323bf
-https://conda.anaconda.org/conda-forge/osx-arm64/libblas-3.11.0-6_h51639a9_openblas.conda#e551103471911260488a02155cef9c94
-https://conda.anaconda.org/conda-forge/osx-arm64/liblapack-3.11.0-6_hd9741b5_openblas.conda#ee33d2d05a7c5ea1f67653b37eb74db1
-https://conda.anaconda.org/conda-forge/osx-arm64/libcblas-3.11.0-6_hb0561ab_openblas.conda#805c6d31c5621fd75e53dfcf21fb243a
-https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.3.5-py313h16eae64_1.conda#c72599556b49dc853839f4439c1eea32
https://conda.anaconda.org/conda-forge/osx-arm64/pandas-3.0.2-py313h1188861_0.conda#13410787da0135eec56a4bb8d674fc42
https://conda.anaconda.org/conda-forge/noarch/pandera-0.24.0-hd8ed1ab_2.conda#a12a21a89519f0cc224e44da86f5be2c
https://conda.anaconda.org/conda-forge/noarch/validators-0.35.0-pyhd8ed1ab_0.conda#3449ef730c7d483adde81993994092b9
@@ -116,7 +150,6 @@ https://conda.anaconda.org/conda-forge/noarch/pygments-2.20.0-pyhd8ed1ab_0.conda
https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda#592132998493b3ff25fd7479396e8351
https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.2.0-pyhd8ed1ab_0.conda#6d03368f2b2b0a5fb6839df53b2eb5e0
https://conda.anaconda.org/conda-forge/noarch/rich-15.0.0-pyhcf101f3_0.conda#0242025a3c804966bf71aa04eee82f66
-https://conda.anaconda.org/conda-forge/noarch/click-8.3.3-pyhc90fa1f_0.conda#2266262ce8a425ecb6523d765f79b303
https://conda.anaconda.org/conda-forge/noarch/annotated-doc-0.0.4-pyhcf101f3_0.conda#52be5139047efadaeeb19c6a5103f92a
https://conda.anaconda.org/conda-forge/noarch/typer-0.25.1-pyhcf101f3_0.conda#ef114c2eb2ff19f6bf616c81f4710841
https://conda.anaconda.org/conda-forge/noarch/tabulate-0.10.0-pyhcf101f3_0.conda#3b887b7b3468b0f494b4fad40178b043
@@ -132,14 +165,12 @@ https://conda.anaconda.org/conda-forge/osx-arm64/backports.zstd-1.4.0-py313h7208
https://conda.anaconda.org/conda-forge/noarch/urllib3-2.7.0-pyhd8ed1ab_0.conda#cbb88288f74dbe6ada1c6c7d0a97223e
https://conda.anaconda.org/conda-forge/noarch/idna-3.13-pyhcf101f3_0.conda#fb7130c190f9b4ec91219840a05ba3ac
https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.7-pyhd8ed1ab_0.conda#a9167b9571f3baa9d448faa2139d1089
-https://conda.anaconda.org/conda-forge/noarch/certifi-2026.4.22-pyhd8ed1ab_0.conda#929471569c93acefb30282a22060dcd5
https://conda.anaconda.org/conda-forge/noarch/requests-2.33.1-pyhcf101f3_1.conda#9659f587a8ceacc21864260acd02fc67
https://conda.anaconda.org/conda-forge/noarch/text-unidecode-1.3-pyhd8ed1ab_2.conda#23b4ba5619c4752976eb7ba1f5acb7e8
https://conda.anaconda.org/conda-forge/noarch/python-slugify-8.0.4-pyhd8ed1ab_1.conda#a4059bc12930bddeb41aef71537ffaed
https://conda.anaconda.org/conda-forge/noarch/petl-1.7.17-pyhd8ed1ab_0.conda#4c2498dcda0d58cf25466e82f7287b32
https://conda.anaconda.org/conda-forge/noarch/marko-2.2.2-pyhd8ed1ab_0.conda#3c3e9339e46fffba5920be28d9233860
https://conda.anaconda.org/conda-forge/osx-arm64/rpds-py-0.30.0-py313h2c089d5_0.conda#190c2d0d4e98ec97df48cdb74caf44d8
-https://conda.anaconda.org/conda-forge/noarch/attrs-26.1.0-pyhcf101f3_0.conda#c6b0543676ecb1fb2d7643941fe375f2
https://conda.anaconda.org/conda-forge/noarch/referencing-0.37.0-pyhcf101f3_0.conda#870293df500ca7e18bedefa5838a22ab
https://conda.anaconda.org/conda-forge/noarch/jsonschema-specifications-2025.9.1-pyhcf101f3_0.conda#439cd0f567d697b20a8f45cb70a1005a
https://conda.anaconda.org/conda-forge/noarch/jsonschema-4.26.0-pyhcf101f3_0.conda#ada41c863af263cc4c5fcbaff7c3e4dc
@@ -153,39 +184,11 @@ https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.6-pyhcf101f3_0.co
https://conda.anaconda.org/conda-forge/noarch/pathspec-1.1.1-pyhd8ed1ab_0.conda#11adc78451c998c0fd162584abfa3559
https://conda.anaconda.org/conda-forge/noarch/black-26.3.1-pyh866005b_0.conda#c7e43448266209d766a229cada982884
https://conda.anaconda.org/conda-forge/noarch/pandera-io-0.24.0-hd8ed1ab_2.conda#d456360daad56c802e27504979ef1e19
-https://conda.anaconda.org/conda-forge/osx-arm64/geos-3.14.0-h4bcf65f_0.conda#adc2b527bb017db48415a1b243abcb68
https://conda.anaconda.org/conda-forge/osx-arm64/shapely-2.1.1-py313hfb5a6ed_2.conda#fe3b80b75f6ca392c17e9d51d9c527d6
https://conda.anaconda.org/conda-forge/noarch/xyzservices-2026.3.0-pyhd8ed1ab_0.conda#4487b9c371d0161d54b5c7bbd890c0fc
-https://conda.anaconda.org/conda-forge/osx-arm64/sqlite-3.53.1-h85ec8f2_0.conda#f7a7a885f173730179da53e02b98ca93
-https://conda.anaconda.org/conda-forge/osx-arm64/libwebp-base-1.6.0-h07db88b_0.conda#e5e7d467f80da752be17796b87fe6385
-https://conda.anaconda.org/conda-forge/osx-arm64/libjpeg-turbo-3.1.4.1-h84a0fba_0.conda#b8a7544c83a67258b0e8592ec6a5d322
-https://conda.anaconda.org/conda-forge/osx-arm64/libdeflate-1.25-hc11a715_0.conda#a6130c709305cd9828b4e1bd9ba0000c
-https://conda.anaconda.org/conda-forge/osx-arm64/lerc-4.1.0-h1eee2c3_0.conda#095e5749868adab9cae42d4b460e5443
-https://conda.anaconda.org/conda-forge/osx-arm64/libtiff-4.7.1-h4030677_1.conda#e2a72ab2fa54ecb6abab2b26cde93500
-https://conda.anaconda.org/conda-forge/osx-arm64/proj-9.7.1-hfb14a63_3.conda#8f33a4a2b856de0e8f006c489beca62a
https://conda.anaconda.org/conda-forge/osx-arm64/pyproj-3.7.2-py313h6de5794_3.conda#1f2ae983e8f36a664dbe220b8d1f7e97
-https://conda.anaconda.org/conda-forge/osx-arm64/xerces-c-3.3.0-h25f632f_1.conda#0b886d06130b774f086d3b2ce0b7277a
-https://conda.anaconda.org/conda-forge/osx-arm64/pcre2-10.46-h7125dd6_0.conda#0e6e82c3cc3835f4692022e9b9cd5df8
-https://conda.anaconda.org/conda-forge/osx-arm64/muparser-2.3.5-h11e0b38_0.conda#1cdbe54881794ee356d3cba7e3ed6668
-https://conda.anaconda.org/conda-forge/osx-arm64/libxml2-devel-2.15.3-h5654f7c_0.conda#469f4af737803bf7deda25d41c557593
-https://conda.anaconda.org/conda-forge/osx-arm64/librttopo-1.1.0-hf7cb3ef_19.conda#093cc30c0744bf29a51209fd50543186
-https://conda.anaconda.org/conda-forge/osx-arm64/minizip-4.2.1-hdb7fadc_0.conda#fcd860469a8fa003e25d472b40b0ff81
-https://conda.anaconda.org/conda-forge/osx-arm64/freexl-2.0.0-h3ab3353_2.conda#dd655a29b40fe0d1bf95c64cf3cb348d
-https://conda.anaconda.org/conda-forge/osx-arm64/libspatialite-5.1.0-gpl_he9e465b_118.conda#2f7972081a15d940ee21708828773a72
-https://conda.anaconda.org/conda-forge/osx-arm64/libpng-1.6.58-h132b30e_0.conda#2259ae0949dbe20c0665850365109b27
-https://conda.anaconda.org/conda-forge/osx-arm64/uriparser-0.9.8-h00cdb27_0.conda#e8ff9e11babbc8cd77af5a4258dc2802
-https://conda.anaconda.org/conda-forge/osx-arm64/libkml-1.3.0-hb833057_1023.conda#3d8eeedb8e541d1cb593e8204fcc397d
-https://conda.anaconda.org/conda-forge/osx-arm64/libhwy-1.4.0-ha332bbd_0.conda#7394850583ca88325244b68b532c7a39
-https://conda.anaconda.org/conda-forge/osx-arm64/libjxl-0.11.2-h934fa54_1.conda#05bead8980f5ae6a070117dacec38b5b
-https://conda.anaconda.org/conda-forge/osx-arm64/lzo-2.10-h925e9cb_1002.conda#e56eaa1beab0e7fed559ae9c0264dd88
-https://conda.anaconda.org/conda-forge/osx-arm64/libarchive-3.8.7-gpl_h6fbacd7_100.conda#014dc9c74fef186581342c4844591ac6
-https://conda.anaconda.org/conda-forge/osx-arm64/json-c-0.18-he4178ee_0.conda#94f14ef6157687c30feb44e1abecd577
-https://conda.anaconda.org/conda-forge/osx-arm64/giflib-5.2.2-h93a5062_0.conda#95fa1486c77505330c20f7202492b913
-https://conda.anaconda.org/conda-forge/osx-arm64/blosc-1.21.6-h7dd00d9_1.conda#925acfb50a750aa178f7a0aced77f351
-https://conda.anaconda.org/conda-forge/osx-arm64/libgdal-core-3.11.4-h693e041_6.conda#dbc028bb7adefb044f57a3d1ef7d5577
-https://conda.anaconda.org/conda-forge/osx-arm64/pyogrio-0.11.1-py313hd8ca31c_1.conda#d617721ce482cbba8c40f4a9872a2c4f
+https://conda.anaconda.org/conda-forge/osx-arm64/pyogrio-0.11.0-py313h4ad91d6_0.conda#dafffca1d5d08b8966815eed08aece8a
https://conda.anaconda.org/conda-forge/osx-arm64/qhull-2020.2-h420ef59_5.conda#6483b1f59526e05d7d894e466b5b6924
-https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda#3687cc0b82a8b4c17e1f0eb7e47163d5
https://conda.anaconda.org/conda-forge/osx-arm64/zlib-ng-2.3.3-hed4e4f5_1.conda#d99c2a23a31b0172e90f456f580b695e
https://conda.anaconda.org/conda-forge/osx-arm64/openjpeg-2.5.4-hd9e9057_0.conda#4b5d3a91320976eec71678fad1e3569b
https://conda.anaconda.org/conda-forge/osx-arm64/xorg-libxdmcp-1.1.5-hc919400_1.conda#9d1299ace1924aa8f4e0bc8e71dd0cf7
@@ -211,10 +214,10 @@ https://conda.anaconda.org/conda-forge/noarch/joblib-1.5.3-pyhd8ed1ab_0.conda#61
https://conda.anaconda.org/conda-forge/osx-arm64/scikit-learn-1.8.0-np2py313h3b23316_1.conda#4434adab69e6300db1e98aff4c3565f3
https://conda.anaconda.org/conda-forge/noarch/networkx-3.6.1-pyhcf101f3_0.conda#a2c1eeadae7a309daed9d62c96012a2b
https://conda.anaconda.org/conda-forge/noarch/mapclassify-2.10.0-pyhd8ed1ab_1.conda#cc293b4cad9909bf66ca117ea90d4631
-https://conda.anaconda.org/conda-forge/noarch/geopandas-base-1.0.1-pyha770c72_3.conda#e8343d1b635bf09dafdd362d7357f395
+https://conda.anaconda.org/conda-forge/noarch/geopandas-base-1.1.3-pyha770c72_0.conda#18789a85c307970ae1786dfc6dfd234f
https://conda.anaconda.org/conda-forge/noarch/branca-0.8.2-pyhd8ed1ab_0.conda#1fcdf88e7a8c296d3df8409bf0690db4
https://conda.anaconda.org/conda-forge/noarch/folium-0.20.0-pyhd8ed1ab_0.conda#a6997a7dcd6673c0692c61dfeaea14ab
-https://conda.anaconda.org/conda-forge/noarch/geopandas-1.0.1-pyhd8ed1ab_3.conda#1baca589eb35814a392eaad6d152447e
+https://conda.anaconda.org/conda-forge/noarch/geopandas-1.1.3-pyhd8ed1ab_0.conda#4eb8b870142ca06d2a1d2c74662eac7d
https://conda.anaconda.org/conda-forge/noarch/pandera-geopandas-0.24.0-hd8ed1ab_2.conda#fb21509f073465506ea994dc4667bf66
https://conda.anaconda.org/conda-forge/noarch/toml-0.10.2-pyhcf101f3_3.conda#d0fc809fa4c4d85e959ce4ab6e1de800
https://conda.anaconda.org/conda-forge/noarch/traitlets-5.15.0-pyhcf101f3_0.conda#4bada6a6d908a27262af8ebddf4f7492
@@ -240,3 +243,4 @@ https://conda.anaconda.org/conda-forge/noarch/jmespath-1.1.0-pyhcf101f3_1.conda#
https://conda.anaconda.org/conda-forge/noarch/botocore-1.40.76-pyhd8ed1ab_0.conda#4babebd5361bc44503358a519a81a465
https://conda.anaconda.org/conda-forge/noarch/s3transfer-0.14.0-pyhd8ed1ab_0.conda#4e3089ce93822a25408c480dd53561b6
https://conda.anaconda.org/conda-forge/noarch/boto3-1.40.46-pyhd8ed1ab_0.conda#a93057bba32eef7b217733734642bfea
+https://conda.anaconda.org/conda-forge/noarch/antimeridian-0.4.7-pyhd8ed1ab_0.conda#56e9ab4ca5ec150ad52ca420f2cec646
diff --git a/workflow/envs/shape.win-64.pin.txt b/workflow/envs/shape.win-64.pin.txt
index cbb1289..dd67ef8 100644
--- a/workflow/envs/shape.win-64.pin.txt
+++ b/workflow/envs/shape.win-64.pin.txt
@@ -18,23 +18,70 @@ https://conda.anaconda.org/conda-forge/win-64/libffi-3.5.2-h3d046cb_0.conda#720b
https://conda.anaconda.org/conda-forge/win-64/libexpat-2.8.0-hac47afa_0.conda#264e350e035092b5135a2147c238aec4
https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-h0ad9c76_9.conda#4cb8e6b48f67de0b018719cdf1136306
https://conda.anaconda.org/conda-forge/win-64/python-3.13.13-h09917c8_100_cp313.conda#7065f7067762c4c2bda1912f18d16239
-https://conda.anaconda.org/conda-forge/noarch/pytz-2026.2-pyhcf101f3_0.conda#03cb60f505ad3ada0a95277af5faeb1a
+https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda#3687cc0b82a8b4c17e1f0eb7e47163d5
+https://conda.anaconda.org/conda-forge/win-64/libiconv-1.18-hc1393d2_2.conda#64571d1dd6cdcfa25d0664a5950fdaa2
+https://conda.anaconda.org/conda-forge/win-64/libxml2-16-2.15.3-h692994f_0.conda#f7d6fcda29570e20851b78d92ea2154e
+https://conda.anaconda.org/conda-forge/win-64/libxml2-2.15.3-hbc0d294_0.conda#e3b5acbb857a12f5d59e8d174bc536c0
+https://conda.anaconda.org/conda-forge/win-64/libwinpthread-12.0.0.r4.gg4f2fc60ca-h57928b3_10.conda#8a86073cf3b343b87d03f41790d8b4e5
+https://conda.anaconda.org/conda-forge/win-64/libhwloc-2.12.2-default_h4379cf1_1000.conda#3b576f6860f838f950c570f4433b086e
+https://conda.anaconda.org/conda-forge/win-64/tbb-2023.0.0-ha3553a1_1.conda#34aa94d586fe95fa121966c0d4e73cf4
+https://conda.anaconda.org/conda-forge/win-64/onemkl-license-2025.3.1-h57928b3_13.conda#eded4ef8a94852a2e3e4c779b3b6fdda
+https://conda.anaconda.org/conda-forge/win-64/llvm-openmp-22.1.4-h4fa8253_0.conda#761757ab617e8bfef18cc422dd02bbad
+https://conda.anaconda.org/conda-forge/win-64/mkl-2025.3.1-hac47afa_13.conda#c058cdc8796d5eb260a1aef2cbb7fbbf
+https://conda.anaconda.org/conda-forge/win-64/libblas-3.11.0-6_hf2e6a31_mkl.conda#95543eec964b4a4a7ca3c4c9be481aa1
+https://conda.anaconda.org/conda-forge/win-64/liblapack-3.11.0-6_hf9ab0e9_mkl.conda#7e9cdaf6f302142bc363bbab3b5e7074
+https://conda.anaconda.org/conda-forge/win-64/libcblas-3.11.0-6_h2a3cdd5_mkl.conda#9e4bf521c07f4d423cba9296b7927e3c
+https://conda.anaconda.org/conda-forge/win-64/numpy-2.3.5-py313hce7ae62_1.conda#78749843445581c6dcc0cb80d146982d
+https://conda.anaconda.org/conda-forge/noarch/snuggs-1.4.7-pyhd8ed1ab_2.conda#9aa358575bbd4be126eaa5e0039f835c
https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda#8e194e7b992f99a5015edbd4ebd38efd
-https://conda.anaconda.org/conda-forge/noarch/pycountry-24.6.1-pyhd8ed1ab_0.conda#62ed8c560f1b5b8d74ed11e68e9ae223
+https://conda.anaconda.org/conda-forge/win-64/sqlite-3.53.1-hdb435a2_0.conda#5833ae18b609bf0790e0bfe6f95b3351
https://conda.anaconda.org/conda-forge/win-64/zstd-1.5.7-h534d264_6.conda#053b84beec00b71ea8ff7a4f84b55207
+https://conda.anaconda.org/conda-forge/win-64/libjpeg-turbo-3.1.4.1-hfd05255_0.conda#25a127bad5470852b30b239f030ec95b
+https://conda.anaconda.org/conda-forge/win-64/libdeflate-1.25-h51727cc_0.conda#e77030e67343e28b084fabd7db0ce43e
+https://conda.anaconda.org/conda-forge/win-64/lerc-4.1.0-hd936e49_0.conda#54b231d595bc1ff9bff668dd443ee012
+https://conda.anaconda.org/conda-forge/win-64/libtiff-4.7.1-h8f73337_1.conda#549845d5133100142452812feb9ba2e8
+https://conda.anaconda.org/conda-forge/win-64/libssh2-1.11.1-h9aa295b_0.conda#9dce2f112bfd3400f4f432b3d0ac07b2
+https://conda.anaconda.org/conda-forge/win-64/krb5-1.22.2-h0ea6238_0.conda#4432f52dc0c8eb6a7a6abc00a037d93c
+https://conda.anaconda.org/conda-forge/win-64/libcurl-8.20.0-h8206538_0.conda#7bee27a8f0a295117ccb864f30d2d87e
+https://conda.anaconda.org/conda-forge/win-64/proj-9.7.1-hd30e2cd_3.conda#f2b0478a02d35bac5b872d4d63b96be3
+https://conda.anaconda.org/conda-forge/win-64/xerces-c-3.3.0-hac47afa_1.conda#d1097e01041cfed41c81f1e3d1f52572
+https://conda.anaconda.org/conda-forge/win-64/pcre2-10.46-h3402e2f_0.conda#889053e920d15353c2665fa6310d7a7a
+https://conda.anaconda.org/conda-forge/win-64/lz4-c-1.10.0-h2466b09_1.conda#0b69331897a92fac3d8923549d48d092
+https://conda.anaconda.org/conda-forge/win-64/libwebp-base-1.6.0-h4d5522a_0.conda#f9bbae5e2537e3b06e0f7310ba76c893
+https://conda.anaconda.org/conda-forge/win-64/zlib-1.3.2-hfd05255_2.conda#5187ecf958be3c39110fe691cbd6873e
+https://conda.anaconda.org/conda-forge/win-64/libxml2-devel-2.15.3-hbc0d294_0.conda#62b6eff67ddb7d8657e92fc3d1382a2d
+https://conda.anaconda.org/conda-forge/win-64/geos-3.14.0-hdade9fe_0.conda#605225b71402d12f4bf0324b0cc1db97
+https://conda.anaconda.org/conda-forge/win-64/librttopo-1.1.0-h5ff11c1_19.conda#41949b02b89c2f2e08c5bd457295f237
+https://conda.anaconda.org/conda-forge/win-64/minizip-4.2.1-h0ffbb96_0.conda#5d55038c4d640e5df06de1cfb4e8d741
+https://conda.anaconda.org/conda-forge/win-64/freexl-2.0.0-hf297d47_2.conda#d6a8059de245e53478b581742b53f71d
+https://conda.anaconda.org/conda-forge/win-64/libspatialite-5.1.0-gpl_h3bf7137_118.conda#a00265bc2dea705fdae1c629f69e65d9
+https://conda.anaconda.org/conda-forge/win-64/libpng-1.6.58-h7351971_0.conda#52f1280563f3b48b5f75414cd2d15dd1
+https://conda.anaconda.org/conda-forge/win-64/uriparser-0.9.8-h5a68840_0.conda#28b4cf9065681f43cc567410edf8243d
+https://conda.anaconda.org/conda-forge/win-64/libkml-1.3.0-h68a222c_1023.conda#b44e0d9eb84c6c086d809787aab0a1da
+https://conda.anaconda.org/conda-forge/win-64/lzo-2.10-h6a83c73_1002.conda#c5cb4159f0eea65663b31dd1e49bbb71
+https://conda.anaconda.org/conda-forge/win-64/libarchive-3.8.7-gpl_he24518a_100.conda#e8575b817fa0ed38f4f31415f1b4accf
+https://conda.anaconda.org/conda-forge/win-64/geotiff-1.7.4-h73469f5_4.conda#2a62961eeffe28d84c166600e4bf6e25
https://conda.anaconda.org/conda-forge/win-64/snappy-1.2.2-h7fa0ca8_1.conda#3075846de68f942150069d4289aaad63
+https://conda.anaconda.org/conda-forge/win-64/blosc-1.21.6-hfd34d9b_1.conda#357d7be4146d5fec543bfaa96a8a40de
+https://conda.anaconda.org/conda-forge/win-64/libgdal-core-3.10.3-h2f24e33_24.conda#0489c36d03b99d3f71d9d0b4742f1620
+https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda#962b9857ee8e7018c22f2776ffa0b2d7
+https://conda.anaconda.org/conda-forge/noarch/click-8.3.3-pyh6dadd2b_0.conda#8f03c7a39b01ebc57b647f7b48bbeed9
+https://conda.anaconda.org/conda-forge/noarch/cligj-0.7.2-pyhd8ed1ab_2.conda#55c7804f428719241a90b152016085a1
+https://conda.anaconda.org/conda-forge/noarch/click-plugins-1.1.1.2-pyhd8ed1ab_0.conda#e9b05deb91c013e5224672a4ba9cf8d1
+https://conda.anaconda.org/conda-forge/noarch/certifi-2026.4.22-pyhd8ed1ab_0.conda#929471569c93acefb30282a22060dcd5
+https://conda.anaconda.org/conda-forge/noarch/attrs-26.1.0-pyhcf101f3_0.conda#c6b0543676ecb1fb2d7643941fe375f2
+https://conda.anaconda.org/conda-forge/noarch/affine-2.4.0-pyhd8ed1ab_1.conda#8c4061f499edec6b8ac7000f6d586829
+https://conda.anaconda.org/conda-forge/win-64/rasterio-1.4.4-py313ha5c5119_0.conda#c094475643548d60959967b5be3638bb
+https://conda.anaconda.org/conda-forge/noarch/pytz-2026.2-pyhcf101f3_0.conda#03cb60f505ad3ada0a95277af5faeb1a
+https://conda.anaconda.org/conda-forge/noarch/pycountry-24.6.1-pyhd8ed1ab_0.conda#62ed8c560f1b5b8d74ed11e68e9ae223
https://conda.anaconda.org/conda-forge/win-64/libabseil-20260107.1-cxx17_h0eb2380_0.conda#60da39dd5fd93b2a4a0f986f3acc2520
https://conda.anaconda.org/conda-forge/win-64/libre2-11-2025.11.05-h04e5de1_1.conda#3d863f1a19f579ca511f6ac02038ab5a
https://conda.anaconda.org/conda-forge/win-64/re2-2025.11.05-ha104f34_1.conda#6807f05dcf3f1736ad6cc9525b8b8725
-https://conda.anaconda.org/conda-forge/win-64/lz4-c-1.10.0-h2466b09_1.conda#0b69331897a92fac3d8923549d48d092
https://conda.anaconda.org/conda-forge/win-64/libprotobuf-6.33.5-h61fc761_0.conda#69e5855826e56ea4b67fb888ef879afd
https://conda.anaconda.org/conda-forge/win-64/orc-2.2.2-h0a1ad0e_1.conda#aa6701a960f0e94478229af1e061c237
https://conda.anaconda.org/conda-forge/win-64/libutf8proc-2.11.3-hb980946_0.conda#5f34fcb6578ea9bdbfd53cc2cfb88200
https://conda.anaconda.org/conda-forge/win-64/c-ares-1.34.6-hfd05255_0.conda#7c6da34e5b6e60b414592c74582e28bf
https://conda.anaconda.org/conda-forge/win-64/libgrpc-1.78.1-h9ff2b3e_0.conda#26dbb65607f8fe485df5ee98fa6eb79f
-https://conda.anaconda.org/conda-forge/win-64/libssh2-1.11.1-h9aa295b_0.conda#9dce2f112bfd3400f4f432b3d0ac07b2
-https://conda.anaconda.org/conda-forge/win-64/krb5-1.22.2-h0ea6238_0.conda#4432f52dc0c8eb6a7a6abc00a037d93c
-https://conda.anaconda.org/conda-forge/win-64/libcurl-8.20.0-h8206538_0.conda#7bee27a8f0a295117ccb864f30d2d87e
https://conda.anaconda.org/conda-forge/win-64/libgoogle-cloud-2.39.0-h01c467a_1.conda#453d3a0347fe049b922a2a851c1c0110
https://conda.anaconda.org/conda-forge/win-64/vs2015_runtime-14.44.35208-h38c0c73_34.conda#f276d1de4553e8fca1dfb6988551ebb4
https://conda.anaconda.org/conda-forge/win-64/libcrc32c-1.1.2-h0e60522_0.tar.bz2#cd4cc2d0c610c8cb5419ccc979f2d6ce
@@ -82,19 +129,6 @@ https://conda.anaconda.org/conda-forge/noarch/pandera-base-0.24.0-pyhd8ed1ab_2.c
https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2026.2-pyhd8ed1ab_0.conda#f6ad7450fc21e00ecc23812baed6d2e4
https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda#3339e3b65d58accf4ca4fb8748ab16b3
https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda#5b8d21249ff20967101ffa321cab24e8
-https://conda.anaconda.org/conda-forge/win-64/libiconv-1.18-hc1393d2_2.conda#64571d1dd6cdcfa25d0664a5950fdaa2
-https://conda.anaconda.org/conda-forge/win-64/libxml2-16-2.15.3-h692994f_0.conda#f7d6fcda29570e20851b78d92ea2154e
-https://conda.anaconda.org/conda-forge/win-64/libxml2-2.15.3-hbc0d294_0.conda#e3b5acbb857a12f5d59e8d174bc536c0
-https://conda.anaconda.org/conda-forge/win-64/libwinpthread-12.0.0.r4.gg4f2fc60ca-h57928b3_10.conda#8a86073cf3b343b87d03f41790d8b4e5
-https://conda.anaconda.org/conda-forge/win-64/libhwloc-2.12.2-default_h4379cf1_1000.conda#3b576f6860f838f950c570f4433b086e
-https://conda.anaconda.org/conda-forge/win-64/tbb-2023.0.0-ha3553a1_1.conda#34aa94d586fe95fa121966c0d4e73cf4
-https://conda.anaconda.org/conda-forge/win-64/onemkl-license-2025.3.1-h57928b3_13.conda#eded4ef8a94852a2e3e4c779b3b6fdda
-https://conda.anaconda.org/conda-forge/win-64/llvm-openmp-22.1.4-h4fa8253_0.conda#761757ab617e8bfef18cc422dd02bbad
-https://conda.anaconda.org/conda-forge/win-64/mkl-2025.3.1-hac47afa_13.conda#c058cdc8796d5eb260a1aef2cbb7fbbf
-https://conda.anaconda.org/conda-forge/win-64/libblas-3.11.0-6_hf2e6a31_mkl.conda#95543eec964b4a4a7ca3c4c9be481aa1
-https://conda.anaconda.org/conda-forge/win-64/liblapack-3.11.0-6_hf9ab0e9_mkl.conda#7e9cdaf6f302142bc363bbab3b5e7074
-https://conda.anaconda.org/conda-forge/win-64/libcblas-3.11.0-6_h2a3cdd5_mkl.conda#9e4bf521c07f4d423cba9296b7927e3c
-https://conda.anaconda.org/conda-forge/win-64/numpy-2.3.5-py313hce7ae62_1.conda#78749843445581c6dcc0cb80d146982d
https://conda.anaconda.org/conda-forge/win-64/pandas-3.0.2-py313h26f5e95_0.conda#4e6201ece5bfb083570145791feab397
https://conda.anaconda.org/conda-forge/noarch/pandera-0.24.0-hd8ed1ab_2.conda#a12a21a89519f0cc224e44da86f5be2c
https://conda.anaconda.org/conda-forge/noarch/validators-0.35.0-pyhd8ed1ab_0.conda#3449ef730c7d483adde81993994092b9
@@ -103,8 +137,6 @@ https://conda.anaconda.org/conda-forge/noarch/pygments-2.20.0-pyhd8ed1ab_0.conda
https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda#592132998493b3ff25fd7479396e8351
https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-4.2.0-pyhd8ed1ab_0.conda#6d03368f2b2b0a5fb6839df53b2eb5e0
https://conda.anaconda.org/conda-forge/noarch/rich-15.0.0-pyhcf101f3_0.conda#0242025a3c804966bf71aa04eee82f66
-https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda#962b9857ee8e7018c22f2776ffa0b2d7
-https://conda.anaconda.org/conda-forge/noarch/click-8.3.3-pyh6dadd2b_0.conda#8f03c7a39b01ebc57b647f7b48bbeed9
https://conda.anaconda.org/conda-forge/noarch/annotated-doc-0.0.4-pyhcf101f3_0.conda#52be5139047efadaeeb19c6a5103f92a
https://conda.anaconda.org/conda-forge/noarch/typer-0.25.1-pyhcf101f3_0.conda#ef114c2eb2ff19f6bf616c81f4710841
https://conda.anaconda.org/conda-forge/noarch/tabulate-0.10.0-pyhcf101f3_0.conda#3b887b7b3468b0f494b4fad40178b043
@@ -121,14 +153,12 @@ https://conda.anaconda.org/conda-forge/win-64/backports.zstd-1.4.0-py313h2a31948
https://conda.anaconda.org/conda-forge/noarch/urllib3-2.7.0-pyhd8ed1ab_0.conda#cbb88288f74dbe6ada1c6c7d0a97223e
https://conda.anaconda.org/conda-forge/noarch/idna-3.13-pyhcf101f3_0.conda#fb7130c190f9b4ec91219840a05ba3ac
https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.7-pyhd8ed1ab_0.conda#a9167b9571f3baa9d448faa2139d1089
-https://conda.anaconda.org/conda-forge/noarch/certifi-2026.4.22-pyhd8ed1ab_0.conda#929471569c93acefb30282a22060dcd5
https://conda.anaconda.org/conda-forge/noarch/requests-2.33.1-pyhcf101f3_1.conda#9659f587a8ceacc21864260acd02fc67
https://conda.anaconda.org/conda-forge/noarch/text-unidecode-1.3-pyhd8ed1ab_2.conda#23b4ba5619c4752976eb7ba1f5acb7e8
https://conda.anaconda.org/conda-forge/noarch/python-slugify-8.0.4-pyhd8ed1ab_1.conda#a4059bc12930bddeb41aef71537ffaed
https://conda.anaconda.org/conda-forge/noarch/petl-1.7.17-pyhd8ed1ab_0.conda#4c2498dcda0d58cf25466e82f7287b32
https://conda.anaconda.org/conda-forge/noarch/marko-2.2.2-pyhd8ed1ab_0.conda#3c3e9339e46fffba5920be28d9233860
https://conda.anaconda.org/conda-forge/win-64/rpds-py-0.30.0-py313hfbe8231_0.conda#58ae648b12cfa6df3923b5fd219931cb
-https://conda.anaconda.org/conda-forge/noarch/attrs-26.1.0-pyhcf101f3_0.conda#c6b0543676ecb1fb2d7643941fe375f2
https://conda.anaconda.org/conda-forge/noarch/referencing-0.37.0-pyhcf101f3_0.conda#870293df500ca7e18bedefa5838a22ab
https://conda.anaconda.org/conda-forge/noarch/jsonschema-specifications-2025.9.1-pyhcf101f3_0.conda#439cd0f567d697b20a8f45cb70a1005a
https://conda.anaconda.org/conda-forge/noarch/jsonschema-4.26.0-pyhcf101f3_0.conda#ada41c863af263cc4c5fcbaff7c3e4dc
@@ -142,38 +172,11 @@ https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.9.6-pyhcf101f3_0.co
https://conda.anaconda.org/conda-forge/noarch/pathspec-1.1.1-pyhd8ed1ab_0.conda#11adc78451c998c0fd162584abfa3559
https://conda.anaconda.org/conda-forge/noarch/black-26.3.1-pyh866005b_0.conda#c7e43448266209d766a229cada982884
https://conda.anaconda.org/conda-forge/noarch/pandera-io-0.24.0-hd8ed1ab_2.conda#d456360daad56c802e27504979ef1e19
-https://conda.anaconda.org/conda-forge/win-64/geos-3.14.0-hdade9fe_0.conda#605225b71402d12f4bf0324b0cc1db97
https://conda.anaconda.org/conda-forge/win-64/shapely-2.1.1-py313hae85795_2.conda#8fad5990956ba5a8bbbdb966e7d017b7
https://conda.anaconda.org/conda-forge/noarch/xyzservices-2026.3.0-pyhd8ed1ab_0.conda#4487b9c371d0161d54b5c7bbd890c0fc
-https://conda.anaconda.org/conda-forge/win-64/sqlite-3.53.1-hdb435a2_0.conda#5833ae18b609bf0790e0bfe6f95b3351
-https://conda.anaconda.org/conda-forge/win-64/libjpeg-turbo-3.1.4.1-hfd05255_0.conda#25a127bad5470852b30b239f030ec95b
-https://conda.anaconda.org/conda-forge/win-64/libdeflate-1.25-h51727cc_0.conda#e77030e67343e28b084fabd7db0ce43e
-https://conda.anaconda.org/conda-forge/win-64/lerc-4.1.0-hd936e49_0.conda#54b231d595bc1ff9bff668dd443ee012
-https://conda.anaconda.org/conda-forge/win-64/libtiff-4.7.1-h8f73337_1.conda#549845d5133100142452812feb9ba2e8
-https://conda.anaconda.org/conda-forge/win-64/proj-9.7.1-hd30e2cd_3.conda#f2b0478a02d35bac5b872d4d63b96be3
https://conda.anaconda.org/conda-forge/win-64/pyproj-3.7.2-py313hbf73894_3.conda#779b40a8eb5e2aa5ffc5eddd3b136fb7
-https://conda.anaconda.org/conda-forge/win-64/xerces-c-3.3.0-hac47afa_1.conda#d1097e01041cfed41c81f1e3d1f52572
-https://conda.anaconda.org/conda-forge/win-64/pcre2-10.46-h3402e2f_0.conda#889053e920d15353c2665fa6310d7a7a
-https://conda.anaconda.org/conda-forge/win-64/muparser-2.3.5-he0c23c2_0.conda#013aabb169d59009bdf7d70319360e9b
-https://conda.anaconda.org/conda-forge/win-64/libwebp-base-1.6.0-h4d5522a_0.conda#f9bbae5e2537e3b06e0f7310ba76c893
-https://conda.anaconda.org/conda-forge/win-64/zlib-1.3.2-hfd05255_2.conda#5187ecf958be3c39110fe691cbd6873e
-https://conda.anaconda.org/conda-forge/win-64/libxml2-devel-2.15.3-hbc0d294_0.conda#62b6eff67ddb7d8657e92fc3d1382a2d
-https://conda.anaconda.org/conda-forge/win-64/librttopo-1.1.0-h5ff11c1_19.conda#41949b02b89c2f2e08c5bd457295f237
-https://conda.anaconda.org/conda-forge/win-64/minizip-4.2.1-h0ffbb96_0.conda#5d55038c4d640e5df06de1cfb4e8d741
-https://conda.anaconda.org/conda-forge/win-64/freexl-2.0.0-hf297d47_2.conda#d6a8059de245e53478b581742b53f71d
-https://conda.anaconda.org/conda-forge/win-64/libspatialite-5.1.0-gpl_h3bf7137_118.conda#a00265bc2dea705fdae1c629f69e65d9
-https://conda.anaconda.org/conda-forge/win-64/libpng-1.6.58-h7351971_0.conda#52f1280563f3b48b5f75414cd2d15dd1
-https://conda.anaconda.org/conda-forge/win-64/uriparser-0.9.8-h5a68840_0.conda#28b4cf9065681f43cc567410edf8243d
-https://conda.anaconda.org/conda-forge/win-64/libkml-1.3.0-h68a222c_1023.conda#b44e0d9eb84c6c086d809787aab0a1da
-https://conda.anaconda.org/conda-forge/win-64/libhwy-1.4.0-h172a326_0.conda#aeca1cb6665f19e560c1fbd20b5bcf34
-https://conda.anaconda.org/conda-forge/win-64/libjxl-0.11.2-h932607e_1.conda#327bce3eb1ef1875c7145e915d25bcd3
-https://conda.anaconda.org/conda-forge/win-64/lzo-2.10-h6a83c73_1002.conda#c5cb4159f0eea65663b31dd1e49bbb71
-https://conda.anaconda.org/conda-forge/win-64/libarchive-3.8.7-gpl_he24518a_100.conda#e8575b817fa0ed38f4f31415f1b4accf
-https://conda.anaconda.org/conda-forge/win-64/blosc-1.21.6-hfd34d9b_1.conda#357d7be4146d5fec543bfaa96a8a40de
-https://conda.anaconda.org/conda-forge/win-64/libgdal-core-3.11.4-h8a8bf46_6.conda#fd3141a9ef5384b6ecad819ffe429378
-https://conda.anaconda.org/conda-forge/win-64/pyogrio-0.11.1-py313h0dbd5a6_1.conda#7d1eaf4ed949aeb268394cf2857e20b5
+https://conda.anaconda.org/conda-forge/win-64/pyogrio-0.11.0-py313h75b81ac_0.conda#7a3d31c8db0ac99557cb2faf51fc42b5
https://conda.anaconda.org/conda-forge/win-64/qhull-2020.2-hc790b64_5.conda#854fbdff64b572b5c0b470f334d34c11
-https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda#3687cc0b82a8b4c17e1f0eb7e47163d5
https://conda.anaconda.org/conda-forge/win-64/zlib-ng-2.3.3-h0261ad2_1.conda#46a21c0a4e65f1a135251fc7c8663f83
https://conda.anaconda.org/conda-forge/win-64/openjpeg-2.5.4-h0e57b4f_0.conda#e723ab7cc2794c954e1b22fde51c16e4
https://conda.anaconda.org/conda-forge/win-64/libgomp-15.2.0-h8ee18e1_19.conda#f1147651e3fdd585e2f442c0c2fc8f2d
@@ -202,10 +205,10 @@ https://conda.anaconda.org/conda-forge/noarch/joblib-1.5.3-pyhd8ed1ab_0.conda#61
https://conda.anaconda.org/conda-forge/win-64/scikit-learn-1.8.0-np2py313h4ce4a18_1.conda#1a636c8e6f5b92fca019972db0ed348e
https://conda.anaconda.org/conda-forge/noarch/networkx-3.6.1-pyhcf101f3_0.conda#a2c1eeadae7a309daed9d62c96012a2b
https://conda.anaconda.org/conda-forge/noarch/mapclassify-2.10.0-pyhd8ed1ab_1.conda#cc293b4cad9909bf66ca117ea90d4631
-https://conda.anaconda.org/conda-forge/noarch/geopandas-base-1.0.1-pyha770c72_3.conda#e8343d1b635bf09dafdd362d7357f395
+https://conda.anaconda.org/conda-forge/noarch/geopandas-base-1.1.3-pyha770c72_0.conda#18789a85c307970ae1786dfc6dfd234f
https://conda.anaconda.org/conda-forge/noarch/branca-0.8.2-pyhd8ed1ab_0.conda#1fcdf88e7a8c296d3df8409bf0690db4
https://conda.anaconda.org/conda-forge/noarch/folium-0.20.0-pyhd8ed1ab_0.conda#a6997a7dcd6673c0692c61dfeaea14ab
-https://conda.anaconda.org/conda-forge/noarch/geopandas-1.0.1-pyhd8ed1ab_3.conda#1baca589eb35814a392eaad6d152447e
+https://conda.anaconda.org/conda-forge/noarch/geopandas-1.1.3-pyhd8ed1ab_0.conda#4eb8b870142ca06d2a1d2c74662eac7d
https://conda.anaconda.org/conda-forge/noarch/pandera-geopandas-0.24.0-hd8ed1ab_2.conda#fb21509f073465506ea994dc4667bf66
https://conda.anaconda.org/conda-forge/noarch/toml-0.10.2-pyhcf101f3_3.conda#d0fc809fa4c4d85e959ce4ab6e1de800
https://conda.anaconda.org/conda-forge/noarch/traitlets-5.15.0-pyhcf101f3_0.conda#4bada6a6d908a27262af8ebddf4f7492
@@ -229,3 +232,4 @@ https://conda.anaconda.org/conda-forge/noarch/jmespath-1.1.0-pyhcf101f3_1.conda#
https://conda.anaconda.org/conda-forge/noarch/botocore-1.40.76-pyhd8ed1ab_0.conda#4babebd5361bc44503358a519a81a465
https://conda.anaconda.org/conda-forge/noarch/s3transfer-0.14.0-pyhd8ed1ab_0.conda#4e3089ce93822a25408c480dd53561b6
https://conda.anaconda.org/conda-forge/noarch/boto3-1.40.46-pyhd8ed1ab_0.conda#a93057bba32eef7b217733734642bfea
+https://conda.anaconda.org/conda-forge/noarch/antimeridian-0.4.7-pyhd8ed1ab_0.conda#56e9ab4ca5ec150ad52ca420f2cec646
diff --git a/workflow/envs/shape.yaml b/workflow/envs/shape.yaml
index 9857891..21e5f99 100644
--- a/workflow/envs/shape.yaml
+++ b/workflow/envs/shape.yaml
@@ -5,7 +5,7 @@ channels:
dependencies:
- boto3 1.40.46.*
- duckdb 1.2.0.*
-- geopandas 1.0.1.*
+- geopandas 1.1.3.*
- ipdb 0.13.13.*
- pandera-geopandas 0.24.*
- pandera-io 0.24.*
@@ -16,3 +16,5 @@ dependencies:
- pandas 3.0.2.*
- pytz 2026.2.*
- requests 2.33.1.*
+- antimeridian 0.4.7.*
+- rasterio 1.4.4.*
diff --git a/workflow/internal/config.schema.yaml b/workflow/internal/config.schema.yaml
index 07d49f8..8dfa47f 100644
--- a/workflow/internal/config.schema.yaml
+++ b/workflow/internal/config.schema.yaml
@@ -10,6 +10,108 @@ $defs:
- type: integer
minimum: 1
+ partialCrsSettings:
+ description: CRS codes (i.e., 'epsg:3035', 'EPSG:4326', 8857).
+ type: object
+ additionalProperties: false
+ properties:
+ projected:
+ description: "Projected CRS code (for area and length calculation)."
+ allOf:
+ - $ref: "#/$defs/crsCode"
+ geographic:
+ description: "Geographic CRS code (for latitude / longitude positioning)."
+ allOf:
+ - $ref: "#/$defs/crsCode"
+
+ crsSettings:
+ allOf:
+ - $ref: "#/$defs/partialCrsSettings"
+ required:
+ - projected
+ - geographic
+
+ partialVoronoiEEZSettings:
+ description: >
+ Optional configuration for the Voronoi EEZ splitting algorithm.
+ type: object
+ additionalProperties: false
+ properties:
+ enabled:
+ description: Activation of the splitting algorithm.
+ type: boolean
+ default: false
+ sample_spacing:
+ description: >
+ Maximum distance between sample points for shorelines.
+ Lower for finer splits at the cost of slower processing.
+ Matches the unit of the projected CRS.
+ type: integer
+ default: 10000
+ minimum: 1
+ min_samples_per_shoreline:
+ description: >
+ Minimum number of sampled points per touching shoreline component.
+ This helps small islands influence the split even when their coastlines
+ are shorter than `sample_spacing`.
+ type: integer
+ default: 8
+ minimum: 1
+ max_samples_per_maritime:
+ description: >
+ Approximate cap for sampled shoreline points per maritime shape.
+ If exceeded, the algorithm raises the effective sample spacing and
+ skips raw shoreline vertices to keep processing bounded.
+ type: integer
+ default: 50000
+ minimum: 1
+ include_shoreline_vertices:
+ description: >
+ Include existing shoreline vertices as Voronoi generators in addition
+ to adaptive midpoint samples.
+ type: boolean
+ default: true
+ shoreline_search_radius:
+ description: >
+ Distance around maritime polygons used to find the marine-facing
+ country exterior boundary. This handles land and EEZ datasets whose
+ coastlines do not exactly coincide. Matches the unit of the projected
+ CRS.
+ type: integer
+ default: 10000
+ minimum: 0
+ uncovered_area_tolerance:
+ description: >
+ Maximum area loss permitted per EEZ polygon after splitting. An error
+ will be raised if exceeded. Matches the unit of the projected CRS.
+ type: number
+ default: 1
+ minimum: 0
+
+ scenario:
+ type: object
+ required:
+ - countries
+ additionalProperties: false
+ properties:
+ crs:
+ $ref: "#/$defs/partialCrsSettings"
+ voronoi_eez:
+ $ref: "#/$defs/partialVoronoiEEZSettings"
+ countries:
+ $ref: "#/$defs/countries"
+
+ countries:
+ description: >
+ Dictionary of countries with each country code as the key.
+ Country code must be in ISO alpha-3 format (e.g., MEX, CHN, DEU).
+ type: object
+ patternProperties:
+ "^[A-Z]{3}$": # Keys must be exactly three uppercase letters
+ $ref: "#/$defs/country"
+ minProperties: 1
+ additionalProperties: false
+
countryBase:
type: object
properties:
@@ -111,35 +213,15 @@ $defs:
description: "Schema for user-provided configuration files."
type: object
+required:
+ - scenarios
+ - crs
+additionalProperties: false
properties:
crs:
- description: CRS codes (i.e., 'epsg:3035', 'EPSG:4326', 8857).
- type: object
- properties:
- projected:
- description: "Projected CRS code (for area and length calculation)."
- allOf:
- - $ref: "#/$defs/crsCode"
- geographic:
- description: "Geographic CRS code (for latitude / longitude positioning)."
- allOf:
- - $ref: "#/$defs/crsCode"
- required:
- - projected
- - geographic
- additionalProperties: false
-
- countries:
- description: >
- Dictionary of countries with each country code as the key.
- Country code must be in ISO alpha-3 format (e.g., MEX, CHN, DEU).
- type: object
- patternProperties:
- "^[A-Z]{3}$": # Keys must be exactly three uppercase letters
- $ref: "#/$defs/country"
- minProperties: 1
- additionalProperties: false
-
+ $ref: "#/$defs/crsSettings"
+ voronoi_eez:
+ $ref: "#/$defs/partialVoronoiEEZSettings"
overture_release:
description: |
Overture data release to use. Two options are possible:
@@ -148,66 +230,13 @@ properties:
type: string
default: "latest"
pattern: "^(?:latest|(?:\\d{4})-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\\d|3[01])\\.\\d+)$"
- voronoi_eez:
+ scenarios:
description: >
- Optional configuration for the Voronoi EEZ splitting algorithm.
+ Shape-building scenarios to run.
+ Downloaded source files will be reused between them if possible.
type: object
- required:
- - enabled
- - sample_spacing
- properties:
- enabled:
- description: Activation of the splitting algorithm.
- type: boolean
- default: false
- sample_spacing:
- description: >
- Maximum distance between sample points for shorelines.
- Lower for finer splits at the cost of slower processing.
- Matches the unit of the projected CRS.
- type: integer
- default: 10000
- minimum: 1
- min_samples_per_shoreline:
- description: >
- Minimum number of sampled points per touching shoreline component.
- This helps small islands influence the split even when their coastlines
- are shorter than `sample_spacing`.
- type: integer
- default: 8
- minimum: 1
- max_samples_per_maritime:
- description: >
- Approximate cap for sampled shoreline points per maritime shape.
- If exceeded, the algorithm raises the effective sample spacing and
- skips raw shoreline vertices to keep processing bounded.
- type: integer
- default: 50000
- minimum: 1
- include_shoreline_vertices:
- description: >
- Include existing shoreline vertices as Voronoi generators in addition
- to adaptive midpoint samples.
- type: boolean
- default: true
- shoreline_search_radius:
- description: >
- Distance around maritime polygons used to find the marine-facing
- country exterior boundary. This handles land and EEZ datasets whose
- coastlines do not exactly coincide. Matches the unit of the projected
- CRS.
- type: integer
- default: 10000
- minimum: 0
- uncovered_area_tolerance:
- description: >
- Maximum area loss permitted per EEZ polygon after splitting. An error
- will be raised if exceeded. Matches the unit of the projected CRS.
- type: number
- default: 1
- minimum: 0
-
-required:
- - countries
- - crs
-additionalProperties: false
+ patternProperties:
+ "^[A-Za-z0-9_-]+$":
+ $ref: "#/$defs/scenario"
+ minProperties: 1
+ additionalProperties: false
diff --git a/workflow/report/build_combined_area.rst b/workflow/report/build_combined_area.rst
index bcbf5bf..8272f54 100644
--- a/workflow/report/build_combined_area.rst
+++ b/workflow/report/build_combined_area.rst
@@ -1,5 +1,7 @@
Resulting polygonal data of country boundaries and marine exclusive economic zones (EEZ).
+Scenario: {{ snakemake.wildcards.scenario }}
+
Countries: {{ snakemake.params.countries }}
Source datasets: {{ snakemake.params.sources }}
diff --git a/workflow/report/build_country.rst b/workflow/report/build_country.rst
index c1b0e33..88d1e0d 100644
--- a/workflow/report/build_country.rst
+++ b/workflow/report/build_country.rst
@@ -1,4 +1,4 @@
-Built combined file for {{ snakemake.wildcards.country }}.
+Built combined file for {{ snakemake.wildcards.scenario}}-{{ snakemake.wildcards.country }}.
* If present, contested EEZ regions are removed.
* Optionally, EEZ regions are broken down using a Voronoi algorithm.
diff --git a/workflow/report/download_harmonised_eez.rst b/workflow/report/download_harmonised_eez.rst
index 2a70269..1651d2b 100644
--- a/workflow/report/download_harmonised_eez.rst
+++ b/workflow/report/download_harmonised_eez.rst
@@ -1,3 +1,3 @@
-Downloaded and harmonised EEZ for {{ snakemake.wildcards.country }}.
+Downloaded and harmonised EEZ for {{ snakemake.wildcards.eez }}.
Source: Flanders Marine Institute: MarineRegions.org. Available online at `www.marineregions.org `_.
diff --git a/workflow/rules/_utils.smk b/workflow/rules/_utils.smk
index e951c1b..6db3347 100644
--- a/workflow/rules/_utils.smk
+++ b/workflow/rules/_utils.smk
@@ -1,18 +1,54 @@
"""Utility functions for snakemake rule handling."""
-def get_country_file(country: str):
- """Build unique file names to avoid overwriting source files."""
- source = config["countries"][country]["source"]
- subtype = config["countries"][country]["subtype"]
+def get_country_file(scenario: str, country: str):
+ """Build unique file names to avoid overwriting source files.
+
+ Scenarios do not affect the downloaded source files.
+ """
+ country_settings: dict = config["scenarios"][scenario]["countries"][country]
+
+ source = country_settings["source"]
+ subtype = country_settings["subtype"]
filename = f"{source}/harmonise/{country}_{subtype}"
if source == "nuts":
- resolution = config["countries"][country]["resolution"]
- year = config["countries"][country]["year"]
+ resolution = country_settings["resolution"]
+ year = country_settings["year"]
filename += f"_{year}_{resolution}"
elif source == "geoboundaries":
- release = config["countries"][country]["release_type"]
+ release = country_settings["release_type"]
filename += f"_{release}"
return filename
+
+
+def get_crs_config(scenario: str) -> dict:
+ """Get CRS configuration in order of priority."""
+ return config["crs"] | config["scenarios"][scenario].get("crs", {})
+
+
+def get_voronoi_eez_config(scenario: str) -> dict:
+ """Get Voronoi configuration in order of priority."""
+ scenario_override = config["scenarios"][scenario].get("voronoi_eez", {})
+ user_overrides = config.get("voronoi_eez", {}) | scenario_override
+ return internal["voronoi_eez"] | user_overrides
+
+
+def get_eez_file(scenario: str, country: str) -> str:
+ """Build an EEZ filename reusable by scenarios with matching EEZ requests."""
+ extra_eez = config["scenarios"][scenario]["countries"][country].get("extra_eez", [])
+ if not isinstance(extra_eez, list):
+ extra_eez = [extra_eez]
+
+ extra_eez = sorted([int(i) for i in extra_eez])
+ if extra_eez:
+ file_path = f"combined/{country}_{'_'.join([str(i) for i in extra_eez])}"
+ else:
+ file_path = f"single/{country}"
+ return file_path
+
+
+def get_extra_eez_from_key(eez_key: str) -> list[int]:
+ """Recover additional EEZ identifiers from an EEZ output wildcard."""
+ return [int(i) for i in eez_key.split("_")]
diff --git a/workflow/rules/build.smk b/workflow/rules/build.smk
index 3fb64f8..28e8944 100644
--- a/workflow/rules/build.smk
+++ b/workflow/rules/build.smk
@@ -1,54 +1,86 @@
"""Rules used to construct the final dataset."""
+rule build_eez:
+ input:
+ country="/automatic/eez/single/{country}.parquet",
+ extra=lambda wc: [
+ f"/automatic/eez/single/{mrgid}.parquet"
+ for mrgid in get_extra_eez_from_key(wc.eez_key)
+ ],
+ output:
+ path="/automatic/eez/combined/{country}_{eez_key}.parquet",
+ log:
+ "/eez/build/{country}_{eez_key}.log",
+ conda:
+ "../envs/shape.yaml"
+ message:
+ "{wildcards.country}: build EEZ dataset {wildcards.eez_key}."
+ script:
+ "../scripts/build_eez.py"
+
+
rule build_country:
input:
- land=lambda wc: f"/automatic/{get_country_file(wc.country)}.parquet",
- maritime="/automatic/eez/{country}.parquet",
+ land=lambda wc: (
+ f"/automatic/{get_country_file(wc.scenario, wc.country)}.parquet"
+ ),
+ maritime=lambda wc: (
+ f"/automatic/eez/{get_eez_file(wc.scenario, wc.country)}.parquet"
+ ),
output:
- country="/automatic/country/{country}.parquet",
+ country="/automatic/scenarios/{scenario}/{country}.parquet",
plot=report(
- "/automatic/country/{country}.png",
+ "/automatic/scenarios/{scenario}/{country}.png",
caption="../report/build_country.rst",
category="Module Geo-Boundaries",
subcategory="Country area",
),
log:
- "/{country}/build_country.log",
+ "/scenarios/{scenario}/build_country/{country}.log",
conda:
"../envs/shape.yaml"
params:
- crs=config["crs"],
- voronoi=internal["voronoi_eez"] | config.get("voronoi_eez", {}),
+ crs=lambda wc: get_crs_config(wc.scenario),
+ voronoi=lambda wc: get_voronoi_eez_config(wc.scenario),
message:
- "{wildcards.country}: build combined land and marine polygons."
+ "{wildcards.scenario}-{wildcards.country}: building combined single-country dataset."
script:
"../scripts/build_country.py"
rule build_combined_area:
input:
- countries=[
- f"/automatic/country/{country}.parquet"
- for country in config["countries"]
+ countries=lambda wc: [
+ f"/automatic/scenarios/{wc.scenario}/{country}.parquet"
+ for country in config["scenarios"][wc.scenario]["countries"]
],
output:
combined="",
plot=report(
- "/shapes.png",
+ "/{scenario}/shapes.png",
caption="../report/build_combined_area.rst",
category="Module Geo-Boundaries",
subcategory="Combined area",
),
log:
- "/build_combined_area.log",
+ "/scenarios/{scenario}/build_combined_area.log",
conda:
"../envs/shape.yaml"
params:
- crs=config["crs"],
- countries=sorted([i for i in config["countries"]]),
- sources=sorted(set([i["source"] for i in config["countries"].values()])),
+ crs=lambda wc: get_crs_config(wc.scenario),
+ countries=lambda wc: sorted(
+ [i for i in config["scenarios"][wc.scenario]["countries"]]
+ ),
+ sources=lambda wc: sorted(
+ set(
+ [
+ i["source"]
+ for i in config["scenarios"][wc.scenario]["countries"].values()
+ ]
+ )
+ ),
message:
- "Combine land and marine polygons."
+ "{wildcards.scenario}: building combined dataset with all countries."
script:
"../scripts/build_combined_area.py"
diff --git a/workflow/rules/harmonise.smk b/workflow/rules/harmonise.smk
index 2723a1a..e59987f 100644
--- a/workflow/rules/harmonise.smk
+++ b/workflow/rules/harmonise.smk
@@ -41,9 +41,6 @@ rule harmonise_gadm:
"/gadm/harmonise/{country}_{subtype}.log",
conda:
"../envs/shape.yaml"
- params:
- country_id=lambda wc: str(wc.country),
- subtype=lambda wc: str(wc.subtype),
message:
"Harmonising '{wildcards.country}_{wildcards.subtype}' GADM dataset."
script:
@@ -67,22 +64,21 @@ rule harmonise_nuts:
rule download_harmonised_eez:
output:
- path="/automatic/eez/{country}.parquet",
+ path="/automatic/eez/single/{eez}.parquet",
plot=report(
- "/automatic/eez/{country}.png",
+ "/automatic/eez/single/{eez}.png",
caption="../report/download_harmonised_eez.rst",
category="Module Geo-Boundaries",
subcategory="EEZ area",
),
log:
- "/eez/download_harmonised/{country}.log",
+ "/eez/download_harmonised/{eez}.log",
localrule: True
conda:
"../envs/shape.yaml"
params:
- extra_eez=lambda wc: config["countries"][wc.country].get("extra_eez", []),
timeouts=internal["timeouts"],
message:
- "Download and harmonise '{wildcards.country}' EEZ dataset."
+ "Download and harmonise EEZ dataset '{wildcards.eez}'."
script:
"../scripts/download_harmonised_eez.py"
diff --git a/workflow/scripts/_geo.py b/workflow/scripts/_geo.py
new file mode 100644
index 0000000..0e48a82
--- /dev/null
+++ b/workflow/scripts/_geo.py
@@ -0,0 +1,131 @@
+"""Reusable geometry helpers."""
+
+from collections.abc import Iterator
+from itertools import pairwise
+from warnings import warn
+
+import antimeridian
+import geopandas as gpd
+from pyproj import CRS
+from rasterio import warp
+from shapely import MultiPolygon, Polygon
+from shapely.geometry import GeometryCollection, mapping, shape
+from shapely.geometry.base import BaseGeometry
+
+CRS_MARINE_REGIONS = "EPSG:4326"
+
+
+def check_crs_config(crs: dict[str, int | str]) -> dict[str, CRS]:
+ """Check the crs configuration settings."""
+ result = {k: CRS.from_user_input(v) for k, v in crs.items()}
+ if not result["projected"].is_projected:
+ raise ValueError(f"CRS must be projected. Got {crs['projected']!r}.")
+ if not result["geographic"].is_geographic:
+ raise ValueError(f"CRS must be geographic. Got {crs['geographic']!r}.")
+ return result
+
+
+def _iter_polygons(geom: BaseGeometry | None) -> Iterator[Polygon]:
+ """Yield polygon parts from possibly mixed geometry."""
+ if geom is None or geom.is_empty:
+ return
+
+ if isinstance(geom, Polygon):
+ yield geom
+ elif isinstance(geom, (MultiPolygon, GeometryCollection)):
+ for part in geom.geoms:
+ yield from _iter_polygons(part)
+
+
+def extract_polygonal_geometry(
+ geom: BaseGeometry | None,
+) -> Polygon | MultiPolygon | None:
+ """Return only Polygon/MultiPolygon components from a geometry."""
+ polygons = list(_iter_polygons(geom))
+ result = None
+ if polygons:
+ result = polygons[0] if len(polygons) == 1 else MultiPolygon(polygons)
+ return result
+
+
+def _rasterio_to_crs(gdf: gpd.GeoDataFrame, to_crs: CRS) -> gpd.GeoDataFrame:
+ """CRS conversion using rasterio's more powerful toolset.
+
+ Compared to geopandas this should adequately handle antimeridian "splitting".
+ Order: geopandas -> GeoJSON-like dict -> rasterio -> geopandas
+ """
+ input_geoms = [mapping(geom) for geom in gdf.geometry]
+ transformed = warp.transform_geom(
+ src_crs=gdf.crs, dst_crs=to_crs, geom=input_geoms, antimeridian_cutting=True
+ )
+ output_geoms = [shape(geom) for geom in transformed]
+ return gdf.set_geometry(gpd.GeoSeries(output_geoms, index=gdf.index, crs=to_crs))
+
+
+def to_projected_crs(gdf: gpd.GeoDataFrame, crs: int | str | CRS) -> gpd.GeoDataFrame:
+ """CRS conversion using rasterio's more powerful toolset.
+
+ Compared to geopandas this adequately handles handles antimeridian "splitting".
+ """
+ to_crs = CRS.from_user_input(crs)
+ if not to_crs.is_projected:
+ raise ValueError(f"This function only converts to geographic CRS. Got {crs!r}.")
+ return _rasterio_to_crs(gdf, to_crs)
+
+
+def _crosses_antimeridian(poly: Polygon) -> bool:
+ rings = [poly.exterior, *poly.interiors]
+
+ crosses = any(
+ 180 < abs(x2 - x1) < 360
+ for ring in rings
+ for (x1, _), (x2, _) in pairwise(ring.coords)
+ )
+
+ return crosses
+
+
+def _fix_antimeridian_geometry(geom: BaseGeometry) -> BaseGeometry:
+ fixed_geom = geom
+
+ if geom.geom_type == "Polygon":
+ if _crosses_antimeridian(geom):
+ fixed_geom = antimeridian.fix_polygon(geom)
+
+ elif geom.geom_type == "MultiPolygon":
+ parts = []
+
+ for poly in geom.geoms:
+ fixed_poly = poly
+
+ if _crosses_antimeridian(poly):
+ fixed_poly = antimeridian.fix_polygon(poly)
+
+ if fixed_poly.geom_type == "MultiPolygon":
+ parts.extend(fixed_poly.geoms)
+ else:
+ parts.append(fixed_poly)
+
+ fixed_geom = MultiPolygon(parts)
+
+ return fixed_geom
+
+
+def to_geographic_crs(gdf: gpd.GeoDataFrame, crs: int | str | CRS) -> gpd.GeoDataFrame:
+ """Convert to a geographic CRS fixing antimeridian-crossings."""
+ target_crs = CRS.from_user_input(crs)
+ if not target_crs.is_geographic:
+ raise ValueError(f"This function only converts to geographic CRS. Got {crs!r}.")
+
+ # Map to 4326 to ensure we match antimeridian algorithm requirements
+ fixed = _rasterio_to_crs(gdf, CRS.from_user_input("EPSG:4326"))
+ fixed.geometry = fixed.geometry.map(_fix_antimeridian_geometry)
+
+ if not fixed.crs.equals(target_crs):
+ warn(
+ f"Target CRS {crs!r} does not match {fixed.crs!r}. "
+ "This might behave oddly near the antimeridian."
+ )
+ fixed = fixed.to_crs(target_crs)
+
+ return fixed
diff --git a/workflow/scripts/_schemas.py b/workflow/scripts/_schemas.py
index af705f5..1e878c3 100644
--- a/workflow/scripts/_schemas.py
+++ b/workflow/scripts/_schemas.py
@@ -1,7 +1,11 @@
-import pandera.pandas as pa
+"""Reusable schemas."""
+
+import geopandas as gpd
+from _geo import extract_polygonal_geometry
+from pandera import pandas as pa
from pandera.typing.geopandas import GeoSeries
from pandera.typing.pandas import Series
-from shapely.validation import make_valid
+from shapely.geometry import MultiPolygon, Polygon
SUPPORTED_DATASETS = ["gadm", "overture", "marineregions", "nuts", "geoboundaries"]
@@ -31,18 +35,24 @@ class Config:
"Human-readable name in the parent dataset."
@pa.dataframe_parser
- def fix_geometries(cls, df):
- """Attempt to correct empty or malformed geometries."""
- mask = df["geometry"].apply(lambda g: (g is not None) and (not g.is_empty))
- df = df.loc[mask]
- df["geometry"] = df["geometry"].apply(
- lambda g: g if g.is_valid else make_valid(g)
- )
- return df
+ def fix_geometries(cls, gdf: gpd.GeoDataFrame) -> gpd.GeoDataFrame: # type: ignore[misc]
+ """Attempt to correct empty, malformed, or non-polygonal geometries."""
+ mask = gdf["geometry"].notna() & ~gdf["geometry"].is_empty
+ gdf = gdf.loc[mask].copy()
+
+ invalid = ~gdf.geometry.is_valid
+ gdf.loc[invalid, "geometry"] = gdf.loc[invalid, "geometry"].make_valid()
+
+ gdf["geometry"] = gdf["geometry"].apply(extract_polygonal_geometry)
+ return gdf.loc[gdf["geometry"].notna()]
@pa.check("geometry", element_wise=True)
- def check_geometries(cls, geom):
- return (geom is not None) and (not geom.is_empty) and geom.is_valid
+ def check_geometries(cls, geom) -> bool:
+ return (
+ isinstance(geom, (Polygon, MultiPolygon))
+ and not geom.is_empty
+ and geom.is_valid
+ )
class EEZSchema(ShapesSchema):
diff --git a/workflow/scripts/_utils.py b/workflow/scripts/_utils.py
index 266d441..5cbf4f4 100644
--- a/workflow/scripts/_utils.py
+++ b/workflow/scripts/_utils.py
@@ -33,28 +33,14 @@ def request_timeout(self) -> tuple[int, int]:
return (self.connect_seconds, self.read_seconds)
-def check_crs_config(crs: dict[str, int | str]) -> dict[str, CRS]:
- """Check the crs configuration settings."""
- result = {k: CRS.from_user_input(v) for k, v in crs.items()}
- if not result["projected"].is_projected:
- raise ValueError(f"CRS must be projected. Got {crs['projected']!r}.")
- if not result["geographic"].is_geographic:
- raise ValueError(f"CRS must be geographic. Got {crs['geographic']!r}.")
- return result
-
-
def plot_shapes(shapes: gpd.GeoDataFrame, crs: str | int | CRS) -> tuple[Figure, Axes]:
"""Generate a nice figure of dataframes that fit the module's schema."""
- gdf = shapes.copy().to_crs(crs)
+ # NOTE: the use of geopandas' to_crs is purposeful.
+ # It's likely what users of the module will rely on later.
+ gdf = shapes.to_crs(crs)
colors = {"land": "olive", "maritime": "tab:blue"}
fig, ax = plt.subplots(layout="constrained")
- ax = gdf.plot(
- ax=ax,
- column="shape_class",
- color=gdf["shape_class"].map(colors),
- legend=False,
- zorder=-1,
- )
+ ax = gdf.plot(ax=ax, color=gdf["shape_class"].map(colors), legend=False, zorder=-1)
gdf.boundary.plot(ax=ax, color="black", lw=0.5, zorder=1)
ax.set(xticks=[], yticks=[], xlabel="", ylabel="")
return fig, ax
diff --git a/workflow/scripts/build_combined_area.py b/workflow/scripts/build_combined_area.py
index ce63718..6a99b9c 100644
--- a/workflow/scripts/build_combined_area.py
+++ b/workflow/scripts/build_combined_area.py
@@ -4,6 +4,7 @@
from collections import defaultdict
from typing import TYPE_CHECKING, Any
+import _geo
import _schemas
import _utils
import geopandas as gpd
@@ -21,7 +22,7 @@ def remove_overlaps(gdf: gpd.GeoDataFrame, crs: dict[str, CRS]) -> gpd.GeoDataFr
The first row wins. Any area shared with an earlier kept geometry is removed
from the later geometry.
"""
- projected = gdf.to_crs(crs["projected"]).copy()
+ projected = _geo.to_projected_crs(gdf, crs["projected"])
left_idx, right_idx = projected.sindex.query(
projected.geometry, predicate="intersects"
@@ -57,22 +58,24 @@ def remove_overlaps(gdf: gpd.GeoDataFrame, crs: dict[str, CRS]) -> gpd.GeoDataFr
projected["geometry"] = geoms
projected = projected.loc[projected.geometry.notna() & ~projected.geometry.is_empty]
-
- result = projected.to_crs(crs["geographic"])
- result.geometry = result.geometry.buffer(0)
+ result = _geo.to_geographic_crs(projected, crs["geographic"])
return result
def main() -> None:
"""Main snakemake process."""
- crs = _utils.check_crs_config(snakemake.params.crs)
-
- country_list = [
- gpd.read_parquet(i).to_crs(crs["geographic"]) for i in snakemake.input.countries
- ]
- combined = _schemas.ShapesSchema.validate(
- pd.concat(country_list, ignore_index=True)
+ crs = _geo.check_crs_config(snakemake.params.crs)
+
+ # Load and ensure inputs are healthy
+ country_list = [gpd.read_parquet(i) for i in snakemake.input.countries]
+ crs_mismatch = [not crs["geographic"].equals(i.crs) for i in country_list]
+ if any(crs_mismatch):
+ raise ValueError(f"Received datasets with invalid CRS: {sum(crs_mismatch)!r} .")
+ combined = gpd.GeoDataFrame(
+ pd.concat(country_list, ignore_index=True),
+ crs=crs["geographic"],
+ geometry="geometry",
)
combined = remove_overlaps(combined, crs)
diff --git a/workflow/scripts/build_country.py b/workflow/scripts/build_country.py
index 47e6e7e..25a7dd0 100644
--- a/workflow/scripts/build_country.py
+++ b/workflow/scripts/build_country.py
@@ -6,6 +6,7 @@
from dataclasses import dataclass
from typing import TYPE_CHECKING, Any
+import _geo
import _schemas
import _utils
import geopandas as gpd
@@ -197,11 +198,7 @@ def _make_shoreline_seed_records(
def _split_one_maritime(
- maritime_row,
- land: gpd.GeoDataFrame,
- *,
- crs: int | str,
- voronoi_config: VoronoiConfig,
+ maritime_row, land: gpd.GeoDataFrame, *, crs: CRS, voronoi_config: VoronoiConfig
) -> tuple[gpd.GeoDataFrame, gpd.GeoDataFrame]:
"""Split a single maritime shape to fit the coastline."""
if land.empty:
@@ -268,6 +265,8 @@ def _split_one_maritime(
.dissolve(by="assigned_shape_id", as_index=False)
.rename(columns={"assigned_shape_id": "_assigned_shape_id"})
)
+ # FIXME: check if rerunning `warp` is necessary to fix things near the antimeridian
+ pieces = _geo.to_projected_crs(pieces, crs)
uncovered_area = maritime_geometry.difference(pieces.geometry.union_all()).area
if uncovered_area > voronoi_config.uncovered_area_tolerance:
raise RuntimeError(
@@ -297,11 +296,9 @@ def split_maritime_by_shoreline_voronoi(
if not voronoi_config.enabled:
return shapes, cells
- shapes = shapes.copy().to_crs(crs["projected"])
-
- land = shapes.loc[shapes["shape_class"].eq("land")]
- maritime = shapes.loc[shapes["shape_class"].eq("maritime")]
-
+ shapes_proj = _geo.to_projected_crs(shapes, crs["projected"])
+ land = shapes_proj.loc[shapes_proj["shape_class"].eq("land")].copy()
+ maritime = shapes_proj.loc[shapes_proj["shape_class"].eq("maritime")].copy()
if maritime.empty:
raise ValueError("Requested voronoi without maritime shapes.")
@@ -310,67 +307,76 @@ def split_maritime_by_shoreline_voronoi(
maritime_row,
land.loc[land["country_id"].eq(maritime_row.country_id)],
voronoi_config=voronoi_config,
- crs=shapes.crs,
+ crs=crs["projected"],
)
for maritime_row in maritime.itertuples(index=False)
]
split_maritime = [pieces for pieces, _ in split_results]
- result = pd.concat([land, *split_maritime], ignore_index=True)
+ result = gpd.GeoDataFrame(
+ pd.concat([land, *split_maritime], ignore_index=True),
+ geometry="geometry",
+ crs=crs["projected"],
+ )
cell_frames = [i for _, i in split_results if not i.empty]
if cell_frames:
cells = gpd.GeoDataFrame(
pd.concat(cell_frames, ignore_index=True),
geometry="geometry",
- crs=shapes.crs,
+ crs=crs["projected"],
)
-
- result = result.to_crs(crs["geographic"])
- result.geometry = result.geometry.buffer(0)
+ result.geometry = result.geometry.make_valid()
+ result = _geo.to_geographic_crs(result, crs["geographic"])
return result, cells
-def combine_shapes(
- land: gpd.GeoDataFrame, maritime: gpd.GeoDataFrame, geo_crs: CRS
+def build_country(
+ land: gpd.GeoDataFrame, maritime: gpd.GeoDataFrame, crs: dict[str, CRS]
) -> gpd.GeoDataFrame:
- """Combine land and marine shapes."""
- combined = land.copy().to_crs(geo_crs)
- if not maritime.empty:
- # remove contested zones and clip to give priority to maritime polygons
- eez = maritime.copy().to_crs(geo_crs)
- eez = eez[eez["contested"].eq(False)].drop(columns="contested")
- combined.geometry = combined.geometry.difference(eez.geometry.union_all())
- combined = pd.concat([combined, eez], ignore_index=True)
-
- # Resolve floating point mismatches that occur during CRS conversion
- combined.geometry = combined.geometry.buffer(0)
- return combined
+ """Build country dataset, with maritime regions if necessary."""
+ if maritime.empty:
+ return _geo.to_geographic_crs(land, crs["geographic"])
+
+ # Reproject
+ p_land = _geo.to_projected_crs(land, crs["projected"])
+ p_marine = _geo.to_projected_crs(maritime, crs["projected"])
+ # Remove contested zones
+ p_marine = p_marine[p_marine["contested"].eq(False)].drop(columns="contested")
+ # Give priority to EEZs
+ p_land.geometry = p_land.geometry.difference(p_marine.geometry.union_all())
+ combined = gpd.GeoDataFrame(
+ pd.concat([p_land, p_marine], ignore_index=True), crs=crs["projected"]
+ )
+ combined.geometry = combined.geometry.make_valid()
+ return _geo.to_geographic_crs(combined, crs["geographic"])
def plot_voronoi_cells(ax: _utils.Axes, cells: gpd.GeoDataFrame, crs: CRS) -> None:
"""Show voronoi tessellation."""
- projected_cells = cells.copy().to_crs(crs)
+ projected_cells = cells.to_crs(crs)
projected_cells.boundary.plot(ax=ax, lw=0.2, color="lightgrey", zorder=0)
def main() -> None:
"""Main snakemake process."""
- crs = _utils.check_crs_config(snakemake.params.crs)
-
+ crs = _geo.check_crs_config(snakemake.params.crs)
country = snakemake.wildcards.country
+
+ # Load and ensure request matches expectations
land = _schemas.ShapesSchema.validate(gpd.read_parquet(snakemake.input.land))
maritime = _schemas.EEZSchema.validate(gpd.read_parquet(snakemake.input.maritime))
-
country_ids = set(land["country_id"]) | set(maritime["country_id"])
- if set(country_ids) - set([country]):
+ if set(country_ids) - {country}:
raise ValueError(
- f"Country processing mismatch for {country!r}. Found {country_ids!r}."
+ f"Country mismatch: expected {country!r}, found {country_ids!r}."
)
- shapes = combine_shapes(land, maritime, crs["geographic"])
+ # Build default country dataset
+ shapes = build_country(land, maritime, crs)
shapes = _schemas.ShapesSchema.validate(shapes)
+ # If requested, run Voronoi splitting
voronoi_config = VoronoiConfig(**snakemake.params.voronoi)
cells = None
if not maritime.empty and voronoi_config.enabled:
@@ -379,11 +385,11 @@ def main() -> None:
)
shapes = _schemas.ShapesSchema.validate(shapes)
+ # Save and show a pretty plot
shapes.to_parquet(snakemake.output.country)
fig, ax = _utils.plot_shapes(shapes, crs["projected"])
if cells is not None and not cells.empty:
plot_voronoi_cells(ax, cells, crs["projected"])
-
fig.savefig(snakemake.output.plot, dpi=200, bbox_inches="tight")
diff --git a/workflow/scripts/build_eez.py b/workflow/scripts/build_eez.py
new file mode 100644
index 0000000..819cfee
--- /dev/null
+++ b/workflow/scripts/build_eez.py
@@ -0,0 +1,48 @@
+"""Build one configured EEZ dataset from cached MarineRegions downloads."""
+
+import sys
+from typing import TYPE_CHECKING, Any
+
+import _schemas
+import geopandas as gpd
+import pandas as pd
+from _geo import CRS_MARINE_REGIONS
+
+if TYPE_CHECKING:
+ snakemake: Any
+
+
+def build_eez(country: str, paths: list[str]) -> gpd.GeoDataFrame:
+ """Combine a country EEZ file with optional extra MarineRegions ID files."""
+ frames = [
+ _schemas.EEZSchema.validate(gpd.read_parquet(path)).to_crs(CRS_MARINE_REGIONS)
+ for path in paths
+ ]
+ frames = [frame for frame in frames if not frame.empty]
+
+ if frames:
+ combined = gpd.GeoDataFrame(pd.concat(frames, ignore_index=True))
+ combined["country_id"] = country
+ combined["shape_id"] = combined["parent_id"].apply(
+ lambda parent_id: "_".join([country, "marineregions", str(parent_id)])
+ )
+ else:
+ combined = gpd.GeoDataFrame(
+ columns=_schemas.EEZSchema.to_schema().columns,
+ geometry="geometry",
+ crs=CRS_MARINE_REGIONS,
+ )
+
+ return _schemas.EEZSchema.validate(combined)
+
+
+def main() -> None:
+ """Main snakemake process."""
+ input_paths = [snakemake.input.country, *snakemake.input.extra]
+ gdf = build_eez(snakemake.wildcards.country, input_paths)
+ gdf.to_parquet(snakemake.output.path)
+
+
+if __name__ == "__main__":
+ sys.stderr = open(snakemake.log[0], "w")
+ main()
diff --git a/workflow/scripts/download_harmonised_eez.py b/workflow/scripts/download_harmonised_eez.py
index 3a52578..8a4014d 100644
--- a/workflow/scripts/download_harmonised_eez.py
+++ b/workflow/scripts/download_harmonised_eez.py
@@ -1,10 +1,9 @@
"""Download data from the Marineregions database.
https://www.marineregions.org/
-Constructs EEZ datasets per country
+
- In cases where no EEZ is available for a country an empty dataframe will be saved.
-- Optionally, additional EEZs may be downloaded if specified in `extra_eez`.
- - These should result in an error if the code is invalid.
+- Individual MarineRegions IDs can be downloaded separately and combined later.
"""
import sys
@@ -13,8 +12,8 @@
import _schemas
import _utils
import geopandas as gpd
-import pandas as pd
import requests
+from _geo import CRS_MARINE_REGIONS
from matplotlib import pyplot as plt
if TYPE_CHECKING:
@@ -22,7 +21,6 @@
WFS_BASE = "https://geo.vliz.be/geoserver/MarineRegions/wfs"
WFS_VERSION = "2.0.0"
-CRS_MARINE_REGIONS = "EPSG:4326"
def _raise_for_geoserver_exception(response: requests.Response) -> None:
@@ -179,45 +177,44 @@ def plot(gdf: gpd.GeoDataFrame, country: str):
return fig, ax
-def download_eezs(
- country: str, extra_eez: list[str], timeouts: _utils.DownloadTimeouts
+def download_eez(
+ cql_filter: str,
+ country_id: str,
+ timeouts: _utils.DownloadTimeouts,
+ *,
+ allow_empty: bool,
) -> gpd.GeoDataFrame:
- """Download EEZ data as requested.
+ """Download and harmonise one EEZ query.
- If no EEZ exists for a country, the dataframe will be empty.
+ If no EEZ exists for a country query, the dataframe will be empty.
+ MarineRegions ID queries are expected to return exactly one dataset.
"""
- eez_gdfs: list[gpd.GeoDataFrame] = []
-
- iso3_eez = get_eez_by_cql(f"iso_ter1='{country}'", timeouts)
- if iso3_eez is not None:
- eez_gdfs.append(iso3_eez)
-
- for mrgid in extra_eez:
- extra_gdf = get_eez_by_cql(f"mrgid={int(mrgid)}", timeouts)
- if extra_gdf is None:
- raise RuntimeError(f"Configured extra_eez {mrgid!r} returned no features")
- eez_gdfs.append(extra_gdf)
-
- combined_gdf = None
- if eez_gdfs:
- combined_gdf = pd.concat(eez_gdfs, ignore_index=True)
+ gdf = get_eez_by_cql(cql_filter, timeouts)
+ if gdf is None and not allow_empty:
+ raise RuntimeError(f"Configured EEZ query {cql_filter!r} returned no features")
- return transform_to_schema(combined_gdf, country)
+ return transform_to_schema(gdf, country_id)
def main() -> None:
"""Main snakemake process."""
- country = snakemake.wildcards.country
- extra_eez = snakemake.params.extra_eez
-
timeouts = _utils.DownloadTimeouts(**snakemake.params.timeouts)
- if not isinstance(extra_eez, list):
- extra_eez = [extra_eez]
+ eez = snakemake.wildcards.eez
+
+ if eez.isdigit():
+ label = f"mrgid {eez}"
+ gdf = download_eez(
+ f"mrgid={int(eez)}", "extra_eez", timeouts, allow_empty=False
+ )
+ elif len(eez) == 3 and eez.isalpha() and eez.isupper():
+ label = eez
+ gdf = download_eez(f"iso_ter1='{eez}'", eez, timeouts, allow_empty=True)
+ else:
+ raise ValueError(f"Unsupported EEZ identifier: {eez!r}")
- gdf = download_eezs(country, extra_eez, timeouts)
gdf.to_parquet(snakemake.output.path)
- fig, _ = plot(gdf, country)
+ fig, _ = plot(gdf, label)
fig.savefig(snakemake.output.plot, bbox_inches="tight", dpi=200)
diff --git a/workflow/scripts/harmonise_gadm.py b/workflow/scripts/harmonise_gadm.py
index dfa34b0..c263941 100644
--- a/workflow/scripts/harmonise_gadm.py
+++ b/workflow/scripts/harmonise_gadm.py
@@ -46,7 +46,7 @@ def standardise_country_gadm(
if __name__ == "__main__":
standardise_country_gadm(
input_path=snakemake.input.raw,
- country_id=snakemake.params.country_id,
- subtype=snakemake.params.subtype,
+ country_id=snakemake.wildcards.country,
+ subtype=snakemake.wildcards.subtype,
output_path=snakemake.output.standardised,
)