diff --git a/README.md b/README.md
index b5a6516..f773ccf 100644
--- a/README.md
+++ b/README.md
@@ -8,6 +8,7 @@ This module performs geospatial analyses to determine the available land area fo
## About
+
This is a modular `snakemake` workflow created as part of the [Modelblocks project](https://www.modelblocks.org/). It can be imported directly into any `snakemake` workflow.
@@ -17,6 +18,7 @@ the [integration example](./tests/integration/Snakefile),
and the `snakemake` [documentation](https://snakemake.readthedocs.io/en/stable/snakefiles/modularization.html).
## Overview
+
Data processing steps:
@@ -25,77 +27,84 @@ Data processing steps:
-
-* Geospatial input data (vector and raster) are acquired. This is automatic for most data, but the following data need to be manually supplied:
- * Geographic boundaries in the parquet format
- * WDPA protected areas database from https://www.protectedplanet.net/ in GeoDB format (choose 'File Geodatabase' when downloading).
-* For the extent of the provided boundaries, the input data are reprojected and rasterised to the resolution of the land cover data (GlobCover), and merged into a single dataset for further processing.
-* Based on the supplied configuration, the land-use analysis is done for each defined technology.
-* Results can be reported on a per-geography and per-technology basis, as pixel surface area values (TIFF files), images for reporting purposes (PNG files), and also as a summary report with per-region capacities (CSV and HTML files)
+- Geospatial input data (vector and raster) are acquired. This is automatic for most data, but the following data need to be manually supplied:
+ - Geographic boundaries in the parquet format
+ - WDPA protected areas database from https://www.protectedplanet.net/ in GeoDB format (choose 'File Geodatabase' when downloading).
+- For the extent of the provided boundaries, the input data are reprojected and rasterised to the resolution of the land cover data (GlobCover), and merged into a single dataset for further processing.
+- Based on the supplied configuration, the land-use analysis is done for each defined technology.
+- Results can be reported on a per-geography and per-technology basis, as pixel surface area values (TIFF files), images for reporting purposes (PNG files), and also as a summary report with per-region capacities (CSV and HTML files)
See below for the [data sources](#references).
## Configuration
+
Please consult the configuration [README](./config/README.md) and the [configuration example](./config/config.yaml) for a general overview on the configuration options of this module.
-In the configuration, you can define any number of `techs`, and for each of them, specify the `initial_area`, `continuous_layers`, and `binary_layers`.
+The configuration is based on an arbitrary number of `scenarios`. Each scenario can define any number of `techs`, and for each tech, the conditions for its land use, via `initial_area`, `continuous_layers`, and `binary_layers`. Results are delivered by scenario and tech, e.g. `/{shape}/{scenario}/area_potential_{tech}.tif`. Defining only a single scenario (e.g. `base`) works fine if no scenarios are needed.
+
+Per-subunit `overrides` inside a scenario can be used to override the specific settings of a tech in just one subunit (the keys of the `split_by` column, e.g. country codes). An example use of this is to provide different offshore wind distance-to-shore numbers for different countries.
By example, here is a `pv_rooftop` tech. We use the `settlement_area`, which is the settlement area in m² in each pixel, as the initial area from which the further analysis proceeds. In `continuous_layers`, we use the `settlement_share`, which is the share (0-1) of area covered by settlement, and exclude pixels with less than 0.01 settlement share while assuming that of those pixels not excluded by that, 0.8 (80%) of the settled area can be used for rooftop PV. Finally, in the `binary_layers`, we include all land use types except `NOT_SUITABLE` (since the main selection is done via the settlement_share). This means that, for example, `FOREST` pixels with a `settlement_area` > 0 can be included.
```yaml
pv_rooftop:
- initial_area: settlement_area
- continuous_layers:
- settlement_share:
- min: 0.01
- max: 1
- share: 0.8
- binary_layers:
- regions_maritime: 0
- regions_land: 1
- protected: 0
- landcover_FARM: 1
- landcover_FOREST: 1
- landcover_URBAN: 1
- landcover_OTHER: 1
- landcover_NOT_SUITABLE: 0
- landcover_WATER: 0
+ initial_area: settlement_area
+ continuous_layers:
+ settlement_share:
+ min: 0.01
+ max: 1
+ share: 0.8
+ binary_layers:
+ regions_maritime: 0
+ regions_land: 1
+ protected: 0
+ landcover_FARM: 1
+ landcover_FOREST: 1
+ landcover_URBAN: 1
+ landcover_OTHER: 1
+ landcover_NOT_SUITABLE: 0
+ landcover_WATER: 0
```
-Here is a `wind_offshore` example. We start with the `pixel_area`, the total surface area in m² for each pixel. We include pixels with a slope up to and including 20 degrees, and exclude pixels with a settlement share above 0.01. Furthermore, we include only land areas (`regions_land: 1` and `regions_maritime: 0`) and completely exclude some areas like protected areas or urban areas (`protected: 0`, `landcover_URBAN: 0`), while including only a fraction of other areas (e.g. if a pixel is considered farmland, only 20% of its surface is available: `landcover_FARM: 0.2`).
+Here is a `wind_onshore` example. We start with the `pixel_area`, the total surface area in m² for each pixel. We include pixels with a slope up to and including 20 degrees, and exclude pixels with a settlement share above 0.01. Furthermore, we include only land areas (`regions_land: 1` and `regions_maritime: 0`) and completely exclude some areas like protected areas or urban areas (`protected: 0`, `landcover_URBAN: 0`), while including only a fraction of other areas (e.g. if a pixel is considered farmland, only 20% of its surface is available: `landcover_FARM: 0.2`).
```yaml
wind_onshore:
- initial_area: pixel_area
- continuous_layers:
- slope_deg:
- min: 0
- max: 20
- settlement_share:
- min: 0
- max: 0.01
- binary_layers:
- regions_maritime: 0
- regions_land: 1
- protected: 0
- landcover_FARM: 0.2
- landcover_FOREST: 0.05
- landcover_URBAN: 0
- landcover_OTHER: 0.3
- landcover_NOT_SUITABLE: 0
- landcover_WATER: 0
-
+ initial_area: pixel_area
+ continuous_layers:
+ slope_deg:
+ min: 0
+ max: 20
+ settlement_share:
+ min: 0
+ max: 0.01
+ binary_layers:
+ regions_maritime: 0
+ regions_land: 1
+ protected: 0
+ landcover_FARM: 0.2
+ landcover_FOREST: 0.05
+ landcover_URBAN: 0
+ landcover_OTHER: 0.3
+ landcover_NOT_SUITABLE: 0
+ landcover_WATER: 0
```
+Some of the processing in this workflow is memory-intensive.
+The memory-heavy rules all specify their expected peak memory with `resources: mem_mb`. This number was hardcoded based on an estimate of country-sized subunits, with up to about 150 million land-cover pixels.
+Snakemake only uses these declarations to control how many memory-heavy jobs are scheduled in parallel, when you tell it how much memory is available overall (e.g., `snakemake --use-conda --cores 4 --resources mem_mb=12000`).
+To help diagnose memory usage, each heavy job also writes a `*.benchmark.tsv` next to its log file, containing its runtime, and on Linux only, peak memory.
## Input / output structure
+
Please consult the [interface file](./INTERFACE.yaml) for more information.
## Development
+
We use [`pixi`](https://pixi.sh/) as our package manager for development.
@@ -108,18 +117,19 @@ pixi install --all
```
Please be aware that this is a multi-environment project (see [pixi.toml](./pixi.toml) for details).
+
- `default`: used for development and integration testing.
-Because it contains `Snakemake`, `conda` and `pytest` as dependencies it **should not be used** in `Snakemake` rules.
+ Because it contains `Snakemake`, `conda` and `pytest` as dependencies it **should not be used** in `Snakemake` rules.
- `module`: contains minimal dependencies used in `Snakemake` rules.
-If modified, be sure to export it to `Snakemake` so it can be recreated by module users:
+ If modified, be sure to export it to `Snakemake` so it can be recreated by module users:
```shell
# create module.yaml and conda-spec pin files in workflow/envs/
pixi run export-snakemake-env module
```
-
## Testing
+
For testing, simply run:
@@ -136,23 +146,36 @@ cd tests/integration/ # navigate to the integration example
snakemake --use-conda --cores 2 # run the workflow!
```
+### Module-specific unit tests
+
+Besides the integration tests, this module also supplies unit tests:
+
+```shell
+pixi run test-unit
+```
+
+The unit tests are run in an isolated `test-unit` Pixi environment that combines `pytest` with the `module` feature. They run through every workflow script on a small synthetic dataset, then compare the outputs with committed reference data in `unit_tests/reference/`.
+
+To regenerate the reference data when results change deliberately, use `pixi run update-reference` (or `update-reference-unit` / `update-reference-integration` separately) and review the resulting diff as part of the change.
+
## References
+
This module is based on the following research and datasets:
-* [GEDTM30](https://github.com/openlandmap/GEDTM30) for slope
- * License: Creative Commons Attribution 4.0 International
-* [GlobCover land cover data](https://due.esrin.esa.int/page_globcover.php)
- * License: "You may use the GlobCover land cover map for educational and/or scientific purposes, without any fee on the condition that you credit ESA and the Université Catholique de Louvain as the source of the GlobCover products."
-* [GEBCO (General Bathymetric Chart of the Oceans)](https://www.gebco.net/data-products/gridded-bathymetry-data) 15 arc-second data
- * License: "The GEBCO Grid is placed in the public domain and may be used free of charge. [...] Users must: Acknowledge the source of The GEBCO Grid. A suitable form of attribution is given in the documentation that accompanies The GEBCO Grid."
-* [GHSL (Global Human Settlement Layer)](https://human-settlement.emergency.copernicus.eu/download.php) built-up surface data (R2023, GHS-BUILT-S, 100m resolution)
- * License: "The GHSL has been produced by the EC JRC as open and free data. Reuse is authorised, provided the source is acknowledged."
-* [World Bank Global Shipping Traffic Density](https://datacatalog.worldbank.org/search/dataset/0037580/global-shipping-traffic-density), the number of AIS-recorded vessel positions per square kilometre accumulated over 2015–2021
- * License: Creative Commons Attribution 4.0 International (CC BY 4.0)
-* [WDPA (World Database on Protected Areas)](https://www.protectedplanet.net/)
- * License: Non-commercial allowed. Citation: "UNEP-WCMC and IUCN (2025), Protected Planet: The World Database on Protected Areas (WDPA) and World Database on Other Effective Area-based Conservation Measures (WD-OECM) [Online], June 2025, Cambridge, UK: UNEP-WCMC and IUCN. Available at: www.protectedplanet.net."
+- [GEDTM30](https://github.com/openlandmap/GEDTM30) for slope
+ - License: Creative Commons Attribution 4.0 International
+- [GlobCover land cover data](https://due.esrin.esa.int/page_globcover.php)
+ - License: "You may use the GlobCover land cover map for educational and/or scientific purposes, without any fee on the condition that you credit ESA and the Université Catholique de Louvain as the source of the GlobCover products."
+- [GEBCO (General Bathymetric Chart of the Oceans)](https://www.gebco.net/data-products/gridded-bathymetry-data) 15 arc-second data
+ - License: "The GEBCO Grid is placed in the public domain and may be used free of charge. [...] Users must: Acknowledge the source of The GEBCO Grid. A suitable form of attribution is given in the documentation that accompanies The GEBCO Grid."
+- [GHSL (Global Human Settlement Layer)](https://human-settlement.emergency.copernicus.eu/download.php) built-up surface data (R2023, GHS-BUILT-S, 100m resolution)
+ - License: "The GHSL has been produced by the EC JRC as open and free data. Reuse is authorised, provided the source is acknowledged."
+- [World Bank Global Shipping Traffic Density](https://datacatalog.worldbank.org/search/dataset/0037580/global-shipping-traffic-density), the number of AIS-recorded vessel positions per square kilometre accumulated over 2015–2021
+ - License: Creative Commons Attribution 4.0 International (CC BY 4.0)
+- [WDPA (World Database on Protected Areas)](https://www.protectedplanet.net/)
+ - License: Non-commercial allowed. Citation: "UNEP-WCMC and IUCN (2025), Protected Planet: The World Database on Protected Areas (WDPA) and World Database on Other Effective Area-based Conservation Measures (WD-OECM) [Online], June 2025, Cambridge, UK: UNEP-WCMC and IUCN. Available at: www.protectedplanet.net."
## Contributors ✨
diff --git a/WAIVER.md b/WAIVER.md
new file mode 100644
index 0000000..443d195
--- /dev/null
+++ b/WAIVER.md
@@ -0,0 +1,3 @@
+Technische Universiteit Delft hereby disclaims all copyright interest in the program "module_area_potentials" (geospatial analysis to determine available land area for energy infrastructure) written by the Author(s).
+
+Cokky Hilhorst, Dean of the Faculty of Technology, Policy and Management (TPM)
diff --git a/figures/rulegraph.png b/figures/rulegraph.png
index 94174a0..d384707 100644
Binary files a/figures/rulegraph.png and b/figures/rulegraph.png differ
diff --git a/pixi.lock b/pixi.lock
index 751b900..0c9fd5b 100644
--- a/pixi.lock
+++ b/pixi.lock
@@ -1,8 +1,20 @@
version: 7
platforms:
- name: linux-64
+ virtual-packages:
+ - __unix=0=0
+ - __linux=4.18
+ - __glibc=2.28
+ - __archspec=0=x86_64
- name: osx-arm64
+ virtual-packages:
+ - __unix=0=0
+ - __osx=13.0
+ - __archspec=0=m1
- name: win-64
+ virtual-packages:
+ - __win=10.0
+ - __archspec=0=x86_64
environments:
default:
channels:
@@ -749,6 +761,772 @@ environments:
module:
channels:
- url: https://conda.anaconda.org/conda-forge/
+ - url: https://conda.anaconda.org/bioconda/
+ packages:
+ linux-64:
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.16.1-hb03c661_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/attr-2.5.2-hb03c661_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-auth-0.9.6-hb9c0fe4_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-cal-0.9.13-h2c9d079_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-common-0.12.6-hb03c661_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-compression-0.3.2-h8b1a151_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-event-stream-0.5.9-h841be55_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-http-0.10.10-hf621c6d_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-io-0.26.1-hc87160b_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-mqtt-0.14.0-ha25ca29_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-s3-0.11.5-h9b5df67_3.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-sdkutils-0.2.4-h8b1a151_4.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-checksums-0.2.10-h8b1a151_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-crt-cpp-0.37.2-hb153662_3.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-sdk-cpp-1.11.606-hc9b1074_13.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/azure-core-cpp-1.16.2-h206d751_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/azure-identity-cpp-1.13.3-hed0cdb0_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/azure-storage-blobs-cpp-12.16.0-hf824e48_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/azure-storage-common-cpp-12.13.0-ha7a2c86_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/azure-storage-files-datalake-cpp-12.14.0-h539c000_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/backports.zstd-1.7.0-py313h8f72f4d_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/blosc-1.21.6-he440d0b_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-1.2.0-hed03a55_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.2.0-hb03c661_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.2.0-py313hf159716_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.8-hebe6cf0_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/cairo-1.18.4-h3394656_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/cftime-1.6.5-py313h29aa505_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.3.3-py313hc8edb43_4.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/curl-8.18.0-h4e3cde8_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/cyrus-sasl-2.1.28-hd9c7081_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/cytoolz-1.1.0-py313h07c4f96_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/dbus-1.16.2-h24cb091_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/double-conversion-3.3.1-h5888daf_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/fiona-1.10.1-py313h7033f15_4.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.18.3-h4db4eae_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.63.0-py313h3dea7bd_0.conda
+ - 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/gdal-3.10.3-py313h60f829d_27.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-h239500f_2.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
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.15-hecca717_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-12.2.0-h15599e2_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/hdf4-4.2.15-h2a13503_7.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/hdf5-1.14.6-nompi_h19486de_106.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/icu-75.1-he02047a_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/json-c-0.18-h6688a6e_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.3-hb9d3cd8_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.5.1-py313h2551ef2_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.21.3-h659f571_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.19.1-h0c24ade_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.46.1-default_hbd61a6d_102.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/lerc-4.2.0-hdb68285_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libabseil-20260107.1-cxx17_h7b12aa8_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libaec-1.1.5-h088129d_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.8.9-gpl_hc2c16d8_100.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libarrow-19.0.1-h3c191e6_45_cpu.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libarrow-acero-19.0.1-h635bf11_45_cpu.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libarrow-dataset-19.0.1-h635bf11_45_cpu.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libarrow-substrait-19.0.1-hb4dd7c2_45_cpu.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libattr-2.5.2-hb03c661_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-8_h4a7cf45_openblas.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.2.0-hb03c661_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.2.0-hb03c661_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.2.0-hb03c661_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-8_h0358290_openblas.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libclang-cpp21.1-21.1.8-default_h99862b1_4.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libclang13-22.1.8-default_h746c552_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libcrc32c-1.1.2-h9c3ff4c_0.tar.bz2
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-hb8b1518_5.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.18.0-h4e3cde8_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.25-h17f619e_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.129-h7cc23a3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libegl-1.7.0-ha4b6fd6_3.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-hd590300_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libevent-2.1.12-hf998b51_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.8.1-hecca717_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype-2.14.3-ha770c72_0.conda
+ - 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-16.2.0-ha9f2e26_4.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-16.2.0-h69a702a_4.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libgdal-arrow-parquet-3.10.3-hef02800_18.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libgdal-core-3.10.3-h95ec890_18.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libgdal-hdf5-3.10.3-h966a9c2_18.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-16.2.0-h69a702a_4.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-16.2.0-h6b99dfc_4.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libgl-1.7.0-ha4b6fd6_3.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.86.2-h32235b2_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libglvnd-1.7.0-ha4b6fd6_3.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libglx-1.7.0-ha4b6fd6_3.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-16.2.0-he0feb66_4.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/libiconv-1.18-h3b78370_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.2.0-hb03c661_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-8_h47877c9_openblas.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libllvm21-21.1.8-hf7376ad_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libllvm22-22.1.8-hf7376ad_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb03c661_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libnetcdf-4.9.3-nompi_hbf2fc22_104.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.68.1-h877daf1_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libntlm-1.8-hb9d3cd8_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.33-pthreads_h94d23a6_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libopengl-1.7.0-ha4b6fd6_3.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libopentelemetry-cpp-1.21.0-h9692893_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libopentelemetry-cpp-headers-1.21.0-ha770c72_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libparquet-19.0.1-h7376487_45_cpu.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libpciaccess-0.19-hb03c661_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.58-h421ea60_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libpq-18.1-h5c52fec_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libprotobuf-6.33.5-h6eeba95_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libre2-11-2025.11.05-h0dc7533_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/librttopo-1.1.0-h96cd706_19.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libspatialite-5.1.0-h2eee824_16.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.4-h0737f62_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.1-hcf80075_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-16.2.0-h934c35e_4.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-16.2.0-hdf11a46_4.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libthrift-0.22.0-h7d032f7_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.2-hcc2c06a_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libutf8proc-2.11.3-hfe17d71_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.3-hcfc3c73_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libvulkan-loader-1.4.357.0-h0e34353_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.6.0-hd42ef1d_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.17.0-h8a09558_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.38-h280c20c_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.13.2-hca5e8e5_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-16-2.15.1-ha9997c6_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.15.1-h26afc86_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-devel-2.15.1-h26afc86_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libxslt-1.1.43-h711ed8c_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libzip-1.11.2-h6991a6a_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/lz4-4.4.5-py313h28739b2_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.10.0-h5888daf_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/lzo-2.10-h280c20c_1002.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.3-py313h3dea7bd_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.10.3-py313h78bf25f_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.10.3-py313h129903b_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/minizip-4.2.2-hc2c9f91_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/msgpack-python-1.2.2-py313h2551ef2_2.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/netcdf4-1.7.2-nompi_py313hfae5b86_104.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-py313hf6604e3_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.4-h55fea9a_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/openldap-2.6.10-he970967_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.4-h781a0a9_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/orc-2.2.2-hbb90d81_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-2.3.0-py313ha87cce1_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.46-h1321c63_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-12.3.0-py313h3b26573_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/pixman-0.46.4-h54a6638_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/proj-9.6.2-h18fbb6c_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/prometheus-cpp-1.3.0-ha5d0236_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/psutil-7.2.2-py313h54dd161_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-hb9d3cd8_1002.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/pyarrow-19.0.1-py313h78bf25f_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/pyarrow-core-19.0.1-py313he109ebe_2_cpu.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.46.5-py313ha296275_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/pyogrio-0.11.0-py313hab4ff3b_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/pyproj-3.7.1-py313hcd509b5_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.10.1-py313h85046ba_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.13.14-h6add32d_100_cp313.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.3-py313h3dea7bd_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/qt6-main-6.10.1-hca0d9c9_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/rasterio-1.4.3-py313h3209d2e_1.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/s2n-1.7.1-h1cbb8d7_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/scikit-learn-1.9.0-np2py313h16d504d_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/scipy-1.18.0-py313h4b8bb8b_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/shapely-2.1.2-py313hfc84eb1_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/snappy-1.2.2-h03e3b7b_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.53.4-h6e79ffa_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/tornado-6.5.8-py313h995f894_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/uriparser-0.9.8-hac33072_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/wayland-1.26.0-hd6090a7_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-0.4.1-h4f16b4b_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-cursor-0.1.6-hb03c661_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-image-0.4.0-hb711507_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-keysyms-0.4.1-hb711507_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-renderutil-0.3.10-hb711507_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-wm-0.4.2-hb711507_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/xerces-c-3.2.5-h988505b_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/xkeyboard-config-2.48-h280c20c_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libice-1.1.2-hb9d3cd8_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.6-he73a12e_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.8.13-he1eb515_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.12-hb03c661_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxcomposite-0.4.7-hb03c661_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxcursor-1.2.3-hb9d3cd8_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdamage-1.1.6-hb9d3cd8_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.5-hb03c661_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxext-1.3.7-hb03c661_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxfixes-6.0.2-hb03c661_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxi-1.8.3-hb03c661_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrandr-1.5.5-hb03c661_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.12-hb9d3cd8_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxtst-1.2.5-hb9d3cd8_3.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxxf86vm-1.1.7-hb03c661_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h280c20c_3.conda
+ - 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-3.0.1-pyhecae5ae_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/annotated-types-0.8.0-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/bokeh-3.10.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/boltons-26.2.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/branca-0.8.2-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.7.22-hbd8a1cb_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.7.22-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.5.1-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/click-8.2.1-pyh707e725_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/cloudpickle-3.1.2-pyhcf101f3_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/dask-2025.7.0-pyhe01879c_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/dask-core-2025.7.0-pyhe01879c_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/distributed-2025.7.0-pyhe01879c_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/face-26.0.0-pyhcf101f3_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/folium-0.20.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2
+ - conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2
+ - conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2
+ - conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-ecosystem-1-0.tar.bz2
+ - conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-hc364b38_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/fsspec-2026.7.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/geopandas-1.1.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/geopandas-base-1.1.0-pyha770c72_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/glom-24.11.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.4.1-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.2.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.19-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-9.0.1-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.6-pyhcf101f3_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/joblib-1.6.0-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/locket-1.0.0-pyhd8ed1ab_0.tar.bz2
+ - conda: https://conda.anaconda.org/conda-forge/noarch/mapclassify-2.11.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/mypy_extensions-1.1.0-pyha770c72_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/narwhals-2.25.0-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/networkx-3.6.1-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.3-pyhc364b38_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pandera-0.24.0-hd8ed1ab_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pandera-base-0.24.0-pyhd8ed1ab_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pandera-geopandas-0.24.0-hd8ed1ab_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/partd-1.4.2-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.13.5-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2026.3-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.13-8_cp313.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2026.3.post1-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.34.2-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/rioxarray-0.19.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-84.0.0-pyh332efcf_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/sortedcontainers-2.4.0-pyhd8ed1ab_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/tblib-3.2.2-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/threadpoolctl-3.6.0-pyhecae5ae_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/toolz-1.1.0-pyhd8ed1ab_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/typeguard-4.6.0-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.16.0-h69aa097_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/typing-inspection-0.4.4-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/typing_inspect-0.9.0-pyhd8ed1ab_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.7.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/utm-0.7.0-pyhd8ed1ab_0.tar.bz2
+ - conda: https://conda.anaconda.org/conda-forge/noarch/xarray-2025.6.1-pyhd8ed1ab_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/xyzservices-2026.9.1-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/zict-3.0.0-pyhd8ed1ab_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-4.1.0-pyhcf101f3_0.conda
+ osx-arm64:
+ - conda: https://conda.anaconda.org/conda-forge/noarch/affine-3.0.1-pyhecae5ae_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/annotated-types-0.8.0-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/bokeh-3.10.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/boltons-26.2.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/branca-0.8.2-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.7.22-hbd8a1cb_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.7.22-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.5.1-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/click-8.2.1-pyh707e725_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/cloudpickle-3.1.2-pyhcf101f3_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/dask-2025.7.0-pyhe01879c_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/dask-core-2025.7.0-pyhe01879c_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/distributed-2025.7.0-pyhe01879c_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/face-26.0.0-pyhcf101f3_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/folium-0.20.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/fsspec-2026.7.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/geopandas-1.1.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/geopandas-base-1.1.0-pyha770c72_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/glom-24.11.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.4.1-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.2.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.19-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-9.0.1-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.6-pyhcf101f3_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/joblib-1.6.0-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/locket-1.0.0-pyhd8ed1ab_0.tar.bz2
+ - conda: https://conda.anaconda.org/conda-forge/noarch/mapclassify-2.11.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/mypy_extensions-1.1.0-pyha770c72_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/narwhals-2.25.0-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/networkx-3.6.1-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.3-pyhc364b38_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pandera-0.24.0-hd8ed1ab_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pandera-base-0.24.0-pyhd8ed1ab_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pandera-geopandas-0.24.0-hd8ed1ab_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/partd-1.4.2-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.13.5-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2026.3-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.13-8_cp313.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2026.3.post1-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.34.2-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/rioxarray-0.19.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-84.0.0-pyh332efcf_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/sortedcontainers-2.4.0-pyhd8ed1ab_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/tblib-3.2.2-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/threadpoolctl-3.6.0-pyhecae5ae_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/toolz-1.1.0-pyhd8ed1ab_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/typeguard-4.6.0-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.16.0-h69aa097_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/typing-inspection-0.4.4-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/typing_inspect-0.9.0-pyhd8ed1ab_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.7.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/utm-0.7.0-pyhd8ed1ab_0.tar.bz2
+ - conda: https://conda.anaconda.org/conda-forge/noarch/xarray-2025.6.1-pyhd8ed1ab_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/xyzservices-2026.9.1-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/zict-3.0.0-pyhd8ed1ab_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-4.1.0-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/_openmp_mutex-4.5-7_kmp_llvm.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-auth-0.9.6-ha02d361_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-cal-0.9.13-h6ee9776_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-common-0.12.6-hc919400_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-compression-0.3.2-h3e7f9b5_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-event-stream-0.5.9-hd533cd8_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-http-0.10.10-ha1850f6_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-io-0.26.1-h4137820_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-mqtt-0.14.0-h5721393_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-s3-0.11.5-h7d214dc_3.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-sdkutils-0.2.4-h16f91aa_4.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-checksums-0.2.10-h3e7f9b5_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-crt-cpp-0.37.2-hcfbc53e_3.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-sdk-cpp-1.11.606-h71a6bcd_13.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/azure-core-cpp-1.16.2-he5ae378_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/azure-identity-cpp-1.13.3-h810541e_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/azure-storage-blobs-cpp-12.16.0-h5446563_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/azure-storage-common-cpp-12.13.0-he467506_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/azure-storage-files-datalake-cpp-12.14.0-hdc9d693_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/backports.zstd-1.7.0-py313h8c7ad59_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/blosc-1.21.6-h7dd00d9_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/brotli-1.2.0-h7d5ae5b_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/brotli-bin-1.2.0-hc919400_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/brotli-python-1.2.0-py313hde1f3bb_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-hd037594_9.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.34.8-h74c22ad_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cftime-1.6.5-py313hf5115c3_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/contourpy-1.3.3-py313h2af2deb_4.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/curl-8.21.0-hd5a2499_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/cytoolz-1.1.0-py313h0997733_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/fiona-1.10.1-py313h0e822ff_4.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/fonttools-4.63.0-py313h65a2061_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/freetype-2.14.3-hce30654_1.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/gdal-3.10.3-py313h976e3e5_27.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-h1d7e6e1_2.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
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/hdf4-4.2.15-h2ee6834_7.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/hdf5-1.14.6-nompi_had3affe_110.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-75.1-hfee45f7_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/json-c-0.18-he4178ee_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/kiwisolver-1.5.1-py313h738389e_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/krb5-1.22.2-hfd3d5f3_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/lcms2-2.19.1-hdfa7624_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/lerc-4.2.0-h1eee2c3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libabseil-20260107.1-cxx17_h2062a1b_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libaec-1.1.5-h8664d51_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libarchive-3.8.9-gpl_h6fbacd7_100.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libarrow-19.0.1-h96c63c9_45_cpu.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libarrow-acero-19.0.1-h0f28eaf_45_cpu.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libarrow-dataset-19.0.1-h0f28eaf_45_cpu.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libarrow-substrait-19.0.1-h8746646_45_cpu.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libblas-3.11.0-8_h51639a9_openblas.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libbrotlicommon-1.2.0-hc919400_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libbrotlidec-1.2.0-hc919400_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libbrotlienc-1.2.0-hc919400_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcblas-3.11.0-8_hb0561ab_openblas.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcrc32c-1.1.2-hbdafb3b_0.tar.bz2
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcurl-8.21.0-hd5a2499_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-23.1.1-h55c6f16_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libdeflate-1.25-hc11a715_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libedit-3.1.20250104-pl5321hafb1f1b_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libev-4.33-h93a5062_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libevent-2.1.12-h2757513_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.8.1-hf6b4638_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.5.2-hcf2aa1b_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libfreetype-2.14.3-hce30654_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libfreetype6-2.14.3-hdfa99f5_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgcc-16.2.0-h3cf6597_4.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgdal-arrow-parquet-3.10.3-h2616c01_18.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgdal-core-3.10.3-h9f236a5_18.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgdal-hdf5-3.10.3-hdacffec_18.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran-16.2.0-h07b0088_4.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran5-16.2.0-hdb7a957_4.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/libiconv-1.18-h23cfdf5_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libjpeg-turbo-3.2.0-h84a0fba_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-8_hd9741b5_openblas.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblzma-5.8.3-h8088a28_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libmpdec-4.0.0-h84a0fba_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libnetcdf-4.9.3-nompi_h7a8d41e_104.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libnghttp2-1.68.1-h8f3e76b_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libopenblas-0.3.33-openmp_he657e61_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libopentelemetry-cpp-1.21.0-h08d5cc3_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libopentelemetry-cpp-headers-1.21.0-hce30654_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libparquet-19.0.1-hdcf9336_45_cpu.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libpng-1.6.58-h132b30e_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libprotobuf-6.33.5-h2d4b707_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libre2-11-2025.11.05-h4c27e2a_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/librttopo-1.1.0-hf7cb3ef_19.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libspatialite-5.1.0-h823fe50_16.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.53.4-h34a968b_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libssh2-1.11.1-h1590b86_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libthrift-0.22.0-h1fb9c8a_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libtiff-4.7.2-hf67920b_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libutf8proc-2.11.3-h2431656_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libwebp-base-1.6.0-h07db88b_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libxcb-1.17.0-hdb1d25a_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libxml2-16-2.15.1-h0ff4647_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libxml2-2.15.1-h9329255_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libxml2-devel-2.15.1-h9329255_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzip-1.11.2-h1336266_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.2-h8088a28_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-openmp-23.1.0-hdb3d66b_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/lz4-4.4.5-py313hd065f0a_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/lz4-c-1.10.0-h286801f_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/lzo-2.10-h925e9cb_1002.conda
+ - 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-3.10.3-py313h39782a4_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/matplotlib-base-3.10.3-py313haaf02c0_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/minizip-4.2.2-h56c1371_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/msgpack-python-1.2.2-py313hcb059c8_2.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/netcdf4-1.7.2-nompi_py313hb28a5cb_104.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
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openjpeg-2.5.4-hd9e9057_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.6.4-h55eecbc_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/orc-2.2.2-h578b684_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pandas-2.3.0-py313h668b085_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pcre2-10.46-h7125dd6_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pillow-12.3.0-py313h4ede67f_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/proj-9.6.2-hdbeaa80_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/prometheus-cpp-1.3.0-h0967b3e_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/psutil-7.2.2-py313h6688731_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pthread-stubs-0.4-hd74edd7_1002.conda
+ - 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.5-py313h680bcb3_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.1-py313h84bd6f1_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.13.14-h448ec07_100_cp313.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.3-py313h9a45b90_1.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/scikit-learn-1.9.0-np2py313h3b23316_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/scipy-1.18.0-py313h52f5312_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/shapely-2.1.2-py313hfb5a6ed_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/snappy-1.2.2-hada39a4_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/sqlite-3.53.4-hdb6324b_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h010d191_3.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tornado-6.5.8-py313hf5449f0_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/uriparser-0.9.8-h00cdb27_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/xerces-c-3.2.5-h92fc2f4_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/xorg-libxau-1.0.12-hc919400_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/xorg-libxdmcp-1.1.5-hc919400_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/yaml-0.2.5-h925e9cb_3.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zlib-1.3.2-h8088a28_2.conda
+ - 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-3.0.1-pyhecae5ae_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/annotated-types-0.8.0-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/bokeh-3.10.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/boltons-26.2.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/branca-0.8.2-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.7.22-h4c7d964_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.7.22-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.5.1-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/click-8.2.1-pyh7428d3b_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/cloudpickle-3.1.2-pyhcf101f3_1.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/dask-2025.7.0-pyhe01879c_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/dask-core-2025.7.0-pyhe01879c_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/distributed-2025.7.0-pyhe01879c_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/face-26.0.0-pyhcf101f3_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/folium-0.20.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2
+ - conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2
+ - conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2
+ - conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-ecosystem-1-0.tar.bz2
+ - conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-hc364b38_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/fsspec-2026.7.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/geopandas-1.1.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/geopandas-base-1.1.0-pyha770c72_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/glom-24.11.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.4.1-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.2.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.19-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-9.0.1-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.6-pyhcf101f3_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/joblib-1.6.0-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/locket-1.0.0-pyhd8ed1ab_0.tar.bz2
+ - conda: https://conda.anaconda.org/conda-forge/noarch/mapclassify-2.11.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/mypy_extensions-1.1.0-pyha770c72_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/narwhals-2.25.0-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/networkx-3.6.1-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.3-pyhc364b38_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pandera-0.24.0-hd8ed1ab_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pandera-base-0.24.0-pyhd8ed1ab_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pandera-geopandas-0.24.0-hd8ed1ab_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/partd-1.4.2-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.13.5-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyh09c184e_7.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2026.3-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.13-8_cp313.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2026.3.post1-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.34.2-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/rioxarray-0.19.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-84.0.0-pyh332efcf_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/sortedcontainers-2.4.0-pyhd8ed1ab_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/tblib-3.2.2-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/threadpoolctl-3.6.0-pyhecae5ae_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/toolz-1.1.0-pyhd8ed1ab_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/typeguard-4.6.0-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.16.0-h69aa097_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/typing-inspection-0.4.4-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/typing_inspect-0.9.0-pyhd8ed1ab_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.7.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/utm-0.7.0-pyhd8ed1ab_0.tar.bz2
+ - conda: https://conda.anaconda.org/conda-forge/noarch/win_inet_pton-1.1.0-pyh7428d3b_8.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/xarray-2025.6.1-pyhd8ed1ab_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/xyzservices-2026.9.1-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/zict-3.0.0-pyhd8ed1ab_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-4.1.0-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/_openmp_mutex-4.5-20_gnu.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/aws-c-auth-0.9.6-hdf23a24_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/aws-c-cal-0.9.13-h46f3b43_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/aws-c-common-0.12.6-hfd05255_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/aws-c-compression-0.3.2-hcb3a2da_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/aws-c-event-stream-0.5.9-h972bbec_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/aws-c-http-0.10.10-hb410799_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/aws-c-io-0.26.1-h0d5b9f9_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/aws-c-mqtt-0.14.0-h833cf40_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/aws-c-s3-0.11.5-h3ec5e31_3.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/aws-c-sdkutils-0.2.4-hcb3a2da_4.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/aws-checksums-0.2.10-hcb3a2da_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/aws-crt-cpp-0.37.2-h5e571c5_3.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/aws-sdk-cpp-1.11.606-ha60a6cd_13.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/backports.zstd-1.7.0-py313h2a31948_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/blosc-1.21.6-hfd34d9b_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/brotli-1.2.0-h2d644bc_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/brotli-bin-1.2.0-hfd05255_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/brotli-python-1.2.0-py313h3ebfc14_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-h0ad9c76_9.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/c-ares-1.34.8-h6a83c73_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/cairo-1.18.4-h5782bbf_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/cftime-1.6.5-py313h0591002_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/contourpy-1.3.3-py313h1a38498_4.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/curl-8.18.0-h43ecb02_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/cytoolz-1.1.0-py313h5ea7bf4_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/double-conversion-3.3.1-he0c23c2_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/fiona-1.10.1-py313hfe59770_4.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/fontconfig-2.18.3-hd47e2ca_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/fonttools-4.63.0-py313hd650c13_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/freetype-2.14.3-h57928b3_1.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/gdal-3.10.3-py313hf168f70_27.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-h86c3423_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/graphite2-1.3.15-hac47afa_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/harfbuzz-12.2.0-h5f2951f_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/hdf4-4.2.15-h5557f11_7.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/hdf5-1.14.6-nompi_hae35d4c_106.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/icu-75.1-he0c23c2_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/kiwisolver-1.5.1-py313h1a38498_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/krb5-1.21.3-hdf4eb48_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/lcms2-2.19.1-hf2c6c5f_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/lerc-4.2.0-hd936e49_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libabseil-20260107.1-cxx17_h0eb2380_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libaec-1.1.5-haf901d7_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libarchive-3.8.9-gpl_he24518a_100.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libarrow-19.0.1-hd086c85_45_cpu.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libarrow-acero-19.0.1-h7d8d6a5_45_cpu.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libarrow-dataset-19.0.1-h7d8d6a5_45_cpu.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libarrow-substrait-19.0.1-h524e9bd_45_cpu.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libblas-3.11.0-8_h8455456_mkl.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libbrotlicommon-1.2.0-hfd05255_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libbrotlidec-1.2.0-hfd05255_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libbrotlienc-1.2.0-hfd05255_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libcblas-3.11.0-8_h2a3cdd5_mkl.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libclang13-22.1.8-default_ha2db4b5_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libcrc32c-1.1.2-h0e60522_0.tar.bz2
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libcurl-8.18.0-h43ecb02_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libdeflate-1.25-h51727cc_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libevent-2.1.12-h3671451_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libexpat-2.8.1-hac47afa_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libffi-3.5.2-h3d046cb_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libfreetype-2.14.3-h57928b3_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libfreetype6-2.14.3-hdbac1cb_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libgcc-16.2.0-h110b43a_4.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libgdal-arrow-parquet-3.10.3-h4b7837c_18.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libgdal-core-3.10.3-h1dbae3e_18.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libgdal-hdf5-3.10.3-h0f01001_18.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libglib-2.86.2-hd9c3897_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libgomp-16.2.0-h8ee18e1_4.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.13.0-default_h049141e_1000.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/libintl-0.22.5-h5728263_3.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libjpeg-turbo-3.2.0-hfd05255_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-8_hf9ab0e9_mkl.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/liblzma-5.8.3-hfd05255_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libmpdec-4.0.0-hfd05255_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libnetcdf-4.9.3-nompi_h3948bcf_104.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libparquet-19.0.1-h7051d1f_45_cpu.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libpng-1.6.58-h7351971_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libprotobuf-6.33.5-h6cf2d3c_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libre2-11-2025.11.05-h04e5de1_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/librttopo-1.1.0-h5ff11c1_19.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libspatialite-5.1.0-h9d118f5_16.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libsqlite-3.53.4-hf5d6505_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libssh2-1.11.1-h9aa295b_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libthrift-0.22.0-h2e43b2f_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libtiff-4.7.2-h8f73337_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libutf8proc-2.11.3-hb980946_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libvulkan-loader-1.4.357.0-h477610d_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libwebp-base-1.6.0-h4d5522a_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libwinpthread-12.0.0.r4.gg4f2fc60ca-h57928b3_10.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libxcb-1.17.0-h0e4246c_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libxml2-16-2.15.1-h06f855e_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libxml2-2.15.1-ha29bfb0_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libxml2-devel-2.15.1-ha29bfb0_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libxslt-1.1.43-h0fbe4c1_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libzip-1.11.2-h3135430_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libzlib-1.3.2-hfd05255_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/llvm-openmp-23.1.0-h49e36cd_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/lz4-4.4.5-py313h4bbca4b_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/lz4-c-1.10.0-h2466b09_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/lzo-2.10-h6a83c73_1002.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/markupsafe-3.0.3-py313hd650c13_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/matplotlib-3.10.3-py313hfa70ccb_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/matplotlib-base-3.10.3-py313h81b4f16_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/minizip-4.2.2-h8fa244a_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/mkl-2026.1.0-hac47afa_235.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/msgpack-python-1.2.2-py313h1a38498_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/netcdf4-1.7.2-nompi_py313hbe59507_104.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/openjpeg-2.5.4-h0e57b4f_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.6.4-hf411b9b_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/orc-2.2.2-h0a1ad0e_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/pandas-2.3.0-py313hf91d08e_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/pcre2-10.46-h3402e2f_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/pillow-12.3.0-py313h38f99e1_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/pixman-0.46.4-h5112557_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/proj-9.6.2-h7990399_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/psutil-7.2.2-py313h5fd188c_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/pthread-stubs-0.4-h0e40799_1002.conda
+ - 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.5-py313hfbe8231_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.1-py313hc3e4018_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/pyside6-6.10.1-py313h475ba69_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/python-3.13.14-h09917c8_100_cp313.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/qt6-main-6.10.1-h7502b6c_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/rasterio-1.4.3-py313hb64d538_1.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/scikit-learn-1.9.0-np2py313h4ce4a18_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/scipy-1.18.0-py313he51e9a2_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/shapely-2.1.2-py313hae85795_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/snappy-1.2.2-h7fa0ca8_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/sqlite-3.53.4-hdb435a2_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/tbb-2023.0.0-hd3d4ead_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/tk-8.6.13-h6ed50ae_3.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/tornado-6.5.8-py313h5ea7bf4_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/ucrt-10.0.26100.0-h57928b3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/uriparser-0.9.8-h5a68840_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/vc-14.5-h1b7c187_39.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/vc14_runtime-14.51.36247-habf1de7_41.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/vcomp14-14.51.36247-habf1de7_41.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/vs2015_runtime-14.51.36247-h633cb9f_41.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/xerces-c-3.2.5-he0c23c2_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/xorg-libxau-1.0.12-hba3369d_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/xorg-libxdmcp-1.1.5-hba3369d_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/yaml-0.2.5-h6a83c73_3.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/zlib-1.3.2-hfd05255_2.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/zlib-ng-2.3.3-h0261ad2_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/zstd-1.5.7-h534d264_6.conda
+ test-unit:
+ channels:
+ - url: https://conda.anaconda.org/conda-forge/
+ - url: https://conda.anaconda.org/bioconda/
packages:
linux-64:
- conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda
@@ -772,13 +1550,13 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/linux-64/azure-storage-blobs-cpp-12.16.0-hf824e48_2.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/azure-storage-common-cpp-12.13.0-ha7a2c86_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/azure-storage-files-datalake-cpp-12.14.0-h539c000_2.conda
- - conda: https://conda.anaconda.org/conda-forge/linux-64/backports.zstd-1.6.0-py313h18e8e13_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/backports.zstd-1.7.0-py313h8f72f4d_1.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/blosc-1.21.6-he440d0b_1.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-1.2.0-hed03a55_1.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.2.0-hb03c661_1.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.2.0-py313hf159716_1.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda
- - conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.6-hb03c661_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.8-hebe6cf0_2.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/cairo-1.18.4-h3394656_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/cftime-1.6.5-py313h29aa505_1.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.3.3-py313hc8edb43_4.conda
@@ -788,7 +1566,7 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/linux-64/dbus-1.16.2-h24cb091_1.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/double-conversion-3.3.1-h5888daf_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/fiona-1.10.1-py313h7033f15_4.conda
- - conda: https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.18.1-h27c8c51_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.18.3-h4db4eae_1.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.63.0-py313h3dea7bd_0.conda
- 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
@@ -805,14 +1583,14 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/linux-64/icu-75.1-he02047a_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/json-c-0.18-h6688a6e_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.3-hb9d3cd8_0.conda
- - conda: https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.5.0-py313hc8edb43_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.5.1-py313h2551ef2_1.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.21.3-h659f571_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.19.1-h0c24ade_1.conda
- - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda
- - conda: https://conda.anaconda.org/conda-forge/linux-64/lerc-4.1.0-hdb68285_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.46.1-default_hbd61a6d_102.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/lerc-4.2.0-hdb68285_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libabseil-20260107.1-cxx17_h7b12aa8_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libaec-1.1.5-h088129d_0.conda
- - conda: https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.8.8-gpl_hc2c16d8_100.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.8.9-gpl_hc2c16d8_100.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libarrow-19.0.1-h3c191e6_45_cpu.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libarrow-acero-19.0.1-h635bf11_45_cpu.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libarrow-dataset-19.0.1-h635bf11_45_cpu.conda
@@ -829,7 +1607,7 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-hb8b1518_5.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.18.0-h4e3cde8_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.25-h17f619e_0.conda
- - conda: https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.127-hb03c661_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.129-h7cc23a3_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libegl-1.7.0-ha4b6fd6_3.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-hd590300_2.conda
@@ -838,23 +1616,23 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype-2.14.3-ha770c72_0.conda
- 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/libgcc-16.2.0-ha9f2e26_4.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-16.2.0-h69a702a_4.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libgdal-arrow-parquet-3.10.3-hef02800_18.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libgdal-core-3.10.3-h95ec890_18.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libgdal-hdf5-3.10.3-h966a9c2_18.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/libgfortran-16.2.0-h69a702a_4.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-16.2.0-h6b99dfc_4.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libgl-1.7.0-ha4b6fd6_3.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.86.2-h32235b2_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libglvnd-1.7.0-ha4b6fd6_3.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libglx-1.7.0-ha4b6fd6_3.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/libgomp-16.2.0-he0feb66_4.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/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/libjpeg-turbo-3.2.0-hb03c661_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-8_h47877c9_openblas.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libllvm21-21.1.8-hf7376ad_0.conda
@@ -877,18 +1655,18 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/linux-64/libre2-11-2025.11.05-h0dc7533_1.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/librttopo-1.1.0-h96cd706_19.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libspatialite-5.1.0-h2eee824_16.conda
- - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.2-h0c1763c_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.4-h0737f62_1.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.1-hcf80075_0.conda
- - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_19.conda
- - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-15.2.0-hdf11a46_19.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-16.2.0-h934c35e_4.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-16.2.0-hdf11a46_4.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libthrift-0.22.0-h7d032f7_2.conda
- - conda: https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.1-h9d88235_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.2-hcc2c06a_1.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libutf8proc-2.11.3-hfe17d71_0.conda
- - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.2-h5347b49_0.conda
- - conda: https://conda.anaconda.org/conda-forge/linux-64/libvulkan-loader-1.4.341.0-h5279c79_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.3-hcfc3c73_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libvulkan-loader-1.4.357.0-h0e34353_2.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.6.0-hd42ef1d_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.17.0-h8a09558_0.conda
- - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.38-h280c20c_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.13.2-hca5e8e5_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-16-2.15.1-ha9997c6_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.15.1-h26afc86_0.conda
@@ -902,19 +1680,19 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-3.0.3-py313h3dea7bd_1.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-3.10.3-py313h78bf25f_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.10.3-py313h129903b_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/msgpack-python-1.2.1-py313h7037e92_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/minizip-4.2.2-hc2c9f91_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/msgpack-python-1.2.2-py313h2551ef2_2.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/netcdf4-1.7.2-nompi_py313hfae5b86_104.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-py313hf6604e3_1.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.4-h55fea9a_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/openldap-2.6.10-he970967_0.conda
- - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.3-h35e630c_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.4-h781a0a9_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/orc-2.2.2-hbb90d81_1.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-2.3.0-py313ha87cce1_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.46-h1321c63_0.conda
- - conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-12.2.0-py313h80991f8_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-12.3.0-py313h3b26573_2.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/pixman-0.46.4-h54a6638_1.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/proj-9.6.2-h18fbb6c_2.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/prometheus-cpp-1.3.0-ha5d0236_0.conda
@@ -922,7 +1700,7 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-hb9d3cd8_1002.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/pyarrow-19.0.1-py313h78bf25f_2.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/pyarrow-core-19.0.1-py313he109ebe_2_cpu.conda
- - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.46.4-py313h843e2db_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.46.5-py313ha296275_1.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/pyogrio-0.11.0-py313hab4ff3b_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/pyproj-3.7.1-py313hcd509b5_1.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/pyside6-6.10.1-py313h85046ba_0.conda
@@ -938,11 +1716,11 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/linux-64/scipy-1.18.0-py313h4b8bb8b_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/shapely-2.1.2-py313hfc84eb1_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/snappy-1.2.2-h03e3b7b_1.conda
- - conda: https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.53.2-hbc0de68_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.53.4-h6e79ffa_1.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda
- - conda: https://conda.anaconda.org/conda-forge/linux-64/tornado-6.5.7-py313h07c4f96_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/tornado-6.5.8-py313h995f894_1.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/uriparser-0.9.8-hac33072_0.conda
- - conda: https://conda.anaconda.org/conda-forge/linux-64/wayland-1.25.0-hd6090a7_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/wayland-1.26.0-hd6090a7_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-0.4.1-h4f16b4b_2.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-cursor-0.1.6-hb03c661_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-image-0.4.0-hb711507_2.conda
@@ -970,23 +1748,25 @@ 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-types-0.7.0-pyhd8ed1ab_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/affine-3.0.1-pyhecae5ae_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/annotated-types-0.8.0-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/bokeh-3.9.1-pyhd8ed1ab_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/boltons-26.0.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/bokeh-3.10.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/boltons-26.2.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/branca-0.8.2-pyhd8ed1ab_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.6.17-hbd8a1cb_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.6.17-pyhd8ed1ab_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/ca-certificates-2026.7.22-hbd8a1cb_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.7.22-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.5.1-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/click-8.2.1-pyh707e725_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/cloudpickle-3.1.2-pyhcf101f3_1.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/dask-2025.7.0-pyhe01879c_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/dask-core-2025.7.0-pyhe01879c_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/distributed-2025.7.0-pyhe01879c_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/face-26.0.0-pyhcf101f3_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/folium-0.20.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2
@@ -995,124 +1775,136 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-ecosystem-1-0.tar.bz2
- conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-hc364b38_1.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/fsspec-2026.6.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/fsspec-2026.7.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/geopandas-1.1.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/geopandas-base-1.1.0-pyha770c72_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/glom-24.11.0-pyhd8ed1ab_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/h2-4.4.1-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.2.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.18-pyhcf101f3_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-9.0.0-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.19-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-9.0.1-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.6-pyhcf101f3_1.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/joblib-1.5.3-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/joblib-1.6.0-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/locket-1.0.0-pyhd8ed1ab_0.tar.bz2
- - conda: https://conda.anaconda.org/conda-forge/noarch/mapclassify-2.10.0-pyhd8ed1ab_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/mapclassify-2.11.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/mypy_extensions-1.1.0-pyha770c72_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/narwhals-2.22.1-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/narwhals-2.25.0-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/networkx-3.6.1-pyhcf101f3_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.3-pyhc364b38_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/pandera-0.24.0-hd8ed1ab_2.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/pandera-base-0.24.0-pyhd8ed1ab_2.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/pandera-geopandas-0.24.0-hd8ed1ab_2.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/partd-1.4.2-pyhd8ed1ab_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.13.4-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.13.5-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.21.0-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-9.1.1-pyhc364b38_2.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2026.2-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2026.3-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.13-8_cp313.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2026.2-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2026.3.post1-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.34.2-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/rioxarray-0.19.0-pyhd8ed1ab_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-84.0.0-pyh332efcf_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/sortedcontainers-2.4.0-pyhd8ed1ab_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/tblib-3.2.2-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/threadpoolctl-3.6.0-pyhecae5ae_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/toolz-1.1.0-pyhd8ed1ab_1.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/typeguard-4.5.2-pyhcf101f3_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.15.0-h396c80c_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/typing-inspection-0.4.2-pyhcf101f3_2.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/typeguard-4.6.0-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.16.0-h69aa097_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/typing-inspection-0.4.4-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/typing_inspect-0.9.0-pyhd8ed1ab_1.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.7.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/utm-0.7.0-pyhd8ed1ab_0.tar.bz2
- conda: https://conda.anaconda.org/conda-forge/noarch/xarray-2025.6.1-pyhd8ed1ab_1.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/xyzservices-2026.3.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/xyzservices-2026.9.1-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/zict-3.0.0-pyhd8ed1ab_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/zipp-4.1.0-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-types-0.7.0-pyhd8ed1ab_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/affine-3.0.1-pyhecae5ae_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/annotated-types-0.8.0-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/bokeh-3.9.1-pyhd8ed1ab_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/boltons-26.0.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/bokeh-3.10.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/boltons-26.2.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/branca-0.8.2-pyhd8ed1ab_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.6.17-hbd8a1cb_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.6.17-pyhd8ed1ab_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/ca-certificates-2026.7.22-hbd8a1cb_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.7.22-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.5.1-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/click-8.2.1-pyh707e725_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/cloudpickle-3.1.2-pyhcf101f3_1.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/dask-2025.7.0-pyhe01879c_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/dask-core-2025.7.0-pyhe01879c_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/distributed-2025.7.0-pyhe01879c_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/face-26.0.0-pyhcf101f3_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/folium-0.20.0-pyhd8ed1ab_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/fsspec-2026.6.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/fsspec-2026.7.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/geopandas-1.1.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/geopandas-base-1.1.0-pyha770c72_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/glom-24.11.0-pyhd8ed1ab_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/h2-4.4.1-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.2.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.18-pyhcf101f3_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-9.0.0-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.19-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-9.0.1-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.6-pyhcf101f3_1.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/joblib-1.5.3-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/joblib-1.6.0-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/locket-1.0.0-pyhd8ed1ab_0.tar.bz2
- - conda: https://conda.anaconda.org/conda-forge/noarch/mapclassify-2.10.0-pyhd8ed1ab_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/mapclassify-2.11.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/mypy_extensions-1.1.0-pyha770c72_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/narwhals-2.22.1-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/narwhals-2.25.0-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/networkx-3.6.1-pyhcf101f3_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.3-pyhc364b38_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/pandera-0.24.0-hd8ed1ab_2.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/pandera-base-0.24.0-pyhd8ed1ab_2.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/pandera-geopandas-0.24.0-hd8ed1ab_2.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/partd-1.4.2-pyhd8ed1ab_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.13.4-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.13.5-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.21.0-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-9.1.1-pyhc364b38_2.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2026.2-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2026.3-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.13-8_cp313.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2026.2-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2026.3.post1-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.34.2-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/rioxarray-0.19.0-pyhd8ed1ab_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-84.0.0-pyh332efcf_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/sortedcontainers-2.4.0-pyhd8ed1ab_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/tblib-3.2.2-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/threadpoolctl-3.6.0-pyhecae5ae_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/toolz-1.1.0-pyhd8ed1ab_1.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/typeguard-4.5.2-pyhcf101f3_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.15.0-h396c80c_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/typing-inspection-0.4.2-pyhcf101f3_2.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/typeguard-4.6.0-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.16.0-h69aa097_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/typing-inspection-0.4.4-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/typing_inspect-0.9.0-pyhd8ed1ab_1.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.7.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/utm-0.7.0-pyhd8ed1ab_0.tar.bz2
- conda: https://conda.anaconda.org/conda-forge/noarch/xarray-2025.6.1-pyhd8ed1ab_1.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/xyzservices-2026.3.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/xyzservices-2026.9.1-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/zict-3.0.0-pyhd8ed1ab_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/zipp-4.1.0-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/_openmp_mutex-4.5-7_kmp_llvm.conda
@@ -1134,13 +1926,13 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/azure-storage-blobs-cpp-12.16.0-h5446563_2.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/azure-storage-common-cpp-12.13.0-he467506_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/azure-storage-files-datalake-cpp-12.14.0-hdc9d693_2.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-arm64/backports.zstd-1.6.0-py313h7208f8c_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/backports.zstd-1.7.0-py313h8c7ad59_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/blosc-1.21.6-h7dd00d9_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/brotli-1.2.0-h7d5ae5b_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/brotli-bin-1.2.0-hc919400_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/brotli-python-1.2.0-py313hde1f3bb_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-hd037594_9.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.34.6-hc919400_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.34.8-h74c22ad_2.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/cftime-1.6.5-py313hf5115c3_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/contourpy-1.3.3-py313h2af2deb_4.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/curl-8.21.0-hd5a2499_0.conda
@@ -1159,13 +1951,13 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/hdf5-1.14.6-nompi_had3affe_110.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-75.1-hfee45f7_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/json-c-0.18-he4178ee_0.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-arm64/kiwisolver-1.5.0-py313h2af2deb_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/kiwisolver-1.5.1-py313h738389e_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/krb5-1.22.2-hfd3d5f3_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/lcms2-2.19.1-hdfa7624_1.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-arm64/lerc-4.1.0-h1eee2c3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/lerc-4.2.0-h1eee2c3_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libabseil-20260107.1-cxx17_h2062a1b_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libaec-1.1.5-h8664d51_0.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libarchive-3.8.8-gpl_h6fbacd7_100.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libarchive-3.8.9-gpl_h6fbacd7_100.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libarrow-19.0.1-h96c63c9_45_cpu.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libarrow-acero-19.0.1-h0f28eaf_45_cpu.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libarrow-dataset-19.0.1-h0f28eaf_45_cpu.conda
@@ -1177,7 +1969,7 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcblas-3.11.0-8_hb0561ab_openblas.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcrc32c-1.1.2-hbdafb3b_0.tar.bz2
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcurl-8.21.0-hd5a2499_0.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-22.1.8-h55c6f16_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-23.1.1-h55c6f16_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libdeflate-1.25-hc11a715_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libedit-3.1.20250104-pl5321hafb1f1b_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libev-4.33-h93a5062_2.conda
@@ -1186,17 +1978,17 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.5.2-hcf2aa1b_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libfreetype-2.14.3-hce30654_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libfreetype6-2.14.3-hdfa99f5_1.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/libgcc-16.2.0-h3cf6597_4.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgdal-arrow-parquet-3.10.3-h2616c01_18.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgdal-core-3.10.3-h9f236a5_18.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgdal-hdf5-3.10.3-hdacffec_18.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/libgfortran-16.2.0-h07b0088_4.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran5-16.2.0-hdb7a957_4.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/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/libjpeg-turbo-3.2.0-h84a0fba_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-8_hd9741b5_openblas.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblzma-5.8.3-h8088a28_0.conda
@@ -1212,10 +2004,10 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libre2-11-2025.11.05-h4c27e2a_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/librttopo-1.1.0-hf7cb3ef_19.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libspatialite-5.1.0-h823fe50_16.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.53.2-h1b79a29_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.53.4-h34a968b_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libssh2-1.11.1-h1590b86_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libthrift-0.22.0-h1fb9c8a_2.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libtiff-4.7.1-h4030677_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libtiff-4.7.2-hf67920b_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libutf8proc-2.11.3-h2431656_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libwebp-base-1.6.0-h07db88b_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libxcb-1.17.0-hdb1d25a_0.conda
@@ -1224,32 +2016,32 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libxml2-devel-2.15.1-h9329255_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzip-1.11.2-h1336266_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.2-h8088a28_2.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-openmp-22.1.8-hc7d1edf_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-openmp-23.1.0-hdb3d66b_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/lz4-4.4.5-py313hd065f0a_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/lz4-c-1.10.0-h286801f_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/lzo-2.10-h925e9cb_1002.conda
- 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-3.10.3-py313h39782a4_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/matplotlib-base-3.10.3-py313haaf02c0_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/msgpack-python-1.2.1-py313h5c29297_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/minizip-4.2.2-h56c1371_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/msgpack-python-1.2.2-py313hcb059c8_2.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/netcdf4-1.7.2-nompi_py313hb28a5cb_104.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
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/openjpeg-2.5.4-hd9e9057_0.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.6.3-hd24854e_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.6.4-h55eecbc_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/orc-2.2.2-h578b684_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pandas-2.3.0-py313h668b085_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pcre2-10.46-h7125dd6_0.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pillow-12.2.0-py313h45e5a15_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pillow-12.3.0-py313h4ede67f_2.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/proj-9.6.2-hdbeaa80_2.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/prometheus-cpp-1.3.0-h0967b3e_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/psutil-7.2.2-py313h6688731_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pthread-stubs-0.4-hd74edd7_1002.conda
- 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/pydantic-core-2.46.5-py313h680bcb3_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.1-py313h84bd6f1_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.13.14-h448ec07_100_cp313.conda
@@ -1262,9 +2054,9 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/scipy-1.18.0-py313h52f5312_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/shapely-2.1.2-py313hfb5a6ed_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/snappy-1.2.2-hada39a4_1.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-arm64/sqlite-3.53.2-h85ec8f2_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/sqlite-3.53.4-hdb6324b_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h010d191_3.conda
- - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tornado-6.5.7-py313h0997733_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tornado-6.5.8-py313hf5449f0_1.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/uriparser-0.9.8-h00cdb27_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/xerces-c-3.2.5-h92fc2f4_2.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/xorg-libxau-1.0.12-hc919400_1.conda
@@ -1274,15 +2066,15 @@ 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-types-0.7.0-pyhd8ed1ab_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/affine-3.0.1-pyhecae5ae_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/annotated-types-0.8.0-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/bokeh-3.9.1-pyhd8ed1ab_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/boltons-26.0.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/bokeh-3.10.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/boltons-26.2.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/branca-0.8.2-pyhd8ed1ab_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.6.17-h4c7d964_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.6.17-pyhd8ed1ab_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/ca-certificates-2026.7.22-h4c7d964_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.7.22-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.5.1-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/click-8.2.1-pyh7428d3b_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
@@ -1292,6 +2084,7 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/noarch/dask-2025.7.0-pyhe01879c_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/dask-core-2025.7.0-pyhe01879c_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/distributed-2025.7.0-pyhe01879c_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/face-26.0.0-pyhcf101f3_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/folium-0.20.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2
@@ -1300,55 +2093,60 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-ecosystem-1-0.tar.bz2
- conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-hc364b38_1.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/fsspec-2026.6.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/fsspec-2026.7.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/geopandas-1.1.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/geopandas-base-1.1.0-pyha770c72_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/glom-24.11.0-pyhd8ed1ab_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/h2-4.4.1-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.2.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.18-pyhcf101f3_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-9.0.0-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.19-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-9.0.1-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.6-pyhcf101f3_1.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/joblib-1.5.3-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/joblib-1.6.0-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/locket-1.0.0-pyhd8ed1ab_0.tar.bz2
- - conda: https://conda.anaconda.org/conda-forge/noarch/mapclassify-2.10.0-pyhd8ed1ab_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/mapclassify-2.11.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/mypy_extensions-1.1.0-pyha770c72_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/narwhals-2.22.1-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/narwhals-2.25.0-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/networkx-3.6.1-pyhcf101f3_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.3-pyhc364b38_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/pandera-0.24.0-hd8ed1ab_2.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/pandera-base-0.24.0-pyhd8ed1ab_2.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/pandera-geopandas-0.24.0-hd8ed1ab_2.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/partd-1.4.2-pyhd8ed1ab_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.13.4-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.13.5-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.21.0-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyh09c184e_7.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-9.1.1-pyhc364b38_2.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2026.2-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2026.3-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.13-8_cp313.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2026.2-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2026.3.post1-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.34.2-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/rioxarray-0.19.0-pyhd8ed1ab_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-84.0.0-pyh332efcf_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/sortedcontainers-2.4.0-pyhd8ed1ab_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/tblib-3.2.2-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/threadpoolctl-3.6.0-pyhecae5ae_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/toolz-1.1.0-pyhd8ed1ab_1.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/typeguard-4.5.2-pyhcf101f3_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.15.0-h396c80c_0.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/typing-inspection-0.4.2-pyhcf101f3_2.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/typeguard-4.6.0-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.16.0-h69aa097_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/typing-inspection-0.4.4-pyhcf101f3_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/typing_inspect-0.9.0-pyhd8ed1ab_1.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.7.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/utm-0.7.0-pyhd8ed1ab_0.tar.bz2
- conda: https://conda.anaconda.org/conda-forge/noarch/win_inet_pton-1.1.0-pyh7428d3b_8.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/xarray-2025.6.1-pyhd8ed1ab_1.conda
- - conda: https://conda.anaconda.org/conda-forge/noarch/xyzservices-2026.3.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/noarch/xyzservices-2026.9.1-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/zict-3.0.0-pyhd8ed1ab_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/zipp-4.1.0-pyhcf101f3_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/_openmp_mutex-4.5-20_gnu.conda
@@ -1365,13 +2163,13 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/win-64/aws-checksums-0.2.10-hcb3a2da_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/aws-crt-cpp-0.37.2-h5e571c5_3.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/aws-sdk-cpp-1.11.606-ha60a6cd_13.conda
- - conda: https://conda.anaconda.org/conda-forge/win-64/backports.zstd-1.6.0-py313h2a31948_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/backports.zstd-1.7.0-py313h2a31948_1.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/blosc-1.21.6-hfd34d9b_1.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/brotli-1.2.0-h2d644bc_1.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/brotli-bin-1.2.0-hfd05255_1.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/brotli-python-1.2.0-py313h3ebfc14_1.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-h0ad9c76_9.conda
- - conda: https://conda.anaconda.org/conda-forge/win-64/c-ares-1.34.6-hfd05255_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/c-ares-1.34.8-h6a83c73_2.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/cairo-1.18.4-h5782bbf_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/cftime-1.6.5-py313h0591002_1.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/contourpy-1.3.3-py313h1a38498_4.conda
@@ -1379,7 +2177,7 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/win-64/cytoolz-1.1.0-py313h5ea7bf4_2.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/double-conversion-3.3.1-he0c23c2_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/fiona-1.10.1-py313hfe59770_4.conda
- - conda: https://conda.anaconda.org/conda-forge/win-64/fontconfig-2.18.1-hd47e2ca_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/fontconfig-2.18.3-hd47e2ca_1.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/fonttools-4.63.0-py313hd650c13_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/freetype-2.14.3-h57928b3_1.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/freexl-2.0.0-hf297d47_2.conda
@@ -1391,13 +2189,13 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/win-64/hdf4-4.2.15-h5557f11_7.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/hdf5-1.14.6-nompi_hae35d4c_106.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/icu-75.1-he0c23c2_0.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/kiwisolver-1.5.1-py313h1a38498_1.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/krb5-1.21.3-hdf4eb48_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/lcms2-2.19.1-hf2c6c5f_1.conda
- - conda: https://conda.anaconda.org/conda-forge/win-64/lerc-4.1.0-hd936e49_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/lerc-4.2.0-hd936e49_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/libabseil-20260107.1-cxx17_h0eb2380_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/libaec-1.1.5-haf901d7_0.conda
- - conda: https://conda.anaconda.org/conda-forge/win-64/libarchive-3.8.8-gpl_he24518a_100.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libarchive-3.8.9-gpl_he24518a_100.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/libarrow-19.0.1-hd086c85_45_cpu.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/libarrow-acero-19.0.1-h7d8d6a5_45_cpu.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/libarrow-dataset-19.0.1-h7d8d6a5_45_cpu.conda
@@ -1416,19 +2214,19 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/win-64/libffi-3.5.2-h3d046cb_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/libfreetype-2.14.3-h57928b3_1.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/libfreetype6-2.14.3-hdbac1cb_1.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/libgcc-16.2.0-h110b43a_4.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/libgdal-arrow-parquet-3.10.3-h4b7837c_18.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/libgdal-core-3.10.3-h1dbae3e_18.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/libgdal-hdf5-3.10.3-h0f01001_18.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/libglib-2.86.2-hd9c3897_0.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/libgomp-16.2.0-h8ee18e1_4.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.13.0-default_h049141e_1000.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/libintl-0.22.5-h5728263_3.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/libjpeg-turbo-3.2.0-hfd05255_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-8_hf9ab0e9_mkl.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/liblzma-5.8.3-hfd05255_0.conda
@@ -1440,12 +2238,12 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/win-64/libre2-11-2025.11.05-h04e5de1_1.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/librttopo-1.1.0-h5ff11c1_19.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/libspatialite-5.1.0-h9d118f5_16.conda
- - conda: https://conda.anaconda.org/conda-forge/win-64/libsqlite-3.53.2-hf5d6505_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libsqlite-3.53.4-hf5d6505_1.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/libssh2-1.11.1-h9aa295b_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/libthrift-0.22.0-h2e43b2f_2.conda
- - conda: https://conda.anaconda.org/conda-forge/win-64/libtiff-4.7.1-h8f73337_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libtiff-4.7.2-h8f73337_1.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/libutf8proc-2.11.3-hb980946_0.conda
- - conda: https://conda.anaconda.org/conda-forge/win-64/libvulkan-loader-1.4.341.0-h477610d_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/libvulkan-loader-1.4.357.0-h477610d_2.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/libwebp-base-1.6.0-h4d5522a_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/libwinpthread-12.0.0.r4.gg4f2fc60ca-h57928b3_10.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/libxcb-1.17.0-h0e4246c_0.conda
@@ -1455,32 +2253,31 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/win-64/libxslt-1.1.43-h0fbe4c1_1.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/libzip-1.11.2-h3135430_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/libzlib-1.3.2-hfd05255_2.conda
- - conda: https://conda.anaconda.org/conda-forge/win-64/llvm-openmp-22.1.8-h4fa8253_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/llvm-openmp-23.1.0-h49e36cd_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/lz4-4.4.5-py313h4bbca4b_1.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/lz4-c-1.10.0-h2466b09_1.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/lzo-2.10-h6a83c73_1002.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/markupsafe-3.0.3-py313hd650c13_1.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/matplotlib-3.10.3-py313hfa70ccb_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/matplotlib-base-3.10.3-py313h81b4f16_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-2026.0.0-hac47afa_908.conda
- - conda: https://conda.anaconda.org/conda-forge/win-64/msgpack-python-1.2.1-py313hf069bd2_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/minizip-4.2.2-h8fa244a_1.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/mkl-2026.1.0-hac47afa_235.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/msgpack-python-1.2.2-py313h1a38498_2.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/netcdf4-1.7.2-nompi_py313hbe59507_104.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-2026.0.0-h57928b3_908.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/openjpeg-2.5.4-h0e57b4f_0.conda
- - conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.6.3-hf411b9b_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.6.4-hf411b9b_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/orc-2.2.2-h0a1ad0e_1.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/pandas-2.3.0-py313hf91d08e_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/pcre2-10.46-h3402e2f_0.conda
- - conda: https://conda.anaconda.org/conda-forge/win-64/pillow-12.2.0-py313h38f99e1_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/pillow-12.3.0-py313h38f99e1_2.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/pixman-0.46.4-h5112557_1.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/proj-9.6.2-h7990399_2.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/psutil-7.2.2-py313h5fd188c_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/pthread-stubs-0.4-h0e40799_1002.conda
- 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/pydantic-core-2.46.5-py313hfbe8231_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.1-py313hc3e4018_1.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/pyside6-6.10.1-py313h475ba69_0.conda
@@ -1494,16 +2291,16 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/win-64/scipy-1.18.0-py313he51e9a2_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/shapely-2.1.2-py313hae85795_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/snappy-1.2.2-h7fa0ca8_1.conda
- - conda: https://conda.anaconda.org/conda-forge/win-64/sqlite-3.53.2-hdb435a2_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/sqlite-3.53.4-hdb435a2_1.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/tbb-2023.0.0-hd3d4ead_2.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/tk-8.6.13-h6ed50ae_3.conda
- - conda: https://conda.anaconda.org/conda-forge/win-64/tornado-6.5.7-py313h5ea7bf4_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/tornado-6.5.8-py313h5ea7bf4_1.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/ucrt-10.0.26100.0-h57928b3_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/uriparser-0.9.8-h5a68840_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/vc-14.5-h1b7c187_39.conda
- - conda: https://conda.anaconda.org/conda-forge/win-64/vc14_runtime-14.51.36231-h1b9f54f_39.conda
- - conda: https://conda.anaconda.org/conda-forge/win-64/vcomp14-14.51.36231-h1b9f54f_39.conda
- - conda: https://conda.anaconda.org/conda-forge/win-64/vs2015_runtime-14.51.36231-h84cd919_39.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/vc14_runtime-14.51.36247-habf1de7_41.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/vcomp14-14.51.36247-habf1de7_41.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/vs2015_runtime-14.51.36247-h633cb9f_41.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/xerces-c-3.2.5-he0c23c2_2.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/xorg-libxau-1.0.12-hba3369d_1.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/xorg-libxdmcp-1.1.5-hba3369d_1.conda
@@ -2041,19 +2838,19 @@ packages:
- azure-storage-files-datalake-cpp >=12.14.0,<12.14.1.0a0
size: 302771
timestamp: 1778763856084
-- conda: https://conda.anaconda.org/conda-forge/linux-64/backports.zstd-1.6.0-py313h18e8e13_0.conda
- sha256: d7aca2b34335035ef80eaaebff4e5a0ae524b6f3792a82a144d38c4a81f42916
- md5: fbc7d3707f09cae6648e6eb1b6203a5c
+- conda: https://conda.anaconda.org/conda-forge/linux-64/backports.zstd-1.7.0-py313h8f72f4d_1.conda
+ sha256: b8e6cbfade3ff6b344f9acc5c69193bd1aa7a2dc792e60eb8e05470fae122a1b
+ md5: 7ce840e6cf17fdba00e3d662f1d89e36
depends:
- python
- __glibc >=2.17,<3.0.a0
- - libgcc >=14
- - python_abi 3.13.* *_cp313
+ - libgcc >=15
- zstd >=1.5.7,<1.6.0a0
+ - python_abi 3.13.* *_cp313
license: BSD-3-Clause AND MIT AND EPL-2.0
run_exports: {}
- size: 242845
- timestamp: 1781450812380
+ size: 243747
+ timestamp: 1788491297080
- conda: https://conda.anaconda.org/conda-forge/linux-64/blosc-1.21.6-he440d0b_1.conda
sha256: e7af5d1183b06a206192ff440e08db1c4e8b2ca1f8376ee45fb2f3a85d4ee45d
md5: 2c2fae981fd2afd00812c92ac47d023d
@@ -2171,19 +2968,19 @@ packages:
purls: []
size: 206884
timestamp: 1744127994291
-- conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.6-hb03c661_0.conda
- sha256: cc9accf72fa028d31c2a038460787751127317dcfa991f8d1f1babf216bb454e
- md5: 920bb03579f15389b9e512095ad995b7
+- conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.8-hebe6cf0_2.conda
+ sha256: 9c37cc233238adf366ea75b0e845662a5be07ceadf62e458183516369340274b
+ md5: 3ad2b403be8fc5612b9159e2ce621f69
depends:
+ - libgcc >=15
- __glibc >=2.17,<3.0.a0
- - libgcc >=14
license: MIT
license_family: MIT
run_exports:
weak:
- - c-ares >=1.34.6,<2.0a0
- size: 207882
- timestamp: 1765214722852
+ - c-ares >=1.34.8,<2.0a0
+ size: 228700
+ timestamp: 1787169971173
- conda: https://conda.anaconda.org/conda-forge/linux-64/cairo-1.18.4-h3394656_0.conda
sha256: 3bd6a391ad60e471de76c0e9db34986c4b5058587fbf2efa5a7f54645e28c2c7
md5: 09262e66b19567aff4f592fb53b28760
@@ -2593,25 +3390,25 @@ packages:
purls: []
size: 265599
timestamp: 1730283881107
-- conda: https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.18.1-h27c8c51_0.conda
- sha256: 2e50bdcebdf70a865b81f2456bbc586386451ec601c60f2b6cd22b8c40a2d384
- md5: e0e050cfa9fa85fe39632ab11cb7f3e0
+- conda: https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.18.3-h4db4eae_1.conda
+ sha256: 5a3eb10b18a97223ab06b3a7f0d7f56658db2f2800e2f2af95836fe3bf55ba63
+ md5: 922776b528a470ab5afa81fd42abfa1d
depends:
- __glibc >=2.17,<3.0.a0
- libexpat >=2.8.1,<3.0a0
- libfreetype >=2.14.3
- libfreetype6 >=2.14.3
- - libgcc >=14
- - libuuid >=2.42.1,<3.0a0
+ - libgcc >=15
+ - libuuid >=2.42.2,<3.0a0
- libzlib >=1.3.2,<2.0a0
license: MIT
license_family: MIT
run_exports:
weak:
- - fontconfig >=2.18.1,<3.0a0
+ - fontconfig >=2.18.3,<3.0a0
- fonts-conda-ecosystem
- size: 281880
- timestamp: 1780450077431
+ size: 296288
+ timestamp: 1786667377340
- conda: https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.63.0-py313h3dea7bd_0.conda
sha256: e0029a390d7aef29bd6e7c12a3759f5e0b989930b5781e544ca9bac0abcd8442
md5: ae83c999b4cfc4c171ce88b99c8b43cc
@@ -3080,20 +3877,20 @@ packages:
- keyutils >=1.6.3,<2.0a0
size: 134088
timestamp: 1754905959823
-- conda: https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.5.0-py313hc8edb43_0.conda
- sha256: 0447d2901639f295989c5ccba7b1c367ed78b216e0d2705327a8c8a87a31177e
- md5: b81883b9dbf5069821c2fb09a8ba1407
+- conda: https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.5.1-py313h2551ef2_1.conda
+ sha256: 773f5eb66391d92a39c6cf6651111594c4a3f9941540934af3b813529c083ce1
+ md5: 6e7bc60a75f1668be8cb9b27191abe54
depends:
- python
- - libstdcxx >=14
- - libgcc >=14
+ - libstdcxx >=15
+ - libgcc >=15
- __glibc >=2.17,<3.0.a0
- python_abi 3.13.* *_cp313
license: BSD-3-Clause
license_family: BSD
run_exports: {}
- size: 76911
- timestamp: 1773067054809
+ size: 75129
+ timestamp: 1788505657484
- conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.21.3-h659f571_0.conda
sha256: 99df692f7a8a5c27cd14b5fb1374ee55e756631b9c3d659ed3ee60830249b238
md5: 3f43953b7d3fb3aaa1d0d0723d91e368
@@ -3139,19 +3936,19 @@ packages:
purls: []
size: 676044
timestamp: 1752032747103
-- conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda
- sha256: 3d584956604909ff5df353767f3a2a2f60e07d070b328d109f30ac40cd62df6c
- md5: 18335a698559cdbcd86150a48bf54ba6
+- conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.46.1-default_hbd61a6d_102.conda
+ sha256: 27d83f1188cd19bcb7754a078b3fa7f4cfb8527f8eb2fde54dd01fc529d1adec
+ md5: 449500f2c089da11c40f5c21312e3e07
depends:
- __glibc >=2.17,<3.0.a0
- zstd >=1.5.7,<1.6.0a0
constrains:
- - binutils_impl_linux-64 2.45.1
+ - binutils_impl_linux-64 2.46.1
license: GPL-3.0-only
license_family: GPL
run_exports: {}
- size: 728002
- timestamp: 1774197446916
+ size: 745303
+ timestamp: 1784214507189
- conda: https://conda.anaconda.org/conda-forge/linux-64/lerc-4.0.0-h0aef613_1.conda
sha256: 412381a43d5ff9bbed82cd52a0bbca5b90623f62e41007c9c42d3870c60945ff
md5: 9344155d33912347b37f0ae6c410a835
@@ -3164,9 +3961,9 @@ packages:
purls: []
size: 264243
timestamp: 1745264221534
-- conda: https://conda.anaconda.org/conda-forge/linux-64/lerc-4.1.0-hdb68285_0.conda
- sha256: f84cb54782f7e9cea95e810ea8fef186e0652d0fa73d3009914fa2c1262594e1
- md5: a752488c68f2e7c456bcbd8f16eec275
+- conda: https://conda.anaconda.org/conda-forge/linux-64/lerc-4.2.0-hdb68285_0.conda
+ sha256: bf9fdebf55d8bc99d83531cdffda00703f4dc5f93a1a956768c147362c72feda
+ md5: fb9d356b1a57d6d54768be7ebd5fce09
depends:
- __glibc >=2.17,<3.0.a0
- libgcc >=14
@@ -3175,9 +3972,9 @@ packages:
license_family: Apache
run_exports:
weak:
- - lerc >=4.1.0,<5.0a0
- size: 261513
- timestamp: 1773113328888
+ - lerc >=4.2.0,<5.0a0
+ size: 271158
+ timestamp: 1785036167977
- conda: https://conda.anaconda.org/conda-forge/linux-64/libabseil-20260107.1-cxx17_h7b12aa8_0.conda
sha256: a7a4481a4d217a3eadea0ec489826a69070fcc3153f00443aa491ed21527d239
md5: 6f7b4302263347698fd24565fbf11310
@@ -3229,9 +4026,9 @@ packages:
purls: []
size: 883383
timestamp: 1749385818314
-- conda: https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.8.8-gpl_hc2c16d8_100.conda
- sha256: f916b51f55f51a9bb2d902e0a5f029490f7b745aee549c349751c1787ddc26b8
- md5: 44652e646cb623f486ea72e7e7479222
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.8.9-gpl_hc2c16d8_100.conda
+ sha256: 000b4baa9ce849b5fb259af9256331d0c7872361ac63a2bba0d0c48eb35663d0
+ md5: 3988040b14a8083b1a5382d99f584e5f
depends:
- __glibc >=2.17,<3.0.a0
- bzip2 >=1.0.8,<2.0a0
@@ -3248,9 +4045,9 @@ packages:
license_family: BSD
run_exports:
weak:
- - libarchive >=3.8.8,<3.9.0a0
- size: 867280
- timestamp: 1782289011634
+ - libarchive >=3.8.9,<3.9.0a0
+ size: 876197
+ timestamp: 1785250447640
- conda: https://conda.anaconda.org/conda-forge/linux-64/libarrow-19.0.1-h3c191e6_45_cpu.conda
build_number: 45
sha256: 26a010858a803bca78d1033c4fd081ea19794b07e0a9dcd8bd41487b09a9a381
@@ -3593,20 +4390,20 @@ packages:
- libdeflate >=1.25,<1.26.0a0
size: 73490
timestamp: 1761979956660
-- conda: https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.127-hb03c661_0.conda
- sha256: 7d3187c11b7ae66c5595a8afd5a7ce352a490527fdf6614cab129bc7f2c16ba3
- md5: d8d16b9b32a3c5df7e5b3350e2cbe058
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.129-h7cc23a3_0.conda
+ sha256: ea46b0ca0fa16af1f8b329b740e6cd8b4577c5378fa8717b28a885f70668633d
+ md5: 64cc91512b6278c315349dc13c53f680
depends:
- __glibc >=2.17,<3.0.a0
- - libgcc >=14
+ - libgcc >=15
- libpciaccess >=0.19,<0.20.0a0
license: MIT
license_family: MIT
run_exports:
weak:
- - libdrm >=2.4.127,<2.5.0a0
- size: 311505
- timestamp: 1778975798004
+ - libdrm >=2.4.129,<2.5.0a0
+ size: 313461
+ timestamp: 1786684701973
- conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda
sha256: d789471216e7aba3c184cd054ed61ce3f6dac6f87a50ec69291b9297f8c18724
md5: c277e0a4d549b03ac1e9d6cbbe3d017b
@@ -3769,20 +4566,20 @@ packages:
purls: []
size: 824921
timestamp: 1750808216066
-- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_19.conda
- sha256: 8e0a3b5e41272e5678499b5dfc4cddb673f9e935de01eb0767ce857001229f46
- md5: 57736f29cc2b0ec0b6c2952d3f101b6a
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-16.2.0-ha9f2e26_4.conda
+ sha256: 24090e675d34403b4ee1cd4372d8f6c0937da7ecfd66a19a57cac2ed0f4ea793
+ md5: cba14d01083fc62ffd32c24d7d390633
depends:
- __glibc >=2.17,<3.0.a0
- _openmp_mutex >=4.5
constrains:
- - libgcc-ng ==15.2.0=*_19
- - libgomp 15.2.0 he0feb66_19
+ - libgcc-ng ==16.2.0=*_4
+ - libgomp 16.2.0 he0feb66_4
license: GPL-3.0-only WITH GCC-exception-3.1
license_family: GPL
run_exports: {}
- size: 1041084
- timestamp: 1778269013026
+ size: 1058083
+ timestamp: 1787618680111
- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.1.0-h69a702a_3.conda
sha256: b0b0a5ee6ce645a09578fc1cb70c180723346f8a45fdb6d23b3520591c6d6996
md5: e66f2b8ad787e7beb0f846e4bd7e8493
@@ -3793,18 +4590,18 @@ packages:
purls: []
size: 29033
timestamp: 1750808224854
-- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_19.conda
- sha256: 9dcf54adfaa5e861123c2da4f2f0451a685464ea7e5a41ad91cf67b31d658d98
- md5: 331ee9b72b9dff570d56b1302c5ab37d
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-16.2.0-h69a702a_4.conda
+ sha256: d8e66c14e23f2b3c70410cff5979d9d357e6edfb990b28d8e630852f4d395629
+ md5: b3e52878163a841f6fb951989cc0b217
depends:
- - libgcc 15.2.0 he0feb66_19
+ - libgcc 16.2.0 ha9f2e26_4
license: GPL-3.0-only WITH GCC-exception-3.1
license_family: GPL
run_exports:
strong:
- libgcc
- size: 27694
- timestamp: 1778269016987
+ size: 28403
+ timestamp: 1787618684957
- conda: https://conda.anaconda.org/conda-forge/linux-64/libgd-2.3.3-h6f5c62b_11.conda
sha256: 19e5be91445db119152217e8e8eec4fd0499d854acc7d8062044fb55a70971cd
md5: 68fc66282364981589ef36868b1a7c78
@@ -3912,18 +4709,18 @@ packages:
purls: []
size: 29057
timestamp: 1750808257258
-- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_19.conda
- sha256: 561a42758ef25b9ce308c4e2cf56daee4f06138385a17e29a492cd928e00be6f
- md5: 42bf7eca1a951735fa06c0e3c0d5c8e6
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-16.2.0-h69a702a_4.conda
+ sha256: 7653be4d88a4d74676c38dd892914d027dcecc0c65c406be772d31cb641f8cfd
+ md5: 5e92b8413fd1c8f8f3006f4661b12def
depends:
- - libgfortran5 15.2.0 h68bc16d_19
+ - libgfortran5 16.2.0 h6b99dfc_4
constrains:
- - libgfortran-ng ==15.2.0=*_19
+ - libgfortran-ng ==16.2.0=*_4
license: GPL-3.0-only WITH GCC-exception-3.1
license_family: GPL
run_exports: {}
- size: 27655
- timestamp: 1778269042954
+ size: 28377
+ timestamp: 1787618711732
- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.1.0-hcea5267_3.conda
sha256: eea6c3cf22ad739c279b4d665e6cf20f8081f483b26a96ddd67d4df3c88dfa0a
md5: 530566b68c3b8ce7eec4cd047eae19fe
@@ -3937,19 +4734,19 @@ packages:
purls: []
size: 1565627
timestamp: 1750808236464
-- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_19.conda
- sha256: 057978bb69fea29ed715a9b98adf71015c31baecc4aeb2bfc20d4fd5d83579d4
- md5: 85072b0ad177c966294f129b7c04a2d5
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-16.2.0-h6b99dfc_4.conda
+ sha256: a5510cbcea3b9e9ab24b336429de997fa727af1dba323031500a962a20e38600
+ md5: c22348a769bb072b6184eb6f7f05e4f2
depends:
- __glibc >=2.17,<3.0.a0
- - libgcc >=15.2.0
+ - libgcc >=16.2.0
constrains:
- - libgfortran 15.2.0
+ - libgfortran 16.2.0
license: GPL-3.0-only WITH GCC-exception-3.1
license_family: GPL
run_exports: {}
- size: 2483673
- timestamp: 1778269025089
+ size: 2526008
+ timestamp: 1787618692926
- conda: https://conda.anaconda.org/conda-forge/linux-64/libgl-1.7.0-ha4b6fd6_3.conda
sha256: ec353b3076ed8e357ed961d0e9ff6997491cade0e603de5bd18a2e301ac78ebd
md5: f25206d7322c0e9648e8b83694d143ab
@@ -4025,9 +4822,9 @@ packages:
purls: []
size: 447068
timestamp: 1750808138400
-- conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_19.conda
- sha256: 5abe4ab9d93f6c9757d654f1969ae2267d4505315c1f2f8fe705fd60af084f1b
- md5: faac990cb7aedc7f3a2224f2c9b0c26c
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-16.2.0-he0feb66_4.conda
+ sha256: 0fe5cb8e0752241ab55e11656ed1b9726248b522d23b929fe7c95b83eb55b9bb
+ md5: 89d2c1231f47bd818f5d624b9411459d
depends:
- __glibc >=2.17,<3.0.a0
license: GPL-3.0-only WITH GCC-exception-3.1
@@ -4035,8 +4832,8 @@ packages:
run_exports:
strong:
- _openmp_mutex >=4.5
- size: 603817
- timestamp: 1778268942614
+ size: 639968
+ timestamp: 1787618616266
- conda: https://conda.anaconda.org/conda-forge/linux-64/libgoogle-cloud-2.39.0-h9d11ab5_1.conda
sha256: 44f8e354431d2336475465ec8d71df7f3dea1397e70df0718c2ac75137976c63
md5: cd398eb8374fb626a710b7a35b7ffa98
@@ -4137,9 +4934,9 @@ packages:
purls: []
size: 628947
timestamp: 1745268527144
-- conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.1.4.1-hb03c661_0.conda
- sha256: 10056646c28115b174de81a44e23e3a0a3b95b5347d2e6c45cc6d49d35294256
- md5: 6178c6f2fb254558238ef4e6c56fb782
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.2.0-hb03c661_1.conda
+ sha256: bba8538e6538ed58a8479b332337b96986561f975d06cfa2039a016c2d246ee4
+ md5: 898d1c9793eaa52efc4727bd84d2e39a
depends:
- __glibc >=2.17,<3.0.a0
- libgcc >=14
@@ -4148,9 +4945,9 @@ packages:
license: IJG AND BSD-3-Clause AND Zlib
run_exports:
weak:
- - libjpeg-turbo >=3.1.4.1,<4.0a0
- size: 633831
- timestamp: 1775962768273
+ - libjpeg-turbo >=3.2.0,<4.0a0
+ size: 650434
+ timestamp: 1785896381946
- conda: https://conda.anaconda.org/conda-forge/linux-64/libkml-1.3.0-haa4a5bd_1023.conda
sha256: f6348ac9cebbc03f765ea6d2da88d57d19531585c8f3a963b98635b208e8bef1
md5: 953b7cca897e21215302dbfe2af5cd0c
@@ -4694,19 +5491,19 @@ packages:
purls: []
size: 935828
timestamp: 1752072043000
-- conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.2-h0c1763c_0.conda
- sha256: 1ab603b6ec93933e76027e1f23b21b22b858ba1b56f1e1695ef6fe5e80cb7358
- md5: 062b0ac602fb0adf250e3dfa86f221c4
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.4-h0737f62_1.conda
+ sha256: 35c05bd0adfaf6fcac01fc3a42214e4e2a44e32f7ce2c77ddae419522c3c328d
+ md5: 17b328272d5caa0994678529be5b86ab
depends:
- __glibc >=2.17,<3.0.a0
- - libgcc >=14
+ - libgcc >=15
- libzlib >=1.3.2,<2.0a0
license: blessing
run_exports:
weak:
- - libsqlite >=3.53.2,<4.0a0
- size: 957849
- timestamp: 1780574429573
+ - libsqlite >=3.53.4,<4.0a0
+ size: 968893
+ timestamp: 1787051134858
- conda: https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.1-hcf80075_0.conda
sha256: fa39bfd69228a13e553bd24601332b7cfeb30ca11a3ca50bb028108fe90a7661
md5: eecce068c7e4eddeb169591baac20ac4
@@ -4734,19 +5531,19 @@ packages:
purls: []
size: 3896407
timestamp: 1750808251302
-- conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_19.conda
- sha256: dff1058c76ec6b8759e41cefa2508162d00e4a5e6721aa68ec3fd10094e702dc
- md5: 5794b3bdc38177caf969dabd3af08549
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-16.2.0-h934c35e_4.conda
+ sha256: 40b792b0186c1e8859280a1f6f19a54fc50a11b32724fc7b637009c1a9bd302b
+ md5: 2f2ef0d96de5bdd8c1270ff22fdf9352
depends:
- __glibc >=2.17,<3.0.a0
- - libgcc 15.2.0 he0feb66_19
+ - libgcc 16.2.0 ha9f2e26_4
constrains:
- - libstdcxx-ng ==15.2.0=*_19
+ - libstdcxx-ng ==16.2.0=*_4
license: GPL-3.0-only WITH GCC-exception-3.1
license_family: GPL
run_exports: {}
- size: 5852044
- timestamp: 1778269036376
+ size: 6613148
+ timestamp: 1787618704262
- conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-15.1.0-h4852527_3.conda
sha256: bbaea1ecf973a7836f92b8ebecc94d3c758414f4de39d2cc6818a3d10cb3216b
md5: 57541755b5a51691955012b8e197c06c
@@ -4757,18 +5554,18 @@ packages:
purls: []
size: 29093
timestamp: 1750808292700
-- conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-15.2.0-hdf11a46_19.conda
- sha256: 0672b6b6e1791c92e8eccad58081a99d614fcf82bca5841f9dfa3c3e658f83b9
- md5: e5ce228e579726c07255dbf90dc62101
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-16.2.0-hdf11a46_4.conda
+ sha256: 4cdebd87b76cf53a58a08ebd6d15336daa79c5f0aa34d83a895ac503c0203632
+ md5: de0dceacf3e33c5fc88e167885dc8274
depends:
- - libstdcxx 15.2.0 h934c35e_19
+ - libstdcxx 16.2.0 h934c35e_4
license: GPL-3.0-only WITH GCC-exception-3.1
license_family: GPL
run_exports:
strong:
- libstdcxx
- size: 27776
- timestamp: 1778269074600
+ size: 28459
+ timestamp: 1787618737021
- conda: https://conda.anaconda.org/conda-forge/linux-64/libthrift-0.22.0-h7d032f7_2.conda
sha256: af6025aa4a4fc3f4e71334000d2739d927e2f678607b109ec630cc17d716918a
md5: b6e326fbe1e3948da50ec29cee0380db
@@ -4804,26 +5601,26 @@ packages:
purls: []
size: 429575
timestamp: 1747067001268
-- conda: https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.1-h9d88235_1.conda
- sha256: e5f8c38625aa6d567809733ae04bb71c161a42e44a9fa8227abe61fa5c60ebe0
- md5: cd5a90476766d53e901500df9215e927
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.2-hcc2c06a_1.conda
+ sha256: 10e125da82ca93e09191e66e5a94d566b2cf8d4024e2a0db3a9114297447e0d9
+ md5: 0907d876f460ebc941ae590338b6102f
depends:
- __glibc >=2.17,<3.0.a0
- - lerc >=4.0.0,<5.0a0
+ - lerc >=4.2.0,<5.0a0
- libdeflate >=1.25,<1.26.0a0
- - libgcc >=14
- - libjpeg-turbo >=3.1.0,<4.0a0
- - liblzma >=5.8.1,<6.0a0
- - libstdcxx >=14
+ - libgcc >=15
+ - libjpeg-turbo >=3.2.0,<4.0a0
+ - liblzma >=5.8.3,<6.0a0
+ - libstdcxx >=15
- libwebp-base >=1.6.0,<2.0a0
- - libzlib >=1.3.1,<2.0a0
+ - libzlib >=1.3.2,<2.0a0
- zstd >=1.5.7,<1.6.0a0
license: HPND
run_exports:
weak:
- - libtiff >=4.7.1,<4.8.0a0
- size: 435273
- timestamp: 1762022005702
+ - libtiff >=4.7.2,<4.8.0a0
+ size: 459753
+ timestamp: 1787755584172
- conda: https://conda.anaconda.org/conda-forge/linux-64/libutf8proc-2.11.3-hfe17d71_0.conda
sha256: ecbf4b7520296ed580498dc66a72508b8a79da5126e1d6dc650a7087171288f9
md5: 1247168fe4a0b8912e3336bccdbf98a5
@@ -4847,37 +5644,37 @@ packages:
purls: []
size: 33601
timestamp: 1680112270483
-- conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.2-h5347b49_0.conda
- sha256: 9b1bdce27a7e31f7d241aeecff67a1f3101d52a2b1e33ccc2cdf2613072bf81f
- md5: 01bb81d12c957de066ea7362007df642
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.3-hcfc3c73_0.conda
+ sha256: aa58bbba56644ffd062a4a9b358782c5eb7560ccead2ab8f7c5c6ede0a7d33a6
+ md5: 74a0a409d9f4561265d36b789d3f398a
depends:
- - libgcc >=14
- __glibc >=2.17,<3.0.a0
+ - libgcc >=15
license: BSD-3-Clause
license_family: BSD
run_exports:
weak:
- - libuuid >=2.42.2,<3.0a0
- size: 40017
- timestamp: 1781625522462
-- conda: https://conda.anaconda.org/conda-forge/linux-64/libvulkan-loader-1.4.341.0-h5279c79_0.conda
- sha256: a68280d57dfd29e3d53400409a39d67c4b9515097eba733aa6fe00c880620e2b
- md5: 31ad065eda3c2d88f8215b1289df9c89
+ - libuuid >=2.42.3,<3.0a0
+ size: 39998
+ timestamp: 1788347719520
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libvulkan-loader-1.4.357.0-h0e34353_2.conda
+ sha256: a70c25b66321ee77f9892b205e3247263c400803f543dc8aca53d569a59c5a77
+ md5: c5f5f159b66332152197893427071695
depends:
- __glibc >=2.17,<3.0.a0
- - libstdcxx >=14
- - libgcc >=14
- - xorg-libx11 >=1.8.12,<2.0a0
+ - libstdcxx >=15
+ - libgcc >=15
- xorg-libxrandr >=1.5.5,<2.0a0
+ - xorg-libx11 >=1.8.13,<2.0a0
constrains:
- - libvulkan-headers 1.4.341.0.*
+ - libvulkan-headers 1.4.357.0.*
license: Apache-2.0
license_family: APACHE
run_exports:
weak:
- - libvulkan-loader >=1.4.341.0,<2.0a0
- size: 199795
- timestamp: 1770077125520
+ - libvulkan-loader >=1.4.357.0,<2.0a0
+ size: 206957
+ timestamp: 1787491938583
- conda: https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.6.0-hd42ef1d_0.conda
sha256: 3aed21ab28eddffdaf7f804f49be7a7d701e8f0e46c856d801270b470820a37b
md5: aea31d2e5b1091feca96fcfe945c3cf9
@@ -4922,6 +5719,18 @@ packages:
- libxcrypt >=4.4.36
size: 100393
timestamp: 1702724383534
+- conda: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.38-h280c20c_0.conda
+ sha256: f7e9292dd219a6435bbb1223da9586c3e70d66d169c5a92f08db3f2127df04e9
+ md5: f7a7ff5a6ab331e037abd34f379a631d
+ depends:
+ - libgcc >=14
+ - __glibc >=2.17,<3.0.a0
+ license: LGPL-2.1-or-later
+ run_exports:
+ weak:
+ - libxcrypt >=4.4.38
+ size: 101957
+ timestamp: 1785887123445
- conda: https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.10.0-h65c71a3_0.conda
sha256: a8043a46157511b3ceb6573a99952b5c0232313283f2d6a066cec7c8dcaed7d0
md5: fedf6bfe5d21d21d2b1785ec00a8889a
@@ -5224,40 +6033,40 @@ packages:
- pkg:pypi/menuinst?source=hash-mapping
size: 172740
timestamp: 1750792417618
-- conda: https://conda.anaconda.org/conda-forge/linux-64/minizip-4.2.1-hb71707f_0.conda
- sha256: 41558b95a387ce2374260aa034a99c3a88cbb98e1a56510f4fa6839063de867b
- md5: fe7b4ff5792fee512aad843294ea809a
+- conda: https://conda.anaconda.org/conda-forge/linux-64/minizip-4.2.2-hc2c9f91_1.conda
+ sha256: 83837ffc5db1abfc14de88f5c9f07d1a666f149cd95249777f0ed09073ae7c22
+ md5: ade84857af069283ff1e3b7aacae1232
depends:
- __glibc >=2.17,<3.0.a0
- bzip2 >=1.0.8,<2.0a0
- - libgcc >=14
+ - libgcc >=15
- libiconv >=1.18,<2.0a0
- liblzma >=5.8.3,<6.0a0
- - libstdcxx >=14
+ - libstdcxx >=15
- libzlib >=1.3.2,<2.0a0
- - openssl >=3.5.6,<4.0a0
+ - openssl >=3.5.8,<4.0a0
- zstd >=1.5.7,<1.6.0a0
license: Zlib
license_family: Other
run_exports:
weak:
- - minizip >=4.2.1,<5.0a0
- size: 520570
- timestamp: 1778002506337
-- conda: https://conda.anaconda.org/conda-forge/linux-64/msgpack-python-1.2.1-py313h7037e92_0.conda
- sha256: 87a569daa29cb526cff5e9e5cca3fc92c479a92f13c0bac6a4ad6b38ef068f5b
- md5: 4f7f0bbf165e65d6f620251860c098c2
+ - minizip >=4.2.2,<5.0a0
+ size: 526042
+ timestamp: 1788051267376
+- conda: https://conda.anaconda.org/conda-forge/linux-64/msgpack-python-1.2.2-py313h2551ef2_2.conda
+ sha256: 902cc244b567552538ca7817673f302c8000b75cb72a46c62f70ad4c05c32462
+ md5: 10eabac2cb17d77ce66a2d46890127bf
depends:
+ - python
- __glibc >=2.17,<3.0.a0
- - libgcc >=14
- - libstdcxx >=14
- - python >=3.13,<3.14.0a0
+ - libstdcxx >=15
+ - libgcc >=15
- python_abi 3.13.* *_cp313
license: Apache-2.0
- license_family: Apache
+ license_family: APACHE
run_exports: {}
- size: 102737
- timestamp: 1782070377224
+ size: 114896
+ timestamp: 1788525095321
- conda: https://conda.anaconda.org/conda-forge/linux-64/mypy-1.16.1-py312h66e93f0_0.conda
sha256: 2d1dca2a580374470e8a108565356e13aec8598c83eec17d888a4cc0b014cddd
md5: d52e9cc0c93e47a87e1024158ed2bcd3
@@ -5426,20 +6235,20 @@ packages:
purls: []
size: 3131002
timestamp: 1751390382076
-- conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.3-h35e630c_0.conda
- sha256: d48f5c22b9897c01e4dff3680f1f57ceb02711ab9c62f74339b080419dfad34b
- md5: 79dd2074b5cd5c5c6b2930514a11e22d
+- conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.4-h781a0a9_0.conda
+ sha256: 4747b2d6a8336f52343bceb8a1ebf41a9e6e665b9d2e3f989972de53a310599e
+ md5: 16e3034a330cc625f2c685edec60cf4e
depends:
- __glibc >=2.17,<3.0.a0
- ca-certificates
- - libgcc >=14
+ - libgcc >=15
license: Apache-2.0
license_family: Apache
run_exports:
weak:
- - openssl >=3.6.3,<4.0a0
- size: 3159683
- timestamp: 1781069855778
+ - openssl >=3.6.4,<4.0a0
+ size: 3202955
+ timestamp: 1787698780103
- conda: https://conda.anaconda.org/conda-forge/linux-64/orc-2.2.2-hbb90d81_1.conda
sha256: c59d22c4e555c09259c52da96f1576797fcb4fba5665073e9c1907393309172d
md5: 9269175175f18091b8844c8e9f213205
@@ -5612,28 +6421,28 @@ packages:
- pcre2 >=10.46,<10.47.0a0
size: 1209177
timestamp: 1756742976157
-- conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-12.2.0-py313h80991f8_0.conda
- sha256: 55a76548bb003ff6deac9bf209b279d428030f230632fb70f15ae153aed05158
- md5: 7245f1bbf52ed5e3818d742f51b44a7d
+- conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-12.3.0-py313h3b26573_2.conda
+ sha256: 400597a5bda2bf748536c2b69c812078901bd9bc2ee8187fd84ac29f3ad578b3
+ md5: 56e4487df0f02a73655d1a24c9a68906
depends:
- python
- - libgcc >=14
- __glibc >=2.17,<3.0.a0
- - libtiff >=4.7.1,<4.8.0a0
- - libjpeg-turbo >=3.1.2,<4.0a0
- - libxcb >=1.17.0,<2.0a0
- - libwebp-base >=1.6.0,<2.0a0
- - tk >=8.6.13,<8.7.0a0
- - libfreetype >=2.14.3
- - libfreetype6 >=2.14.3
+ - libgcc >=15
- python_abi 3.13.* *_cp313
- zlib-ng >=2.3.3,<2.4.0a0
+ - libtiff >=4.7.2,<4.8.0a0
+ - libfreetype >=2.14.3
+ - libfreetype6 >=2.14.3
- openjpeg >=2.5.4,<3.0a0
- - lcms2 >=2.18,<3.0a0
+ - libjpeg-turbo >=3.2.0,<4.0a0
+ - libxcb >=1.17.0,<2.0a0
+ - libwebp-base >=1.6.0,<2.0a0
+ - lcms2 >=2.19.1,<3.0a0
+ - tk >=8.6.13,<8.7.0a0
license: HPND
run_exports: {}
- size: 1052168
- timestamp: 1775060059882
+ size: 1072892
+ timestamp: 1788610327434
- conda: https://conda.anaconda.org/conda-forge/linux-64/pixman-0.46.2-h29eaf8c_0.conda
sha256: 6cb261595b5f0ae7306599f2bb55ef6863534b6d4d1bc0dcfdfa5825b0e4e53d
md5: 39b4228a867772d610c02e06f939a5b8
@@ -5818,22 +6627,22 @@ packages:
- pkg:pypi/pydantic-core?source=hash-mapping
size: 1890081
timestamp: 1746625309715
-- conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.46.4-py313h843e2db_0.conda
- sha256: d6705962afa2655cc22edcd075ce1f7e67c4407c005137d6d63c0dc5eaa76f47
- md5: ef0f9efec6ec28b17e22f787c7672c67
+- conda: https://conda.anaconda.org/conda-forge/linux-64/pydantic-core-2.46.5-py313ha296275_1.conda
+ sha256: ba744cf30856ccda82fa4dca2058294fd3574c0f36e737b16411b49eaa5f24cd
+ md5: 41286094042803a6cd590db9d13f5aa1
depends:
- python
- typing-extensions >=4.6.0,!=4.7.0
+ - libgcc >=15
- __glibc >=2.17,<3.0.a0
- - libgcc >=14
- python_abi 3.13.* *_cp313
constrains:
- __glibc >=2.17
license: MIT
license_family: MIT
run_exports: {}
- size: 1893749
- timestamp: 1778084222642
+ size: 1877111
+ timestamp: 1787928978287
- conda: https://conda.anaconda.org/conda-forge/linux-64/pydot-4.0.1-py312h7900ff3_0.conda
sha256: be87ec5ee93853c3deb8115099c74f002e0af711410e23b1ae14cc30c12c0041
md5: 6ff35cf1336b0aa49338b8171aa74c94
@@ -6360,22 +7169,22 @@ packages:
license_family: MIT
size: 3707065
timestamp: 1775241332871
-- conda: https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.53.2-hbc0de68_0.conda
- sha256: b7c3217b437f8aa531b4a18c89dc137b6066757f1e93146dc0d8d999ef55da09
- md5: 38d9bf35a4cc83094a327811e548b660
+- conda: https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.53.4-h6e79ffa_1.conda
+ sha256: 45babc48aef7a468175a609848d56242e43c043a5c2a4d595c220cfc31488028
+ md5: 237875bda674b2da7ca68765ffb22645
depends:
- __glibc >=2.17,<3.0.a0
- - libgcc >=14
- - libsqlite 3.53.2 h0c1763c_0
+ - libgcc >=15
+ - libsqlite 3.53.4 h0737f62_1
- libzlib >=1.3.2,<2.0a0
- ncurses >=6.6,<7.0a0
- readline >=8.3,<9.0a0
license: blessing
run_exports:
weak:
- - libsqlite >=3.53.2,<4.0a0
- size: 205545
- timestamp: 1780574435288
+ - libsqlite >=3.53.4,<4.0a0
+ size: 205639
+ timestamp: 1787051140325
- conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda
sha256: cafeec44494f842ffeca27e9c8b0c27ed714f93ac77ddadc6aaf726b5554ebac
md5: cffd3bdd58090148f4cfcd831f4b26ab
@@ -6418,19 +7227,19 @@ packages:
- pkg:pypi/tornado?source=hash-mapping
size: 850902
timestamp: 1748003427956
-- conda: https://conda.anaconda.org/conda-forge/linux-64/tornado-6.5.7-py313h07c4f96_0.conda
- sha256: ed2f17b2bc92389187b47e7444aa7d6ab6c70c3f3ba6bf2ced508027e60e82cb
- md5: 9665531f18d2bcbc946e3ba0cf53ea91
+- conda: https://conda.anaconda.org/conda-forge/linux-64/tornado-6.5.8-py313h995f894_1.conda
+ sha256: 0816baa2de2bae5bcb590ef8b649577b2eb9e823525632dc66d24a4918a73798
+ md5: 4d57957c3ef7171f5c4f654c1e8fb0ac
depends:
- __glibc >=2.17,<3.0.a0
- - libgcc >=14
+ - libgcc >=15
- python >=3.13,<3.14.0a0
- python_abi 3.13.* *_cp313
license: Apache-2.0
license_family: Apache
run_exports: {}
- size: 885824
- timestamp: 1781006802459
+ size: 892774
+ timestamp: 1788524837756
- conda: https://conda.anaconda.org/conda-forge/linux-64/uriparser-0.9.8-hac33072_0.conda
sha256: 2aad2aeff7c69a2d7eecd7b662eef756b27d6a6b96f3e2c2a7071340ce14543e
md5: d71d3a66528853c0a1ac2c02d79a0284
@@ -6458,12 +7267,12 @@ packages:
purls: []
size: 330474
timestamp: 1751817998141
-- conda: https://conda.anaconda.org/conda-forge/linux-64/wayland-1.25.0-hd6090a7_0.conda
- sha256: ea374d57a8fcda281a0a89af0ee49a2c2e99cc4ac97cf2e2db7064e74e764bdb
- md5: 996583ea9c796e5b915f7d7580b51ea6
+- conda: https://conda.anaconda.org/conda-forge/linux-64/wayland-1.26.0-hd6090a7_0.conda
+ sha256: 6b9e182021ef3a64ab3bf788ebdab6de6775035612237c639ccafc941639eb13
+ md5: b34c5559f45d8996e3bc0b6250a6cc84
depends:
- __glibc >=2.17,<3.0.a0
- - libexpat >=2.7.4,<3.0a0
+ - libexpat >=2.8.1,<3.0a0
- libffi >=3.5.2,<3.6.0a0
- libgcc >=14
- libstdcxx >=14
@@ -6471,9 +7280,9 @@ packages:
license_family: MIT
run_exports:
weak:
- - wayland >=1.25.0,<2.0a0
- size: 334139
- timestamp: 1773959575393
+ - wayland >=1.26.0,<2.0a0
+ size: 340543
+ timestamp: 1784249169392
- conda: https://conda.anaconda.org/conda-forge/linux-64/wrapt-1.17.2-py312h66e93f0_0.conda
sha256: ed3a1700ecc5d38c7e7dc7d2802df1bc1da6ba3d6f6017448b8ded0affb4ae00
md5: 669e63af87710f8d52fdec9d4d63b404
@@ -7081,16 +7890,17 @@ packages:
purls: []
size: 619606
timestamp: 1750236493212
-- conda: https://conda.anaconda.org/conda-forge/noarch/affine-2.4.0-pyhd8ed1ab_1.conda
- sha256: 0deeaf0c001d5543719db9b2686bc1920c86c7e142f9bec74f35e1ce611b1fc2
- md5: 8c4061f499edec6b8ac7000f6d586829
+- conda: https://conda.anaconda.org/conda-forge/noarch/affine-3.0.1-pyhecae5ae_0.conda
+ sha256: 8801cd5b4e0f0203b7a18e8def15929f3413e93e2da88d5b918b735454106f85
+ md5: aeb404cab9e719a49264ab40928f80c8
depends:
- - python >=3.9
+ - attrs >=21.3.0
+ - python >=3.10
license: BSD-3-Clause
license_family: BSD
run_exports: {}
- size: 19164
- timestamp: 1733762153202
+ size: 22619
+ timestamp: 1788134268940
- conda: https://conda.anaconda.org/conda-forge/noarch/amply-0.1.6-pyhd8ed1ab_1.conda
sha256: e8d87cb66bcc62bc8d8168037b776de962ebf659e45acb1a813debde558f7339
md5: 5a81866192811f3a0827f5f93e589f02
@@ -7116,6 +7926,17 @@ packages:
run_exports: {}
size: 18074
timestamp: 1733247158254
+- conda: https://conda.anaconda.org/conda-forge/noarch/annotated-types-0.8.0-pyhd8ed1ab_0.conda
+ sha256: b8fcb994134d3918d1c64a9d62f4168ff85d5bfb89e698102fe4ed679fe0df24
+ md5: 108c928d2a8551832dbc762b535e90bb
+ depends:
+ - python >=3.10
+ - typing-extensions >=4.0.0
+ license: MIT
+ license_family: MIT
+ run_exports: {}
+ size: 19461
+ timestamp: 1784935220549
- conda: https://conda.anaconda.org/conda-forge/noarch/appdirs-1.4.4-pyhd8ed1ab_1.conda
sha256: 5b9ef6d338525b332e17c3ed089ca2f53a5d74b7a7b432747d29c6466e39346d
md5: f4e90937bbfc3a4a92539545a37bb448
@@ -7209,9 +8030,9 @@ packages:
license_family: MIT
size: 171751
timestamp: 1773315364851
-- conda: https://conda.anaconda.org/conda-forge/noarch/bokeh-3.9.1-pyhd8ed1ab_0.conda
- sha256: b3d3b93a17fa678e81cd5ff5309fe64c7feb65c71cb134f14e4fe2113dc0c8d5
- md5: 123fcfe0df4b6fc21804538e59cdaafe
+- conda: https://conda.anaconda.org/conda-forge/noarch/bokeh-3.10.0-pyhd8ed1ab_0.conda
+ sha256: 34bb5cc4f6ccff1e410dea2d39880190f88a8be7ad5cfe9ff0da2cf3d2ad7ea1
+ md5: 67d0ed593951a4933024453b76ef1355
depends:
- contourpy >=1.2
- jinja2 >=2.9
@@ -7219,7 +8040,7 @@ packages:
- numpy >=1.16
- packaging >=16.8
- pillow >=7.1.0
- - python >=3.10
+ - python >=3.12
- pyyaml >=3.10
- tornado >=6.2
- xyzservices >=2021.09.1
@@ -7228,8 +8049,8 @@ packages:
license: BSD-3-Clause
license_family: BSD
run_exports: {}
- size: 4526315
- timestamp: 1781002115296
+ size: 4454345
+ timestamp: 1787144786949
- conda: https://conda.anaconda.org/conda-forge/noarch/boltons-25.0.0-pyhd8ed1ab_0.conda
sha256: ea5f4c876eff2ed469551b57f1cc889a3c01128bf3e2e10b1fea11c3ef39eac2
md5: c7eb87af73750d6fd97eff8bbee8cb9c
@@ -7241,16 +8062,15 @@ packages:
- pkg:pypi/boltons?source=hash-mapping
size: 302296
timestamp: 1749686302834
-- conda: https://conda.anaconda.org/conda-forge/noarch/boltons-26.0.0-pyhd8ed1ab_0.conda
- sha256: d3c8be0524a5223bfed89c4a5be90598bfca28e0c702014f7799b978027eb5e1
- md5: 06c2cbdcfd20af2f72a95e09f8747c52
+- conda: https://conda.anaconda.org/conda-forge/noarch/boltons-26.2.0-pyhd8ed1ab_0.conda
+ sha256: 8fd76dc72d31a8688159039cfbb17eabe21c65792a96b5245be04e5887c2291c
+ md5: 52f3c30dbe025efb8050021f35648949
depends:
- - python >=3.10
+ - python >=3.11
license: BSD-3-Clause
- license_family: BSD
run_exports: {}
- size: 307488
- timestamp: 1781879511321
+ size: 321343
+ timestamp: 1788865918329
- conda: https://conda.anaconda.org/conda-forge/noarch/branca-0.8.2-pyhd8ed1ab_0.conda
sha256: 1acf87c77d920edd098ddc91fa785efc10de871465dee0f463815b176e019e8b
md5: 1fcdf88e7a8c296d3df8409bf0690db4
@@ -7280,24 +8100,24 @@ packages:
purls: []
size: 152448
timestamp: 1752037382564
-- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.6.17-h4c7d964_0.conda
- sha256: 7f458e4a82514d7bebbfef23d92817794a16aaf1c748a15f04870d4fb49aeab2
- md5: b9696b2cf00dfeec138c70cee38ed192
+- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.7.22-h4c7d964_0.conda
+ sha256: 95e8e74062a5fe5f870ac8c90302b6e89945165fdaed7810606e84ddee6aac12
+ md5: e27d2ac27b096dc51fedfcf775a53f9b
depends:
- __win
license: ISC
run_exports: {}
- size: 129352
- timestamp: 1781709016515
-- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.6.17-hbd8a1cb_0.conda
- sha256: f8e3c730fa14ee3f170493779f06522c4acf89169f43db4f039727709b6419cf
- md5: a9965dd99f683c5f444428f896635716
+ size: 132136
+ timestamp: 1784754918886
+- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.7.22-hbd8a1cb_0.conda
+ sha256: 0a0544cf95f64394fe4959286f5c71f5444ad58feb0602e53becb27448d24da6
+ md5: 0f51e2391ade309db462a55611263e9c
depends:
- __unix
license: ISC
run_exports: {}
- size: 128866
- timestamp: 1781708962055
+ size: 131780
+ timestamp: 1784754889428
- conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2025.7.9-pyhd8ed1ab_0.conda
sha256: d5bcebb3748005b50479055b69bd6a19753219effcf921b9158ef3ff588c752b
md5: fac657ab965a05f69ba777a7b934255a
@@ -7308,15 +8128,15 @@ packages:
- pkg:pypi/certifi?source=compressed-mapping
size: 156733
timestamp: 1752115379962
-- conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.6.17-pyhd8ed1ab_0.conda
- sha256: 6c13620e458ba43278379d0cdacc30c497336bddfda81681fd50d114a65c702f
- md5: c13824fedced67005d3832c152fe9c2f
+- conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2026.7.22-pyhd8ed1ab_0.conda
+ sha256: fb167de4388e64e52aa3907ed099afab944c1fa6e5f74b281a312dae1bcf7f3b
+ md5: 37e13edbe3b48f1095a9d085ef9cd83b
depends:
- python >=3.10
license: ISC
run_exports: {}
- size: 133877
- timestamp: 1781719949728
+ size: 137015
+ timestamp: 1784717699092
- conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.2-pyhd8ed1ab_0.conda
sha256: 535ae5dcda8022e31c6dc063eb344c80804c537a5a04afba43a845fa6fa130f5
md5: 40fe4284b8b5835a9073a645139f35af
@@ -7328,16 +8148,16 @@ packages:
- pkg:pypi/charset-normalizer?source=hash-mapping
size: 50481
timestamp: 1746214981991
-- conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.7-pyhd8ed1ab_0.conda
- sha256: 3f9483d62ce24ecd063f8a5a714448445dc8d9e201147c46699fc0033e824457
- md5: a9167b9571f3baa9d448faa2139d1089
+- conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.5.1-pyhd8ed1ab_0.conda
+ sha256: cb60ef3e0631c8bacb4f7057196dee4496091a22baa3bb4b9bccb12c7e1c921b
+ md5: e0ac3accc64e23e40969d660e5f58ac8
depends:
- python >=3.10
license: MIT
license_family: MIT
run_exports: {}
- size: 58872
- timestamp: 1775127203018
+ size: 64487
+ timestamp: 1786835648298
- conda: https://conda.anaconda.org/conda-forge/noarch/click-8.2.1-pyh707e725_0.conda
sha256: 8aee789c82d8fdd997840c952a586db63c6890b00e88c4fb6e80a38edd5f51c0
md5: 94b550b8d3a614dbd326af798c7dfb40
@@ -7660,6 +8480,16 @@ packages:
- pkg:pypi/exceptiongroup?source=compressed-mapping
size: 21284
timestamp: 1746947398083
+- conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda
+ sha256: ee6cf346d017d954255bbcbdb424cddea4d14e4ed7e9813e429db1d795d01144
+ md5: 8e662bd460bda79b1ea39194e3c4c9ab
+ depends:
+ - python >=3.10
+ - typing_extensions >=4.6.0
+ license: MIT and PSF-2.0
+ run_exports: {}
+ size: 21333
+ timestamp: 1763918099466
- conda: https://conda.anaconda.org/conda-forge/noarch/executing-2.2.0-pyhd8ed1ab_0.conda
sha256: 7510dd93b9848c6257c43fdf9ad22adf62e7aa6da5f12a6a757aed83bcfedf05
md5: 81d30c08f9a3e556e8ca9e124b044d14
@@ -7771,16 +8601,16 @@ packages:
run_exports: {}
size: 4059
timestamp: 1762351264405
-- conda: https://conda.anaconda.org/conda-forge/noarch/fsspec-2026.6.0-pyhd8ed1ab_0.conda
- sha256: fe0156e6d658be3531aad2a99e42e8ad1ee23c69837d469c44c1b6010373913d
- md5: 7d7e6c826ba0743fc491ebee0e7b899c
+- conda: https://conda.anaconda.org/conda-forge/noarch/fsspec-2026.7.0-pyhd8ed1ab_0.conda
+ sha256: 3cd1c985695d8114bdba2a4a38c87e86d633fadd7cfe7a6733ebb3fe807fdc86
+ md5: b9176565976c773a0739bd83deaf06cc
depends:
- python >=3.10
license: BSD-3-Clause
license_family: BSD
run_exports: {}
- size: 149709
- timestamp: 1781615868173
+ size: 151868
+ timestamp: 1785325238671
- conda: https://conda.anaconda.org/conda-forge/noarch/geopandas-1.1.0-pyhd8ed1ab_0.conda
sha256: 6f5658fc545065c71a61523a9b35c888a44d008d908963b7686e7e8a302bb61e
md5: 6172cf7532433bf6b19ba5012444ee06
@@ -7863,19 +8693,19 @@ packages:
- pkg:pypi/h2?source=hash-mapping
size: 53888
timestamp: 1738578623567
-- conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_0.conda
- sha256: 84c64443368f84b600bfecc529a1194a3b14c3656ee2e832d15a20e0329b6da3
- md5: 164fc43f0b53b6e3a7bc7dce5e4f1dc9
+- conda: https://conda.anaconda.org/conda-forge/noarch/h2-4.4.1-pyhcf101f3_0.conda
+ sha256: 307dd6ec90140c3cf4171071b0e5e870abec314f4565c1edd5bc433e942cdcc0
+ md5: e652ac7756069c456d0da2a922cd7df5
depends:
- python >=3.10
- hyperframe >=6.1,<7
- - hpack >=4.1,<5
+ - hpack >=4.2,<5
- python
license: MIT
license_family: MIT
run_exports: {}
- size: 95967
- timestamp: 1756364871835
+ size: 100789
+ timestamp: 1785796355216
- conda: https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda
sha256: 6ad78a180576c706aabeb5b4c8ceb97c0cb25f1e112d76495bff23e3779948ba
md5: 0a802cb9888dd14eeefc611f05c40b6e
@@ -7945,17 +8775,17 @@ packages:
- pkg:pypi/idna?source=hash-mapping
size: 49765
timestamp: 1733211921194
-- conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.18-pyhcf101f3_0.conda
- sha256: c75632ea624aa450a394f570749420c5a2e0997d0216bc29d5d45b0f39df0426
- md5: 577b04680ae422adb86fc60d7b940659
+- conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.19-pyhcf101f3_0.conda
+ sha256: 1c35a59c1545ad0fdaddf1fbde7bcfa6ef41a8d68c3a2b0b4a291be00676163e
+ md5: a39ae05027e9b707742e41b30d296b75
depends:
- python >=3.10
- python
license: BSD-3-Clause
license_family: BSD
run_exports: {}
- size: 163869
- timestamp: 1781620148226
+ size: 177433
+ timestamp: 1787059857580
- conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.7.0-pyhe01879c_1.conda
sha256: c18ab120a0613ada4391b15981d86ff777b5690ca461ea7e9e49531e8f374745
md5: 63ccfdc3a3ce25b027b8767eb722fca8
@@ -7969,9 +8799,9 @@ packages:
- pkg:pypi/importlib-metadata?source=hash-mapping
size: 34641
timestamp: 1747934053147
-- conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-9.0.0-pyhcf101f3_0.conda
- sha256: 43e2a5497cad1598ff88a3e69f69bc88b7b8f141fa63c60eab5db296317318b8
- md5: ffc17e785d64e12fc311af9184221839
+- conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-9.0.1-pyhcf101f3_0.conda
+ sha256: 95a074a7d3f58b3494c068d4789c364dcb591c56b70ca6b12f149a540f9aeea4
+ md5: 77ec68e0aa61c3fff9ecbf840f93d64e
depends:
- python >=3.10
- zipp >=3.20
@@ -7979,8 +8809,8 @@ packages:
license: Apache-2.0
license_family: APACHE
run_exports: {}
- size: 34766
- timestamp: 1779714582554
+ size: 34920
+ timestamp: 1787943971257
- conda: https://conda.anaconda.org/conda-forge/noarch/importlib_resources-6.5.2-pyhd8ed1ab_0.conda
sha256: acc1d991837c0afb67c75b77fdc72b4bf022aac71fedd8b9ea45918ac9b08a80
md5: c85c76dc67d75619a92f51dfbce06992
@@ -8006,6 +8836,16 @@ packages:
- pkg:pypi/iniconfig?source=hash-mapping
size: 11474
timestamp: 1733223232820
+- conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda
+ sha256: e1a9e3b1c8fe62dc3932a616c284b5d8cbe3124bbfbedcf4ce5c828cb166ee19
+ md5: 9614359868482abba1bd15ce465e3c42
+ depends:
+ - python >=3.10
+ license: MIT
+ license_family: MIT
+ run_exports: {}
+ size: 13387
+ timestamp: 1760831448842
- conda: https://conda.anaconda.org/conda-forge/noarch/ipdb-0.13.13-pyhd8ed1ab_1.conda
sha256: 33275d537122e67df200203d541170db8b55886667d30cc7262cc1e463b04406
md5: 044c5249ad8ea18a414d07baa1f369ea
@@ -8190,17 +9030,18 @@ packages:
- pkg:pypi/jinja2?source=compressed-mapping
size: 112714
timestamp: 1741263433881
-- conda: https://conda.anaconda.org/conda-forge/noarch/joblib-1.5.3-pyhd8ed1ab_0.conda
- sha256: 301539229d7be6420c084490b8145583291123f0ce6b92f56be5948a2c83a379
- md5: 615de2a4d97af50c350e5cf160149e77
+- conda: https://conda.anaconda.org/conda-forge/noarch/joblib-1.6.0-pyhcf101f3_0.conda
+ sha256: 96b76ace583404ce4fbc234baa6cdb3de485887913104d4ac51994f9b6656696
+ md5: 4ebc70ef1af2e21cdc8edb1bfa1ec28d
depends:
- python >=3.10
- - setuptools
+ - cloudpickle >=3.0
+ - python
license: BSD-3-Clause
license_family: BSD
run_exports: {}
- size: 226448
- timestamp: 1765794135253
+ size: 228858
+ timestamp: 1788177170105
- conda: https://conda.anaconda.org/conda-forge/noarch/jsonpatch-1.33-pyhd8ed1ab_1.conda
sha256: 304955757d1fedbe344af43b12b5467cca072f83cce6109361ba942e186b3993
md5: cb60ae9cf02b9fcb8004dec4089e5691
@@ -8300,21 +9141,21 @@ packages:
run_exports: {}
size: 8250
timestamp: 1650660473123
-- conda: https://conda.anaconda.org/conda-forge/noarch/mapclassify-2.10.0-pyhd8ed1ab_1.conda
- sha256: 967841d300598b17f76ba812e7dae642176692ed2a6735467b93c2b2debe35c1
- md5: cc293b4cad9909bf66ca117ea90d4631
+- conda: https://conda.anaconda.org/conda-forge/noarch/mapclassify-2.11.0-pyhd8ed1ab_0.conda
+ sha256: 791137f3e107c73315c74bb0c7be34e5f7c36da1828efbc4584544311121484c
+ md5: 0323c95182d828bb1bcf708c4077db3b
depends:
- - networkx >=3.2
- - numpy >=1.26
- - pandas >=2.1
- - python >=3.11
- - scikit-learn >=1.4
- - scipy >=1.12
+ - networkx >=3.4
+ - numpy >=2.0
+ - pandas >=2.3
+ - python >=3.12
+ - scikit-learn >=1.5
+ - scipy >=1.14
license: BSD-3-Clause
license_family: BSD
run_exports: {}
- size: 810830
- timestamp: 1752271625200
+ size: 448635
+ timestamp: 1786480374013
- conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.1.7-pyhd8ed1ab_1.conda
sha256: 69b7dc7131703d3d60da9b0faa6dd8acbf6f6c396224cf6aef3e855b8c0c41c6
md5: af6ab708897df59bd6e7283ceab1b56b
@@ -8349,17 +9190,17 @@ packages:
run_exports: {}
size: 11766
timestamp: 1745776666688
-- conda: https://conda.anaconda.org/conda-forge/noarch/narwhals-2.22.1-pyhcf101f3_0.conda
- sha256: dd2744a501f2db0aef084566bf3d0c2b312661dc91beb5a4cc97d27cdda0a959
- md5: 9450fb40fb1e147d0bcbdf07cd02ca96
+- conda: https://conda.anaconda.org/conda-forge/noarch/narwhals-2.25.0-pyhcf101f3_0.conda
+ sha256: e48d972fae8e32ca43eefd1a9649afa3a82b4dda5fe12caa441f0bc9e8d1938d
+ md5: 0117bf65e45c951a9b0004172cfaeef6
depends:
- python >=3.10
- python
license: MIT
license_family: MIT
run_exports: {}
- size: 285532
- timestamp: 1780672242196
+ size: 293989
+ timestamp: 1787261063562
- conda: https://conda.anaconda.org/conda-forge/noarch/nbformat-5.10.4-pyhd8ed1ab_1.conda
sha256: 7a5bd30a2e7ddd7b85031a5e2e14f290898098dc85bea5b3a5bf147c25122838
md5: bbe1963f1e47f594070ffe87cdf612ea
@@ -8431,17 +9272,17 @@ packages:
- pkg:pypi/packaging?source=compressed-mapping
size: 62477
timestamp: 1745345660407
-- conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda
- sha256: 3906abfb6511a3bb309e39b9b1b7bc38f50a723971de2395489fd1f379255890
- md5: 4c06a92e74452cfa53623a81592e8934
+- conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.3-pyhc364b38_0.conda
+ sha256: c432626b16768b8dab228bfb706f7060c2d462a21c516d240f68f2f902b5a044
+ md5: 936687ed80f295a1f5dbcf8bd34c252c
depends:
- - python >=3.8
+ - python >=3.9
- python
license: Apache-2.0
license_family: APACHE
run_exports: {}
- size: 91574
- timestamp: 1777103621679
+ size: 116363
+ timestamp: 1785888127370
- conda: https://conda.anaconda.org/conda-forge/noarch/pandera-0.24.0-hd8ed1ab_2.conda
sha256: 857657552f1a8441e4c9e723637b8270f46b6262403dc18a76559dd5a5ba782e
md5: a12a21a89519f0cc224e44da86f5be2c
@@ -8607,6 +9448,17 @@ packages:
- pkg:pypi/pluggy?source=hash-mapping
size: 24246
timestamp: 1747339794916
+- conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda
+ sha256: e14aafa63efa0528ca99ba568eaf506eb55a0371d12e6250aaaa61718d2eb62e
+ md5: d7585b6550ad04c8c5e21097ada2888e
+ depends:
+ - python >=3.9
+ - python
+ license: MIT
+ license_family: MIT
+ run_exports: {}
+ size: 25877
+ timestamp: 1764896838868
- conda: https://conda.anaconda.org/conda-forge/noarch/prompt-toolkit-3.0.51-pyha770c72_0.conda
sha256: ebc1bb62ac612af6d40667da266ff723662394c0ca78935340a5b5c14831227b
md5: d17ae9db4dc594267181bd199bf9a551
@@ -8678,21 +9530,21 @@ packages:
- pkg:pypi/pydantic?source=compressed-mapping
size: 307333
timestamp: 1749927245525
-- conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.13.4-pyhcf101f3_0.conda
- sha256: 69700e31165df070e9716315e042196aa92525dae5deb5107785847ab9f4189f
- md5: 729843edafc0899b3348bd3f19525b9d
+- conda: https://conda.anaconda.org/conda-forge/noarch/pydantic-2.13.5-pyhcf101f3_0.conda
+ sha256: 701ed8122021f62e1c9a46bdf4932ada911c10afa56ba0459f56da940bcbe5a7
+ md5: 2d0f9304fc1cb1e3e94e7b37c14cd70a
depends:
- typing-inspection >=0.4.2
- typing_extensions >=4.14.1
- python >=3.10
- annotated-types >=0.6.0
- - pydantic-core ==2.46.4
+ - pydantic-core ==2.46.5
- python
license: MIT
license_family: MIT
run_exports: {}
- size: 346511
- timestamp: 1778103405862
+ size: 346633
+ timestamp: 1787941273167
- conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda
sha256: 5577623b9f6685ece2697c6eb7511b4c9ac5fb607c9babc2646c811b428fd46a
md5: 6b6ece66ebcae2d5f326c77ef2c5a066
@@ -8704,6 +9556,17 @@ packages:
- pkg:pypi/pygments?source=compressed-mapping
size: 889287
timestamp: 1750615908735
+- conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.21.0-pyhcf101f3_0.conda
+ sha256: f5f015ff1bc3e1b7fc08eee096b1865234189ae0b82bebdb86a5369116e42fa0
+ md5: 2882dee445dfa45b0c5afce3ffb7730a
+ depends:
+ - python >=3.10
+ - python
+ license: BSD-2-Clause
+ license_family: BSD
+ run_exports: {}
+ size: 959376
+ timestamp: 1786995678795
- conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.3-pyhd8ed1ab_1.conda
sha256: b92afb79b52fcf395fd220b29e0dd3297610f2059afac45298d44e00fcbf23b6
md5: 513d3c262ee49b54a8fec85c5bc99764
@@ -8773,6 +9636,26 @@ packages:
- pkg:pypi/pytest?source=hash-mapping
size: 276562
timestamp: 1750239526127
+- conda: https://conda.anaconda.org/conda-forge/noarch/pytest-9.1.1-pyhc364b38_2.conda
+ sha256: 430051d80765207a7d782b2b188230ba1489d35c6e75fd9903f76cb9fda4af16
+ md5: 64c98a12c4e23eb238bf66bbecafdf3c
+ depends:
+ - colorama
+ - pygments >=2.7.2
+ - python >=3.10
+ - iniconfig >=1.0.1
+ - packaging >=22
+ - pluggy >=1.5,<2
+ - tomli >=1
+ - exceptiongroup >=1
+ - python
+ constrains:
+ - pytest-faulthandler >=2
+ license: MIT
+ license_family: MIT
+ run_exports: {}
+ size: 306724
+ timestamp: 1782127176429
- conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda
sha256: d6a17ece93bbd5139e02d2bd7dbfa80bee1a4261dced63f65f679121686bf664
md5: 5b8d21249ff20967101ffa321cab24e8
@@ -8809,16 +9692,16 @@ packages:
- pkg:pypi/tzdata?source=compressed-mapping
size: 144160
timestamp: 1742745254292
-- conda: https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2026.2-pyhd8ed1ab_0.conda
- sha256: e943f9c15a6bdba2e1b9f423ab913b3f6b02197b0ef9f8e6b7464d78b59965b9
- md5: f6ad7450fc21e00ecc23812baed6d2e4
+- conda: https://conda.anaconda.org/conda-forge/noarch/python-tzdata-2026.3-pyhd8ed1ab_0.conda
+ sha256: 3f05db78cf8be33cf6dbc469664b8e3a01f3980d61d6d6bef48669b171896d8a
+ md5: eefc8d916bd2e708d76d40398ef9a1ee
depends:
- python >=3.10
license: Apache-2.0
license_family: APACHE
run_exports: {}
- size: 146639
- timestamp: 1777068997932
+ size: 146862
+ timestamp: 1783704822814
- conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.12-7_cp312.conda
build_number: 7
sha256: a1bbced35e0df66cc713105344263570e835625c28d1bdee8f748f482b2d7793
@@ -8851,17 +9734,17 @@ packages:
license_family: MIT
size: 201725
timestamp: 1773679724369
-- conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2026.2-pyhcf101f3_0.conda
- sha256: 5020863d629f584b5c057333a67a7aed43e3ed013ba15dd70f353501ccb5aff6
- md5: 03cb60f505ad3ada0a95277af5faeb1a
+- conda: https://conda.anaconda.org/conda-forge/noarch/pytz-2026.3.post1-pyhcf101f3_0.conda
+ sha256: ad774abda71c759baef515983bfedbba34d56d6227974c23715c04612f812a90
+ md5: eb2fb9070c0232e96ae5515d8b28e4f9
depends:
- python >=3.10
- python
license: MIT
license_family: MIT
run_exports: {}
- size: 201747
- timestamp: 1777892201250
+ size: 201126
+ timestamp: 1785077087428
- conda: https://conda.anaconda.org/conda-forge/noarch/referencing-0.36.2-pyh29332c3_0.conda
sha256: e20909f474a6cece176dfc0dc1addac265deb5fa92ea90e975fbca48085b20c3
md5: 9140f1c09dd5489549c6a33931b943c7
@@ -8938,16 +9821,16 @@ packages:
- pkg:pypi/setuptools?source=hash-mapping
size: 748788
timestamp: 1748804951958
-- conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda
- sha256: 82088a6e4daa33329a30bc26dc19a98c7c1d3f05c0f73ce9845d4eab4924e9e1
- md5: 8e194e7b992f99a5015edbd4ebd38efd
+- conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-84.0.0-pyh332efcf_0.conda
+ sha256: 9e200ee5f9ff19a4d94e4b51c4856d53dec849f91032f345cf0c6bc3d51a7183
+ md5: 62ac906f1cd582c6c264c95625cb9d6f
depends:
- python >=3.10
license: MIT
license_family: MIT
run_exports: {}
- size: 639697
- timestamp: 1773074868565
+ size: 524488
+ timestamp: 1786282924579
- conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhd8ed1ab_0.conda
sha256: 41db0180680cc67c3fa76544ffd48d6a5679d96f4b71d7498a759e94edc9a2db
md5: a451d576819089b0d672f18768be0f65
@@ -9116,6 +9999,17 @@ packages:
- pkg:pypi/tomli?source=hash-mapping
size: 19167
timestamp: 1733256819729
+- conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda
+ sha256: 91cafdb64268e43e0e10d30bd1bef5af392e69f00edd34dfaf909f69ab2da6bd
+ md5: b5325cf06a000c5b14970462ff5e4d58
+ depends:
+ - python >=3.10
+ - python
+ license: MIT
+ license_family: MIT
+ run_exports: {}
+ size: 21561
+ timestamp: 1774492402955
- conda: https://conda.anaconda.org/conda-forge/noarch/toolz-1.1.0-pyhd8ed1ab_1.conda
sha256: 4e379e1c18befb134247f56021fdf18e112fb35e64dd1691858b0a0f3bea9a45
md5: c07a6153f8306e45794774cf9b13bd32
@@ -9176,21 +10070,20 @@ packages:
- pkg:pypi/typeguard?source=hash-mapping
size: 35158
timestamp: 1750249264892
-- conda: https://conda.anaconda.org/conda-forge/noarch/typeguard-4.5.2-pyhcf101f3_0.conda
- sha256: 59d7851d32fddb5b510272e6557aa982edeb927d349648dac27f5bf01d18bb26
- md5: 4460f039b7dedf15f7df086446ca75ae
+- conda: https://conda.anaconda.org/conda-forge/noarch/typeguard-4.6.0-pyhcf101f3_0.conda
+ sha256: 82cb76b4dd554d1da90a9e1ea5f99e24aaa4997bcd19ceef8233fc17d9da432e
+ md5: a61716f1640d9986d5d6de1c4d140b42
depends:
- typing_extensions >=4.14.0
- python >=3.10
- - importlib-metadata >=3.6
- python
constrains:
- pytest >=7
license: MIT
license_family: MIT
run_exports: {}
- size: 38297
- timestamp: 1778779291237
+ size: 38525
+ timestamp: 1785075519409
- conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.14.1-h4440ef1_0.conda
sha256: 349951278fa8d0860ec6b61fcdc1e6f604e6fce74fabf73af2e39a37979d0223
md5: 75be1a943e0a7f99fcf118309092c635
@@ -9201,16 +10094,16 @@ packages:
purls: []
size: 90486
timestamp: 1751643513473
-- conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.15.0-h396c80c_0.conda
- sha256: 7c2df5721c742c2a47b2c8f960e718c930031663ac1174da67c1ed5999f7938c
- md5: edd329d7d3a4ab45dcf905899a7a6115
+- conda: https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.16.0-h69aa097_0.conda
+ sha256: b141933ece3518f6d7b75dfb59451e2f26b405a44c18e2518a83e9a02e09315c
+ md5: c680b5747e8c4c8f23dca0bb7042a8fc
depends:
- - typing_extensions ==4.15.0 pyhcf101f3_0
+ - typing_extensions ==4.16.0 pyhcf101f3_0
license: PSF-2.0
license_family: PSF
run_exports: {}
- size: 91383
- timestamp: 1756220668932
+ size: 94080
+ timestamp: 1783002732887
- conda: https://conda.anaconda.org/conda-forge/noarch/typing-inspection-0.4.1-pyhd8ed1ab_0.conda
sha256: 4259a7502aea516c762ca8f3b8291b0d4114e094bdb3baae3171ccc0900e722f
md5: e0c3cd765dc15751ee2f0b03cd015712
@@ -9223,18 +10116,18 @@ packages:
- pkg:pypi/typing-inspection?source=compressed-mapping
size: 18809
timestamp: 1747870776989
-- conda: https://conda.anaconda.org/conda-forge/noarch/typing-inspection-0.4.2-pyhcf101f3_2.conda
- sha256: 8b90d2f19f9458b8c58a55e1fcdc1d90c1603a847a47654d8a454549413ba60a
- md5: 53f5409c5cfd6c5a66417d68e3f0a864
+- conda: https://conda.anaconda.org/conda-forge/noarch/typing-inspection-0.4.4-pyhcf101f3_0.conda
+ sha256: 293c66b208468d186a94ff486c2ffbf67859a2bde8c88e965fc9d06c517191b2
+ md5: 880e91eac5d926568ef278e20554148e
depends:
- python >=3.10
- - typing_extensions >=4.12.0
+ - typing_extensions >=4.15.0
- python
license: MIT
license_family: MIT
run_exports: {}
- size: 20935
- timestamp: 1777105465795
+ size: 21070
+ timestamp: 1786818918217
- conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.14.1-pyhe01879c_0.conda
sha256: 4f52390e331ea8b9019b87effaebc4f80c6466d09f68453f52d5cdc2a3e1194f
md5: e523f4f1e980ed7a4240d7e27e9ec81f
@@ -9247,17 +10140,17 @@ packages:
- pkg:pypi/typing-extensions?source=hash-mapping
size: 51065
timestamp: 1751643513473
-- conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda
- sha256: 032271135bca55aeb156cee361c81350c6f3fb203f57d024d7e5a1fc9ef18731
- md5: 0caa1af407ecff61170c9437a808404d
+- conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda
+ sha256: 2d888f90af0686044882c74193ec80a90ec1943145d94a7b1b048958acda1848
+ md5: c70ad746c22219b9700931707482992c
depends:
- python >=3.10
- python
license: PSF-2.0
license_family: PSF
run_exports: {}
- size: 51692
- timestamp: 1756220668932
+ size: 52631
+ timestamp: 1783002732887
- conda: https://conda.anaconda.org/conda-forge/noarch/typing_inspect-0.9.0-pyhd8ed1ab_1.conda
sha256: a3fbdd31b509ff16c7314e8d01c41d9146504df632a360ab30dbc1d3ca79b7c0
md5: fa31df4d4193aabccaf09ce78a187faf
@@ -9279,13 +10172,13 @@ packages:
purls: []
size: 122968
timestamp: 1742727099393
-- conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda
- sha256: 1d30098909076af33a35017eed6f2953af1c769e273a0626a04722ac4acaba3c
- md5: ad659d0a2b3e47e38d829aa8cad2d610
+- conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda
+ sha256: b928c30ddcb0e3f544c6eade8352737e6e610e263276b90232db6a578ef899d8
+ md5: fcb489df604d100968b737f2cb6076c6
license: LicenseRef-Public-Domain
run_exports: {}
- size: 119135
- timestamp: 1767016325805
+ size: 118849
+ timestamp: 1784250406640
- conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.5.0-pyhd8ed1ab_0.conda
sha256: 4fb9789154bd666ca74e428d973df81087a697dbb987775bc3198d2215f240f8
md5: 436c165519e140cb08d246a4472a9d6a
@@ -9382,16 +10275,16 @@ packages:
run_exports: {}
size: 879913
timestamp: 1749743321359
-- conda: https://conda.anaconda.org/conda-forge/noarch/xyzservices-2026.3.0-pyhd8ed1ab_0.conda
- sha256: 663ea9b00d68c2da309114923924686ab6d3f59ef1b196c5029ba16799e7bb07
- md5: 4487b9c371d0161d54b5c7bbd890c0fc
+- conda: https://conda.anaconda.org/conda-forge/noarch/xyzservices-2026.9.1-pyhd8ed1ab_0.conda
+ sha256: b9439f1716ff580ce56e9b4a4df7ea92e5ed2bdc9567d25cdff223d62c3183a8
+ md5: 5d7c149ba9c728d4951f3fe6d3ce0f84
depends:
- python >=3.9
license: BSD-3-Clause
license_family: BSD
run_exports: {}
- size: 51732
- timestamp: 1774900074457
+ size: 53963
+ timestamp: 1788530754725
- conda: https://conda.anaconda.org/conda-forge/noarch/yte-1.8.1-pyha770c72_0.conda
sha256: 439ebef131ef2e4711f286375240f8d779fce2fe54b4ec786fb58c6c9141b17b
md5: 55a52c71e7919a4951cfc6cccf4fa16f
@@ -9744,9 +10637,9 @@ packages:
- azure-storage-files-datalake-cpp >=12.14.0,<12.14.1.0a0
size: 198818
timestamp: 1778764243281
-- conda: https://conda.anaconda.org/conda-forge/osx-arm64/backports.zstd-1.6.0-py313h7208f8c_0.conda
- sha256: 4d39bf744249f60212a728369dbc6cd6ec4d5aef6668a14321f747d7eb4bac2d
- md5: 6ab3d07883ad437c12a8f5fd90c1df5b
+- conda: https://conda.anaconda.org/conda-forge/osx-arm64/backports.zstd-1.7.0-py313h8c7ad59_1.conda
+ sha256: 824139728f10836e49aabc4d14cf8f594a430ecaf5815d471d50f10b66c8073f
+ md5: b50a4cca2d4af559fab07843625a598c
depends:
- python
- __osx >=11.0
@@ -9754,8 +10647,8 @@ packages:
- python_abi 3.13.* *_cp313
license: BSD-3-Clause AND MIT AND EPL-2.0
run_exports: {}
- size: 243873
- timestamp: 1781450811773
+ size: 241808
+ timestamp: 1788491298513
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/blosc-1.21.6-h7dd00d9_1.conda
sha256: c3fe902114b9a3ac837e1a32408cc2142c147ec054c1038d37aec6814343f48a
md5: 925acfb50a750aa178f7a0aced77f351
@@ -9867,18 +10760,18 @@ packages:
purls: []
size: 179696
timestamp: 1744128058734
-- conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.34.6-hc919400_0.conda
- sha256: 2995f2aed4e53725e5efbc28199b46bf311c3cab2648fc4f10c2227d6d5fa196
- md5: bcb3cba70cf1eec964a03b4ba7775f01
+- conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.34.8-h74c22ad_2.conda
+ sha256: 82bdd5a3fcada6afef6255a9bf41172f07b362f36e04a354dc2abc0a29bfb756
+ md5: 4cc01a374215de38387d45e19c8c5c9c
depends:
- __osx >=11.0
license: MIT
license_family: MIT
run_exports:
weak:
- - c-ares >=1.34.6,<2.0a0
- size: 180327
- timestamp: 1765215064054
+ - c-ares >=1.34.8,<2.0a0
+ size: 197819
+ timestamp: 1787169996553
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/cairo-1.18.4-h6a3b0d2_0.conda
sha256: 00439d69bdd94eaf51656fdf479e0c853278439d22ae151cabf40eb17399d95f
md5: 38f6df8bc8c668417b904369a01ba2e2
@@ -10582,20 +11475,20 @@ packages:
- pkg:pypi/jsonpointer?source=hash-mapping
size: 17865
timestamp: 1725303130815
-- conda: https://conda.anaconda.org/conda-forge/osx-arm64/kiwisolver-1.5.0-py313h2af2deb_0.conda
- sha256: b0ac975a7eb40638b1405c8092835c47222ce758eb26114afee50a8d1ce98569
- md5: bd1e04d017f340e42431706402db8b02
+- conda: https://conda.anaconda.org/conda-forge/osx-arm64/kiwisolver-1.5.1-py313h738389e_1.conda
+ sha256: a94fbdf1974a51b8e4a32d1952f54b95095f7ff058988a94166119e99c504232
+ md5: 24ee9d68fcbe92d1a6b8ac67b5e9dd80
depends:
- python
- - python 3.13.* *_cp313
- - libcxx >=19
- __osx >=11.0
+ - python 3.13.* *_cp313
+ - libcxx >=21
- python_abi 3.13.* *_cp313
license: BSD-3-Clause
license_family: BSD
run_exports: {}
- size: 69457
- timestamp: 1773067363162
+ size: 66486
+ timestamp: 1788505929375
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/krb5-1.21.3-h237132a_0.conda
sha256: 4442f957c3c77d69d9da3521268cad5d54c9033f1a73f99cde0a3658937b159b
md5: c6dc8a0fdec13a0565936655c33069a1
@@ -10651,9 +11544,9 @@ packages:
purls: []
size: 188306
timestamp: 1745264362794
-- conda: https://conda.anaconda.org/conda-forge/osx-arm64/lerc-4.1.0-h1eee2c3_0.conda
- sha256: 66e5ffd301a44da696f3efc2f25d6d94f42a9adc0db06c44ad753ab844148c51
- md5: 095e5749868adab9cae42d4b460e5443
+- conda: https://conda.anaconda.org/conda-forge/osx-arm64/lerc-4.2.0-h1eee2c3_0.conda
+ sha256: c97aa17d16d2ac332ba9f184e82ce8f72dcb10e9a10c5f299030be2d44e191b9
+ md5: e429aec4037d5cb8fd34ded9f5dadd39
depends:
- __osx >=11.0
- libcxx >=19
@@ -10661,9 +11554,9 @@ packages:
license_family: Apache
run_exports:
weak:
- - lerc >=4.1.0,<5.0a0
- size: 164222
- timestamp: 1773114244984
+ - lerc >=4.2.0,<5.0a0
+ size: 166477
+ timestamp: 1785036480092
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libabseil-20260107.1-cxx17_h2062a1b_0.conda
sha256: 756611fbb8d2957a5b4635d9772bd8432cb6ddac05580a6284cca6fdc9b07fca
md5: bb65152e0d7c7178c0f1ee25692c9fd1
@@ -10713,9 +11606,9 @@ packages:
purls: []
size: 788465
timestamp: 1749385999215
-- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libarchive-3.8.8-gpl_h6fbacd7_100.conda
- sha256: 05c370fae4f2a5fd7baf59c15d75caec718d785ec47e813dbf7bff68355e4bb7
- md5: cfa10f3c4b14c13f676dc08e2ea29023
+- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libarchive-3.8.9-gpl_h6fbacd7_100.conda
+ sha256: b58cfffd0774142d308a25f1bdc610c46d71cb67489f1b1eec0891e78ede5b11
+ md5: 4963589c8bed67dd0540d890ba690f53
depends:
- __osx >=11.0
- bzip2 >=1.0.8,<2.0a0
@@ -10732,9 +11625,9 @@ packages:
license_family: BSD
run_exports:
weak:
- - libarchive >=3.8.8,<3.9.0a0
- size: 796153
- timestamp: 1782289667690
+ - libarchive >=3.8.9,<3.9.0a0
+ size: 800281
+ timestamp: 1785251408018
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libarrow-19.0.1-h96c63c9_45_cpu.conda
build_number: 45
sha256: 7907d58e8fbb1b54fb048820e489afdb4d3427dd276cefd2d9287865e2304065
@@ -11001,16 +11894,16 @@ packages:
purls: []
size: 567309
timestamp: 1752050056857
-- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-22.1.8-h55c6f16_0.conda
- sha256: a2e7abab5add9750fab064c024394de48e49f97631c605ad5db5c8ac3fc769ef
- md5: 89f76a2a21a3ec3ec983b5eb237c4113
+- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-23.1.1-h55c6f16_0.conda
+ sha256: 3f902803f0fc2643a4f82ff15a06811d974ff5fb6fa8f957720a7ef84e13ad98
+ md5: b61106a0b5ac7cfe874f8b2e4f067dfa
depends:
- __osx >=11.0
license: Apache-2.0 WITH LLVM-exception
license_family: Apache
run_exports: {}
- size: 569349
- timestamp: 1781670209146
+ size: 578565
+ timestamp: 1788869180613
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libdeflate-1.24-h5773f1b_0.conda
sha256: 417d52b19c679e1881cce3f01cad3a2d542098fa2d6df5485aac40f01aede4d1
md5: 3baf58a5a87e7c2f4d243ce2f8f2fe5c
@@ -11161,19 +12054,19 @@ packages:
run_exports: {}
size: 338442
timestamp: 1780933611662
-- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgcc-15.2.0-hcbb3090_19.conda
- sha256: 06644fa4d34d57c9e48f4d84b1256f9e5f654fdb37f43acc8a58a396952d42b7
- md5: 644058123986582db33aebd4ae2ca184
+- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgcc-16.2.0-h3cf6597_4.conda
+ sha256: 00b8d07ea98344c72c6e332a09b8060f4176849d5fd0eb78dd5b30176ad97ca4
+ md5: 408af8d9d5226ff45ff04756ff1aa91e
depends:
- _openmp_mutex
constrains:
- - libgcc-ng ==15.2.0=*_19
- - libgomp 15.2.0 19
+ - libgcc-ng ==16.2.0=*_4
+ - libgomp 16.2.0 4
license: GPL-3.0-only WITH GCC-exception-3.1
license_family: GPL
run_exports: {}
- size: 404080
- timestamp: 1778273064154
+ size: 365758
+ timestamp: 1787617459249
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgd-2.3.3-hb2c3a21_11.conda
sha256: be038eb8dfe296509aee2df21184c72cb76285b0340448525664bc396aa6146d
md5: 4581aa3cfcd1a90967ed02d4a9f3db4b
@@ -11266,18 +12159,18 @@ packages:
run_exports: {}
size: 598531
timestamp: 1758004553771
-- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran-15.2.0-h07b0088_19.conda
- sha256: d4837b3b9b30af3132d260225e91ab9dde83be04c59513f500cc81050fb37486
- md5: 1ea03f87cdb1078fbc0e2b2deb63752c
+- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran-16.2.0-h07b0088_4.conda
+ sha256: 7582efbbffc6964093afd80e01c2ac60d89aa4e404cac664544675b9d4d1c5e7
+ md5: aa6c627acd0f5709d9c79bf708a7b81b
depends:
- - libgfortran5 15.2.0 hdae7583_19
+ - libgfortran5 16.2.0 hdb7a957_4
constrains:
- - libgfortran-ng ==15.2.0=*_19
+ - libgfortran-ng ==16.2.0=*_4
license: GPL-3.0-only WITH GCC-exception-3.1
license_family: GPL
run_exports: {}
- size: 139675
- timestamp: 1778273280875
+ size: 99624
+ timestamp: 1787617544212
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran-5.0.0-14_2_0_h6c33f7e_103.conda
sha256: 8628746a8ecd311f1c0d14bb4f527c18686251538f7164982ccbe3b772de58b5
md5: 044a210bc1d5b8367857755665157413
@@ -11300,18 +12193,18 @@ packages:
purls: []
size: 806566
timestamp: 1743863491726
-- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran5-15.2.0-hdae7583_19.conda
- sha256: d0a68b7a121d115b80c169e24d1265dcc25a3fe58d107df1bbc430797e226d88
- md5: ba36d8c606a6a53fe0b8c12d47267b3d
+- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran5-16.2.0-hdb7a957_4.conda
+ sha256: 902719c38c7a390d305435a362dc83893754c3f933569a38347c434cd1c12540
+ md5: d54390644d893d50e739b19145aae45f
depends:
- - libgcc >=15.2.0
+ - libgcc >=16.2.0
constrains:
- - libgfortran 15.2.0
+ - libgfortran 16.2.0
license: GPL-3.0-only WITH GCC-exception-3.1
license_family: GPL
run_exports: {}
- size: 599691
- timestamp: 1778273075448
+ size: 554806
+ timestamp: 1787617465010
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libglib-2.84.2-hbec27ea_0.conda
sha256: 5fcc5e948706cc64e45e2454267f664ed5a1e84f15345aae04a41d852a879c0e
md5: 7bbb8961dca1b4b9f2b01b6e722111a7
@@ -11432,9 +12325,9 @@ packages:
purls: []
size: 553624
timestamp: 1745268405713
-- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libjpeg-turbo-3.1.4.1-h84a0fba_0.conda
- sha256: 17e035ae6a520ff6a6bb5dd93a4a7c3895891f4f9743bcb8c6ef607445a31cd0
- md5: b8a7544c83a67258b0e8592ec6a5d322
+- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libjpeg-turbo-3.2.0-h84a0fba_1.conda
+ sha256: 05006418f9392c9b723e8428808db106de0350a497832f95f921b85ff1072310
+ md5: b2f8c8e5a7651a1d7c05404c3a159517
depends:
- __osx >=11.0
constrains:
@@ -11442,9 +12335,9 @@ packages:
license: IJG AND BSD-3-Clause AND Zlib
run_exports:
weak:
- - libjpeg-turbo >=3.1.4.1,<4.0a0
- size: 555681
- timestamp: 1775962975624
+ - libjpeg-turbo >=3.2.0,<4.0a0
+ size: 558459
+ timestamp: 1785896382474
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libkml-1.3.0-hb833057_1023.conda
sha256: bfc6c0b1f30de524e3270eed2171d87e6b96552ff90cf2a5eb34c00d6bcb3dfa
md5: 3d8eeedb8e541d1cb593e8204fcc397d
@@ -11869,18 +12762,18 @@ packages:
purls: []
size: 899248
timestamp: 1752072259470
-- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.53.2-h1b79a29_0.conda
- sha256: f06b6d9d50d5ad1bed09daada386eb1aa8ed7a9ca4618facd3aead75b82db9ff
- md5: 530ef68b7f9f7bee04f67db8d435f872
+- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.53.4-h34a968b_1.conda
+ sha256: 3fbd885062e6e8de5118515a8b801ecaf3c49ff30a940fe80c2f71c2b82f0db7
+ md5: d583309355fba01165ca2508c71a0970
depends:
- __osx >=11.0
- libzlib >=1.3.2,<2.0a0
license: blessing
run_exports:
weak:
- - libsqlite >=3.53.2,<4.0a0
- size: 923664
- timestamp: 1780574869893
+ - libsqlite >=3.53.4,<4.0a0
+ size: 938877
+ timestamp: 1787051200294
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libssh2-1.11.1-h1590b86_0.conda
sha256: 8bfe837221390ffc6f111ecca24fa12d4a6325da0c8d131333d63d6c37f27e0a
md5: b68e8f66b94b44aaa8de4583d3d4cc40
@@ -11928,25 +12821,25 @@ packages:
purls: []
size: 370943
timestamp: 1747067160710
-- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libtiff-4.7.1-h4030677_1.conda
- sha256: e9248077b3fa63db94caca42c8dbc6949c6f32f94d1cafad127f9005d9b1507f
- md5: e2a72ab2fa54ecb6abab2b26cde93500
+- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libtiff-4.7.2-hf67920b_1.conda
+ sha256: 847d22a86ae28f66d3888702698254d25bb4eac3a0f64c1fabfb1842ac00be4c
+ md5: b6b191267455bf202af79f973690ed5d
depends:
- __osx >=11.0
- - lerc >=4.0.0,<5.0a0
- - libcxx >=19
+ - lerc >=4.2.0,<5.0a0
+ - libcxx >=21
- libdeflate >=1.25,<1.26.0a0
- - libjpeg-turbo >=3.1.0,<4.0a0
- - liblzma >=5.8.1,<6.0a0
+ - libjpeg-turbo >=3.2.0,<4.0a0
+ - liblzma >=5.8.3,<6.0a0
- libwebp-base >=1.6.0,<2.0a0
- - libzlib >=1.3.1,<2.0a0
+ - libzlib >=1.3.2,<2.0a0
- zstd >=1.5.7,<1.6.0a0
license: HPND
run_exports:
weak:
- - libtiff >=4.7.1,<4.8.0a0
- size: 373892
- timestamp: 1762022345545
+ - libtiff >=4.7.2,<4.8.0a0
+ size: 380645
+ timestamp: 1787756067271
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libutf8proc-2.11.3-h2431656_0.conda
sha256: ae1a82e62cd4e3c18e005ae7ff4358ed72b2bfbfe990d5a6a5587f81e9a100dc
md5: 2255add2f6ae77d0a96624a5cbde6d45
@@ -12108,21 +13001,21 @@ packages:
purls: []
size: 281996
timestamp: 1749892286735
-- conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-openmp-22.1.8-hc7d1edf_0.conda
- sha256: ccbaad6bbc88f135ab849bc36af5fa6eda36a9ed18ce6f58e3dde3d11784c156
- md5: a9c118f6343fb6301b6f3b4e94c4c562
+- conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-openmp-23.1.0-hdb3d66b_0.conda
+ sha256: 996d3a9de61c8ccc3fcb265938f9845f11868251f38e6db4e7190de3f9a971a2
+ md5: 0affff5130a421d11d4d77ffbb00dad7
depends:
- __osx >=11.0
constrains:
- intel-openmp <0.0a0
- - openmp 22.1.8|22.1.8.*
+ - openmp 23.1.0|23.1.0.*
license: Apache-2.0 WITH LLVM-exception
license_family: APACHE
run_exports:
strong:
- - llvm-openmp >=22.1.8
- size: 286313
- timestamp: 1781736516782
+ - llvm-openmp >=23.1.0
+ size: 287808
+ timestamp: 1787723323710
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/lz4-4.4.5-py313hd065f0a_1.conda
sha256: 71dfac3971dcd134c8a31b3f670d00b8d551e275fb386568ec11ab68d95fe540
md5: ece4dab2afb98b065b69ce769a5c6c42
@@ -12256,39 +13149,38 @@ packages:
- pkg:pypi/menuinst?source=hash-mapping
size: 174339
timestamp: 1750792742701
-- conda: https://conda.anaconda.org/conda-forge/osx-arm64/minizip-4.2.1-hdb7fadc_0.conda
- sha256: 4b1d4e4b17d27bbec50b1ad144e000c3b077cc4e0ef487ef11011c52ef8c86ab
- md5: fcd860469a8fa003e25d472b40b0ff81
+- conda: https://conda.anaconda.org/conda-forge/osx-arm64/minizip-4.2.2-h56c1371_1.conda
+ sha256: 0a737bebd276d48f0436842ca47b38b823b4f8e3c3065848c9d1f421f334a4aa
+ md5: b7819f4118a456301e220e995afd53ac
depends:
- __osx >=11.0
- bzip2 >=1.0.8,<2.0a0
- - libcxx >=19
+ - libcxx >=21
- libiconv >=1.18,<2.0a0
- liblzma >=5.8.3,<6.0a0
- libzlib >=1.3.2,<2.0a0
- - openssl >=3.5.6,<4.0a0
+ - openssl >=3.5.8,<4.0a0
- zstd >=1.5.7,<1.6.0a0
license: Zlib
license_family: Other
run_exports:
weak:
- - minizip >=4.2.1,<5.0a0
- size: 459816
- timestamp: 1778003052237
-- conda: https://conda.anaconda.org/conda-forge/osx-arm64/msgpack-python-1.2.1-py313h5c29297_0.conda
- sha256: 12f2c785c34a465f399e7af89e6b88a86684bde704e25460789e83efc0d8fd87
- md5: b929e2af3d4059fedfb0a5da0007556f
+ - minizip >=4.2.2,<5.0a0
+ size: 462531
+ timestamp: 1788051612824
+- conda: https://conda.anaconda.org/conda-forge/osx-arm64/msgpack-python-1.2.2-py313hcb059c8_2.conda
+ sha256: 7846717fdd4ab12617c308ece9c5f8f862b7aecd529abee1a70eb5a99cee1a6f
+ md5: 4e90283eebfa97c70d4fe6d46f6e273c
depends:
+ - python
- __osx >=11.0
- - libcxx >=19
- - python >=3.13,<3.14.0a0
- - python >=3.13,<3.14.0a0 *_cp313
+ - libcxx >=21
- python_abi 3.13.* *_cp313
license: Apache-2.0
- license_family: Apache
+ license_family: APACHE
run_exports: {}
- size: 91552
- timestamp: 1782070886759
+ size: 101084
+ timestamp: 1788525103407
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/mypy-1.16.1-py312hea69d52_0.conda
sha256: 32920a7074b450a15f0f7b1ba48e5246484c44c167d38311db85ca9d7b100eac
md5: ab4b5c37bfdd0002491a92239a580af7
@@ -12435,9 +13327,9 @@ packages:
purls: []
size: 3071649
timestamp: 1751390309393
-- conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.6.3-hd24854e_0.conda
- sha256: b3e3ca895c336d4eb91c5d2f244a312bdb59a0de8cfa0cc4c179225ab2f6bbfb
- md5: 8187a86242741725bfa74785fe812979
+- conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.6.4-h55eecbc_0.conda
+ sha256: f23239eacd75c4c50705e68fae1aa3292da473e6a3a4abe2330f1e6afa680704
+ md5: ae71ab40048c19a389a7dcccb86c2481
depends:
- __osx >=11.0
- ca-certificates
@@ -12445,9 +13337,9 @@ packages:
license_family: Apache
run_exports:
weak:
- - openssl >=3.6.3,<4.0a0
- size: 3102584
- timestamp: 1781069820667
+ - openssl >=3.6.4,<4.0a0
+ size: 3110142
+ timestamp: 1787698648639
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/orc-2.2.2-h578b684_1.conda
sha256: a25faa4aa71832f908dec90ff3f66490ab06c47304d3c1e474c9f6306ae78452
md5: 5ed1fedefe1098670f8d8e8189dcda7c
@@ -12616,28 +13508,27 @@ packages:
- pcre2 >=10.46,<10.47.0a0
size: 835080
timestamp: 1756743041908
-- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pillow-12.2.0-py313h45e5a15_0.conda
- sha256: 90333643a7868b10724999633bb393d005bc5f539d05666f80c41fb67e5f0f3f
- md5: 6186601fd72a394a6f7c7b7096f6a063
+- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pillow-12.3.0-py313h4ede67f_2.conda
+ sha256: 7d49dd4fbe81e0b6cd0cbcad50c233416308acbd3c2eaa834bc94262a08fe918
+ md5: 0815276151429fe3f361115c834aab72
depends:
- python
- - python 3.13.* *_cp313
- __osx >=11.0
- - openjpeg >=2.5.4,<3.0a0
- libxcb >=1.17.0,<2.0a0
- - libjpeg-turbo >=3.1.2,<4.0a0
- - libtiff >=4.7.1,<4.8.0a0
+ - openjpeg >=2.5.4,<3.0a0
+ - libjpeg-turbo >=3.2.0,<4.0a0
+ - libtiff >=4.7.2,<4.8.0a0
+ - libwebp-base >=1.6.0,<2.0a0
+ - zlib-ng >=2.3.3,<2.4.0a0
- libfreetype >=2.14.3
- libfreetype6 >=2.14.3
- - libwebp-base >=1.6.0,<2.0a0
- - lcms2 >=2.18,<3.0a0
- - tk >=8.6.13,<8.7.0a0
- python_abi 3.13.* *_cp313
- - zlib-ng >=2.3.3,<2.4.0a0
+ - lcms2 >=2.19.1,<3.0a0
+ - tk >=8.6.13,<8.7.0a0
license: HPND
run_exports: {}
- size: 977319
- timestamp: 1775060469004
+ size: 996699
+ timestamp: 1788610377472
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pixman-0.46.2-h2f9eb0b_0.conda
sha256: 68d1eef12946d779ce4b4b9de88bc295d07adce5dd825a0baf0e1d7cf69bc5a6
md5: 0587a57e200568a71982173c07684423
@@ -12803,13 +13694,12 @@ packages:
- pkg:pypi/pydantic-core?source=hash-mapping
size: 1715338
timestamp: 1746625327204
-- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pydantic-core-2.46.4-py313h212e517_0.conda
- sha256: 5bcc20f2c21d8a20d8f2821caf31d8c0ef2fa3bcdaf7a9bdce62e37be819f1d7
- md5: 32bb0d4dbb1be2064c06248a1190aa96
+- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pydantic-core-2.46.5-py313h680bcb3_1.conda
+ sha256: 475c4d1896024dbb856ff9d58b8725cb5082db32e84dbe9f2851b891ddf69c95
+ md5: 1faebbbbd03a8e59b1d9e574469cb81e
depends:
- python
- typing-extensions >=4.6.0,!=4.7.0
- - python 3.13.* *_cp313
- __osx >=11.0
- python_abi 3.13.* *_cp313
constrains:
@@ -12817,8 +13707,8 @@ packages:
license: MIT
license_family: MIT
run_exports: {}
- size: 1720475
- timestamp: 1778084300413
+ size: 1689376
+ timestamp: 1787928984245
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pydot-4.0.1-py312h81bd7bf_0.conda
sha256: 1d9fc2c0f982ff9b1ee9d7bd27bdbed6cbcb53bedd8200b6249f12710c48e359
md5: 2e6a2e3c32f6a48b6cacfec0e1f3da90
@@ -13224,21 +14114,21 @@ packages:
license_family: MIT
size: 3697021
timestamp: 1775241400922
-- conda: https://conda.anaconda.org/conda-forge/osx-arm64/sqlite-3.53.2-h85ec8f2_0.conda
- sha256: 5d0a6544dcbbec6322c06a8ee994d6823916af35bbd5a0f8c35387869f1b5d76
- md5: 1966e1b7f598b30cd746309ba483e541
+- conda: https://conda.anaconda.org/conda-forge/osx-arm64/sqlite-3.53.4-hdb6324b_1.conda
+ sha256: 7ea31b7063fe292f5c7e543bc7d2c6077c33f608eabcdadf963e2335e50ab3e1
+ md5: a70594a09c2167c484156a77455fa1de
depends:
- __osx >=11.0
- - libsqlite 3.53.2 h1b79a29_0
+ - libsqlite 3.53.4 h34a968b_1
- libzlib >=1.3.2,<2.0a0
- ncurses >=6.6,<7.0a0
- readline >=8.3,<9.0a0
license: blessing
run_exports:
weak:
- - libsqlite >=3.53.2,<4.0a0
- size: 182161
- timestamp: 1780574896374
+ - libsqlite >=3.53.4,<4.0a0
+ size: 179881
+ timestamp: 1787051206584
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h010d191_3.conda
sha256: 799cab4b6cde62f91f750149995d149bc9db525ec12595e8a1d91b9317f038b3
md5: a9d86bc62f39b94c4661716624eb21b0
@@ -13277,9 +14167,9 @@ packages:
- pkg:pypi/tornado?source=hash-mapping
size: 851614
timestamp: 1748003575892
-- conda: https://conda.anaconda.org/conda-forge/osx-arm64/tornado-6.5.7-py313h0997733_0.conda
- sha256: 02c7b05be4d74da0d7329f92445646e3489634f0c3e59b26efefd846662ac20a
- md5: dbc95e65c936251c3d32111c867d84e1
+- conda: https://conda.anaconda.org/conda-forge/osx-arm64/tornado-6.5.8-py313hf5449f0_1.conda
+ sha256: 7f7895de1dce43905cc1642ea0b2811bcf242a3b789ce071a0cf4284caaaee7a
+ md5: 90cf89c127d4be14a3f1acdbbb0ba37e
depends:
- __osx >=11.0
- python >=3.13,<3.14.0a0
@@ -13288,8 +14178,8 @@ packages:
license: Apache-2.0
license_family: Apache
run_exports: {}
- size: 889689
- timestamp: 1781007967544
+ size: 894250
+ timestamp: 1788525258397
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/uriparser-0.9.8-h00cdb27_0.conda
sha256: fa0bcbfb20a508ca9bf482236fe799581cbd0eab016e47a865e9fa44dbe3c512
md5: e8ff9e11babbc8cd77af5a4258dc2802
@@ -13718,20 +14608,20 @@ packages:
- aws-sdk-cpp >=1.11.606,<1.11.607.0a0
size: 3438987
timestamp: 1771598251928
-- conda: https://conda.anaconda.org/conda-forge/win-64/backports.zstd-1.6.0-py313h2a31948_0.conda
- sha256: 65eb354dbaba5925f536613c8d645a6254226eb6c6f16cc6e57033eb97cc0159
- md5: 144ae232f6f920307f4aadc088137589
+- conda: https://conda.anaconda.org/conda-forge/win-64/backports.zstd-1.7.0-py313h2a31948_1.conda
+ sha256: c9421fb36888e70029a3f564a4e870019eb070e24c440a9d9071c57c8e82c794
+ md5: d742785ccf2834a29b834892ddb23672
depends:
- python
- vc >=14.3,<15
- vc14_runtime >=14.44.35208
- ucrt >=10.0.20348.0
- - zstd >=1.5.7,<1.6.0a0
- python_abi 3.13.* *_cp313
+ - zstd >=1.5.7,<1.6.0a0
license: BSD-3-Clause AND MIT AND EPL-2.0
run_exports: {}
- size: 241936
- timestamp: 1781450845361
+ size: 242878
+ timestamp: 1788491289149
- conda: https://conda.anaconda.org/conda-forge/win-64/blosc-1.21.6-hfd34d9b_1.conda
sha256: 9303a7a0e03cf118eab3691013f6d6cbd1cbac66efbc70d89b20f5d0145257c0
md5: 357d7be4146d5fec543bfaa96a8a40de
@@ -13842,20 +14732,20 @@ packages:
purls: []
size: 54927
timestamp: 1720974860185
-- conda: https://conda.anaconda.org/conda-forge/win-64/c-ares-1.34.6-hfd05255_0.conda
- sha256: 5e1e2e24ce279f77e421fcc0e5846c944a8a75f7cf6158427c7302b02984291a
- md5: 7c6da34e5b6e60b414592c74582e28bf
+- conda: https://conda.anaconda.org/conda-forge/win-64/c-ares-1.34.8-h6a83c73_2.conda
+ sha256: b474e4b7f3136576c321533e340b34368a5ce671949bc1a77ef446eb94870136
+ md5: b5a0be28d048d8bbe81df51e4b750500
depends:
- - ucrt >=10.0.20348.0
- vc >=14.3,<15
- vc14_runtime >=14.44.35208
+ - ucrt >=10.0.20348.0
license: MIT
license_family: MIT
run_exports:
weak:
- - c-ares >=1.34.6,<2.0a0
- size: 193550
- timestamp: 1765215100218
+ - c-ares >=1.34.8,<2.0a0
+ size: 210803
+ timestamp: 1787169972884
- conda: https://conda.anaconda.org/conda-forge/win-64/cairo-1.18.4-h5782bbf_0.conda
sha256: b9f577bddb033dba4533e851853924bfe7b7c1623d0697df382eef177308a917
md5: 20e32ced54300292aff690a69c5e7b97
@@ -14184,9 +15074,9 @@ packages:
purls: []
size: 192355
timestamp: 1730284147944
-- conda: https://conda.anaconda.org/conda-forge/win-64/fontconfig-2.18.1-hd47e2ca_0.conda
- sha256: 9217184c4a8e82101b0e512b059ae3ff67e3913133b9031edad89ab5341284e4
- md5: abd79bad98c99c1a116154d6de74ea89
+- conda: https://conda.anaconda.org/conda-forge/win-64/fontconfig-2.18.3-hd47e2ca_1.conda
+ sha256: f26139e3c774a6434c8a73381c08e3d2a4c2f9d9ef9587c66aab8836211ee2ec
+ md5: ed95670fed91b091fe34ba6cae6677d7
depends:
- libexpat >=2.8.1,<3.0a0
- libfreetype >=2.14.3
@@ -14201,10 +15091,10 @@ packages:
license_family: MIT
run_exports:
weak:
- - fontconfig >=2.18.1,<3.0a0
+ - fontconfig >=2.18.3,<3.0a0
- fonts-conda-ecosystem
- size: 202630
- timestamp: 1780450217840
+ size: 217988
+ timestamp: 1786667461139
- conda: https://conda.anaconda.org/conda-forge/win-64/fonttools-4.63.0-py313hd650c13_0.conda
sha256: 10cd3c3606219bc8e1a387757b069175b8202c54f02244b1557c283bd6c252d1
md5: 2b7be2be35fc3b035f1365a015af9706
@@ -14550,9 +15440,9 @@ packages:
- pkg:pypi/jsonpointer?source=hash-mapping
size: 42235
timestamp: 1725303419414
-- conda: https://conda.anaconda.org/conda-forge/win-64/kiwisolver-1.5.0-py313h1a38498_0.conda
- sha256: 58c7b7d85ea3c0fac593fde238b994ee2d4fa8467decfe369dabfb5516b7ded4
- md5: 7e40c4c1af80d907eb2973ab73418095
+- conda: https://conda.anaconda.org/conda-forge/win-64/kiwisolver-1.5.1-py313h1a38498_1.conda
+ sha256: 09f049337936bbc764098e67bb4b14a7194d7f1ad57536cf63ed628ccb2d36a5
+ md5: e4cb42764087bafbdf394d394ec3a0c1
depends:
- python
- vc >=14.3,<15
@@ -14562,8 +15452,8 @@ packages:
license: BSD-3-Clause
license_family: BSD
run_exports: {}
- size: 73548
- timestamp: 1773067061126
+ size: 73459
+ timestamp: 1788505726845
- conda: https://conda.anaconda.org/conda-forge/win-64/krb5-1.21.3-hdf4eb48_0.conda
sha256: 18e8b3430d7d232dad132f574268f56b3eb1a19431d6d5de8c53c29e6c18fa81
md5: 31aec030344e962fbd7dbbbbd68e60a9
@@ -14608,9 +15498,9 @@ packages:
purls: []
size: 164701
timestamp: 1745264384716
-- conda: https://conda.anaconda.org/conda-forge/win-64/lerc-4.1.0-hd936e49_0.conda
- sha256: 45df58fca800b552b17c3914cc9ab0d55a82c5172d72b5c44a59c710c06c5473
- md5: 54b231d595bc1ff9bff668dd443ee012
+- conda: https://conda.anaconda.org/conda-forge/win-64/lerc-4.2.0-hd936e49_0.conda
+ sha256: 93d666f63f284ef77b87b0b1f77b70f7d36d315a132f9afa64bc0012d937ba39
+ md5: add59e2b60ac9d4299d17c938185c75a
depends:
- ucrt >=10.0.20348.0
- vc >=14.3,<15
@@ -14619,9 +15509,9 @@ packages:
license_family: Apache
run_exports:
weak:
- - lerc >=4.1.0,<5.0a0
- size: 172395
- timestamp: 1773113455582
+ - lerc >=4.2.0,<5.0a0
+ size: 175297
+ timestamp: 1785036247761
- conda: https://conda.anaconda.org/conda-forge/win-64/libabseil-20260107.1-cxx17_h0eb2380_0.conda
sha256: 7e7f3754f8afaabd946dc11d7c00fd1dc93f0388a2d226a7abf1bf07deab0e2b
md5: 60da39dd5fd93b2a4a0f986f3acc2520
@@ -14674,9 +15564,9 @@ packages:
purls: []
size: 1098688
timestamp: 1749386269743
-- conda: https://conda.anaconda.org/conda-forge/win-64/libarchive-3.8.8-gpl_he24518a_100.conda
- sha256: abeec1902a9933f71a70bb54a436897d54ea08b290f084c0ce511e4d7eb24548
- md5: e61cb5e50e73c4563c2427de40435171
+- conda: https://conda.anaconda.org/conda-forge/win-64/libarchive-3.8.9-gpl_he24518a_100.conda
+ sha256: d27338b30444c82b7958c833ecd6db905d45ee4d88df6e29faa7c65140b1a601
+ md5: 3267f5cd28472841f357865668e17c10
depends:
- bzip2 >=1.0.8,<2.0a0
- liblzma >=5.8.3,<6.0a0
@@ -14694,9 +15584,9 @@ packages:
license_family: BSD
run_exports:
weak:
- - libarchive >=3.8.8,<3.9.0a0
- size: 1117061
- timestamp: 1782289351052
+ - libarchive >=3.8.9,<3.9.0a0
+ size: 1149153
+ timestamp: 1785250768915
- conda: https://conda.anaconda.org/conda-forge/win-64/libarrow-19.0.1-hd086c85_45_cpu.conda
build_number: 45
sha256: 634bac7300c6de1f507e5f9a6a3dd5123a3232f4458db45a14223eb1a4d65e1d
@@ -15120,21 +16010,21 @@ packages:
purls: []
size: 669602
timestamp: 1750808309041
-- conda: https://conda.anaconda.org/conda-forge/win-64/libgcc-15.2.0-h8ee18e1_19.conda
- sha256: 80e80ef5e31b00b12539db3c5aaecde60dab91381abfc1060e323d5c3b016dce
- md5: cc5d690fc1c629038f13c68e88e65f44
+- conda: https://conda.anaconda.org/conda-forge/win-64/libgcc-16.2.0-h110b43a_4.conda
+ sha256: 32c0d1adcc96835d5f681c7e72b7f5e2e30088149239e002b8a6f581a072e1d2
+ md5: 02793cf48b68687fee158a48c92850a6
depends:
- _openmp_mutex >=4.5
- libwinpthread >=12.0.0.r4.gg4f2fc60ca
constrains:
+ - libgcc-ng ==16.2.0=*_4
+ - libgomp 16.2.0 h8ee18e1_4
- msys2-conda-epoch <0.0a0
- - libgcc-ng ==15.2.0=*_19
- - libgomp 15.2.0 h8ee18e1_19
license: GPL-3.0-only WITH GCC-exception-3.1
license_family: GPL
run_exports: {}
- size: 821854
- timestamp: 1778273037795
+ size: 826694
+ timestamp: 1787625780171
- conda: https://conda.anaconda.org/conda-forge/win-64/libgd-2.3.3-h7208af6_11.conda
sha256: 485a30af9e710feeda8d5b537b2db1e32e41f29ef24683bbe7deb6f7fd915825
md5: 2070a706123b2d5e060b226a00e96488
@@ -15280,9 +16170,9 @@ packages:
purls: []
size: 535456
timestamp: 1750808243424
-- conda: https://conda.anaconda.org/conda-forge/win-64/libgomp-15.2.0-h8ee18e1_19.conda
- sha256: 4dc958ced2fc7f42bc675b07e2c9abe3e150875ffdf62ca551d94fc6facf1fd7
- md5: f1147651e3fdd585e2f442c0c2fc8f2d
+- conda: https://conda.anaconda.org/conda-forge/win-64/libgomp-16.2.0-h8ee18e1_4.conda
+ sha256: 9ef1a22fb50b31fbf9c01cf709e8f55b60fd3c02401d150be4a55943f9e3832f
+ md5: 91189f0bc9ff21f385fcda6232346612
depends:
- libwinpthread >=12.0.0.r4.gg4f2fc60ca
constrains:
@@ -15292,9 +16182,9 @@ packages:
run_exports:
strong:
- _openmp_mutex >=4.5
- - libgomp >=15.2.0
- size: 664640
- timestamp: 1778272979661
+ - libgomp >=16.2.0
+ size: 688168
+ timestamp: 1787625720312
- conda: https://conda.anaconda.org/conda-forge/win-64/libgoogle-cloud-2.39.0-h01c467a_1.conda
sha256: 098ac4abc51752a1c56c1c05ed4220e88daa7d0e18922b0d355056d5b305f167
md5: 453d3a0347fe049b922a2a851c1c0110
@@ -15439,9 +16329,9 @@ packages:
purls: []
size: 838154
timestamp: 1745268437136
-- conda: https://conda.anaconda.org/conda-forge/win-64/libjpeg-turbo-3.1.4.1-hfd05255_0.conda
- sha256: 698d57b5b90120270eaa401298319fcb25ea186ae95b340c2f4813ed9171083d
- md5: 25a127bad5470852b30b239f030ec95b
+- conda: https://conda.anaconda.org/conda-forge/win-64/libjpeg-turbo-3.2.0-hfd05255_1.conda
+ sha256: df78ab4c0eecb3dd9331898f96baeed8e5ca1c363346332517abeb0b614b9a53
+ md5: fc2c23bacefd1e733f1e1d6cd3b2aaeb
depends:
- ucrt >=10.0.20348.0
- vc >=14.3,<15
@@ -15451,9 +16341,9 @@ packages:
license: IJG AND BSD-3-Clause AND Zlib
run_exports:
weak:
- - libjpeg-turbo >=3.1.4.1,<4.0a0
- size: 842806
- timestamp: 1775962811457
+ - libjpeg-turbo >=3.2.0,<4.0a0
+ size: 990125
+ timestamp: 1785896494014
- conda: https://conda.anaconda.org/conda-forge/win-64/libkml-1.3.0-h68a222c_1023.conda
sha256: 6b2c6506dc7d7bb3bc4128d575e4ae6c2cf18d3f9828a4be331e0b5e49edf108
md5: b44e0d9eb84c6c086d809787aab0a1da
@@ -15773,9 +16663,9 @@ packages:
purls: []
size: 1288312
timestamp: 1752072137328
-- conda: https://conda.anaconda.org/conda-forge/win-64/libsqlite-3.53.2-hf5d6505_0.conda
- sha256: 4cd81319dcc58fb758da20a6d5595950c021adc2c18d7cffeadcfb590529629f
- md5: df294e7f9f24a6063f0e226f4d028fda
+- conda: https://conda.anaconda.org/conda-forge/win-64/libsqlite-3.53.4-hf5d6505_1.conda
+ sha256: 0a45d7c0f20146fff787a106f8fa187872e309c70975ff8f0936e188914c26ad
+ md5: a72d495965b144bb7da033642d389047
depends:
- ucrt >=10.0.20348.0
- vc >=14.3,<15
@@ -15783,9 +16673,9 @@ packages:
license: blessing
run_exports:
weak:
- - libsqlite >=3.53.2,<4.0a0
- size: 1313306
- timestamp: 1780574491977
+ - libsqlite >=3.53.4,<4.0a0
+ size: 1314919
+ timestamp: 1787051140039
- conda: https://conda.anaconda.org/conda-forge/win-64/libssh2-1.11.1-h9aa295b_0.conda
sha256: cbdf93898f2e27cefca5f3fe46519335d1fab25c4ea2a11b11502ff63e602c09
md5: 9dce2f112bfd3400f4f432b3d0ac07b2
@@ -15837,15 +16727,15 @@ packages:
purls: []
size: 979074
timestamp: 1747067408877
-- conda: https://conda.anaconda.org/conda-forge/win-64/libtiff-4.7.1-h8f73337_1.conda
- sha256: f1b8cccaaeea38a28b9cd496694b2e3d372bb5be0e9377c9e3d14b330d1cba8a
- md5: 549845d5133100142452812feb9ba2e8
+- conda: https://conda.anaconda.org/conda-forge/win-64/libtiff-4.7.2-h8f73337_1.conda
+ sha256: 3575a092e3e52625a1767804a4ebd321becaadf61b63dcd6735ebb88c0b3c359
+ md5: 970dbe48f843e7fbd179a9b6c22f865a
depends:
- - lerc >=4.0.0,<5.0a0
+ - lerc >=4.2.0,<5.0a0
- libdeflate >=1.25,<1.26.0a0
- - libjpeg-turbo >=3.1.0,<4.0a0
- - liblzma >=5.8.1,<6.0a0
- - libzlib >=1.3.1,<2.0a0
+ - libjpeg-turbo >=3.2.0,<4.0a0
+ - liblzma >=5.8.3,<6.0a0
+ - libzlib >=1.3.2,<2.0a0
- ucrt >=10.0.20348.0
- vc >=14.3,<15
- vc14_runtime >=14.44.35208
@@ -15853,9 +16743,9 @@ packages:
license: HPND
run_exports:
weak:
- - libtiff >=4.7.1,<4.8.0a0
- size: 993166
- timestamp: 1762022118895
+ - libtiff >=4.7.2,<4.8.0a0
+ size: 1014211
+ timestamp: 1787755773611
- conda: https://conda.anaconda.org/conda-forge/win-64/libutf8proc-2.11.3-hb980946_0.conda
sha256: 5d82af0779eab283416240da792a0d2fe4f8213c447e9f04aeaab1801468a90c
md5: 5f34fcb6578ea9bdbfd53cc2cfb88200
@@ -15870,22 +16760,22 @@ packages:
- libutf8proc >=2.11.3,<2.12.0a0
size: 89061
timestamp: 1768735187639
-- conda: https://conda.anaconda.org/conda-forge/win-64/libvulkan-loader-1.4.341.0-h477610d_0.conda
- sha256: 0f0965edca8b255187604fc7712c53fe9064b31a1845a7dfb2b63bf660de84a7
- md5: 804880b2674119b84277d6c16b01677d
+- conda: https://conda.anaconda.org/conda-forge/win-64/libvulkan-loader-1.4.357.0-h477610d_2.conda
+ sha256: 4b094443126c5fc38d200eb0ea335b67e64d966d7aa737bb3141217a787b0c73
+ md5: aaeed7feddbfd7454f8853a5eae8d902
depends:
- vc >=14.3,<15
- vc14_runtime >=14.44.35208
- ucrt >=10.0.20348.0
constrains:
- - libvulkan-headers 1.4.341.0.*
+ - libvulkan-headers 1.4.357.0.*
license: Apache-2.0
license_family: APACHE
run_exports:
weak:
- - libvulkan-loader >=1.4.341.0,<2.0a0
- size: 282251
- timestamp: 1770077165680
+ - libvulkan-loader >=1.4.357.0,<2.0a0
+ size: 288787
+ timestamp: 1787491929908
- conda: https://conda.anaconda.org/conda-forge/win-64/libwebp-base-1.6.0-h4d5522a_0.conda
sha256: 7b6316abfea1007e100922760e9b8c820d6fc19df3f42fb5aca684cfacb31843
md5: f9bbae5e2537e3b06e0f7310ba76c893
@@ -16080,23 +16970,23 @@ packages:
- libzlib >=1.3.2,<2.0a0
size: 58347
timestamp: 1774072851498
-- conda: https://conda.anaconda.org/conda-forge/win-64/llvm-openmp-22.1.8-h4fa8253_0.conda
- sha256: 50c02902bb516eeb56680358f052be38b5bf74b40e78ea4b2a675e84957e7307
- md5: de3551bf6508d45ca46b714639e52823
+- conda: https://conda.anaconda.org/conda-forge/win-64/llvm-openmp-23.1.0-h49e36cd_0.conda
+ sha256: f9658ec83a6744f38e2b8188c76e1c2dea2614f5aa0e14d9d274b19f60646b8c
+ md5: 79055ec79e1b43749763122cead30976
depends:
- ucrt >=10.0.20348.0
- vc >=14.3,<15
- vc14_runtime >=14.44.35208
constrains:
- - openmp 22.1.8|22.1.8.*
- intel-openmp <0.0a0
+ - openmp 23.1.0|23.1.0.*
license: Apache-2.0 WITH LLVM-exception
license_family: APACHE
run_exports:
strong:
- - llvm-openmp >=22.1.8
- size: 348002
- timestamp: 1781737042070
+ - llvm-openmp >=23.1.0
+ size: 342468
+ timestamp: 1787722783678
- conda: https://conda.anaconda.org/conda-forge/win-64/lz4-4.4.5-py313h4bbca4b_1.conda
sha256: c00d35e5228ac375658495e86d33e1daa819ed11161034a5799dcb07bfa328c9
md5: e8df314d3f3fa27e935b6cb449d754f3
@@ -16246,9 +17136,9 @@ packages:
- pkg:pypi/menuinst?source=hash-mapping
size: 140384
timestamp: 1750792754303
-- conda: https://conda.anaconda.org/conda-forge/win-64/minizip-4.2.1-h0ffbb96_0.conda
- sha256: 208b235b20232891d1dc9f468d08b00c53e7ca65a18b9bc0ff4c4867680b9a75
- md5: 5d55038c4d640e5df06de1cfb4e8d741
+- conda: https://conda.anaconda.org/conda-forge/win-64/minizip-4.2.2-h8fa244a_1.conda
+ sha256: ee989609be75355a6b9125e28e0ac7e36c29ce77dd65890b5bc469a4a6d14e86
+ md5: 124e35907d5fb36b1e0cb3b74c20bc9d
depends:
- bzip2 >=1.0.8,<2.0a0
- liblzma >=5.8.3,<6.0a0
@@ -16261,9 +17151,9 @@ packages:
license_family: Other
run_exports:
weak:
- - minizip >=4.2.1,<5.0a0
- size: 106290
- timestamp: 1778002682910
+ - minizip >=4.2.2,<5.0a0
+ size: 116615
+ timestamp: 1788051329472
- conda: https://conda.anaconda.org/conda-forge/win-64/mkl-2024.2.2-h66d3029_15.conda
sha256: 20e52b0389586d0b914a49cd286c5ccc9c47949bed60ca6df004d1d295f2edbd
md5: 302dff2807f2927b3e9e0d19d60121de
@@ -16275,12 +17165,11 @@ packages:
purls: []
size: 103106385
timestamp: 1730232843711
-- conda: https://conda.anaconda.org/conda-forge/win-64/mkl-2026.0.0-hac47afa_908.conda
- sha256: f997bfc9bc4d4e14261cdcd1ad195d64a72ee44dca3145d24c1349f8d1311aa5
- md5: 36ea6e1292e9d5e89374201da79646ef
+- conda: https://conda.anaconda.org/conda-forge/win-64/mkl-2026.1.0-hac47afa_235.conda
+ sha256: bb8abe071f73765446df62924031e6599577e8ac9003264dc4569e78c0fea16d
+ md5: ace316c48c178d7faa403dee51e30c7b
depends:
- - llvm-openmp >=22.1.5
- - onemkl-license 2026.0.0 h57928b3_908
+ - llvm-openmp >=22.1.8
- tbb >=2023.0.0
- ucrt >=10.0.20348.0
- vc >=14.3,<15
@@ -16288,8 +17177,8 @@ packages:
license: LicenseRef-IntelSimplifiedSoftwareOct2022
license_family: Proprietary
run_exports: {}
- size: 114354729
- timestamp: 1779293121860
+ size: 114686732
+ timestamp: 1787725739779
- conda: https://conda.anaconda.org/conda-forge/win-64/mkl-include-2024.2.2-h66d3029_15.conda
sha256: 87b53fd205282de67ff0627ea43d1d4293b7f5d6c5d5a62902c07b71bee7eb58
md5: e2f516189b44b6e042199d13e7015361
@@ -16310,20 +17199,20 @@ packages:
purls: []
size: 108659788
timestamp: 1730233129079
-- conda: https://conda.anaconda.org/conda-forge/win-64/msgpack-python-1.2.1-py313hf069bd2_0.conda
- sha256: 08cfc45c7160779556abc25ea2ac1352fc68c05a7db5c8f7eaa051c928ce93b8
- md5: 83ede6d6d5227244621c126264ccaea9
+- conda: https://conda.anaconda.org/conda-forge/win-64/msgpack-python-1.2.2-py313h1a38498_2.conda
+ sha256: adc02df0943c297b71390b70ca31132082004ec9ab22bbc6ca902e45aa5a92b6
+ md5: 2747a4f5c12412e25f1da5c6313474ef
depends:
- - python >=3.13,<3.14.0a0
- - python_abi 3.13.* *_cp313
- - ucrt >=10.0.20348.0
+ - python
- vc >=14.3,<15
- vc14_runtime >=14.44.35208
+ - ucrt >=10.0.20348.0
+ - python_abi 3.13.* *_cp313
license: Apache-2.0
- license_family: Apache
+ license_family: APACHE
run_exports: {}
- size: 89970
- timestamp: 1782070487087
+ size: 90195
+ timestamp: 1788525100970
- conda: https://conda.anaconda.org/conda-forge/win-64/mypy-1.16.1-py312h4389bb4_0.conda
sha256: 5bb00863b7a736e5bfdabc576af1ff93bb95ab78b3f35e5d800feda57148ba1d
md5: 749b32d06a926c492bc48de440fc6919
@@ -16416,14 +17305,6 @@ packages:
- numpy >=1.23,<3
size: 7524105
timestamp: 1766383318405
-- conda: https://conda.anaconda.org/conda-forge/win-64/onemkl-license-2026.0.0-h57928b3_908.conda
- sha256: 42ad15cbb3bf31830efa04d4b86dd2d5c0dd590c86f98adcd3c8c1f75acf5dd5
- md5: 9c9303e08b50e09f5c23e1dac99d0936
- license: LicenseRef-IntelSimplifiedSoftwareOct2022
- license_family: Proprietary
- run_exports: {}
- size: 41580
- timestamp: 1779292867015
- conda: https://conda.anaconda.org/conda-forge/win-64/openjpeg-2.5.4-h0e57b4f_0.conda
sha256: 24342dee891a49a9ba92e2018ec0bde56cc07fdaec95275f7a55b96f03ea4252
md5: e723ab7cc2794c954e1b22fde51c16e4
@@ -16454,9 +17335,9 @@ packages:
purls: []
size: 9327033
timestamp: 1751392489008
-- conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.6.3-hf411b9b_0.conda
- sha256: cb6e7ba0d010ee0d3249ce9886de3d7613d26d9965d4c95666fa66b9c4c31001
- md5: e99f95734a326c0fd4d02bbd995150d4
+- conda: https://conda.anaconda.org/conda-forge/win-64/openssl-3.6.4-hf411b9b_0.conda
+ sha256: 9dddb559ba49744d5d94092d8d13cb0567f5c3b3f439f3acf28433d1f4256acc
+ md5: 73cb1783f47c452be4c309430fbef89f
depends:
- ca-certificates
- ucrt >=10.0.20348.0
@@ -16466,9 +17347,9 @@ packages:
license_family: Apache
run_exports:
weak:
- - openssl >=3.6.3,<4.0a0
- size: 9414790
- timestamp: 1781071745579
+ - openssl >=3.6.4,<4.0a0
+ size: 9474879
+ timestamp: 1787699876495
- conda: https://conda.anaconda.org/conda-forge/win-64/orc-2.2.2-h0a1ad0e_1.conda
sha256: dcfca3c3c117e9102fcfca116ec9e4f0bbcd0f13b3fce06ff111ae9f107d04b7
md5: aa6701a960f0e94478229af1e061c237
@@ -16644,29 +17525,29 @@ packages:
- pcre2 >=10.46,<10.47.0a0
size: 1034703
timestamp: 1756743085974
-- conda: https://conda.anaconda.org/conda-forge/win-64/pillow-12.2.0-py313h38f99e1_0.conda
- sha256: 54df76a56eff31deab5e72350ca906c79dfb71f0ac9d84bf2f7420ab2ee00151
- md5: 72666a34e563494859af5c5fc10364a0
+- conda: https://conda.anaconda.org/conda-forge/win-64/pillow-12.3.0-py313h38f99e1_2.conda
+ sha256: c9f95ee0a4c06bcf6e5e57377eb311eb3073e3dfd4babd7e1c3cc03f40b74758
+ md5: 0290df58ee4827dc40a26e7d1f9b5d3f
depends:
- python
- vc >=14.3,<15
- vc14_runtime >=14.44.35208
- ucrt >=10.0.20348.0
- libwebp-base >=1.6.0,<2.0a0
- - openjpeg >=2.5.4,<3.0a0
- - libtiff >=4.7.1,<4.8.0a0
+ - zlib-ng >=2.3.3,<2.4.0a0
+ - python_abi 3.13.* *_cp313
+ - lcms2 >=2.19.1,<3.0a0
- tk >=8.6.13,<8.7.0a0
- - lcms2 >=2.18,<3.0a0
- - libjpeg-turbo >=3.1.2,<4.0a0
- libfreetype >=2.14.3
- libfreetype6 >=2.14.3
- - python_abi 3.13.* *_cp313
- libxcb >=1.17.0,<2.0a0
- - zlib-ng >=2.3.3,<2.4.0a0
+ - openjpeg >=2.5.4,<3.0a0
+ - libtiff >=4.7.2,<4.8.0a0
+ - libjpeg-turbo >=3.2.0,<4.0a0
license: HPND
run_exports: {}
- size: 957015
- timestamp: 1775060119774
+ size: 962638
+ timestamp: 1788610331353
- conda: https://conda.anaconda.org/conda-forge/win-64/pixman-0.46.2-had0cd8c_0.conda
sha256: d7d1f1052f15601406883f17ec149abf5e99262782ef536a415a41add060596e
md5: 2566a45fb15e2f540eff14261f1242af
@@ -16842,9 +17723,9 @@ packages:
- pkg:pypi/pydantic-core?source=hash-mapping
size: 1900306
timestamp: 1746625389678
-- conda: https://conda.anaconda.org/conda-forge/win-64/pydantic-core-2.46.4-py313hfbe8231_0.conda
- sha256: 6466b7e441adb71e29308de2a87c9787d5d0100601ede2d02ed4f85c251699d6
- md5: 9981bc46be6341306a5473b290b2f366
+- conda: https://conda.anaconda.org/conda-forge/win-64/pydantic-core-2.46.5-py313hfbe8231_1.conda
+ sha256: 96927a9eaccfa212b43a79e44e2d3db5ec2a12c58d4674d5c793dfcc1efd4877
+ md5: b17d876e4ba18b462a899addacb15a6b
depends:
- python
- typing-extensions >=4.6.0,!=4.7.0
@@ -16855,8 +17736,8 @@ packages:
license: MIT
license_family: MIT
run_exports: {}
- size: 1888029
- timestamp: 1778084253466
+ size: 1865505
+ timestamp: 1787928988442
- conda: https://conda.anaconda.org/conda-forge/win-64/pydot-4.0.1-py312h2e8e312_0.conda
sha256: 2aed920a88a9bc003e56da4b462c181b91776817ba4ebc12949a400f8d1d3d97
md5: c81f64a8ee9e03f87155db2c7876d965
@@ -17335,20 +18216,20 @@ packages:
license_family: MIT
size: 3665426
timestamp: 1775241406935
-- conda: https://conda.anaconda.org/conda-forge/win-64/sqlite-3.53.2-hdb435a2_0.conda
- sha256: 0640ffa3360669c8826f05a8295f38c3bc57dc9cac0c9732940897ff5256f996
- md5: 58e6f936ab416fddc633d4105f43aea2
+- conda: https://conda.anaconda.org/conda-forge/win-64/sqlite-3.53.4-hdb435a2_1.conda
+ sha256: 7616fec2d6ded67e111a47d4842738d0b3730c0acf3eaebe928cf6d3e15a6822
+ md5: df9d7c5d34602e0f2655a524d31fce87
depends:
- - libsqlite 3.53.2 hf5d6505_0
+ - libsqlite 3.53.4 hf5d6505_1
- ucrt >=10.0.20348.0
- vc >=14.3,<15
- vc14_runtime >=14.44.35208
license: blessing
run_exports:
weak:
- - libsqlite >=3.53.2,<4.0a0
- size: 425926
- timestamp: 1780574498030
+ - libsqlite >=3.53.4,<4.0a0
+ size: 426888
+ timestamp: 1787051146089
- conda: https://conda.anaconda.org/conda-forge/win-64/tbb-2021.13.0-h62715c5_1.conda
sha256: 03cc5442046485b03dd1120d0f49d35a7e522930a2ab82f275e938e17b07b302
md5: 9190dd0a23d925f7602f9628b3aed511
@@ -17416,9 +18297,9 @@ packages:
- pkg:pypi/tornado?source=hash-mapping
size: 853357
timestamp: 1748003925528
-- conda: https://conda.anaconda.org/conda-forge/win-64/tornado-6.5.7-py313h5ea7bf4_0.conda
- sha256: 973322f987fcbcc25bf67cd65a7f17b2cb57606e688ec7bb6e203d7dedf83d4a
- md5: e80e3b9589e828c0b0b83f149438c29c
+- conda: https://conda.anaconda.org/conda-forge/win-64/tornado-6.5.8-py313h5ea7bf4_1.conda
+ sha256: 1fd6385331280c32b560edda948a7adb07d297c4e1f5de1799711a389d6c3c08
+ md5: 5b7993a5cf3b70c41f49998c38565a9d
depends:
- python >=3.13,<3.14.0a0
- python_abi 3.13.* *_cp313
@@ -17428,8 +18309,8 @@ packages:
license: Apache-2.0
license_family: Apache
run_exports: {}
- size: 888693
- timestamp: 1781006912014
+ size: 894638
+ timestamp: 1788524943705
- conda: https://conda.anaconda.org/conda-forge/win-64/ucrt-10.0.22621.0-h57928b3_1.conda
sha256: db8dead3dd30fb1a032737554ce91e2819b43496a0db09927edf01c32b577450
md5: 6797b005cd0f439c4c5c9ac565783700
@@ -17499,33 +18380,33 @@ packages:
purls: []
size: 756109
timestamp: 1750371459116
-- conda: https://conda.anaconda.org/conda-forge/win-64/vc14_runtime-14.51.36231-h1b9f54f_39.conda
- sha256: 8153ed849c92e891eacac0f2f8d7ecb79f9b5fd7f7917fbb896f252a60a40390
- md5: 06a5bf5a1ca16cce0df6eaa91fc42bc2
+- conda: https://conda.anaconda.org/conda-forge/win-64/vc14_runtime-14.51.36247-habf1de7_41.conda
+ sha256: 4e4cb599cdc41bf2109d1464c127b5bcbddf548ce3e322e612afb691338b48f8
+ md5: ac5333bb3d429361f23adf704cc49a78
depends:
- ucrt >=10.0.20348.0
- - vcomp14 14.51.36231 h1b9f54f_39
+ - vcomp14 14.51.36247 habf1de7_41
constrains:
- - vs2015_runtime 14.51.36231.* *_39
+ - vs2015_runtime 14.51.36247.* *_41
license: LicenseRef-MicrosoftVisualCpp2015-2022Runtime
license_family: Proprietary
run_exports: {}
- size: 737434
- timestamp: 1781320964561
-- conda: https://conda.anaconda.org/conda-forge/win-64/vcomp14-14.51.36231-h1b9f54f_39.conda
- sha256: 07fb14713c4bc62e2533a2e23a363abfb0e65650681fba0ae4c840e2219350f3
- md5: 8b53a83fda40ec679e4d63fa32fae989
+ size: 767955
+ timestamp: 1785359364369
+- conda: https://conda.anaconda.org/conda-forge/win-64/vcomp14-14.51.36247-habf1de7_41.conda
+ sha256: 731e043390c9457299484d39e427221fc868a9249540a498a5a4f6456c7744d1
+ md5: 350bb67a5c8e5f1c53347ac544ab6600
depends:
- ucrt >=10.0.20348.0
constrains:
- - vs2015_runtime 14.51.36231.* *_39
+ - vs2015_runtime 14.51.36247.* *_41
license: LicenseRef-MicrosoftVisualCpp2015-2022Runtime
license_family: Proprietary
run_exports:
strong:
- - vcomp14 >=14.51.36231
- size: 120684
- timestamp: 1781320948530
+ - vcomp14 >=14.51.36247
+ size: 155910
+ timestamp: 1785359349999
- conda: https://conda.anaconda.org/conda-forge/win-64/vs2015_runtime-14.44.35208-h38c0c73_26.conda
sha256: d18d77c8edfbad37fa0e0bb0f543ad80feb85e8fe5ced0f686b8be463742ec0b
md5: 312f3a0a6b3c5908e79ce24002411e32
@@ -17536,16 +18417,16 @@ packages:
purls: []
size: 17888
timestamp: 1750371463202
-- conda: https://conda.anaconda.org/conda-forge/win-64/vs2015_runtime-14.51.36231-h84cd919_39.conda
- sha256: 6de6c2cf008fc2dce61060b583f2d8494c83883106952b201381b6b0505f03d7
- md5: 2ccc63d7b7d066a814ed9f99072832d7
+- conda: https://conda.anaconda.org/conda-forge/win-64/vs2015_runtime-14.51.36247-h633cb9f_41.conda
+ sha256: ee0ae67c96b80b9fdb50c3f617c6329dbcdf1562d0267604f6c0e24f494431d6
+ md5: 21504569fa34b5d3a67760219e3ff1cc
depends:
- - vc14_runtime >=14.51.36231
+ - vc14_runtime >=14.51.36247
license: BSD-3-Clause
license_family: BSD
run_exports: {}
- size: 20355
- timestamp: 1781320968804
+ size: 21386
+ timestamp: 1785359368990
- conda: https://conda.anaconda.org/conda-forge/win-64/wrapt-1.17.2-py312h4389bb4_0.conda
sha256: a1b86d727cc5f9d016a6fc9d8ac8b3e17c8e137764e018555ecadef05979ce93
md5: b9a81b36e0d35c9a172587ead532273b
diff --git a/pixi.toml b/pixi.toml
index cce4095..f3db0e0 100644
--- a/pixi.toml
+++ b/pixi.toml
@@ -7,6 +7,7 @@ readme = "README.md"
channels = ["conda-forge", "bioconda"]
platforms = ["win-64", "linux-64", "osx-arm64"]
homepage = "https://www.modelblocks.org/"
+requires-pixi = ">=0.79.0"
[dependencies]
clio-tools = ">=2026.06.23"
@@ -49,11 +50,40 @@ glom = ">=24.11.0"
dask = ">=2025.7.0"
numpy = ">=2.3.5"
+[feature.test-unit.dependencies]
+pytest = ">=8.3.5"
+
+[feature.test-unit.tasks]
+test-unit = "pytest unit_tests"
+update-reference-unit = "pytest unit_tests --update-reference"
+
[environments]
-module = { features = ["module"], no-default-feature = true }
+module = { features = ["module"], no-default-feature = true, solve-group = "module" }
+# Unit tests exercise workflow scripts directly, so they combine pytest with the
+# module runtime dependencies while remaining isolated from the default environment.
+test-unit = { features = ["test-unit", "module"], no-default-feature = true, solve-group = "module" }
-[tasks]
-test-integration = {cmd = "pytest tests/integration_test.py"}
+[tasks.test-integration]
+cmd = "pytest tests/integration_test.py"
+depends-on = [
+ { task = "test-unit", environment = "test-unit" },
+]
+
+# Regenerate the integration reference data: run the integration workflow, then
+# freeze its report CSV. Review the resulting diff deliberately before committing.
+[tasks.update-reference-integration]
+cwd = "tests/integration"
+cmd = """
+set -e
+snakemake --use-conda --cores 2
+python -c 'import shutil; shutil.copy("resources/module/results/NLD/base/area_potential_report.csv", "../reference/NLD_area_potential_report.csv")'
+"""
+
+[tasks.update-reference]
+depends-on = [
+ { task = "update-reference-unit", environment = "test-unit" },
+ { task = "update-reference-integration", environment = "default" },
+]
[tasks.export-snakemake-env]
diff --git a/tests/integration/test_config.yaml b/tests/integration/test_config.yaml
index 622dc74..21880a8 100644
--- a/tests/integration/test_config.yaml
+++ b/tests/integration/test_config.yaml
@@ -74,3 +74,9 @@ module_area_potentials:
protected: 0
shapes_buffer:
land: 10000 # meters
+ # Exercise the per-subunit override (glom merge) code path end-to-end
+ overrides:
+ NLD:
+ wind_offshore:
+ shapes_buffer:
+ land: 2000 # meters
diff --git a/tests/integration_test.py b/tests/integration_test.py
index c56b086..bd2a42a 100644
--- a/tests/integration_test.py
+++ b/tests/integration_test.py
@@ -4,13 +4,19 @@
Contents may be updated in future template updates.
"""
+import copy
+import csv
+import math
import subprocess
import tomllib
from pathlib import Path
import pytest
+import yaml
from clio_tools.data_module import ModuleInterface
+INTEGRATION_TECHS = ["pv_rooftop", "pv_open_field", "wind_onshore", "wind_offshore"]
+
@pytest.fixture(scope="module")
def pixi_platforms(module_path) -> list[str]:
@@ -82,3 +88,194 @@ def test_snakemake_integration_testing(module_path):
check=True,
cwd=module_path / "tests/integration",
)
+
+
+##
+# Module-specific tests: compare the integration workflow outputs against
+# committed reference data (regenerate deliberately via `pixi run update-reference`).
+# These use only the standard library because the dev environment has no pandas.
+##
+
+
+def _report_csv_path(module_path):
+ """Path of the report CSV produced by the integration workflow run."""
+ path = (
+ module_path
+ / "tests/integration/resources/module/results/NLD/base/area_potential_report.csv"
+ )
+ assert path.exists(), (
+ "Integration workflow outputs not found; "
+ "test_snakemake_integration_testing must run (and pass) first."
+ )
+ return path
+
+
+def _read_csv_rows(path):
+ """Read a CSV file into a list of rows (lists of strings)."""
+ with open(path, newline="") as f:
+ return list(csv.reader(f))
+
+
+def _cells_equal(actual, expected, rel_tol, abs_tol):
+ """Compare two CSV cells, numerically where possible."""
+ if actual == expected:
+ return True
+ try:
+ actual_num, expected_num = float(actual), float(expected)
+ except ValueError:
+ return False
+ if math.isnan(actual_num) and math.isnan(expected_num):
+ return True
+ return math.isclose(actual_num, expected_num, rel_tol=rel_tol, abs_tol=abs_tol)
+
+
+def test_integration_output_files_exist(module_path):
+ """The aggregated area potential rasters exist for every configured tech."""
+ _report_csv_path(module_path)
+ for tech in INTEGRATION_TECHS:
+ tif = (
+ module_path
+ / f"tests/integration/results/outputs/NLD/base/area_potential_{tech}.tif"
+ )
+ assert tif.exists(), f"Missing output raster: {tif}"
+
+
+def test_integration_output_values(module_path):
+ """The report CSV matches the committed reference data cell by cell.
+
+ Tolerances are deliberately tight: the workflow is expected to be
+ reproducible from pinned inputs and pinned dependencies. Performance
+ rewrites that change floating-point precision must relax these tolerances
+ consciously, so the change is visible in review.
+ """
+ rel_tol, abs_tol = 1e-5, 1e-6
+ actual_rows = _read_csv_rows(_report_csv_path(module_path))
+ reference_csv = module_path / "tests/reference/NLD_area_potential_report.csv"
+ assert reference_csv.exists(), (
+ f"Missing reference data {reference_csv}; "
+ "generate it with `pixi run update-reference-integration`."
+ )
+ expected_rows = _read_csv_rows(reference_csv)
+ # Tech columns are named after the tif paths, which depend on where the
+ # workflow places its outputs (e.g. the scenario segment); compare basenames.
+ assert [Path(col).name for col in actual_rows[0]] == [
+ Path(col).name for col in expected_rows[0]
+ ], "Report CSV header changed"
+ assert len(actual_rows) == len(expected_rows), "Report CSV row count changed"
+ mismatches = [
+ f"row {i} column '{actual_rows[0][j]}': {actual!r} != reference {expected!r}"
+ for i, (actual_row, expected_row) in enumerate(
+ zip(actual_rows[1:], expected_rows[1:])
+ )
+ for j, (actual, expected) in enumerate(zip(actual_row, expected_row))
+ if not _cells_equal(actual, expected, rel_tol, abs_tol)
+ ]
+ assert not mismatches, "Report differs from reference data:\n" + "\n".join(
+ mismatches
+ )
+
+
+def test_integration_output_sanity(module_path):
+ """Basic physical sanity of the report, independent of reference data."""
+ rows = _read_csv_rows(_report_csv_path(module_path))
+ header = rows[0]
+ tech_columns = {
+ tech: header.index(
+ next(col for col in header if f"area_potential_{tech}" in col)
+ )
+ for tech in INTEGRATION_TECHS
+ }
+ class_column = header.index("shape_class")
+
+ def values(tech, shape_class=None):
+ return [
+ float(row[tech_columns[tech]])
+ for row in rows[1:]
+ if row[tech_columns[tech]] not in ("", "nan")
+ and (shape_class is None or row[class_column] == shape_class)
+ ]
+
+ for tech in INTEGRATION_TECHS:
+ assert sum(values(tech)) > 0, f"No area potential at all for {tech}"
+ # Offshore wind exists only in maritime regions; land techs only on land.
+ assert sum(values("wind_offshore", "land")) == pytest.approx(0, abs=1e-6)
+ for tech in ["pv_rooftop", "pv_open_field", "wind_onshore"]:
+ assert sum(values(tech, "maritime")) == pytest.approx(0, abs=1e-6)
+
+
+##
+# Rule-level regression tests: dry-run the integration workflow (after it has
+# run, so the breakup_shape checkpoint is resolved) and inspect the DAG and the
+# resolved shell commands. These guard config plumbing in the rules that no
+# script-level test can see.
+##
+
+
+def _dry_run(module_path, *args):
+ """Dry-run the integration workflow and return its combined output.
+
+ Only modification times decide what would rerun, so provenance changes
+ (e.g. a re-locked environment) cannot re-trigger the checkpoint and hide
+ every job downstream of it.
+ """
+ integration = module_path / "tests/integration"
+ assert (integration / "resources/module/resources/automatic/shapes/NLD").exists(), (
+ "Integration workflow outputs not found; "
+ "test_snakemake_integration_testing must run (and pass) first."
+ )
+ process = subprocess.run(
+ ["snakemake", "--dry-run", "--rerun-triggers", "mtime", *args],
+ cwd=integration,
+ capture_output=True,
+ text=True,
+ )
+ assert process.returncode == 0, process.stdout + process.stderr
+ return process.stdout + process.stderr
+
+
+def test_subunit_overrides_reach_area_potential(module_path):
+ """Per-subunit overrides configured inside a scenario are passed to the script.
+
+ Guards the override lookup in the area_potential rule: the test config
+ overrides the NLD wind_offshore land buffer, which must show up in the
+ resolved --override_config argument (and nothing must be passed for techs
+ without an override).
+ """
+ output = _dry_run(
+ module_path,
+ "--printshellcmds",
+ "--forcerun",
+ "module_area_potentials_area_potential",
+ )
+ commands = [line for line in output.splitlines() if "area_potential.py" in line]
+ assert len(commands) == len(INTEGRATION_TECHS), output
+ for command in commands:
+ # The mapping is passed through shell quoting; undo it before inspecting.
+ override = command.split("--override_config=", 1)[1].replace("'\"'\"'", "'")
+ if "area_potential_wind_offshore.tif" in command:
+ assert "'land': 2000" in override, command
+ else:
+ assert override.startswith("'{}'"), command
+
+
+@pytest.mark.parametrize("where", ["tech", "override", "nowhere"])
+def test_ship_travel_layer_activates_its_rules(module_path, tmp_path, where):
+ """A ship_travel layer in any scenario tech or override pulls in the ship-travel rules.
+
+ Guards uses_ship_travel(): the download/clip rules for the ship traffic
+ density raster are only part of the DAG when some tech uses the layer.
+ """
+ config_path = module_path / "tests/integration/test_config.yaml"
+ config = yaml.safe_load(config_path.read_text())
+ scenario = config["module_area_potentials"]["scenarios"]["base"]
+ layer = {"ship_travel": {"min": 0, "max": 21024000}}
+ if where == "tech":
+ scenario["techs"]["wind_offshore"]["continuous_layers"].update(layer)
+ elif where == "override":
+ scenario["overrides"]["NLD"]["wind_offshore"]["continuous_layers"] = layer
+ modified = tmp_path / "test_config.yaml"
+ modified.write_text(yaml.safe_dump(copy.deepcopy(config)))
+
+ output = _dry_run(module_path, "--configfile", str(modified))
+ expected = where != "nowhere"
+ assert ("module_area_potentials_clip_ship_travel" in output) == expected, output
diff --git a/tests/reference/NLD_area_potential_report.csv b/tests/reference/NLD_area_potential_report.csv
new file mode 100644
index 0000000..bd260a2
--- /dev/null
+++ b/tests/reference/NLD_area_potential_report.csv
@@ -0,0 +1,14 @@
+group,shape_id,country_id,shape_class,parent_name,results/outputs/NLD/base/area_potential_pv_rooftop.tif,results/outputs/NLD/base/area_potential_pv_open_field.tif,results/outputs/NLD/base/area_potential_wind_onshore.tif,results/outputs/NLD/base/area_potential_wind_offshore.tif
+0.0,NLD_overture_0850d5ed3fffffff01410bf814c95115,NLD,land,Zeeland,45614939.491241455,70568063.23730469,138924692.73242188,0.0
+1.0,NLD_overture_08500891bfffffff01caffd8afbb104e,NLD,land,Zuid-Holland,239411790.89245605,55707915.19970703,98879005.13964844,0.0
+2.0,NLD_overture_08506b42ffffffff01dad4872a9ad536,NLD,land,Noord-Brabant,261438655.82162476,58555851.94970703,114348744.1159668,0.0
+3.0,NLD_overture_0850503cffffffff01a6ec42c4a7a1fa,NLD,land,Utrecht,83359157.83892822,32028171.57373047,51261075.75830078,0.0
+4.0,NLD_overture_08524a277fffffff015d1e37b5c6abb2,NLD,land,Noord-Holland,170660031.9779663,50628361.48730469,92422923.20507812,0.0
+5.0,NLD_overture_085141db7fffffff010809a6ddfd85ce,NLD,land,Flevoland,36199708.75198364,56640749.30078125,111569143.37866211,0.0
+6.0,NLD_overture_0854e2ea3fffffff0161e67fa4077784,NLD,land,Fryslân,70711468.42324829,161790043.7783203,263544557.79711914,0.0
+7.0,NLD_overture_08518a6b7fffffff013c19db89489cbe,NLD,land,Limburg,123171626.34689331,21578642.947753906,44680078.654052734,0.0
+8.0,NLD_overture_08504091bfffffff01cc3ea32562a467,NLD,land,Gelderland,194579421.5802002,68436695.53027344,117513411.03979492,0.0
+9.0,NLD_overture_08522d863fffffff012b3bf2187a9c6c,NLD,land,Overijssel,113906781.70489502,73087938.67871094,124642033.91137695,0.0
+10.0,NLD_overture_085474bb3fffffff012829670273578e,NLD,land,Drenthe,54898098.48864746,70948774.9921875,134381847.76489258,0.0
+11.0,NLD_overture_0855cd063fffffff013415aa0479994d,NLD,land,Groningen,53845676.44485474,106020352.90917969,198487599.1689453,0.0
+12.0,NLD_marineregions_5668,NLD,maritime,Dutch Exclusive Economic Zone,0.0,0.0,0.0,37547919565.48047
diff --git a/unit_tests/conftest.py b/unit_tests/conftest.py
new file mode 100644
index 0000000..1c879c0
--- /dev/null
+++ b/unit_tests/conftest.py
@@ -0,0 +1,143 @@
+"""Pytest configuration for the unit test suite.
+
+Makes the workflow scripts importable (they are plain scripts, not a package)
+and provides the reference-data machinery: tests compare computed outputs
+against files committed under ``unit_tests/reference/``, which are regenerated
+with ``pytest unit_tests --update-reference`` (``pixi run update-reference-unit``).
+"""
+
+import os
+import sys
+from pathlib import Path
+
+# Scripts import matplotlib.pyplot at import time; force a headless backend
+# before any of them is imported.
+os.environ.setdefault("MPLBACKEND", "Agg")
+
+REPO_ROOT = Path(__file__).parent.parent
+sys.path.insert(0, str(REPO_ROOT / "workflow" / "scripts"))
+
+import fixtures # noqa: E402
+import numpy as np # noqa: E402
+import pandas as pd # noqa: E402
+import pytest # noqa: E402
+import yaml # noqa: E402
+
+REFERENCE_DIR = Path(__file__).parent / "reference"
+
+
+def pytest_addoption(parser):
+ """Add the --update-reference flag."""
+ parser.addoption(
+ "--update-reference",
+ action="store_true",
+ default=False,
+ help="Write reference data from current outputs instead of comparing against it.",
+ )
+
+
+class ReferenceComparer:
+ """Compares computed outputs against committed reference files."""
+
+ def __init__(self, update):
+ """If ``update`` is True, checks write reference files instead of comparing."""
+ self.update = update
+
+ def check_arrays(self, name, arrays, rtol=1e-6, atol=0.0):
+ """Compare a dict of named arrays against ``.npz`` reference data.
+
+ Integer arrays must match exactly. Floating-point arrays are compared
+ with a small relative tolerance because the reference data is generated
+ on one platform but compared on all CI platforms, whose libm/SIMD
+ implementations of log/sin and GDAL warps differ in the last ulp.
+ """
+ path = REFERENCE_DIR / f"{name}.npz"
+ arrays = {key: np.asarray(value) for key, value in arrays.items()}
+ if self.update:
+ path.parent.mkdir(parents=True, exist_ok=True)
+ np.savez_compressed(path, **arrays)
+ return
+ assert path.exists(), (
+ f"Missing reference file {path}. Generate it with: pixi run update-reference-unit"
+ )
+ stored = np.load(path)
+ assert set(stored.files) == set(arrays), (
+ f"{name}: array names differ from reference: "
+ f"{sorted(arrays)} vs {sorted(stored.files)}"
+ )
+ for key, actual in arrays.items():
+ is_float = np.issubdtype(actual.dtype, np.floating)
+ np.testing.assert_allclose(
+ actual,
+ stored[key],
+ rtol=rtol if is_float else 0.0,
+ atol=atol if is_float else 0.0,
+ equal_nan=True,
+ err_msg=f"{name}:{key} differs from reference data",
+ )
+
+ def check_dataframe(self, name, csv_path, rtol=0.0):
+ """Compare a CSV file produced by a test against ``.csv`` reference data."""
+ path = REFERENCE_DIR / f"{name}.csv"
+ if self.update:
+ path.parent.mkdir(parents=True, exist_ok=True)
+ path.write_text(Path(csv_path).read_text())
+ return
+ assert path.exists(), (
+ f"Missing reference file {path}. Generate it with: pixi run update-reference-unit"
+ )
+ actual = pd.read_csv(csv_path, index_col=0)
+ stored = pd.read_csv(path, index_col=0)
+ pd.testing.assert_frame_equal(
+ actual, stored, check_exact=rtol == 0.0, rtol=rtol or 1e-15
+ )
+
+
+@pytest.fixture(scope="session")
+def reference(request):
+ """Reference-data comparer honouring the --update-reference flag."""
+ return ReferenceComparer(update=request.config.getoption("--update-reference"))
+
+
+@pytest.fixture(scope="session")
+def world(tmp_path_factory):
+ """Paths to the deterministic synthetic input dataset."""
+ return fixtures.write_world(tmp_path_factory.mktemp("world"))
+
+
+@pytest.fixture(scope="session")
+def wdpa_raster_path(world, tmp_path_factory):
+ """Protected-areas raster produced by the clip_and_rasterise_polys CLI."""
+ from clip_and_rasterise_polys import clip_and_rasterise_polys
+
+ path = tmp_path_factory.mktemp("wdpa") / "wdpa.tif"
+ fixtures.run_cli(
+ clip_and_rasterise_polys,
+ [world["shapes"], world["landcover"], world["protected"], path],
+ )
+ return path
+
+
+@pytest.fixture(scope="session")
+def resampled_path(world, wdpa_raster_path, tmp_path_factory):
+ """Resampled input NetCDF produced by the resample CLI."""
+ from resample import resample_inputs
+
+ directory = tmp_path_factory.mktemp("resampled")
+ path = directory / "resampled.nc"
+ fixtures.run_cli(
+ resample_inputs,
+ [
+ world["shapes"],
+ world["landcover"],
+ world["slope"],
+ world["settlement"],
+ world["bathymetry"],
+ wdpa_raster_path,
+ yaml.dump(fixtures.LAND_COVER_TYPES),
+ path,
+ "--ship-travel-path",
+ world["ship_travel"],
+ ],
+ )
+ return path
diff --git a/unit_tests/fixtures.py b/unit_tests/fixtures.py
new file mode 100644
index 0000000..e60fade
--- /dev/null
+++ b/unit_tests/fixtures.py
@@ -0,0 +1,179 @@
+"""Deterministic synthetic geodata used by the unit tests.
+
+All builders are seeded so that repeated test runs (and the committed reference
+data) are reproducible. The geography is a small area near the Dutch coast:
+two abutting land regions and one maritime region, with input rasters at
+resolutions mimicking the real datasets (land cover 10 arcsec as the reference
+grid; slope finer; settlement and bathymetry coarser).
+"""
+
+from pathlib import Path
+
+import geopandas as gpd
+import numpy as np
+import rioxarray as rxr
+import xarray as xr
+import yaml
+from click.testing import CliRunner
+from resample import GLOBCOVER_TYPES
+from shapely.geometry import box
+
+REPO_ROOT = Path(__file__).parent.parent
+LAND_COVER_TYPES = yaml.safe_load(
+ (REPO_ROOT / "workflow" / "internal" / "settings.yaml").read_text()
+)["land_cover_types"]
+
+# Three abutting regions of 0.05 x 0.1 degrees: two land, one maritime.
+SHAPES_BOUNDS = (5.0, 52.0, 5.15, 52.1)
+LANDCOVER_RESOLUTION = 1 / 360 # 10 arcsec, like GlobCover
+SLOPE_RESOLUTION = 1 / 450
+SETTLEMENT_RESOLUTION = 1 / 120 # 30 arcsec, like GHSL
+BATHYMETRY_RESOLUTION = 1 / 240 # 15 arcsec, like GEBCO
+SHIP_TRAVEL_RESOLUTION = 1 / 200
+SLOPE_NODATA = -32768
+SHIP_TRAVEL_NODATA = -1.0
+
+
+def run_cli(command, args):
+ """Invoke a click command in-process and assert it succeeded."""
+ result = CliRunner().invoke(
+ command, [str(arg) for arg in args], catch_exceptions=False
+ )
+ assert result.exit_code == 0, result.output
+ return result
+
+
+def load_raster(path):
+ """Load a raster into memory and close its backing file handle."""
+ with rxr.open_rasterio(path) as raster:
+ return raster.load()
+
+
+def make_shapes(include_subpixel_region=False):
+ """Return the region shapes as a GeoDataFrame matching ShapesSchema."""
+ records = [
+ ("region_a", "AAA", "land", box(5.0, 52.0, 5.05, 52.1)),
+ ("region_b", "AAA", "land", box(5.05, 52.0, 5.1, 52.1)),
+ ("region_sea", "AAA", "maritime", box(5.1, 52.0, 5.15, 52.1)),
+ ]
+ if include_subpixel_region:
+ # Far smaller than one land-cover pixel and placed away from any pixel
+ # center, so rasterisation burns no pixels for it.
+ records.append(
+ ("region_tiny", "AAA", "land", box(5.12, 52.05, 5.1201, 52.0501))
+ )
+ shape_ids, country_ids, shape_classes, geometries = zip(*records)
+ return gpd.GeoDataFrame(
+ {
+ "shape_id": list(shape_ids),
+ "country_id": list(country_ids),
+ "shape_class": list(shape_classes),
+ "parent_name": [f"Parent of {shape_id}" for shape_id in shape_ids],
+ "geometry": list(geometries),
+ },
+ crs="EPSG:4326",
+ )
+
+
+def grid_coords(resolution, pad_pixels=0, bounds=SHAPES_BOUNDS):
+ """Return (x, y) pixel-center coordinates covering ``bounds`` plus padding."""
+ xmin, ymin, xmax, ymax = bounds
+ pad = pad_pixels * resolution
+ x = np.arange(xmin - pad + resolution / 2, xmax + pad, resolution)
+ y = np.arange(ymax + pad - resolution / 2, ymin - pad, -resolution)
+ return x, y
+
+
+def make_raster(values, x, y, nodata=None):
+ """Wrap a 2D array into a (band, y, x) DataArray with CRS EPSG:4326."""
+ da = xr.DataArray(
+ np.asarray(values)[np.newaxis, ...],
+ coords={"band": [1], "y": y, "x": x},
+ dims=("band", "y", "x"),
+ )
+ da.rio.write_crs("EPSG:4326", inplace=True)
+ if nodata is not None:
+ da.rio.write_nodata(nodata, inplace=True)
+ return da
+
+
+def make_landcover(rng):
+ """Random land cover raster guaranteed to contain every GlobCover code.
+
+ Also contains the code 13, which is not a valid GlobCover code, to pin down
+ how unmapped codes are treated (they belong to no category).
+ """
+ codes = np.array(sorted(GLOBCOVER_TYPES) + [13], dtype=np.uint8)
+ x, y = grid_coords(LANDCOVER_RESOLUTION, pad_pixels=3)
+ values = rng.choice(codes, size=(len(y), len(x))).astype(np.uint8)
+ values[0, : len(codes)] = codes
+ return make_raster(values, x, y)
+
+
+def make_slope(rng):
+ """Random slope raster: int16 slope * 100, like GEDTM30, with nodata holes."""
+ x, y = grid_coords(SLOPE_RESOLUTION, pad_pixels=3)
+ values = rng.integers(0, 3000, size=(len(y), len(x))).astype(np.int16)
+ values[rng.random(values.shape) < 0.05] = SLOPE_NODATA
+ return make_raster(values, x, y, nodata=SLOPE_NODATA)
+
+
+def make_settlement(rng):
+ """Random settlement raster: built-up surface in m2 per pixel, like GHSL."""
+ x, y = grid_coords(SETTLEMENT_RESOLUTION, pad_pixels=3)
+ values = rng.uniform(0, 500_000, size=(len(y), len(x))).astype(np.float32)
+ values[rng.random(values.shape) < 0.6] = 0.0
+ return make_raster(values, x, y)
+
+
+def make_bathymetry(rng):
+ """Random bathymetry raster: int16 elevation in m, like GEBCO."""
+ x, y = grid_coords(BATHYMETRY_RESOLUTION, pad_pixels=3)
+ values = rng.integers(-80, 40, size=(len(y), len(x))).astype(np.int16)
+ return make_raster(values, x, y)
+
+
+def make_ship_travel(rng):
+ """Random ship traffic density raster (AIS position counts) with nodata."""
+ x, y = grid_coords(SHIP_TRAVEL_RESOLUTION, pad_pixels=3)
+ values = rng.integers(0, 50_000, size=(len(y), len(x))).astype(np.float32)
+ values[rng.random(values.shape) < 0.3] = 0.0
+ values[rng.random(values.shape) < 0.05] = SHIP_TRAVEL_NODATA
+ return make_raster(values, x, y, nodata=SHIP_TRAVEL_NODATA)
+
+
+def make_protected_areas():
+ """Two protected-area polygons inside region_a."""
+ return gpd.GeoDataFrame(
+ {
+ "site_name": ["site_1", "site_2"],
+ "geometry": [
+ box(5.005, 52.010, 5.020, 52.040),
+ box(5.025, 52.050, 5.040, 52.090),
+ ],
+ },
+ crs="EPSG:4326",
+ )
+
+
+def write_world(directory):
+ """Write the full synthetic input dataset and return a dict of paths."""
+ directory = Path(directory)
+ rng = np.random.default_rng(20260707)
+ paths = {
+ "shapes": directory / "shapes.parquet",
+ "landcover": directory / "landcover.tif",
+ "slope": directory / "slope.tif",
+ "settlement": directory / "settlement.tif",
+ "bathymetry": directory / "bathymetry.tif",
+ "ship_travel": directory / "ship_travel.tif",
+ "protected": directory / "protected.gpkg",
+ }
+ make_shapes().to_parquet(paths["shapes"])
+ make_landcover(rng).rio.to_raster(paths["landcover"])
+ make_slope(rng).rio.to_raster(paths["slope"])
+ make_settlement(rng).rio.to_raster(paths["settlement"])
+ make_bathymetry(rng).rio.to_raster(paths["bathymetry"])
+ make_ship_travel(rng).rio.to_raster(paths["ship_travel"])
+ make_protected_areas().to_file(paths["protected"], driver="GPKG")
+ return paths
diff --git a/unit_tests/reference/area_potential_binary_overlapping.npz b/unit_tests/reference/area_potential_binary_overlapping.npz
new file mode 100644
index 0000000..29e9e4e
Binary files /dev/null and b/unit_tests/reference/area_potential_binary_overlapping.npz differ
diff --git a/unit_tests/reference/area_potential_continuous_no_share.npz b/unit_tests/reference/area_potential_continuous_no_share.npz
new file mode 100644
index 0000000..3e4c159
Binary files /dev/null and b/unit_tests/reference/area_potential_continuous_no_share.npz differ
diff --git a/unit_tests/reference/area_potential_continuous_with_share.npz b/unit_tests/reference/area_potential_continuous_with_share.npz
new file mode 100644
index 0000000..c4588c4
Binary files /dev/null and b/unit_tests/reference/area_potential_continuous_with_share.npz differ
diff --git a/unit_tests/reference/area_potential_missing_layers_warn.npz b/unit_tests/reference/area_potential_missing_layers_warn.npz
new file mode 100644
index 0000000..b7622ff
Binary files /dev/null and b/unit_tests/reference/area_potential_missing_layers_warn.npz differ
diff --git a/unit_tests/reference/area_potential_offshore_buffer_epsg.npz b/unit_tests/reference/area_potential_offshore_buffer_epsg.npz
new file mode 100644
index 0000000..458791e
Binary files /dev/null and b/unit_tests/reference/area_potential_offshore_buffer_epsg.npz differ
diff --git a/unit_tests/reference/area_potential_offshore_buffer_utm.npz b/unit_tests/reference/area_potential_offshore_buffer_utm.npz
new file mode 100644
index 0000000..8ccefd4
Binary files /dev/null and b/unit_tests/reference/area_potential_offshore_buffer_utm.npz differ
diff --git a/unit_tests/reference/area_potential_offshore_ship_travel.npz b/unit_tests/reference/area_potential_offshore_ship_travel.npz
new file mode 100644
index 0000000..b391145
Binary files /dev/null and b/unit_tests/reference/area_potential_offshore_ship_travel.npz differ
diff --git a/unit_tests/reference/area_potential_override_merge.npz b/unit_tests/reference/area_potential_override_merge.npz
new file mode 100644
index 0000000..499f08a
Binary files /dev/null and b/unit_tests/reference/area_potential_override_merge.npz differ
diff --git a/unit_tests/reference/report.csv b/unit_tests/reference/report.csv
new file mode 100644
index 0000000..50bc12f
--- /dev/null
+++ b/unit_tests/reference/report.csv
@@ -0,0 +1,4 @@
+group,shape_id,country_id,shape_class,parent_name,area_potential_tech_a.tif,area_potential_tech_b.tif
+0.0,region_a,AAA,land,Parent of region_a,2437283.5775748244,2437438.2973064715
+1.0,region_b,AAA,land,Parent of region_b,2274233.103636447,2214124.083677837
+2.0,region_sea,AAA,maritime,Parent of region_sea,2264137.349540678,2239610.5665923944
diff --git a/unit_tests/reference/resample_output.npz b/unit_tests/reference/resample_output.npz
new file mode 100644
index 0000000..8ab5f3e
Binary files /dev/null and b/unit_tests/reference/resample_output.npz differ
diff --git a/unit_tests/reference/wdpa_raster.npz b/unit_tests/reference/wdpa_raster.npz
new file mode 100644
index 0000000..b339b34
Binary files /dev/null and b/unit_tests/reference/wdpa_raster.npz differ
diff --git a/unit_tests/test_cli_area_potential.py b/unit_tests/test_cli_area_potential.py
new file mode 100644
index 0000000..a7de08a
--- /dev/null
+++ b/unit_tests/test_cli_area_potential.py
@@ -0,0 +1,337 @@
+"""Reference and equivalence tests for the area_potential.py CLI.
+
+Two safety nets for the planned mask/factor rewrite:
+
+- reference tests pin the output rasters for configs covering every code path
+ (both initial areas, continuous min/max with and without share, binary layers
+ with value 0 / 1 / fractional, overlapping binary layers, buffering with a
+ fixed CRS and with UTM, config overrides, missing layers);
+- an oracle re-implementing the current *sequential* semantics is compared
+ bit-exactly against the CLI output, including on randomized configs.
+"""
+
+import fixtures
+import glom
+import numpy as np
+import pytest
+import xarray as xr
+import yaml
+from area_potential import get_area_potential
+
+BINARY_OVERLAPPING = {
+ "initial_area": "pixel_area",
+ "binary_layers": {
+ "regions_maritime": 0,
+ "regions_land": 1,
+ "protected": 0,
+ "landcover_FARM": 0.1,
+ "landcover_FOREST": 0,
+ "landcover_URBAN": 0,
+ "landcover_OTHER": 0.2,
+ "landcover_NOT_SUITABLE": 0,
+ "landcover_WATER": 0,
+ },
+}
+CONTINUOUS_WITH_SHARE = {
+ "initial_area": "settlement_area",
+ "continuous_layers": {"settlement_share": {"min": 0.001, "max": 1, "share": 0.8}},
+ "binary_layers": {"regions_maritime": 0, "regions_land": 1, "protected": 0},
+}
+CONTINUOUS_NO_SHARE = {
+ "initial_area": "pixel_area",
+ "continuous_layers": {"slope_deg": {"min": 0, "max": 10}},
+ "binary_layers": {"regions_land": 1, "protected": 0},
+}
+OFFSHORE_BUFFERED = {
+ "initial_area": "pixel_area",
+ "continuous_layers": {"bathymetry": {"min": -60, "max": 0, "share": 0.9}},
+ "binary_layers": {"regions_land": 0, "regions_maritime": 1},
+ "shapes_buffer": {"land": 1500},
+}
+OFFSHORE_SHIP_TRAVEL = {
+ "initial_area": "pixel_area",
+ "continuous_layers": {
+ "bathymetry": {"min": -80, "max": 0},
+ # Below the fixture's maximum traffic density, so busy pixels drop out
+ "ship_travel": {"min": 0, "max": 20000},
+ },
+ "binary_layers": {"regions_land": 0, "regions_maritime": 1},
+}
+MISSING_LAYERS = {
+ "initial_area": "pixel_area",
+ "continuous_layers": {"not_a_continuous_layer": {"min": 0, "max": 1}},
+ "binary_layers": {
+ "not_a_binary_layer": 0,
+ "also_missing": 1,
+ "regions_land": 1,
+ "protected": 0,
+ },
+}
+
+# case id -> (config, buffer_crs, override config or None)
+CASES = {
+ "binary_overlapping": (BINARY_OVERLAPPING, "epsg:8857", None),
+ "continuous_with_share": (CONTINUOUS_WITH_SHARE, "epsg:8857", None),
+ "continuous_no_share": (CONTINUOUS_NO_SHARE, "epsg:8857", None),
+ "offshore_buffer_epsg": (OFFSHORE_BUFFERED, "epsg:8857", None),
+ "offshore_buffer_utm": (OFFSHORE_BUFFERED, "utm", None),
+ "offshore_ship_travel": (OFFSHORE_SHIP_TRAVEL, "epsg:8857", None),
+ "override_merge": (
+ BINARY_OVERLAPPING,
+ "epsg:8857",
+ {"binary_layers": {"landcover_FARM": 0.5}},
+ ),
+ "missing_layers_warn": (MISSING_LAYERS, "epsg:8857", None),
+}
+UNBUFFERED_CASES = [case for case in CASES if "buffer" not in case]
+
+
+def _run_area_potential(world, resampled_path, tmp_path, config, buffer_crs, override):
+ """Run the CLI, returning (output DataArray, CLI output text)."""
+ tif_path = tmp_path / "area_potential.tif"
+ args = [world["shapes"], resampled_path, yaml.dump(config), buffer_crs, tif_path]
+ if override is not None:
+ args.append(f"--override_config={yaml.dump(override)}")
+ result = fixtures.run_cli(get_area_potential, args)
+ return fixtures.load_raster(tif_path), result.output
+
+
+def _parsed_config(config, override):
+ """The config exactly as the CLI sees it (YAML round-trip plus glom merge)."""
+ config = yaml.safe_load(yaml.dump(config))
+ if override is not None:
+ config = glom.merge([config, yaml.safe_load(yaml.dump(override))])
+ return config
+
+
+def sequential_area_potential(ds, config):
+ """Oracle mirroring the current sequential where-chain (without buffering).
+
+ The CLI writes float32 rasters, so oracle expectations are cast to float32
+ before comparison — bit-exactness is required at the output granularity.
+ """
+ potential = ds[config["initial_area"]].squeeze(drop=True)
+ binary_layers = config.get("binary_layers", {})
+ for layer, value in binary_layers.items():
+ if value == 0 and layer in ds:
+ potential = potential.where(~(ds[layer] > 0), other=0)
+ for layer, layer_config in config.get("continuous_layers", {}).items():
+ if layer in ds:
+ potential = potential.where(
+ (ds[layer] <= layer_config["max"]) & (ds[layer] >= layer_config["min"]),
+ other=0,
+ )
+ if "share" in layer_config:
+ potential = potential * layer_config["share"]
+ for layer, value in binary_layers.items():
+ if layer in ds and value != 0:
+ potential = xr.where(
+ ds[layer] != 0, potential * ds[layer] * value, potential
+ )
+ return potential
+
+
+@pytest.mark.parametrize("case_id", sorted(CASES))
+def test_area_potential_reference(case_id, world, resampled_path, tmp_path, reference):
+ """The output raster matches the committed reference data for each config."""
+ config, buffer_crs, override = CASES[case_id]
+ da, _ = _run_area_potential(
+ world, resampled_path, tmp_path, config, buffer_crs, override
+ )
+ reference.check_arrays(f"area_potential_{case_id}", {"values": da.values})
+
+
+@pytest.mark.parametrize("case_id", sorted(CASES))
+def test_area_potential_invariants(case_id, world, resampled_path, tmp_path):
+ """Output rasters are (band, y, x), NaN-free, non-negative, with nodata -1."""
+ config, buffer_crs, override = CASES[case_id]
+ da, _ = _run_area_potential(
+ world, resampled_path, tmp_path, config, buffer_crs, override
+ )
+ assert da.dims == ("band", "y", "x")
+ assert da.rio.nodata == -1
+ values = da.values
+ assert not np.isnan(values).any()
+ assert ((values >= 0) | (values == -1)).all()
+
+
+def test_area_potential_warns_on_missing_layers(world, resampled_path, tmp_path):
+ """Layers absent from the dataset are skipped with a warning."""
+ config, buffer_crs, override = CASES["missing_layers_warn"]
+ _, output = _run_area_potential(
+ world, resampled_path, tmp_path, config, buffer_crs, override
+ )
+ assert "Warning: Layer 'not_a_binary_layer' not found" in output
+ assert "Warning: Layer 'not_a_continuous_layer' not found" in output
+
+
+def test_area_potential_buffer_removes_nearshore_pixels(
+ world, resampled_path, tmp_path
+):
+ """Buffering land shapes clips pixels out of the offshore potential."""
+ config, buffer_crs, _ = CASES["offshore_buffer_epsg"]
+ buffered, _ = _run_area_potential(
+ world, resampled_path, tmp_path, config, buffer_crs, None
+ )
+ unbuffered_config = {k: v for k, v in config.items() if k != "shapes_buffer"}
+ unbuffered, _ = _run_area_potential(
+ world, resampled_path, tmp_path, unbuffered_config, buffer_crs, None
+ )
+ n_valid_buffered = int((buffered.values != -1).sum())
+ n_valid_unbuffered = int((unbuffered.values != -1).sum())
+ assert 0 < n_valid_buffered < n_valid_unbuffered
+
+
+@pytest.mark.parametrize("case_id", UNBUFFERED_CASES)
+def test_area_potential_matches_sequential_oracle(
+ case_id, world, resampled_path, tmp_path
+):
+ """CLI output equals the sequential oracle bit-for-bit (no buffering)."""
+ config, buffer_crs, override = CASES[case_id]
+ da, _ = _run_area_potential(
+ world, resampled_path, tmp_path, config, buffer_crs, override
+ )
+ with xr.open_dataset(resampled_path, decode_coords="all") as ds:
+ expected = sequential_area_potential(
+ ds.load(), _parsed_config(config, override)
+ )
+ expected = expected.transpose("band", "y", "x").fillna(-1.0)
+ np.testing.assert_array_equal(da.values, expected.values.astype(np.float32))
+
+
+def test_area_potential_inclusive_min_max_boundaries(world, resampled_path, tmp_path):
+ """Continuous min/max bounds are inclusive.
+
+ The bounds are taken from exact data values, so that an accidental switch
+ to strict comparisons in a rewrite changes the output and fails this test.
+ """
+ with xr.open_dataset(resampled_path, decode_coords="all") as ds:
+ ds = ds.load()
+ slope = np.squeeze(ds["slope_deg"].values)
+ finite = np.unique(slope[np.isfinite(slope)])
+ config = {
+ "initial_area": "pixel_area",
+ "continuous_layers": {
+ "slope_deg": {"min": float(finite[1]), "max": float(finite[-2])}
+ },
+ "binary_layers": {"protected": 0},
+ }
+ da, _ = _run_area_potential(
+ world, resampled_path, tmp_path, config, "epsg:8857", None
+ )
+ expected = sequential_area_potential(ds, _parsed_config(config, None))
+ expected = expected.transpose("band", "y", "x").fillna(-1.0)
+ np.testing.assert_array_equal(da.values, expected.values.astype(np.float32))
+ # Pixels lying exactly on the bounds must survive the min/max filter.
+ values = np.squeeze(da.values)
+ on_boundary = (slope == finite[1]) | (slope == finite[-2])
+ assert (values[on_boundary] > 0).any()
+
+
+def _random_config(rng, ds):
+ """A random but valid tech config referencing existing layers."""
+ binary_pool = sorted(
+ name
+ for name in ds.data_vars
+ if name.startswith("landcover_")
+ or name in ["regions_land", "regions_maritime", "protected"]
+ )
+ continuous_pool = ["slope_deg", "settlement_share", "bathymetry", "ship_travel"]
+ config = {
+ "initial_area": str(rng.choice(["pixel_area", "settlement_area"])),
+ # Always include one banded layer: the CLI requires the band dimension
+ # to be broadcast back into the potential.
+ "binary_layers": {"landcover_FARM": float(rng.choice([0.0, 1.0, 0.3]))},
+ }
+ for layer in rng.choice(binary_pool, size=3, replace=False):
+ config["binary_layers"][str(layer)] = float(rng.choice([0.0, 1.0, 0.3, 2.0]))
+ config["continuous_layers"] = {}
+ for layer in rng.choice(
+ continuous_pool, size=int(rng.integers(1, 3)), replace=False
+ ):
+ low, high = np.nanquantile(ds[str(layer)].values, [0.2, 0.8])
+ layer_config = {"min": float(low), "max": float(high)}
+ if rng.random() < 0.5:
+ layer_config["share"] = float(rng.uniform(0.1, 0.9))
+ config["continuous_layers"][str(layer)] = layer_config
+ return config
+
+
+@pytest.mark.parametrize("seed", range(4))
+def test_area_potential_matches_sequential_oracle_randomized(
+ seed, world, resampled_path, tmp_path
+):
+ """Randomized configs also agree with the sequential oracle bit-for-bit."""
+ with xr.open_dataset(resampled_path, decode_coords="all") as ds:
+ ds = ds.load()
+ config = _random_config(np.random.default_rng(seed), ds)
+ da, _ = _run_area_potential(
+ world, resampled_path, tmp_path, config, "epsg:8857", None
+ )
+ expected = sequential_area_potential(ds, _parsed_config(config, None))
+ expected = expected.transpose("band", "y", "x").fillna(-1.0)
+ np.testing.assert_array_equal(da.values, expected.values.astype(np.float32))
+
+
+def test_area_potential_all_excluded(world, resampled_path, tmp_path):
+ """A config whose criteria exclude every pixel yields an all-zero raster."""
+ config = {
+ "initial_area": "pixel_area",
+ # No slope value lies in this range, so every pixel is zeroed out
+ # (pixels with NaN slope fail the comparison as well).
+ "continuous_layers": {"slope_deg": {"min": 1e9, "max": 2e9}},
+ "binary_layers": {"landcover_FARM": 1},
+ }
+ da, _ = _run_area_potential(
+ world, resampled_path, tmp_path, config, "epsg:8857", None
+ )
+ with xr.open_dataset(resampled_path, decode_coords="all") as ds:
+ expected = sequential_area_potential(ds.load(), _parsed_config(config, None))
+ expected = expected.transpose("band", "y", "x").fillna(-1.0)
+ np.testing.assert_array_equal(da.values, expected.values.astype(np.float32))
+ assert (da.values == 0).all()
+
+
+def test_area_potential_tiny_grid(world, resampled_path, tmp_path):
+ """The CLI works on a 2x2-pixel dataset and agrees with the oracle."""
+ with xr.open_dataset(resampled_path, decode_coords="all") as ds:
+ ds = ds.load()
+ # Anchor on a land pixel so that the potential is non-trivial.
+ y_idx, x_idx = np.argwhere(np.squeeze(ds["regions_land"].values) == 1)[0]
+ tiny = ds.isel(y=slice(y_idx, y_idx + 2), x=slice(x_idx, x_idx + 2))
+ tiny_path = tmp_path / "tiny.nc"
+ tiny.to_netcdf(tiny_path)
+ config = {
+ "initial_area": "pixel_area",
+ "continuous_layers": {"slope_deg": {"min": 0, "max": 90, "share": 0.5}},
+ "binary_layers": {"regions_land": 1, "landcover_FARM": 0.3},
+ }
+ da, _ = _run_area_potential(world, tiny_path, tmp_path, config, "epsg:8857", None)
+ assert da.shape == (1, 2, 2)
+ expected = sequential_area_potential(tiny, _parsed_config(config, None))
+ expected = expected.transpose("band", "y", "x").fillna(-1.0)
+ np.testing.assert_array_equal(da.values, expected.values.astype(np.float32))
+
+
+def test_area_potential_ship_travel_excludes_busy_pixels(
+ world, resampled_path, tmp_path
+):
+ """A ship_travel criterion removes maritime pixels with dense traffic."""
+ config, buffer_crs, _ = CASES["offshore_ship_travel"]
+ with_layer, _ = _run_area_potential(
+ world, resampled_path, tmp_path, config, buffer_crs, None
+ )
+ without_config = {
+ **config,
+ "continuous_layers": {
+ k: v for k, v in config["continuous_layers"].items() if k != "ship_travel"
+ },
+ }
+ without_layer, _ = _run_area_potential(
+ world, resampled_path, tmp_path, without_config, buffer_crs, None
+ )
+ with_values, without_values = with_layer.values, without_layer.values
+ # The criterion can only take potential away, never add it...
+ assert (with_values <= without_values).all()
+ # ...and in the fixture it does take some away.
+ assert (with_values > 0).sum() < (without_values > 0).sum()
diff --git a/unit_tests/test_cli_breakup.py b/unit_tests/test_cli_breakup.py
new file mode 100644
index 0000000..2c69941
--- /dev/null
+++ b/unit_tests/test_cli_breakup.py
@@ -0,0 +1,49 @@
+"""Tests for the breakup_shape.py CLI."""
+
+import fixtures
+import geopandas as gpd
+import pandas as pd
+import pytest
+from breakup_shape import breakup_shape
+from shapely.geometry import box
+
+
+@pytest.fixture
+def two_country_shapes():
+ """Four regions across two countries."""
+ shapes = fixtures.make_shapes()
+ extra = gpd.GeoDataFrame(
+ {
+ "shape_id": ["region_c"],
+ "country_id": ["BBB"],
+ "shape_class": ["land"],
+ "parent_name": ["Parent of region_c"],
+ "geometry": [box(6.0, 52.0, 6.1, 52.1)],
+ },
+ crs="EPSG:4326",
+ )
+ return pd.concat([shapes, extra], ignore_index=True)
+
+
+def test_breakup_shape_splits_by_column(two_country_shapes, tmp_path):
+ """Splitting by country_id writes one parquet file per country."""
+ shapes_path = tmp_path / "shapes.parquet"
+ two_country_shapes.to_parquet(shapes_path)
+ output_path = tmp_path / "subunits"
+ fixtures.run_cli(breakup_shape, [shapes_path, "country_id", output_path])
+ assert sorted(path.name for path in output_path.iterdir()) == [
+ "AAA.parquet",
+ "BBB.parquet",
+ ]
+ assert len(gpd.read_parquet(output_path / "AAA.parquet")) == 3
+ assert len(gpd.read_parquet(output_path / "BBB.parquet")) == 1
+
+
+def test_breakup_shape_split_by_none(two_country_shapes, tmp_path):
+ """split_by 'none' writes everything to a single all.parquet."""
+ shapes_path = tmp_path / "shapes.parquet"
+ two_country_shapes.to_parquet(shapes_path)
+ output_path = tmp_path / "subunits"
+ fixtures.run_cli(breakup_shape, [shapes_path, "none", output_path])
+ assert [path.name for path in output_path.iterdir()] == ["all.parquet"]
+ assert len(gpd.read_parquet(output_path / "all.parquet")) == 4
diff --git a/unit_tests/test_cli_clip_rasterise.py b/unit_tests/test_cli_clip_rasterise.py
new file mode 100644
index 0000000..cfb4ce5
--- /dev/null
+++ b/unit_tests/test_cli_clip_rasterise.py
@@ -0,0 +1,47 @@
+"""Reference tests for the clip_and_rasterise_polys CLI.
+
+Guards the planned switch to bbox-filtered vector reading: the output raster
+for the synthetic protected areas must stay identical.
+"""
+
+import fixtures
+import geopandas as gpd
+import numpy as np
+from clip_and_rasterise_polys import clip_and_rasterise_polys
+
+
+def test_wdpa_raster_reference(wdpa_raster_path, reference):
+ """The rasterised protected areas match the committed reference data."""
+ da = fixtures.load_raster(wdpa_raster_path)
+ reference.check_arrays(
+ "wdpa_raster", {"values": da.values, "x": da.x.values, "y": da.y.values}
+ )
+
+
+def test_wdpa_raster_marks_protected_pixels(wdpa_raster_path, world):
+ """Pixels inside the protected polygons carry values from the reference raster."""
+ da = fixtures.load_raster(wdpa_raster_path).squeeze(drop=True)
+ # Pixel centers inside the first protected polygon (5.005..5.020, 52.010..52.040)
+ inside = da.sel(x=slice(5.006, 5.019), y=slice(52.039, 52.011))
+ assert inside.size > 0
+ assert np.count_nonzero(inside.values) == inside.size
+
+
+def test_wdpa_raster_reprojected_source(world, tmp_path):
+ """Polygons in another CRS give the same raster (boxes stay boxes in Mercator)."""
+ reprojected = tmp_path / "protected_3857.gpkg"
+ gpd.read_file(world["protected"]).to_crs("EPSG:3857").to_file(
+ reprojected, driver="GPKG"
+ )
+ fixtures.run_cli(
+ clip_and_rasterise_polys,
+ [world["shapes"], world["landcover"], reprojected, tmp_path / "wdpa.tif"],
+ )
+ fixtures.run_cli(
+ clip_and_rasterise_polys,
+ [world["shapes"], world["landcover"], world["protected"], tmp_path / "ref.tif"],
+ )
+ np.testing.assert_array_equal(
+ fixtures.load_raster(tmp_path / "wdpa.tif").values,
+ fixtures.load_raster(tmp_path / "ref.tif").values,
+ )
diff --git a/unit_tests/test_cli_report.py b/unit_tests/test_cli_report.py
new file mode 100644
index 0000000..f77406b
--- /dev/null
+++ b/unit_tests/test_cli_report.py
@@ -0,0 +1,95 @@
+"""Reference and oracle tests for report.py.
+
+Guards the planned groupby-to-bincount rewrite of the per-region aggregation,
+including the edge cases that rewrite must preserve: nodata pixels (NaN after
+masking), pixels outside all regions, and a region too small to own any pixel.
+"""
+
+import fixtures
+import numpy as np
+import pandas as pd
+import pytest
+from rasterio.features import rasterize
+from report import report
+
+TECH_FILES = ["area_potential_tech_a.tif", "area_potential_tech_b.tif"]
+NODATA = -1.0
+
+
+def _write_potential_tif(path, rng):
+ """A synthetic area-potential raster with zeros and nodata patches."""
+ x, y = fixtures.grid_coords(fixtures.LANDCOVER_RESOLUTION)
+ values = rng.uniform(0, 1e4, size=(len(y), len(x)))
+ values[rng.random(values.shape) < 0.2] = 0.0
+ values[rng.random(values.shape) < 0.1] = NODATA
+ da = fixtures.make_raster(values, x, y, nodata=NODATA)
+ da.rio.to_raster(path)
+
+
+@pytest.fixture
+def report_outputs(tmp_path, monkeypatch):
+ """Run report() on synthetic tifs; returns (shapes, csv path, html path).
+
+ Runs in tmp_path with relative tif paths so that the tif-derived column
+ names in the CSV are stable for reference comparison.
+ """
+ monkeypatch.chdir(tmp_path)
+ shapes = fixtures.make_shapes(include_subpixel_region=True)
+ shapes.to_parquet("shapes.parquet")
+ rng = np.random.default_rng(42)
+ for tech_file in TECH_FILES:
+ _write_potential_tif(tech_file, rng)
+ report("shapes.parquet", TECH_FILES, "report.csv", "report.html")
+ return shapes, tmp_path / "report.csv", tmp_path / "report.html"
+
+
+def test_report_reference(report_outputs, reference):
+ """The report CSV matches the committed reference data."""
+ _, csv_path, _ = report_outputs
+ reference.check_dataframe("report", csv_path)
+
+
+def test_report_matches_naive_region_sums(report_outputs):
+ """Per-region sums equal an independent mask-based aggregation."""
+ shapes, csv_path, _ = report_outputs
+ df = pd.read_csv(csv_path, index_col=0)
+ for tech_file in TECH_FILES:
+ da = fixtures.load_raster(tech_file).squeeze(drop=True)
+ values = np.where(da.values == NODATA, np.nan, da.values)
+ regions = rasterize(
+ zip(shapes.geometry, shapes.index),
+ out_shape=da.rio.shape,
+ transform=da.rio.transform(),
+ fill=-9999,
+ )
+ for region_index in [0, 1, 2]:
+ expected = np.nansum(values[regions == region_index])
+ assert df.loc[region_index, tech_file] == pytest.approx(expected, rel=1e-12)
+
+
+def test_report_drops_pixel_free_regions(report_outputs):
+ """A region too small to own a pixel does not appear in the report."""
+ _, csv_path, _ = report_outputs
+ df = pd.read_csv(csv_path, index_col=0)
+ assert set(df.index) == {0.0, 1.0, 2.0}
+
+
+def test_report_metadata_columns(report_outputs):
+ """Shape metadata columns are aligned with the region raster indices."""
+ shapes, csv_path, _ = report_outputs
+ df = pd.read_csv(csv_path, index_col=0)
+ assert list(df.columns[:4]) == [
+ "shape_id",
+ "country_id",
+ "shape_class",
+ "parent_name",
+ ]
+ for region_index in [0, 1, 2]:
+ assert df.loc[region_index, "shape_id"] == shapes.loc[region_index, "shape_id"]
+
+
+def test_report_writes_html_with_total_row(report_outputs):
+ """The HTML report exists and contains the appended Total row."""
+ _, _, html_path = report_outputs
+ html = html_path.read_text()
+ assert "Total" in html
diff --git a/unit_tests/test_cli_resample.py b/unit_tests/test_cli_resample.py
new file mode 100644
index 0000000..32c99c9
--- /dev/null
+++ b/unit_tests/test_cli_resample.py
@@ -0,0 +1,107 @@
+"""Reference tests for the resample.py CLI on the synthetic world.
+
+This is the broadest guard for the resampling rewrite: it pins the variable
+set, the reference grid, dtypes and every resampled value.
+"""
+
+import fixtures
+import numpy as np
+import pytest
+import xarray as xr
+
+EXPECTED_VARIABLES = {
+ f"landcover_{category}" for category in set(fixtures.LAND_COVER_TYPES.values())
+} | {
+ "pixel_area",
+ "regions",
+ "regions_land",
+ "regions_maritime",
+ "slope_deg",
+ "settlement_share",
+ "settlement_area",
+ "bathymetry",
+ "protected",
+ "ship_travel",
+}
+
+
+@pytest.fixture(scope="module")
+def resampled(resampled_path):
+ """The resampled dataset, loaded into memory."""
+ with xr.open_dataset(resampled_path, decode_coords="all") as ds:
+ return ds.load()
+
+
+def test_resample_variable_set(resampled):
+ """All expected variables are present."""
+ assert set(resampled.data_vars) - {"spatial_ref"} == EXPECTED_VARIABLES
+
+
+def test_resample_grid_is_landcover_grid(resampled):
+ """The output grid is the land-cover grid clipped to the shapes' bounds."""
+ xmin, ymin, xmax, ymax = fixtures.SHAPES_BOUNDS
+ resolution = fixtures.LANDCOVER_RESOLUTION
+ x = resampled.x.values
+ y = resampled.y.values
+ assert np.allclose(np.diff(x), resolution)
+ assert np.allclose(np.diff(y), -resolution)
+ # clip_box keeps pixels that merely touch the bounds, so pixel centers may
+ # lie up to one resolution step outside them.
+ assert abs(x.min() - xmin) <= resolution
+ assert abs(x.max() - xmax) <= resolution
+ assert abs(y.min() - ymin) <= resolution
+ assert abs(y.max() - ymax) <= resolution
+
+
+def test_resample_region_masks(resampled):
+ """Land/maritime masks are 1 inside their regions and NaN elsewhere."""
+ regions = resampled["regions"].values
+ land = resampled["regions_land"].values
+ maritime = resampled["regions_maritime"].values
+ # regions 0 and 1 are land, region 2 is maritime (fixture ordering)
+ assert (land[np.isin(regions, [0.0, 1.0])] == 1).all()
+ assert np.isnan(land[regions == 2.0]).all()
+ assert (maritime[regions == 2.0] == 1).all()
+ assert np.isnan(maritime[np.isin(regions, [0.0, 1.0])]).all()
+
+
+def test_resample_reference_values(resampled, reference):
+ """Every resampled variable matches the committed reference data."""
+ arrays = {name: resampled[name].values for name in sorted(resampled.data_vars)}
+ arrays["x"] = resampled.x.values
+ arrays["y"] = resampled.y.values
+ reference.check_arrays("resample_output", arrays)
+
+
+# On-disk dtypes as written by the current pipeline (queried with
+# mask_and_scale=False). Any change here is a deliberate storage change.
+ON_DISK_DTYPES = {
+ "bathymetry": "float32",
+ "pixel_area": "float32",
+ "protected": "float32",
+ "regions": "float32",
+ "regions_land": "int8",
+ "regions_maritime": "int8",
+ "settlement_area": "float32",
+ "settlement_share": "float32",
+ "ship_travel": "float32",
+ "slope_deg": "float32",
+} | {
+ f"landcover_{category}": "int8"
+ for category in set(fixtures.LAND_COVER_TYPES.values())
+}
+
+
+def test_resample_on_disk_dtypes(resampled_path):
+ """Variables are stored on disk with the documented dtypes."""
+ with xr.open_dataset(resampled_path, mask_and_scale=False) as ds:
+ actual = {name: str(ds[name].dtype) for name in ds.data_vars}
+ actual.pop("spatial_ref", None)
+ assert actual == ON_DISK_DTYPES
+
+
+def test_resample_decoded_dtypes(resampled):
+ """No variable decodes as float64: masks are int8, everything else float32."""
+ for name in set(resampled.data_vars) - {"spatial_ref"}:
+ expected = np.int8 if name.startswith("landcover_") else np.float32
+ assert resampled[name].dtype == expected, name
diff --git a/unit_tests/test_geo.py b/unit_tests/test_geo.py
new file mode 100644
index 0000000..160b2af
--- /dev/null
+++ b/unit_tests/test_geo.py
@@ -0,0 +1,57 @@
+"""Unit tests for the UTM buffering helpers in _geo.py."""
+
+import geopandas as gpd
+import numpy as np
+import pyproj
+import pytest
+from _geo import apply_utm_buffer, get_utm_crs_from_lonlat
+from shapely.geometry import box
+
+GEOD = pyproj.Geod(ellps="WGS84")
+
+
+@pytest.mark.parametrize(
+ ("lon", "lat", "epsg"),
+ [
+ (5.0, 52.0, 32631),
+ # Norway exception: zone 32 is widened at 56-64N, so 5E is zone 32, not 31
+ (5.0, 60.0, 32632),
+ (5.0, -30.0, 32731),
+ (-70.0, 45.0, 32619),
+ ],
+)
+def test_get_utm_crs_from_lonlat(lon, lat, epsg):
+ """The UTM zone (including the Norway exception) is selected per centroid."""
+ assert get_utm_crs_from_lonlat(lon, lat).to_epsg() == epsg
+
+
+def _geodesic_area(geom):
+ """Unsigned geodesic area of a lon/lat geometry in m2."""
+ area, _ = GEOD.geometry_area_perimeter(geom)
+ return abs(area)
+
+
+def test_apply_utm_buffer_grows_geometries():
+ """Buffered geometries contain the originals and grow by roughly the right area."""
+ gdf = gpd.GeoDataFrame(
+ {"geometry": [box(5.0, 52.0, 5.1, 52.1), box(15.0, 48.0, 15.1, 48.1)]},
+ crs="EPSG:4326",
+ )
+ distance = 10_000
+ buffered = apply_utm_buffer(gdf, buffer_distance_m=distance)
+ assert buffered.crs == gdf.crs
+ for original, result in zip(gdf.geometry, buffered.geometry):
+ assert result.contains(original)
+ _, perimeter = GEOD.geometry_area_perimeter(original)
+ expected_area = (
+ _geodesic_area(original) + perimeter * distance + np.pi * distance**2
+ )
+ assert _geodesic_area(result) == pytest.approx(expected_area, rel=0.15)
+
+
+def test_apply_utm_buffer_out_of_range_returns_none():
+ """Geometries whose centroid has no UTM zone produce a warning and None."""
+ gdf = gpd.GeoDataFrame({"geometry": [box(5.0, 85.0, 5.1, 85.1)]}, crs="EPSG:4326")
+ with pytest.warns(UserWarning, match="Failed to buffer"):
+ buffered = apply_utm_buffer(gdf)
+ assert buffered.geometry.isna().all()
diff --git a/unit_tests/test_resample.py b/unit_tests/test_resample.py
new file mode 100644
index 0000000..f7622cc
--- /dev/null
+++ b/unit_tests/test_resample.py
@@ -0,0 +1,165 @@
+"""Unit tests for the pure functions in resample.py.
+
+These pin down current behaviour so that performance rewrites (land-cover
+lookup table, vectorised pixel areas) can be verified to be output-preserving.
+"""
+
+import fixtures
+import geopandas as gpd
+import numpy as np
+import pyproj
+import pytest
+import xarray as xr
+from resample import (
+ GLOBCOVER_TYPES,
+ _rasterize_regions,
+ aggregate_land_cover_types,
+ determine_pixel_areas,
+)
+from shapely.geometry import box
+
+
+def _landcover_da(values):
+ """Wrap a 2D uint8 array into a (band, y, x) DataArray like open_rasterio."""
+ values = np.asarray(values, dtype=np.uint8)
+ height, width = values.shape
+ return xr.DataArray(
+ values[np.newaxis, ...],
+ coords={
+ "band": [1],
+ "y": np.arange(height, dtype=float),
+ "x": np.arange(width, dtype=float),
+ },
+ dims=("band", "y", "x"),
+ )
+
+
+def _expected_masks(values, mapping):
+ """Independent oracle: per-category membership masks via np.isin."""
+ expected = {}
+ for category in sorted(set(mapping.values())):
+ codes = [
+ code for code, name in GLOBCOVER_TYPES.items() if mapping[name] == category
+ ]
+ expected[category] = np.isin(values, codes).astype(np.int8)
+ return expected
+
+
+def test_aggregate_land_cover_types_all_codes():
+ """Every GlobCover code lands in exactly the category configured for it."""
+ codes = np.array(sorted(GLOBCOVER_TYPES), dtype=np.uint8)
+ values = np.tile(codes, (3, 1))
+ result = aggregate_land_cover_types(
+ _landcover_da(values), fixtures.LAND_COVER_TYPES
+ )
+ expected = _expected_masks(values, fixtures.LAND_COVER_TYPES)
+ assert set(result.data_vars) == set(expected)
+ for category, mask in expected.items():
+ np.testing.assert_array_equal(np.squeeze(result[category].values), mask)
+ assert result[category].dtype == np.int8
+
+
+def test_aggregate_land_cover_types_unmapped_code():
+ """Codes not in GLOBCOVER_TYPES (here: 13) belong to no category."""
+ values = np.array([[13, 11, 13], [13, 13, 210]], dtype=np.uint8)
+ result = aggregate_land_cover_types(
+ _landcover_da(values), fixtures.LAND_COVER_TYPES
+ )
+ total = sum(np.squeeze(result[var].values) for var in result.data_vars)
+ np.testing.assert_array_equal(total, np.array([[0, 1, 0], [0, 0, 1]]))
+
+
+def test_aggregate_land_cover_types_empty_category():
+ """A configured category with no pixels yields an all-zero mask."""
+ values = np.full((4, 4), 14, dtype=np.uint8) # RAINFED_CROPLANDS -> FARM
+ result = aggregate_land_cover_types(
+ _landcover_da(values), fixtures.LAND_COVER_TYPES
+ )
+ assert np.squeeze(result["FARM"].values).all()
+ for category in set(fixtures.LAND_COVER_TYPES.values()) - {"FARM"}:
+ assert not result[category].values.any()
+
+
+@pytest.mark.parametrize("seed", range(5))
+def test_aggregate_land_cover_types_randomized(seed):
+ """Random rasters (including unmapped codes) match the np.isin oracle."""
+ rng = np.random.default_rng(seed)
+ codes = np.array(sorted(GLOBCOVER_TYPES) + [13, 255], dtype=np.uint8)
+ values = rng.choice(codes, size=(17, 23))
+ result = aggregate_land_cover_types(
+ _landcover_da(values), fixtures.LAND_COVER_TYPES
+ )
+ for category, mask in _expected_masks(values, fixtures.LAND_COVER_TYPES).items():
+ np.testing.assert_array_equal(np.squeeze(result[category].values), mask)
+
+
+def test_aggregate_land_cover_types_custom_mapping():
+ """The mapping argument is respected, not just the internal defaults."""
+ mapping = {
+ name: ("LOW" if code < 100 else "HIGH")
+ for code, name in GLOBCOVER_TYPES.items()
+ }
+ rng = np.random.default_rng(7)
+ values = rng.choice(np.array(sorted(GLOBCOVER_TYPES), dtype=np.uint8), size=(9, 9))
+ result = aggregate_land_cover_types(_landcover_da(values), mapping)
+ assert set(result.data_vars) == {"LOW", "HIGH"}
+ for category, mask in _expected_masks(values, mapping).items():
+ np.testing.assert_array_equal(np.squeeze(result[category].values), mask)
+
+
+def _pixel_area_raster(resolution=0.5):
+ """A raster spanning 60N..60S used for pixel-area tests."""
+ x = np.arange(0, 2, resolution) + resolution / 2
+ y = np.arange(60, -60, -resolution) - resolution / 2
+ values = np.ones((len(y), len(x)), dtype=np.int8)
+ return fixtures.make_raster(values, x, y)
+
+
+def test_determine_pixel_areas_matches_geodesic():
+ """Pixel areas agree with exact geodesic areas from pyproj at various latitudes."""
+ resolution = 0.5
+ raster = _pixel_area_raster(resolution)
+ pixel_area = determine_pixel_areas(raster)
+ geod = pyproj.Geod(ellps="WGS84")
+ for lat in [59.75, 45.25, 0.25, -45.25, -59.75]:
+ # Densify the cell outline: pyproj measures geodesic edges, while the
+ # pixel is bounded by parallels, which are not geodesics.
+ cell = box(
+ 0, lat - resolution / 2, resolution, lat + resolution / 2
+ ).segmentize(resolution / 100)
+ expected_m2, _ = geod.geometry_area_perimeter(cell)
+ actual_m2 = float(pixel_area.sel(y=lat))
+ assert actual_m2 == pytest.approx(abs(expected_m2), rel=1e-6)
+
+
+def test_determine_pixel_areas_north_south_symmetric():
+ """Pixel areas are symmetric about the equator."""
+ pixel_area = determine_pixel_areas(_pixel_area_raster())
+ north = pixel_area.sel(y=45.25)
+ south = pixel_area.sel(y=-45.25)
+ assert float(north) == pytest.approx(float(south), rel=1e-12)
+
+
+def test_determine_pixel_areas_requires_wgs84():
+ """Non-WGS84 rasters are rejected."""
+ raster = _pixel_area_raster()
+ raster = raster.rio.write_crs("EPSG:3857")
+ with pytest.raises(AssertionError, match="EPSG:4326"):
+ determine_pixel_areas(raster)
+
+
+def test_rasterize_regions():
+ """Region indices are burned into the raster; uncovered pixels are NaN."""
+ resolution = 0.1
+ x = np.arange(0, 1, resolution) + resolution / 2
+ y = np.arange(1, 0, -resolution) - resolution / 2
+ reference = fixtures.make_raster(np.ones((len(y), len(x)), dtype=np.int8), x, y)
+ shapes = gpd.GeoDataFrame(
+ {"geometry": [box(0, 0, 0.4, 1), box(0.6, 0, 1, 1)]}, crs="EPSG:4326"
+ )
+ result = _rasterize_regions(shapes, reference)
+ assert result.dtype == np.float32
+ assert result.shape == (10, 10)
+ np.testing.assert_array_equal(result[:, :4], 0.0)
+ np.testing.assert_array_equal(result[:, 6:], 1.0)
+ assert np.isnan(result[:, 4:6]).all()
diff --git a/workflow/Snakefile b/workflow/Snakefile
index da99a40..ecbb410 100644
--- a/workflow/Snakefile
+++ b/workflow/Snakefile
@@ -30,7 +30,7 @@ with open(workflow.source_path("internal/settings.yaml"), "r") as f:
# Python files that are imported from other scripts and need to be included when accessing the module
workflow.source_path("scripts/_geo.py")
workflow.source_path("scripts/_schemas.py")
-workflow.source_path("scripts/_script_utils.py")
+workflow.source_path("scripts/_plots.py")
wildcard_constraints:
diff --git a/workflow/rules/automatic.smk b/workflow/rules/automatic.smk
index c81ce06..479d6a1 100644
--- a/workflow/rules/automatic.smk
+++ b/workflow/rules/automatic.smk
@@ -179,7 +179,8 @@ rule download_ship_travel:
"Download Global Ship Density for all vessel types."
shell:
"""
- curl -sSLo {output:q} {params.url:q} >{log:q} 2>&1
+ # The World Bank host resets HTTP/2 streams on large transfers (curl exit 92)
+ curl --http1.1 --retry 3 -sSLo {output:q} {params.url:q} >{log:q} 2>&1
"""
@@ -284,8 +285,12 @@ rule rasterise_clip_wdpa:
"/automatic/cutout/{shape}/wdpa.tif",
log:
"/{shape}/clip_wdpa.log",
+ benchmark:
+ "/{shape}/clip_wdpa.benchmark.tsv"
conda:
"../envs/module.yaml"
+ resources:
+ mem_mb=3000,
message:
"Rasterise and cut WDPA data to the bounds of the input shapefile, using the landcover raster as reference for the rasterisation."
shell:
diff --git a/workflow/rules/functions.smk b/workflow/rules/functions.smk
index d15c26b..f0c9122 100644
--- a/workflow/rules/functions.smk
+++ b/workflow/rules/functions.smk
@@ -13,10 +13,35 @@ def get_techs(wildcards):
def uses_ship_travel(wildcards):
- """Return whether a base tech or this subunit's overrides use ship travel."""
- tech_configs = list(config.get("techs", {}).values())
- tech_configs.extend(config.get("overrides", {}).get(wildcards.subunit, {}).values())
+ """Return whether any scenario's techs or this subunit's overrides use ship travel."""
+ tech_configs = []
+ for scenario in config["scenarios"].values():
+ tech_configs.extend(scenario["techs"].values())
+ tech_configs.extend(
+ scenario.get("overrides", {}).get(wildcards.subunit, {}).values()
+ )
return any(
"ship_travel" in tech_config.get("continuous_layers", {})
for tech_config in tech_configs
)
+
+
+def get_subunit_input_plots(wildcards):
+ checkpoint_output = checkpoints.breakup_shape.get(**wildcards).output[0]
+ return expand(
+ "/automatic/resampled_inputs/{{shape}}/{subunit}.png",
+ subunit=glob_wildcards(
+ os.path.join(checkpoint_output, "{subunit}.parquet")
+ ).subunit,
+ )
+
+
+def get_subunit_potential_plots(wildcards):
+ checkpoint_output = checkpoints.breakup_shape.get(**wildcards).output[0]
+ return expand(
+ "/{{shape}}/{{scenario}}/{subunit}/area_potential_{tech}.png",
+ subunit=glob_wildcards(
+ os.path.join(checkpoint_output, "{subunit}.parquet")
+ ).subunit,
+ tech=get_techs(wildcards),
+ )
diff --git a/workflow/rules/process.smk b/workflow/rules/process.smk
index 8905622..2820c0c 100644
--- a/workflow/rules/process.smk
+++ b/workflow/rules/process.smk
@@ -1,3 +1,9 @@
+# Note: memory reservations (mem_mb) are sized for country-sized subunits of ~150
+# million reference pixels (this covers e.g. Norway including its EEZ).
+# They only constrain scheduling when snakemake is given a limit:
+# `snakemake --resources mem_mb=`
+# Override per rule with `--set-resources` if needed.
+
import shlex
@@ -17,14 +23,15 @@ rule prepare_resampled_inputs:
),
output:
resampled_input="/automatic/resampled_inputs/{shape}/{subunit}.nc",
- plot=report(
- "/automatic/resampled_inputs/{shape}/{subunit}.png",
- category="resampled_input",
- ),
log:
"/{shape}/{subunit}/prepare_resampled_inputs.log",
+ benchmark:
+ "/{shape}/{subunit}/prepare_resampled_inputs.benchmark.tsv"
conda:
"../envs/module.yaml"
+ threads: 4
+ resources:
+ mem_mb=4500,
params:
# Use internal defaults if not overridden
land_cover_types_yaml_string=internal["land_cover_types"]
@@ -42,11 +49,33 @@ rule prepare_resampled_inputs:
"{input.shapes}/{wildcards.subunit}.parquet" \
{input.land_cover_path:q} {input.slope_path:q} {input.settlement_path:q} {input.bathymetry_path:q} {input.protected_area_path:q} \
{params.land_cover_types_yaml_string:q} \
- {output.resampled_input:q} {output.plot:q} \
- {params.ship_travel_arg} >{log:q} 2>&1
+ {output.resampled_input:q} \
+ --num-threads {threads} {params.ship_travel_arg} >{log:q} 2>&1
"""
+rule plot_resampled_inputs:
+ input:
+ rules.prepare_resampled_inputs.output.resampled_input,
+ output:
+ report(
+ "/automatic/resampled_inputs/{shape}/{subunit}.png",
+ category="resampled_input",
+ ),
+ log:
+ "/{shape}/{subunit}/plot_resampled_inputs.log",
+ benchmark:
+ "/{shape}/{subunit}/plot_resampled_inputs.benchmark.tsv"
+ conda:
+ "../envs/module.yaml"
+ resources:
+ mem_mb=3000,
+ message:
+ "Plot resampled inputs for {wildcards.subunit} in {wildcards.shape}."
+ script:
+ "../scripts/nc_to_png.py"
+
+
rule area_potential:
input:
script=workflow.source_path("../scripts/area_potential.py"),
@@ -54,20 +83,22 @@ rule area_potential:
resampled_path=rules.prepare_resampled_inputs.output.resampled_input,
output:
area_potential="/{shape}/{scenario}/{subunit}/area_potential_{tech}.tif",
- plot=report(
- "/{shape}/{scenario}/{subunit}/area_potential_{tech}.png",
- category="area_potential",
- ),
log:
"/{shape}/{scenario}/{subunit}/area_potential_{tech}.log",
+ benchmark:
+ "/{shape}/{scenario}/{subunit}/area_potential_{tech}.benchmark.tsv"
conda:
"../envs/module.yaml"
+ resources:
+ mem_mb=4200,
params:
config=lambda wildcards: config["scenarios"][f"{wildcards.scenario}"]["techs"][
f"{wildcards.tech}"
],
- subunit_override_config=lambda wildcards: config.get("overrides", {})
- .get(wildcards.scenario, {})
+ subunit_override_config=lambda wildcards: config["scenarios"][
+ wildcards.scenario
+ ]
+ .get("overrides", {})
.get(wildcards.subunit, {})
.get(wildcards.tech, {}),
buffer_crs=lambda wildcards: config["buffer_crs"],
@@ -75,10 +106,30 @@ rule area_potential:
"Compute area potential for the scenario {wildcards.scenario}, the tech {wildcards.tech} and {wildcards.subunit} in {wildcards.shape}."
shell:
"""
- python {input.script:q} "{input.shapes}/{wildcards.subunit}.parquet" {input.resampled_path:q} {params.config:q} {params.buffer_crs:q} {output.area_potential:q} {output.plot:q} --override_config={params.subunit_override_config:q} >{log:q} 2>&1
+ python {input.script:q} "{input.shapes}/{wildcards.subunit}.parquet" {input.resampled_path:q} {params.config:q} {params.buffer_crs:q} {output.area_potential:q} --override_config={params.subunit_override_config:q} >{log:q} 2>&1
"""
+rule plot_area_potential:
+ input:
+ rules.area_potential.output.area_potential,
+ output:
+ report(
+ "/{shape}/{scenario}/{subunit}/area_potential_{tech}.png",
+ category="area_potential",
+ ),
+ log:
+ "/{shape}/{scenario}/{subunit}/plot_area_potential_{tech}.log",
+ conda:
+ "../envs/module.yaml"
+ resources:
+ mem_mb=600,
+ message:
+ "Plot area potential for the tech {wildcards.tech} and {wildcards.subunit} in {wildcards.shape}."
+ script:
+ "../scripts/tif_to_png.py"
+
+
rule aggregate_area_potential:
input:
get_subunits,
@@ -86,13 +137,19 @@ rule aggregate_area_potential:
aggregated_area_potential="",
log:
"/{shape}/{scenario}/aggregate_area_potential_{tech}.log",
+ benchmark:
+ "/{shape}/{scenario}/aggregate_area_potential_{tech}.benchmark.tsv"
conda:
"../envs/module.yaml"
+ threads: 4
+ resources:
+ # gdalwarp is allowed up to 3 GB of cache and warp memory below
+ mem_mb=3500,
message:
"Aggregate area potential for the scenario {wildcards.scenario} and the tech {wildcards.tech} in {wildcards.shape}."
shell:
"""
- gdalwarp --config GDAL_CACHEMAX 3000 -wm 3000 -of GTiff -co COMPRESS=LZW {input} {output.aggregated_area_potential:q} >{log:q} 2>&1
+ gdalwarp --config GDAL_CACHEMAX 3000 -wm 3000 -multi -wo NUM_THREADS={threads} -of GTiff -co COMPRESS=LZW -co PREDICTOR=3 {input} {output.aggregated_area_potential:q} >{log:q} 2>&1
"""
@@ -108,6 +165,8 @@ rule plot_aggregated_area_potential:
"/{shape}/{scenario}/plot_aggregated_area_potential_{tech}.log",
conda:
"../envs/module.yaml"
+ resources:
+ mem_mb=600,
message:
"Plot aggregated area potential for the scenario {wildcards.scenario} and the tech {wildcards.tech} in {wildcards.shape}."
script:
@@ -126,6 +185,10 @@ rule area_potential_report:
"/{{shape}}/{{scenario}}/area_potential_{tech}.png",
tech=get_techs,
),
+ # Not used by the report itself: pulls in the per-subunit diagnostic
+ # plots, which run in parallel jobs off the area_potential critical path
+ resampled_input_plots=get_subunit_input_plots,
+ subunit_potential_plots=get_subunit_potential_plots,
output:
csv="/{shape}/{scenario}/area_potential_report.csv",
html=report(
@@ -134,8 +197,12 @@ rule area_potential_report:
),
log:
"/{shape}/{scenario}/area_potential_report.log",
+ benchmark:
+ "/{shape}/{scenario}/area_potential_report.benchmark.tsv"
conda:
"../envs/module.yaml"
+ resources:
+ mem_mb=4000,
message:
"Generate an overview report of the area potential for scenario {wildcards.scenario} for all techs in shapes {wildcards.shape}."
script:
diff --git a/workflow/scripts/_geo.py b/workflow/scripts/_geo.py
index 654d3a1..0750ffe 100644
--- a/workflow/scripts/_geo.py
+++ b/workflow/scripts/_geo.py
@@ -2,7 +2,6 @@
import warnings
-import geopandas as gpd
import utm
from pyproj import CRS
@@ -24,44 +23,13 @@ def get_utm_crs_from_lonlat(lon, lat):
return CRS.from_epsg(epsg_code)
-def utm_buffer(geom, buffer_distance_m=10000, source_crs="EPSG:4326"):
- """Project a geom to UTM, buffer it, then re-project to its source CRS.
-
- Args:
- geom (shapely.geometry): The geometry to buffer, in the given source_crs.
- buffer_distance_m (int): The buffer distance in meters (default is 10,000 m).
- source_crs (str): The source CRS of the geometry (default is "EPSG:4326").
-
- Returns:
- shapely.geometry: The buffered geometry in its original CRS.
-
- """
- try:
- centroid = geom.centroid
- lon, lat = centroid.x, centroid.y
- local_crs = get_utm_crs_from_lonlat(lon, lat)
-
- # Project to local UTM CRS
- gdf_single = gpd.GeoDataFrame(geometry=[geom], crs=source_crs)
- gdf_utm = gdf_single.to_crs(local_crs)
-
- # Buffer in meters
- gdf_utm["geometry"] = gdf_utm.buffer(buffer_distance_m)
-
- # Reproject back to WGS84
- gdf_buffered = gdf_utm.to_crs(source_crs)
- return gdf_buffered.iloc[0].geometry
-
- except Exception as e:
- warnings.warn(f"Failed to buffer geometry: {e}")
- return None
-
-
def apply_utm_buffer(gdf, buffer_distance_m=10000):
"""Apply a UTM-based buffer to a GeoDataFrame with an arbitrary CRS.
- The buffering will be performed row-by-row using the most appropriate UTM zone for
- each geometry's centroid.
+ The most appropriate UTM zone is chosen per geometry from its centroid.
+ Geometries are then grouped by UTM zone, and each group is projected, buffered
+ and re-projected in one vectorised operation. Geometries that cannot be buffered
+ (e.g. centroid outside the UTM latitude range) produce a warning and None.
Args:
gdf (geopandas.GeoDataFrame): The GeoDataFrame containing geometries to buffer.
@@ -73,7 +41,30 @@ def apply_utm_buffer(gdf, buffer_distance_m=10000):
"""
source_crs = gdf.crs
gdf_buffered = gdf.copy()
- gdf_buffered["geometry"] = gdf_buffered["geometry"].apply(
- lambda geom: utm_buffer(geom, buffer_distance_m, source_crs)
- )
+
+ zone_indices = {}
+ for index, geom in gdf_buffered["geometry"].items():
+ try:
+ centroid = geom.centroid
+ local_crs = get_utm_crs_from_lonlat(centroid.x, centroid.y)
+ except Exception as e:
+ warnings.warn(f"Failed to buffer geometry: {e}")
+ gdf_buffered.loc[index, "geometry"] = None
+ continue
+ zone_indices.setdefault(local_crs, []).append(index)
+
+ for local_crs, indices in zone_indices.items():
+ try:
+ buffered = (
+ gdf_buffered.loc[indices, "geometry"]
+ .set_crs(source_crs, allow_override=True)
+ .to_crs(local_crs)
+ .buffer(buffer_distance_m)
+ .to_crs(source_crs)
+ )
+ except Exception as e:
+ warnings.warn(f"Failed to buffer geometry: {e}")
+ buffered = None
+ gdf_buffered.loc[indices, "geometry"] = buffered
+
return gdf_buffered
diff --git a/workflow/scripts/_script_utils.py b/workflow/scripts/_plots.py
similarity index 82%
rename from workflow/scripts/_script_utils.py
rename to workflow/scripts/_plots.py
index b05ed67..a13cf89 100644
--- a/workflow/scripts/_script_utils.py
+++ b/workflow/scripts/_plots.py
@@ -1,4 +1,4 @@
-"""Utility functions."""
+"""Plotting helpers shared by the plotting scripts."""
import math
@@ -29,8 +29,9 @@ def random_categorical_cmap(n, base_cmap="tab20", seed=42):
def plot_with_zero_separate(ax, da, cmap="viridis", zero_color="#e0e0e0"):
"""Plot data array with zero values in a separate color."""
- da.where(da != 0).plot(ax=ax, cmap=cmap)
- da.where(da == 0).plot(
+ da = da.squeeze() # imshow needs 2D data, so size-1 dims (band) are squeezed
+ da.where(da != 0).plot.imshow(ax=ax, cmap=cmap)
+ da.where(da == 0).plot.imshow(
ax=ax, cmap=mcolors.ListedColormap([zero_color]), add_colorbar=False
)
return ax
@@ -38,8 +39,9 @@ def plot_with_zero_separate(ax, da, cmap="viridis", zero_color="#e0e0e0"):
def plot_all_dataset_variables(ds, ncols=2, savefig=None, categorical_vars=[]):
"""Plot all variables in an xarray dataset on a grid of plots."""
- # If needed, resample `ds` to fit within a maximum of `max_pixels` pixels
- max_pixels = 5000000
+ # If needed, resample `ds` to fit within a maximum of `max_pixels` pixels.
+ # 2 million pixels per panel is sufficient for our targeted plot sizes
+ max_pixels = 2000000
total_pixels = ds.sizes["y"] * ds.sizes["x"]
if total_pixels > max_pixels:
# Calculate the new resolution to fit within the max_pixels limit
@@ -82,9 +84,12 @@ def plot_all_dataset_variables(ds, ncols=2, savefig=None, categorical_vars=[]):
for j in range(i + 1, len(axes)):
axes[j].set_visible(False)
- plt.tight_layout()
+ fig.tight_layout()
if savefig:
- plt.savefig(savefig, dpi=300, bbox_inches="tight")
+ # This call contains two optimisations for speed:
+ # 1. fig.savefig (rather than plt.savefig) disables pyplot's post-save re-render.
+ # 2. Omitting bbox_inches="tight" skips a measurement pre-render step.
+ fig.savefig(savefig, dpi=300)
return fig
diff --git a/workflow/scripts/area_potential.py b/workflow/scripts/area_potential.py
index 31da213..1ff59a6 100644
--- a/workflow/scripts/area_potential.py
+++ b/workflow/scripts/area_potential.py
@@ -4,10 +4,8 @@
import click
import geopandas as gpd
import glom
-import matplotlib.pyplot as plt
import xarray as xr
import yaml
-from _script_utils import plot_with_zero_separate
@click.command()
@@ -16,16 +14,9 @@
@click.argument("config", type=str)
@click.argument("buffer_crs", type=str)
@click.argument("output_path", type=str)
-@click.argument("plot_path", type=str)
@click.option("--override_config", type=str)
def get_area_potential(
- shapes_path,
- resampled_path,
- config,
- buffer_crs,
- output_path,
- plot_path,
- override_config,
+ shapes_path, resampled_path, config, buffer_crs, output_path, override_config
):
"""Calculate the area potential based on the provided configuration.
@@ -35,7 +26,6 @@ def get_area_potential(
config (str): Configuration YAML string.
buffer_crs (str): Coordinate Reference System for buffering shapes.
output_path (str): Path to save the resulting area potential raster.
- plot_path (str): Path to save the plot of the area potential.
override_config (str): Configuration override YAML string.
Returns:
@@ -43,7 +33,9 @@ def get_area_potential(
"""
shapes = gpd.read_parquet(shapes_path)
- ds = xr.open_dataset(resampled_path, decode_coords="all")
+ # cache=False: layers are read when used and released afterwards instead
+ # of every touched layer staying resident for the whole run.
+ ds = xr.open_dataset(resampled_path, decode_coords="all", cache=False)
# NOTE: this is a workaround for the CRS not being set correctly, ideally this
# should not be necessary
ds.rio.write_crs(ds.spatial_ref.attrs["crs_wkt"], inplace=True)
@@ -56,30 +48,42 @@ def get_area_potential(
# Start with the configured pixel area as a base
potential_da = ds[config["initial_area"]].squeeze(drop=True) # Drop `band`
- # Zero out pixels from binary layers with share 0 from potential_da
+ # `keep` is a boolean "to keep"-mask used to accumulate all "zero-out" criteria, which
+ # can then be applied in a single .where() call at the very end
+ keep = None
+
+ def _all_of(mask, condition):
+ return condition if mask is None else mask & condition
+
+ # Zero out pixels from binary layers with share 0
binary_layers = config.get("binary_layers", {})
- zero_binary_layers = [layer for layer, value in binary_layers.items() if value == 0]
- for layer in zero_binary_layers:
+ for layer, value in binary_layers.items():
+ if value != 0:
+ continue
if layer in ds:
- potential_da = potential_da.where(~(ds[layer] > 0), other=0)
+ keep = _all_of(keep, ~(ds[layer] > 0))
else:
print(f"Warning: Layer '{layer}' not found in dataset. Skipping.")
- # Apply the continuous_layers criteria to zero out additional pixels
+ # Zero out pixels outside the min-max criteria of the continuous layers
continuous_layers = config.get("continuous_layers", {})
for layer, layer_config in continuous_layers.items():
if layer in ds:
- # Apply the min-max criteria
- potential_da = potential_da.where(
+ keep = _all_of(
+ keep,
(ds[layer] <= layer_config["max"]) & (ds[layer] >= layer_config["min"]),
- other=0,
)
- # If a share is defined, multiply the pixel area by the share
- if "share" in layer_config:
- potential_da = potential_da * layer_config["share"]
else:
print(f"Warning: Layer '{layer}' not found in dataset. Skipping.")
+ if keep is not None:
+ potential_da = potential_da.where(keep, other=0)
+
+ # If a share is defined for a continuous layer, multiply the pixel area by the share
+ for layer, layer_config in continuous_layers.items():
+ if layer in ds and "share" in layer_config:
+ potential_da = potential_da * layer_config["share"]
+
# Multiply pixels by their share from the binary layers
for layer, value in binary_layers.items():
if layer in ds:
@@ -102,27 +106,26 @@ def get_area_potential(
else:
buffer = shapes_subset.to_crs(buffer_crs).buffer(buffer_distance)
- # Clip the potential area with the buffered shapes
+ # Clip the potential area with the buffered shapes. drop=False keeps the
+ # output grid identical across techs - clipped-out pixels become nodata.
potential_da.rio.write_crs(ds.rio.crs, inplace=True)
buffer_geo = gpd.GeoDataFrame(geometry=buffer).to_crs(ds.rio.crs)
potential_da = potential_da.rio.clip(
- buffer_geo.geometry, buffer_geo.crs, invert=True
+ buffer_geo.geometry, buffer_geo.crs, invert=True, drop=False
)
potential_da.name = "area_potential"
potential_da = potential_da.transpose("band", "y", "x")
potential_da.rio.write_crs(ds.rio.crs, inplace=True)
- fig, ax = plt.subplots(1, 1)
- ax = plot_with_zero_separate(ax=ax, da=potential_da)
- plt.savefig(plot_path, bbox_inches="tight")
-
- # Fill NaN with a nodata value only after plotting
+ # Fill NaN with a nodata value and coerce to float32, which halves the file size
+ # while keeping the per-pixel error below 0.01
nodata_value = -1
- potential_da = potential_da.fillna(nodata_value)
+ potential_da = potential_da.fillna(nodata_value).astype("float32", copy=False)
potential_da.rio.write_nodata(nodata_value, inplace=True)
+ # PREDICTOR=3 improves LZW compression of float data
potential_da.rio.to_raster(
- output_path, driver="GTiff", compress="LZW", write_nodata=True
+ output_path, driver="GTiff", compress="LZW", predictor=3, write_nodata=True
)
diff --git a/workflow/scripts/breakup_shape.py b/workflow/scripts/breakup_shape.py
index 615eb4a..09731a3 100644
--- a/workflow/scripts/breakup_shape.py
+++ b/workflow/scripts/breakup_shape.py
@@ -18,7 +18,6 @@ def breakup_shape(shapes_path, split_by, output_path):
shapes_path (str): Path to the input shapes in the parquet format.
split_by (str): Column on which to split the shapes.
output_path (str): Path to save the resulting broken-up shapes.
- output_list_of_subunits (str): Path to save the list of subunits.
Returns:
None
@@ -28,12 +27,6 @@ def breakup_shape(shapes_path, split_by, output_path):
shapes = gpd.read_parquet(shapes_path)
shapes = ShapesSchema.validate(shapes)
- # Print rows where geometry is empty
- if shapes.geometry.is_empty.any():
- print("Warning: The following rows have empty geometries and will be removed:")
- print(shapes[shapes.geometry.is_empty])
- shapes = shapes[~shapes.geometry.is_empty]
-
if split_by == "none":
subunits = ["all"]
shapes.to_parquet(Path(output_path / "all.parquet"))
diff --git a/workflow/scripts/clip_and_rasterise_polys.py b/workflow/scripts/clip_and_rasterise_polys.py
index 448516e..b880764 100644
--- a/workflow/scripts/clip_and_rasterise_polys.py
+++ b/workflow/scripts/clip_and_rasterise_polys.py
@@ -1,8 +1,82 @@
-"""Subset to a bounding box and rasterise polygons."""
+"""Rasterise protected-area polygons onto the grid of a reference raster."""
import click
-import geopandas as gpd
+import numpy as np
+import pyogrio
+import pyproj
import rioxarray as rxr
+import xarray as xr
+from osgeo import gdal, gdal_array, ogr, osr
+from rasterio.warp import transform_bounds
+
+gdal.UseExceptions()
+ogr.UseExceptions()
+osr.UseExceptions()
+
+# Features per Arrow batch read from the vector source; each batch is burned
+# and released before the next one is read.
+BATCH_SIZE = 500
+
+
+def rasterise_polygons(polygons_path, reference_raster, batch_size=BATCH_SIZE):
+ """Burn the polygons intersecting the reference grid into a boolean mask.
+
+ This function streams the geometry of features intersecting the reference_raster's
+ bounds in Arrow batches. It turns each batch into OGR geometries and burns these
+ (via GDAL) into a raster that wraps a NumPy mask. By implementing this directly and
+ sidestepping rasterio's `rasterize`, memory use and computation time are greatly
+ reduced. Polygons in a different CRS are reprojected on the fly.
+
+ """
+ raster_crs = pyproj.CRS.from_user_input(reference_raster.rio.crs)
+ layer_crs = pyproj.CRS.from_user_input(pyogrio.read_info(polygons_path)["crs"])
+ bbox = transform_bounds(
+ raster_crs, layer_crs, *reference_raster.rio.bounds(), densify_pts=21
+ )
+
+ mask = np.zeros(reference_raster.rio.shape, dtype=np.uint8)
+ target = gdal_array.OpenNumPyArray(mask, True)
+ target.SetGeoTransform(reference_raster.rio.transform().to_gdal())
+ target.SetProjection(raster_crs.to_wkt())
+
+ def srs(crs):
+ result = osr.SpatialReference()
+ result.ImportFromWkt(crs.to_wkt())
+ result.SetAxisMappingStrategy(osr.OAMS_TRADITIONAL_GIS_ORDER)
+ return result
+
+ layer_srs, raster_srs = srs(layer_crs), srs(raster_crs)
+ reprojection = (
+ None
+ if layer_crs.equals(raster_crs)
+ else osr.CoordinateTransformation(layer_srs, raster_srs)
+ )
+
+ n_features = 0
+ with pyogrio.open_arrow(
+ polygons_path, bbox=bbox, columns=[], use_pyarrow=True, batch_size=batch_size
+ ) as (meta, reader):
+ for batch in reader:
+ wkbs = batch.column(meta["geometry_name"] or "wkb_geometry").to_pylist()
+ source = ogr.GetDriverByName("Memory").CreateDataSource("batch")
+ layer = source.CreateLayer("batch", raster_srs, ogr.wkbUnknown)
+ definition = layer.GetLayerDefn()
+ for wkb in wkbs:
+ if wkb is None:
+ continue
+ geometry = ogr.CreateGeometryFromWkb(wkb)
+ if reprojection is not None:
+ geometry.Transform(reprojection)
+ feature = ogr.Feature(definition)
+ feature.SetGeometry(geometry)
+ layer.CreateFeature(feature)
+ n_features += 1
+ gdal.RasterizeLayer(target, [1], layer, burn_values=[1])
+ del layer, source, wkbs
+ target.FlushCache()
+ del target
+ print(f"Protected areas intersecting the reference raster: {n_features}")
+ return mask.astype(bool)
@click.command()
@@ -13,21 +87,18 @@
def clip_and_rasterise_polys(
shapes_path, reference_raster_path, protected_area_path, output_path
):
- """Clip the polygons in SHAPES_PATH to the bounding box of the reference raster, and save the clipped polygons as a raster to OUTPUT_PATH."""
- shapes = gpd.read_parquet(shapes_path)
+ """Rasterise the polygons in PROTECTED_AREA_PATH onto reference raster grid.
+
+ A 0/1 uint8 raster on the full reference grid (1 = inside a polygon) is saved to
+ OUTPUT_PATH. SHAPES_PATH is accepted for interface compatibility but not used.
+ """
reference_raster = rxr.open_rasterio(reference_raster_path)
# FIXME: read the right layer(s) and deal with both poly and point layers
- xmin, ymin, xmax, ymax = shapes.total_bounds
- protected_areas = gpd.read_file(protected_area_path)
- print(f"Protected areas: {len(protected_areas)}")
- protected_areas = protected_areas.to_crs(shapes.crs)
- protected_areas = protected_areas.cx[xmin:xmax, ymin:ymax]
- print(f"Protected areas after applying total_bounds: {len(protected_areas)}")
-
- protected_raster = reference_raster.rio.clip(
- protected_areas.geometry, protected_areas.crs
- )
+ mask = rasterise_polygons(protected_area_path, reference_raster)
+ protected_raster = xr.zeros_like(reference_raster, dtype=np.uint8)
+ protected_raster.data[0] = mask
+ protected_raster.rio.write_nodata(None, inplace=True)
protected_raster.rio.to_raster(output_path, driver="GTiff", compress="LZW")
diff --git a/workflow/scripts/nc_to_png.py b/workflow/scripts/nc_to_png.py
new file mode 100644
index 0000000..897e695
--- /dev/null
+++ b/workflow/scripts/nc_to_png.py
@@ -0,0 +1,19 @@
+"""This script plots all variables of a NetCDF file to PNG format."""
+
+import sys
+
+import xarray as xr
+from _plots import plot_all_dataset_variables
+
+
+def nc_to_png(nc_file_in, png_file_out):
+ """Plot all variables of a NetCDF file on a grid of panels."""
+ # `plot_all_dataset_variables` reads one variable at a time, so setting
+ # cache=False here ensures that only one layer is in memory at a time.
+ with xr.open_dataset(nc_file_in, decode_coords="all", cache=False) as ds:
+ plot_all_dataset_variables(ds, ncols=3, savefig=png_file_out)
+
+
+if __name__ == "__main__":
+ sys.stderr = open(snakemake.log[0], "w", buffering=1)
+ nc_to_png(snakemake.input[0], snakemake.output[0])
diff --git a/workflow/scripts/report.py b/workflow/scripts/report.py
index f551b3c..2154ecc 100644
--- a/workflow/scripts/report.py
+++ b/workflow/scripts/report.py
@@ -3,44 +3,85 @@
import sys
import geopandas as gpd
+import numpy as np
import pandas as pd
-import rioxarray as rxr
-import xarray as xr
-from resample import _rasterize_regions
+import rasterio
+import rasterio.windows
+from rasterio.features import rasterize
+
+# Rows per processing window, which are full-width strips with the number of rows
+# defined here. The purpose of this is to bound memory use by iteratively aggregating
+# summary data one window at a time.
+ROWS_PER_WINDOW = 1024
def report(shapes, area_potentials, csv_path, html_path):
"""Generate a report summarizing area potentials for different technologies."""
shapes = gpd.read_parquet(shapes)
- print("Generating reference raster and rasterizing regions...")
- reference_raster = rxr.open_rasterio(area_potentials[0])
- regions = xr.DataArray(
- _rasterize_regions(shapes, reference_raster),
- dims=("y", "x"),
- coords={"y": reference_raster.y, "x": reference_raster.x},
- )
- # regions = xr.DataArray(("y", "x"), _rasterize_regions(shapes, reference_raster))
- del reference_raster
+ with rasterio.open(area_potentials[0]) as src:
+ reference_shape = (src.height, src.width)
+ reference_transform = src.transform
+ windows = [
+ rasterio.windows.Window(
+ 0, row, src.width, min(ROWS_PER_WINDOW, src.height - row)
+ )
+ for row in range(0, src.height, ROWS_PER_WINDOW)
+ ]
- # Collect the area potentials from the input files
- # Group the area potentials by regions, sum them up, and collect the resulting Series
- # into a DataFrame, where each column corresponds to a technology's area potential,
- # and the index corresponds to the regions.
- dataframes = []
- for area_potential_file in area_potentials:
- print(f"Processing area potential file: {area_potential_file}")
- da_area_potential = (
- rxr.open_rasterio(area_potential_file, mask_and_scale=True)
- .squeeze()
- .drop_vars(["band", "spatial_ref"])
+ # Sums (and pixel counts) per region are accumulated strip by strip: the
+ # region index is burned per strip and each technology mosaic is read per
+ # strip, so memory stays bounded by a strip instead of several full-size
+ # copies of a country-group mosaic. (Rasters small enough for one strip
+ # give bit-identical sums to a whole-raster aggregation.)
+ sums = {path: np.zeros(len(shapes)) for path in area_potentials}
+ pixel_counts = np.zeros(len(shapes), dtype=np.int64)
+ sources = [rasterio.open(path) for path in area_potentials]
+ try:
+ for src in sources:
+ # All technology mosaics must lie on the same grid, otherwise the
+ # region index would silently aggregate the wrong pixels.
+ assert (src.height, src.width) == reference_shape, (
+ f"Raster shape of {src.name} does not match {area_potentials[0]}"
+ )
+ assert src.transform == reference_transform, (
+ f"Raster transform of {src.name} does not match {area_potentials[0]}"
+ )
+ print(
+ f"Aggregating {len(area_potentials)} rasters over {len(windows)} windows..."
)
- df_ = da_area_potential.groupby(regions).sum().to_pandas()
- df_.name = area_potential_file
- dataframes.append(df_)
- del da_area_potential
+ for window in windows:
+ # Burn each shape's row position (-1 = no region) for this window
+ region_ids = rasterize(
+ zip(shapes.geometry, range(len(shapes))),
+ out_shape=(window.height, window.width),
+ transform=rasterio.windows.transform(window, reference_transform),
+ fill=-1,
+ dtype=np.int32,
+ ).ravel()
+ valid = region_ids >= 0
+ if not valid.any():
+ continue
+ region_ids = region_ids[valid]
+ pixel_counts += np.bincount(region_ids, minlength=len(shapes))
+ for path, src in zip(area_potentials, sources):
+ values = src.read(1, window=window, masked=True).ravel()[valid]
+ # nodata/NaN pixels contribute nothing (as the groupby-sum did)
+ weights = np.nan_to_num(values.filled(np.nan))
+ sums[path] += np.bincount(
+ region_ids, weights=weights, minlength=len(shapes)
+ )
+ finally:
+ for src in sources:
+ src.close()
+ columns = sums
- df = pd.concat(dataframes, axis=1)
+ # Drop shapes that received no pixel at all (smaller than the grid can
+ # resolve). Bincount reports them as 0.0, which would read as "no
+ # potential", when in fact nothing is known about them.
+ df = pd.DataFrame(columns, index=shapes.index.astype(float))
+ df = df[pixel_counts > 0].sort_index()
+ df.index.name = "group"
# Add metadata columns from shapes in front of the data columns
df.insert(0, "parent_name", shapes["parent_name"])
diff --git a/workflow/scripts/resample.py b/workflow/scripts/resample.py
index 3abdec0..7ba9303 100644
--- a/workflow/scripts/resample.py
+++ b/workflow/scripts/resample.py
@@ -1,16 +1,19 @@
"""This script resamples various geospatial datasets to a common shape and resolution."""
+import gc
import math
-import _script_utils
import click
import geopandas as gpd
import numpy as np
+import rasterio
import rioxarray as rxr
import xarray as xr
import yaml
from rasterio.enums import Resampling
from rasterio.features import rasterize
+from rasterio.warp import reproject
+from rasterio.windows import Window, from_bounds
# LAND COVER
# Original classification categories taken from GlobCover 2009 land cover.
@@ -44,23 +47,44 @@
}
-def aggregate_land_cover_types(ds_land_cover, land_cover_types):
- """Convert raw GlobCover data to a dataset with suitable land cover types."""
- suitable_land_cover = xr.Dataset(coords=ds_land_cover.coords)
+def land_cover_category_ids(ds_land_cover, land_cover_types):
+ """Map GlobCover codes to small category ids in one vectorised pass.
+
+ Returns ``(mapped, category_ids)``:
+ `mapped`: a uint8 array shaped like ds_land_cover, holding the `id` of
+ each pixel's category
+ `category_ids`: a dict mapping `category` to `id`
- # convert the input value to land cover type of interest
- for value in np.unique(ds_land_cover.data):
- if value in GLOBCOVER_TYPES:
- ds_land_cover = ds_land_cover.where(
- ds_land_cover != value,
- other=land_cover_types[GLOBCOVER_TYPES[value]],
- drop=False,
- )
+ Codes without a category (not in GLOBCOVER_TYPES) map to the sentinel 0
+ and belong to no category.
- # check if each pixel is in the list of suitable land cover types
- for type_ in sorted(list(set(land_cover_types.values()))):
- suitable_land_cover[type_] = (ds_land_cover == type_).astype(np.byte)
+ """
+ data = ds_land_cover.data
+ categories = sorted(set(land_cover_types.values()))
+ category_ids = {category: i for i, category in enumerate(categories, start=1)}
+ # Size the table from the dtype rather than data.max(): the latter would
+ # load and scan the whole raster just to build a 256-entry table.
+ lut = np.zeros(np.iinfo(data.dtype).max + 1, dtype=np.uint8)
+ for code, name in GLOBCOVER_TYPES.items():
+ lut[code] = category_ids[land_cover_types[name]]
+ return lut[data], category_ids
+
+
+def land_cover_mask(ds_land_cover, mapped, category_id):
+ """Return the 0/1 int8 membership mask of one land cover category."""
+ return xr.DataArray(
+ (mapped == category_id).astype(np.byte),
+ dims=ds_land_cover.dims,
+ coords=ds_land_cover.coords,
+ )
+
+def aggregate_land_cover_types(ds_land_cover, land_cover_types):
+ """Turn a GlobCover class raster into a Dataset of per-category membership masks."""
+ mapped, category_ids = land_cover_category_ids(ds_land_cover, land_cover_types)
+ suitable_land_cover = xr.Dataset(coords=ds_land_cover.coords)
+ for type_, category_id in category_ids.items():
+ suitable_land_cover[type_] = land_cover_mask(ds_land_cover, mapped, category_id)
return suitable_land_cover
@@ -71,9 +95,10 @@ def _area_of_pixel(pixel_size, center_lat):
Parameters:
pixel_size (float): length of side of pixel in degrees.
- center_lat (float): latitude of the center of the pixel. Note this
- value +/- half the `pixel-size` must not exceed 90/-90 degrees
- latitude or an invalid area will be calculated.
+ center_lat (float or np.ndarray): latitude of the center of the pixel
+ (scalar or array). Note this value +/- half the `pixel-size` must
+ not exceed 90/-90 degrees latitude or an invalid area will be
+ calculated.
Returns:
Area of square pixel of side length `pixel_size` centered at
@@ -83,16 +108,17 @@ def _area_of_pixel(pixel_size, center_lat):
a = 6378137 # meters
b = 6356752.3142 # meters
e = math.sqrt(1 - (b / a) ** 2)
- area_list = []
- for f in [center_lat + pixel_size / 2, center_lat - pixel_size / 2]:
- zm = 1 - e * math.sin(math.radians(f))
- zp = 1 + e * math.sin(math.radians(f))
- area_list.append(
- math.pi
- * b**2
- * (math.log(zp / zm) / (2 * e) + math.sin(math.radians(f)) / (zp * zm))
- )
- return pixel_size / 360.0 * (area_list[0] - area_list[1]) / 1e6
+
+ def zone_area(latitude):
+ sin_lat = np.sin(np.radians(latitude))
+ zm = 1 - e * sin_lat
+ zp = 1 + e * sin_lat
+ return np.pi * b**2 * (np.log(zp / zm) / (2 * e) + sin_lat / (zp * zm))
+
+ center_lat = np.asarray(center_lat)
+ upper = zone_area(center_lat + pixel_size / 2)
+ lower = zone_area(center_lat - pixel_size / 2)
+ return pixel_size / 360.0 * (upper - lower) / 1e6
def determine_pixel_areas(raster_input):
@@ -111,13 +137,126 @@ def determine_pixel_areas(raster_input):
"raster_input does not have the projection EPSG:4326"
)
resolution = raster_input.rio.resolution()[0] # resolution in degrees
- varea_of_pixel = np.vectorize(lambda lat: _area_of_pixel(resolution, lat))
- pixel_area = varea_of_pixel(raster_input.y) * 1000**2 # convert to m^2
+ pixel_area = _area_of_pixel(resolution, np.asarray(raster_input.y)) * 1000**2 # m^2
pixel_area_da = xr.DataArray(pixel_area, coords={"y": raster_input.y}, dims="y")
return pixel_area_da
+def _warp_from_file(
+ input_raster_path, reference_raster, prepare, num_threads=1, warp_nodata=None
+):
+ """Warp an input raster from file onto the reference grid with average resampling.
+
+ This function goes through the following procedure:
+
+ - Reads the window of ``input_raster_path`` covering the reference grid (plus a
+ two-pixel buffer) in its native dtype.
+ - Lets ``prepare(data, nodata, transform)`` turn it into the float32 array to
+ warp, and assigns NaN where there is no useful value.
+ - Warps the prepared array.
+
+ This process reduces the copies held in memory compared to xarray + reproject_match.
+
+ ``num_threads`` is passed on to GDAL's warp.
+
+ ``warp_nodata`` is the nodata value declared to GDAL. Set it to ``None``, ``"file"``
+ for the source file's own, or an explicit value. Declared nodata pixels
+ are excluded from the averages; any other NaN turns every target pixel it
+ touches into NaN.
+
+ Returns a float32 ``(band, y, x)`` DataArray on the reference grid, with
+ the reference CRS written and NaN wherever the warp produced no value.
+
+ """
+ with rasterio.open(input_raster_path) as src:
+ xmin, ymin, xmax, ymax = reference_raster.rio.bounds()
+ pad = 2 * max(abs(res) for res in src.res)
+ window = from_bounds(
+ xmin - pad, ymin - pad, xmax + pad, ymax + pad, transform=src.transform
+ )
+ window = window.round_offsets().round_lengths()
+ window = window.intersection(Window(0, 0, src.width, src.height))
+ data = src.read(1, window=window)
+ src_transform = src.window_transform(window)
+ src_crs = src.crs
+ src_nodata = src.nodata
+ data = prepare(data, src_nodata, src_transform)
+ assert data.dtype == np.float32
+ if isinstance(warp_nodata, str) and warp_nodata == "file":
+ warp_nodata = src_nodata
+ destination = np.full(reference_raster.rio.shape, np.nan, dtype=np.float32)
+ reproject(
+ source=data,
+ destination=destination,
+ src_transform=src_transform,
+ src_crs=src_crs,
+ src_nodata=warp_nodata,
+ dst_transform=reference_raster.rio.transform(),
+ dst_crs=reference_raster.rio.crs,
+ dst_nodata=np.nan,
+ resampling=Resampling.average,
+ num_threads=num_threads,
+ )
+ del data
+ warped = xr.DataArray(
+ destination[np.newaxis],
+ dims=("band", "y", "x"),
+ coords={"band": [1], "y": reference_raster.y, "x": reference_raster.x},
+ )
+ return warped.rio.write_crs(reference_raster.rio.crs, inplace=True)
+
+
+def _masked_float32(data, nodata, _transform, rows_per_chunk=1024):
+ """Native array to float32 with NaN where the source declares nodata.
+
+ Converted in row chunks so that no full-size temporary (e.g. the boolean
+ nodata mask) exists next to the input and output arrays.
+ """
+ out = np.empty(data.shape, dtype=np.float32)
+ for start in range(0, data.shape[0], rows_per_chunk):
+ rows = slice(start, start + rows_per_chunk)
+ out[rows] = data[rows]
+ if nodata is not None:
+ out[rows][data[rows] == nodata] = np.nan
+ return out
+
+
+class _NetcdfWriter:
+ """Write variables to a NetCDF file one at a time.
+
+ Holding every resampled layer in memory before a single ``to_netcdf`` would make
+ the peak memory of this script proportional to the *sum* of all outputs
+ (several GB for country-sized subunits). Appending variables as soon as
+ they are computed bounds it to the largest single layer pipeline instead.
+ """
+
+ def __init__(self, path):
+ self.path = path
+ self.mode = "w"
+
+ def write(self, name, da, dtype=None, fill_value=None):
+ encoding = {"zlib": True, "complevel": 1}
+ if dtype is not None:
+ encoding["dtype"] = dtype
+ if fill_value is not None:
+ encoding["_FillValue"] = fill_value
+ # Source rasters carry no-op scale_factor/add_offset attributes that
+ # would be written to the file and make the variable decode as float64
+ # downstream, doubling the memory of area_potential.py.
+ for attr in ["scale_factor", "add_offset"]:
+ da.attrs.pop(attr, None)
+ da.encoding.pop(attr, None)
+ da.to_dataset(name=name).to_netcdf(
+ self.path, mode=self.mode, encoding={name: encoding}
+ )
+ self.mode = "a"
+ # rioxarray caches its accessor on the array and the accessor points
+ # back at it, so large buffers are only released by the cyclic GC.
+ del da
+ gc.collect()
+
+
def _rasterize_regions(shapes, reference_raster):
regions = [(geom, idx) for idx, geom in zip(shapes.index, shapes.geometry)]
return rasterize(
@@ -138,8 +277,14 @@ def _rasterize_regions(shapes, reference_raster):
@click.argument("protected_area_path", type=str)
@click.argument("land_cover_configuration_yaml_string", type=str)
@click.argument("output_path", type=str)
-@click.argument("plot_path", type=str)
@click.option("--ship-travel-path", type=str)
+@click.option(
+ "--num-threads",
+ type=int,
+ default=1,
+ show_default=True,
+ help="Threads used by the GDAL warps (set from the rule's threads).",
+)
def resample_inputs(
shapes_path,
land_cover_path,
@@ -149,18 +294,20 @@ def resample_inputs(
protected_area_path,
land_cover_configuration_yaml_string,
output_path,
- plot_path,
ship_travel_path,
+ num_threads,
):
"""Resample various geospatial datasets to a common shape and resolution.
- Results are saved to the specified output path in NetCDF format,
- and a plot of the resampled data is saved to the specified plot path.
+ Results are saved to the specified output path in NetCDF format.
+ (Plotting is a separate workflow step, so that downstream rules do not
+ wait for it: see nc_to_png.py.)
"""
shapes = gpd.read_parquet(shapes_path)
xmin, ymin, xmax, ymax = shapes.total_bounds
- resampled = xr.Dataset()
+ writer = _NetcdfWriter(output_path)
+ print("Saving results to output path:", output_path)
##
# Land cover
@@ -177,132 +324,171 @@ def resample_inputs(
reference_raster = xr.ones_like(ds_land_cover, dtype=np.byte)
reference_resolution = ds_land_cover.rio.resolution()
print(f"Land cover resolution used as reference resolution: {reference_resolution}")
- land_cover = aggregate_land_cover_types(ds_land_cover, land_cover_types)
- for land_type in sorted(list(set(land_cover_types.values()))):
- resampled[f"landcover_{land_type}"] = land_cover[land_type]
- del ds_land_cover, land_cover
+ # Below, we go through the different inputs one by one.
+ # The warped inputs come first. The slope warp is the largest single memory
+ # allocation of this script, and running it before anything else is
+ # resident in memory keeps the peak memory to that one stage.
##
- # Pixel area
+ # Slope: GEDTM30 stores degrees * 100 as uint16
##
-
- pixel_area = determine_pixel_areas(resampled)
- resampled["pixel_area"] = pixel_area.expand_dims({"x": resampled.x}).transpose(
- "y", "x"
+ def prepare_slope(data, nodata, transform):
+ out = _masked_float32(data, nodata, transform)
+ out /= 100
+ return out
+
+ writer.write(
+ "slope_deg",
+ _warp_from_file(slope_path, reference_raster, prepare_slope, num_threads),
+ dtype="float32",
)
- del pixel_area
##
- # Regions
+ # Settlement in sum of area of built-up surface (m2)
##
- shapes_land = shapes[shapes["shape_class"] == "land"].index
- shapes_maritime = shapes[shapes["shape_class"] == "maritime"].index
- print(f"Number of regions in input data: {len(shapes)}")
- print(f"Number of land regions: {len(shapes_land)}")
- print(f"Number of maritime regions: {len(shapes_maritime)}")
+ # One value per row (dims: y); broadcast against x only when written.
+ pixel_area = determine_pixel_areas(reference_raster).astype(np.float32)
- resampled["regions"] = (("y", "x"), _rasterize_regions(shapes, reference_raster))
+ def prepare_settlement(data, nodata, transform):
+ # Divide built-up surface (m2) by the source pixel area (m2) to get the
+ # built-up share; both operands float32 so the result stays float32.
+ # Pixel areas depend on latitude only (one value per row).
+ assert rasterio.crs.CRS.from_user_input(src_crs).to_epsg() == 4326, (
+ "settlement raster does not have the projection EPSG:4326"
+ )
+ rows = np.arange(data.shape[0])
+ centre_lat = transform.f + transform.e * (rows + 0.5)
+ pixel_area_m2 = (_area_of_pixel(abs(transform.a), centre_lat) * 1000**2).astype(
+ np.float32
+ )
+ return data.astype(np.float32) / pixel_area_m2[:, np.newaxis]
- mask_land = xr.DataArray(
- np.isin(resampled["regions"], shapes_land),
- dims=resampled["regions"].dims,
- coords=resampled["regions"].coords,
- )
- mask_maritime = xr.DataArray(
- np.isin(resampled["regions"], shapes_maritime),
- dims=resampled["regions"].dims,
- coords=resampled["regions"].coords,
+ with rasterio.open(settlement_path) as src:
+ src_crs = src.crs
+ print(f"Settlement resolution: {src.res}")
+ settlement_share = _warp_from_file(
+ settlement_path, reference_raster, prepare_settlement, num_threads
)
- resampled["regions_land"] = xr.where(mask_land, np.half(1.0), np.half(np.nan))
- resampled["regions_maritime"] = xr.where(
- mask_maritime, np.half(1.0), np.half(np.nan)
+ writer.write("settlement_share", settlement_share, dtype="float32")
+ writer.write(
+ "settlement_area",
+ (settlement_share * pixel_area).transpose(*settlement_share.dims),
+ dtype="float32",
)
- del mask_land, mask_maritime
+ del settlement_share
##
- # Slope
+ # Bathymetry: only keep values <= 0, i.e., below sea level
##
- da_slope = rxr.open_rasterio(slope_path, masked=True) / 100
- print(f"Slope resolution: {da_slope.rio.resolution()}")
- resampled["slope_deg"] = da_slope.rio.reproject_match(
- reference_raster, resampling=Resampling.average
+ def prepare_bathymetry(data, nodata, transform):
+ out = data.astype(np.float32)
+ out[out > 0] = np.nan
+ return out
+
+ writer.write(
+ "bathymetry",
+ _warp_from_file(
+ bathymetry_path,
+ reference_raster,
+ prepare_bathymetry,
+ num_threads,
+ warp_nodata="file",
+ ),
+ dtype="float32",
)
- del da_slope
##
- # Settlement in sum of area of built-up surface (m2)
+ # Protected areas (0/1 mask, becomes the protected fraction when averaged)
##
- ds_settlement = rxr.open_rasterio(settlement_path)
- print(f"Settlement resolution: {ds_settlement.rio.resolution()}")
-
- ds_settlement_pixel_area = (
- determine_pixel_areas(ds_settlement)
- .expand_dims({"x": ds_settlement.x})
- .transpose("y", "x")
+ def prepare_protected(data, nodata, transform):
+ return data.astype(np.float32)
+
+ writer.write(
+ "protected",
+ _warp_from_file(
+ protected_area_path,
+ reference_raster,
+ prepare_protected,
+ num_threads,
+ warp_nodata="file",
+ ),
+ dtype="float32",
)
- # Divide built-up surface (m2) by pixel area (m2) to get built-up surface density,
- # then reproject to match the reference raster
- resampled["settlement_share"] = (
- ds_settlement / ds_settlement_pixel_area
- ).rio.reproject_match(reference_raster, resampling=Resampling.average)
-
- resampled["settlement_area"] = (
- resampled["settlement_share"] * resampled["pixel_area"]
- )
- del ds_settlement, ds_settlement_pixel_area
-
##
- # Bathymetry
+ # Global shipping traffic density (AIS position counts per square kilometre)
##
-
- ds_bathymetry = rxr.open_rasterio(bathymetry_path)
- # Only keep values <= 0, i.e., below sea level
- ds_bathymetry = ds_bathymetry.where(ds_bathymetry <= 0, other=np.nan)
- print(f"Bathymetry resolution: {ds_bathymetry.rio.resolution()}")
- resampled["bathymetry"] = ds_bathymetry.rio.reproject_match(
- reference_raster, resampling=Resampling.average
- )
- del ds_bathymetry
+ if ship_travel_path:
+ writer.write(
+ "ship_travel",
+ _warp_from_file(
+ ship_travel_path,
+ reference_raster,
+ _masked_float32,
+ num_threads,
+ warp_nodata=np.nan,
+ ),
+ dtype="float32",
+ )
##
- # Protected areas
+ # Pixel area
##
- protected_areas = rxr.open_rasterio(protected_area_path)
- resampled["protected"] = protected_areas.rio.reproject_match(
- reference_raster, resampling=Resampling.average
+
+ writer.write(
+ "pixel_area",
+ pixel_area.expand_dims({"x": reference_raster.x})
+ .transpose("y", "x")
+ .rio.write_crs(reference_raster.rio.crs, inplace=True),
+ dtype="float32",
)
- del protected_areas
##
- # Global shipping traffic density (AIS position counts per square kilometre)
+ # Regions
##
- if ship_travel_path:
- ship_travel = rxr.open_rasterio(ship_travel_path, masked=True)
- print(f"Ship travel resolution: {ship_travel.rio.resolution()}")
- resampled["ship_travel"] = ship_travel.rio.reproject_match(
- reference_raster, resampling=Resampling.average
+
+ shapes_land = shapes[shapes["shape_class"] == "land"].index
+ shapes_maritime = shapes[shapes["shape_class"] == "maritime"].index
+ print(f"Number of regions in input data: {len(shapes)}")
+ print(f"Number of land regions: {len(shapes_land)}")
+ print(f"Number of maritime regions: {len(shapes_maritime)}")
+
+ regions = xr.DataArray(
+ _rasterize_regions(shapes, reference_raster),
+ dims=("y", "x"),
+ coords={"y": reference_raster.y, "x": reference_raster.x},
+ ).rio.write_crs(reference_raster.rio.crs, inplace=True)
+ writer.write("regions", regions)
+
+ # int8 with a fill value decodes as float32 (1 / NaN). No scale_factor or
+ # add_offset: even no-op ones make xarray decode the variable as float64.
+ for name, index in [
+ ("regions_land", shapes_land),
+ ("regions_maritime", shapes_maritime),
+ ]:
+ mask = xr.DataArray(
+ np.isin(regions, index), dims=regions.dims, coords=regions.coords
+ )
+ writer.write(
+ name,
+ xr.where(mask, np.half(1.0), np.half(np.nan)).rio.write_crs(
+ reference_raster.rio.crs, inplace=True
+ ),
+ dtype="int8",
+ fill_value=-128,
+ )
+ del mask
+ del regions
+
+ mapped, category_ids = land_cover_category_ids(ds_land_cover, land_cover_types)
+ for land_type, category_id in category_ids.items():
+ writer.write(
+ f"landcover_{land_type}",
+ land_cover_mask(ds_land_cover, mapped, category_id),
)
- del ship_travel
-
- netcdf4_encoding = {
- var: {"zlib": True, "complevel": 1}
- for var in resampled.data_vars
- if var not in ["spatial_ref", "band"]
- }
- for v in ["regions_land", "regions_maritime"]:
- netcdf4_encoding[v]["dtype"] = "int8"
- netcdf4_encoding[v]["scale_factor"] = 1
- netcdf4_encoding[v]["add_offset"] = 0
- netcdf4_encoding[v]["_FillValue"] = -128
-
- print("Saving result to output path:", output_path)
- resampled.to_netcdf(output_path, encoding=netcdf4_encoding)
-
- print("Saving image to plot path:", plot_path)
- _script_utils.plot_all_dataset_variables(resampled, ncols=3, savefig=plot_path)
+ del ds_land_cover, mapped
if __name__ == "__main__":
diff --git a/workflow/scripts/tif_to_png.py b/workflow/scripts/tif_to_png.py
index 645ee9e..3cc3522 100644
--- a/workflow/scripts/tif_to_png.py
+++ b/workflow/scripts/tif_to_png.py
@@ -1,16 +1,52 @@
"""This script plots a TIF file to PNG format."""
+import math
import sys
-import rioxarray as rxr
-from _script_utils import plot_all_dataset_variables
+import numpy as np
+import rasterio
+import rioxarray # noqa: F401 # activates the .rio accessor
+import xarray as xr
+from _plots import plot_all_dataset_variables
+from rasterio.enums import Resampling
+
+MAX_PIXELS = 2_000_000 # Matches the cap in plot_all_dataset_variables
+
+
+def read_decimated(tif_file, max_pixels=MAX_PIXELS):
+ """Read a single-band raster with at most ``max_pixels`` pixels in total.
+
+ Reading through GDAL's decimated I/O means that blocks are averaged on the fly.
+ Therefore, the full-resolution raster is never held in memory, saving GBs of RAM
+ on large plots.
+
+ Returns a float32 ``(y, x)`` DataArray with pixel-centre coordinates and the
+ raster's CRS, and NaN where the source has no data.
+
+ """
+ # Specify a block cache of 256 MB. GDAL would otherwise keep decoded blocks of the
+ # full-resolution raster around (default cache is 5% of RAM).
+ with rasterio.Env(GDAL_CACHEMAX=256), rasterio.open(tif_file) as src:
+ factor = max(1, math.ceil(math.sqrt(src.width * src.height / max_pixels)))
+ height, width = math.ceil(src.height / factor), math.ceil(src.width / factor)
+ data = src.read(
+ 1, out_shape=(height, width), resampling=Resampling.average, masked=True
+ )
+ transform = src.transform * src.transform.scale(
+ src.width / width, src.height / height
+ )
+ crs = src.crs
+ x = transform.c + transform.a * (np.arange(width) + 0.5)
+ y = transform.f + transform.e * (np.arange(height) + 0.5)
+ da = xr.DataArray(
+ data.filled(np.nan).astype(np.float32), dims=("y", "x"), coords={"y": y, "x": x}
+ )
+ return da.rio.write_crs(crs, inplace=True)
def tif_to_png(tif_file_in, png_file_out):
"""Convert a TIF file to PNG format."""
- ds = rxr.open_rasterio(tif_file_in, mask_and_scale=True).to_dataset(
- name=tif_file_in
- )
+ ds = read_decimated(tif_file_in).to_dataset(name=tif_file_in)
plot_all_dataset_variables(
ds, ncols=2, savefig=png_file_out, categorical_vars=["regions"]
)