First analysis

This commit is contained in:
Tobias Hölzer 2026-02-18 17:00:29 +01:00
parent f9df8e9fe6
commit a0cb298e8f
15 changed files with 3508 additions and 1227 deletions

210
pixi.lock generated
View file

@ -258,7 +258,7 @@ environments:
- pypi: https://files.pythonhosted.org/packages/31/4a/72dc383d1a0d14f1d453e334e3461e229762edb1bf3f75b3ab977e9386ed/arro3_core-0.6.5-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/31/4a/72dc383d1a0d14f1d453e334e3461e229762edb1bf3f75b3ab977e9386ed/arro3_core-0.6.5-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- pypi: https://files.pythonhosted.org/packages/1b/df/2a5a1306dc1699b51b02c1c38c55f3564a8c4f84087c23c61e7e7ae37dfa/arro3_io-0.6.5-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/1b/df/2a5a1306dc1699b51b02c1c38c55f3564a8c4f84087c23c61e7e7ae37dfa/arro3_io-0.6.5-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- pypi: https://files.pythonhosted.org/packages/c3/1c/f06ad85180e7dd9855aa5ede901bfc2be858d7bee17d4e978a14c0ecec14/astropy-7.2.0-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/c3/1c/f06ad85180e7dd9855aa5ede901bfc2be858d7bee17d4e978a14c0ecec14/astropy-7.2.0-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
- pypi: https://files.pythonhosted.org/packages/4e/67/6af8b422c04dec79c908cf60fdcd4725c3c112b2a058087c4ff58284a142/astropy_iers_data-0.2026.2.9.0.50.33-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/49/94/dcdac330d2c26776956555610ef584147584acc6b060e451aa65dd9142d9/astropy_iers_data-0.2026.2.16.0.48.25-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/d2/39/e7eaf1799466a4aef85b6a4fe7bd175ad2b1c6345066aa33f1f58d4b18d0/asttokens-3.0.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d2/39/e7eaf1799466a4aef85b6a4fe7bd175ad2b1c6345066aa33f1f58d4b18d0/asttokens-3.0.1-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/2d/1b/37d8a28965907d23eeba8bce56272932ee01176d192cefdf19a4a0b53c00/autogluon_common-1.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/2d/1b/37d8a28965907d23eeba8bce56272932ee01176d192cefdf19a4a0b53c00/autogluon_common-1.5.0-py3-none-any.whl
@ -270,6 +270,7 @@ environments:
- pypi: https://files.pythonhosted.org/packages/df/73/b6e24bd22e6720ca8ee9a85a0c4a2971af8497d8f3193fa05390cbd46e09/backoff-2.2.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/df/73/b6e24bd22e6720ca8ee9a85a0c4a2971af8497d8f3193fa05390cbd46e09/backoff-2.2.1-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/1a/39/47f9197bdd44df24d67ac8893641e16f386c984a0619ef2ee4c51fbbc019/beautifulsoup4-4.14.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/1a/39/47f9197bdd44df24d67ac8893641e16f386c984a0619ef2ee4c51fbbc019/beautifulsoup4-4.14.3-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/0b/c7/b2e7aca3de8981f4ecb6ab1e0334c3c4a512e5e9898b57b3d8734b086da7/biopython-1.86-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
- pypi: https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/bf/51/472e7b36a6bedb5242a9757e7486f702c3619eff76e256735d0c8b1679c6/blis-1.3.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl - pypi: https://files.pythonhosted.org/packages/bf/51/472e7b36a6bedb5242a9757e7486f702c3619eff76e256735d0c8b1679c6/blis-1.3.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
- pypi: https://files.pythonhosted.org/packages/f6/a8/877f306720bc114c612579c5af36bcb359026b83d051226945499b306b1a/bokeh-3.8.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f6/a8/877f306720bc114c612579c5af36bcb359026b83d051226945499b306b1a/bokeh-3.8.2-py3-none-any.whl
@ -281,7 +282,7 @@ environments:
- pypi: https://files.pythonhosted.org/packages/7e/50/fc9680058e63161f2f63165b84c957a0df1415431104c408e8104a3a18ef/branca-0.8.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/7e/50/fc9680058e63161f2f63165b84c957a0df1415431104c408e8104a3a18ef/branca-0.8.2-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/19/0d/669d4bbeb36b87ba504409d85c68ec297e6f434ea6525424f8aa5f14abac/cartopy-0.25.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/19/0d/669d4bbeb36b87ba504409d85c68ec297e6f434ea6525424f8aa5f14abac/cartopy-0.25.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
- pypi: https://files.pythonhosted.org/packages/9e/96/d32b941a501ab566a16358d68b6eb4e4acc373fab3c3c4d7d9e649f7b4bb/catalogue-2.0.10-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/9e/96/d32b941a501ab566a16358d68b6eb4e4acc373fab3c3c4d7d9e649f7b4bb/catalogue-2.0.10-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/0c/4b/d04e067df4401902cb2249df241bc1502bf90e990c6a3da5f82ba7de60fa/catboost-1.2.8-cp313-cp313-manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/e7/07/893b53c492fc2c827d0c6de5fe4d47cd016c57596b1f7318cc14cf57121f/catboost-1.2.9-cp313-cp313-manylinux2014_x86_64.whl
- pypi: https://files.pythonhosted.org/packages/4f/f4/4a65460d5cb6784128019fd707a87993f378db25e796eba01400a0903f62/cdsapi-0.7.7-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/4f/f4/4a65460d5cb6784128019fd707a87993f378db25e796eba01400a0903f62/cdsapi-0.7.7-py2.py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/ce/0c/00c768197bbcba5835f22b69c2611cb422c0f8a9dc93af62e26d14584b29/cdshealpix-0.8.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/ce/0c/00c768197bbcba5835f22b69c2611cb422c0f8a9dc93af62e26d14584b29/cdshealpix-0.8.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- pypi: https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl
@ -302,7 +303,7 @@ environments:
- pypi: https://files.pythonhosted.org/packages/6b/e7/237155ae19a9023de7e30ec64e5d99a9431a567407ac21170a046d22a5a3/cryptography-46.0.5-cp311-abi3-manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/6b/e7/237155ae19a9023de7e30ec64e5d99a9431a567407ac21170a046d22a5a3/cryptography-46.0.5-cp311-abi3-manylinux_2_28_x86_64.whl
- pypi: https://files.pythonhosted.org/packages/fa/25/0be9314cd72fe2ee2ef89ceb1f438bc156428a12177d684040456eee4a56/cupy_xarray-0.1.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fa/25/0be9314cd72fe2ee2ef89ceb1f438bc156428a12177d684040456eee4a56/cupy_xarray-0.1.4-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/2b/03/f906829bcfcbb945f19d6a64240ffb66a31d69ca5533e95882f0efc9c13c/cyclopts-4.5.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/3a/1f/d8bce383a90d8a6a11033327777afa4d4d611ec11869284adb6f48152906/cyclopts-4.5.3-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/36/36/bc980b9a14409f3356309c45a8d88d58797d02002a9d794dd6c84e809d3a/cymem-2.0.13-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl - pypi: https://files.pythonhosted.org/packages/36/36/bc980b9a14409f3356309c45a8d88d58797d02002a9d794dd6c84e809d3a/cymem-2.0.13-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
- pypi: https://files.pythonhosted.org/packages/e5/23/d39ccc4ed76222db31530b0a7d38876fdb7673e23f838e8d8f0ed4651a4f/dask-2026.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e5/23/d39ccc4ed76222db31530b0a7d38876fdb7673e23f838e8d8f0ed4651a4f/dask-2026.1.2-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/28/0e/b11ad5fd77e3dd0baad9cac3184315be7654ae401e3b0b0c324503f23d96/datashader-0.18.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/28/0e/b11ad5fd77e3dd0baad9cac3184315be7654ae401e3b0b0c324503f23d96/datashader-0.18.2-py3-none-any.whl
@ -315,7 +316,7 @@ environments:
- pypi: https://files.pythonhosted.org/packages/02/10/5da547df7a391dcde17f59520a231527b8571e6f46fc8efb02ccb370ab12/docutils-0.22.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/02/10/5da547df7a391dcde17f59520a231527b8571e6f46fc8efb02ccb370ab12/docutils-0.22.4-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/0c/d5/c5db1ea3394c6e1732fb3286b3bd878b59507a8f77d32a2cebda7d7b7cd4/donfig-0.8.1.post1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0c/d5/c5db1ea3394c6e1732fb3286b3bd878b59507a8f77d32a2cebda7d7b7cd4/donfig-0.8.1.post1-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/53/32/256df3dbaa198c58539ad94f9a41e98c2c8ff23f126b8f5f52c7dcd0a738/duckdb-1.4.4-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/53/32/256df3dbaa198c58539ad94f9a41e98c2c8ff23f126b8f5f52c7dcd0a738/duckdb-1.4.4-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl
- pypi: https://files.pythonhosted.org/packages/c2/0f/875b6df73f884062f3bd7d62a2fb9bfc1d07d1c93a611e999401c5b10ca0/earthengine_api-1.7.13-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fd/62/d5aa7b3a3e637def1df38ac114dc04f042489cd22210ffc6cd03e259f87a/earthengine_api-1.7.14-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/04/40/2ccf4c87a5f9c8198fe71600d5f307f5dada201c091af8774a9c1e360865/ecmwf_datastores_client-0.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/04/40/2ccf4c87a5f9c8198fe71600d5f307f5dada201c091af8774a9c1e360865/ecmwf_datastores_client-0.4.2-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/65/54/5e3b0e41799e17e5eff1547fda4aab53878c0adb4243de6b95f8ddef899e/ee_extra-2025.7.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/65/54/5e3b0e41799e17e5eff1547fda4aab53878c0adb4243de6b95f8ddef899e/ee_extra-2025.7.2-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/06/98/3e22f4386f6c1957f5994c9aa9cedd8a442bb75766bd0b2e2c1c92854af9/eemont-2025.7.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/06/98/3e22f4386f6c1957f5994c9aa9cedd8a442bb75766bd0b2e2c1c92854af9/eemont-2025.7.1-py3-none-any.whl
@ -326,13 +327,13 @@ environments:
- pypi: https://files.pythonhosted.org/packages/cf/22/fdc2e30d43ff853720042fa15baa3e6122722be1a7950a98233ebb55cd71/eval_type_backport-0.3.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/cf/22/fdc2e30d43ff853720042fa15baa3e6122722be1a7950a98233ebb55cd71/eval_type_backport-0.3.1-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/7e/31/d229f6cdb9cbe03020499d69c4b431b705aa19a55aa0fe698c98022b2fef/faiss_cpu-1.12.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/7e/31/d229f6cdb9cbe03020499d69c4b431b705aa19a55aa0fe698c98022b2fef/faiss_cpu-1.12.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
- pypi: https://files.pythonhosted.org/packages/c7/7d/74dd43d58f37584b32f0d781c8dbea9a286ee73e90393394e70569d4f254/fastai-2.8.6-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/49/92/9429cce6bd4048cec9e4c2458c6bdb56144327afe1e7f29341f807d97dca/fastai-2.8.7-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/59/f3/f71552b94a39509b62e72c4a26b6e4440bb9ce6decacf90af2916829e69e/fastcluster-1.3.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/59/f3/f71552b94a39509b62e72c4a26b6e4440bb9ce6decacf90af2916829e69e/fastcluster-1.3.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- pypi: https://files.pythonhosted.org/packages/ea/d6/bb13c44b5863c0be7a27ef02982eca88f50d717549df1979e85942292239/fastcore-1.12.12-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d0/c0/b7fa771dda08001eb004112114094370d6b94b857ed902a32472ed74a8fe/fastcore-1.12.14-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/47/60/ed35253a05a70b63e4f52df1daa39a6a464a3e22b0bd060b77f63e2e2b6a/fastdownload-0.0.7-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/47/60/ed35253a05a70b63e4f52df1daa39a6a464a3e22b0bd060b77f63e2e2b6a/fastdownload-0.0.7-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/cb/a8/20d0723294217e47de6d9e2e40fd4a9d2f7c4b6ef974babd482a59743694/fastjsonschema-2.21.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/cb/a8/20d0723294217e47de6d9e2e40fd4a9d2f7c4b6ef974babd482a59743694/fastjsonschema-2.21.2-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/fe/a7/af33584fa6d17b911cfaba460efd3409cb5dd47083c181a4fdfec4bef840/fastlite-0.2.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fe/a7/af33584fa6d17b911cfaba460efd3409cb5dd47083c181a4fdfec4bef840/fastlite-0.2.4-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/79/45/4aa502bbda9b63c792463c3466a2c5ef3c0830935f81906043f66b2b6c74/fastprogress-1.1.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/da/8e/4ffb242418e2924ef3216b712f1382d4369a5f494c30052c3ac8dfb757d9/fastprogress-1.1.5-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/47/3d/4b85b47a7e70d5c7cc0cf7d7b2883646c9c0bd3ef54a33f23d5873aa910c/fasttransform-0.0.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/47/3d/4b85b47a7e70d5c7cc0cf7d7b2883646c9c0bd3ef54a33f23d5873aa910c/fasttransform-0.0.2-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/92/54/dc5aec836660a37f11a8c66300bc2c18be254ef3a78ff08869ed1960c0fb/flox-0.11.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/92/54/dc5aec836660a37f11a8c66300bc2c18be254ef3a78ff08869ed1960c0fb/flox-0.11.1-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/b5/a8/5f764f333204db0390362a4356d03a43626997f26818a0e9396f1b3bd8c9/folium-0.20.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b5/a8/5f764f333204db0390362a4356d03a43626997f26818a0e9396f1b3bd8c9/folium-0.20.0-py2.py3-none-any.whl
@ -445,8 +446,7 @@ environments:
- pypi: https://files.pythonhosted.org/packages/c0/db/61efa0d08a99f897ef98256b03e563092d36cc38dc4ebe4a85020fe40b31/pbr-7.0.3-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c0/db/61efa0d08a99f897ef98256b03e563092d36cc38dc4ebe4a85020fe40b31/pbr-7.0.3-py2.py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/71/24/538bff45bde96535d7d998c6fed1a751c75ac7c53c37c90dc2601b243893/pillow-12.1.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/71/24/538bff45bde96535d7d998c6fed1a751c75ac7c53c37c90dc2601b243893/pillow-12.1.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
- pypi: https://files.pythonhosted.org/packages/de/f0/c81e05b613866b76d2d1066490adf1a3dbc4ee9d9c839961c3fc8a6997af/pip-26.0.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/48/31/05e764397056194206169869b50cf2fee4dbbbc71b344705b9c0d878d4d8/platformdirs-4.9.2-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/da/10/1b0dcf51427326f70e50d98df21b18c228117a743a1fc515a42f8dc7d342/platformdirs-4.6.0-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/8a/67/f95b5460f127840310d2187f916cf0023b5875c0717fdf893f71e1325e87/plotly-6.5.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8a/67/f95b5460f127840310d2187f916cf0023b5875c0717fdf893f71e1325e87/plotly-6.5.2-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/42/88/71fa06eb487ed9d4fab0ad173300b7a58706385f98fb66b1ccdc3ec3d4dd/plum_dispatch-2.6.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/42/88/71fa06eb487ed9d4fab0ad173300b7a58706385f98fb66b1ccdc3ec3d4dd/plum_dispatch-2.6.1-py3-none-any.whl
@ -466,11 +466,12 @@ environments:
- pypi: https://files.pythonhosted.org/packages/68/fb/bc7f639aed026bca6e7beb1e33f6951e16b7d315594e7635a4f7d21d63f4/py_spy-0.4.1-py2.py3-none-manylinux_2_5_x86_64.manylinux1_x86_64.whl - pypi: https://files.pythonhosted.org/packages/68/fb/bc7f639aed026bca6e7beb1e33f6951e16b7d315594e7635a4f7d21d63f4/py_spy-0.4.1-py2.py3-none-manylinux_2_5_x86_64.manylinux1_x86_64.whl
- pypi: https://files.pythonhosted.org/packages/44/b5/a96872e5184f354da9c84ae119971a0a4c221fe9b27a4d94bd43f2596727/pyasn1-0.6.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/44/b5/a96872e5184f354da9c84ae119971a0a4c221fe9b27a4d94bd43f2596727/pyasn1-0.6.2-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/35/ef/a0090b20af352b9e8ca7b5ccef81940df63ba15cf5c66baf5c6145620537/pycirclize-1.10.1-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/8c/b2/23f4032cd1c9744aa8e9ecda43cd4d755fcb209f7f40fae035248f31a679/pyct-0.6.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8c/b2/23f4032cd1c9744aa8e9ecda43cd4d755fcb209f7f40fae035248f31a679/pyct-0.6.0-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/cf/4e/35a80cae583a37cf15604b44240e45c05e04e86f9cfd766623149297e971/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/cf/4e/35a80cae583a37cf15604b44240e45c05e04e86f9cfd766623149297e971/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- pypi: https://files.pythonhosted.org/packages/c1/60/5d4751ba3f4a40a6891f24eec885f51afd78d208498268c734e256fb13c4/pydantic_settings-2.12.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b0/1a/dd1b9d7e627486cf8e7523d09b70010e05a4bc41414f4ae6ce184cf0afb6/pydantic_settings-2.13.0-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/ab/4c/b888e6cf58bd9db9c93f40d1c6be8283ff49d88919231afe93a6bcf61626/pydeck-0.9.1-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ab/4c/b888e6cf58bd9db9c93f40d1c6be8283ff49d88919231afe93a6bcf61626/pydeck-0.9.1-py2.py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/e5/e0/050018d855d26d3c0b4a7d1b2ed692be758ce276d8289e2a2b44ba1014a5/pyerfa-2.0.1.5-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/e5/e0/050018d855d26d3c0b4a7d1b2ed692be758ce276d8289e2a2b44ba1014a5/pyerfa-2.0.1.5-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- pypi: https://files.pythonhosted.org/packages/46/35/b874f79d03e9f900012cf609f7fff97b77164f2e14ee5aac282f8a999c1b/pyogrio-0.12.1-cp313-cp313-manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/46/35/b874f79d03e9f900012cf609f7fff97b77164f2e14ee5aac282f8a999c1b/pyogrio-0.12.1-cp313-cp313-manylinux_2_28_x86_64.whl
@ -485,7 +486,7 @@ environments:
- pypi: https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/88/ae/baf3a8057d8129896a7e02619df43ea0d918fc5b2bb66eb6e2470595fbac/python_box-7.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/88/ae/baf3a8057d8129896a7e02619df43ea0d918fc5b2bb66eb6e2470595fbac/python_box-7.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- pypi: https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/22/da/e890190fd9b3bd465c796a341fb24cbb1b0f9d831f511d21db9faf056e32/python_fasthtml-0.12.41-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d8/83/9a9188aad05b3fe84d3f163e3978458e95d6db0991de614501a5473fe6c7/python_fasthtml-0.12.42-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/1b/d0/397f9626e711ff749a95d96b7af99b9c566a9bb5129b8e4c10fc4d100304/python_multipart-0.0.22-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/1b/d0/397f9626e711ff749a95d96b7af99b9c566a9bb5129b8e4c10fc4d100304/python_multipart-0.0.22-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/0e/93/c8c361bf0a2fe50f828f32def460e8b8a14b93955d3fd302b1a9b63b19e4/pytorch_lightning-2.6.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0e/93/c8c361bf0a2fe50f828f32def460e8b8a14b93955d3fd302b1a9b63b19e4/pytorch_lightning-2.6.1-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
@ -506,7 +507,7 @@ environments:
- pypi: https://files.pythonhosted.org/packages/a0/60/429e9b1cb3fc651937727befe258ea24122d9663e4d5709a48c9cbfceecb/safetensors-0.7.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/a0/60/429e9b1cb3fc651937727befe258ea24122d9663e4d5709a48c9cbfceecb/safetensors-0.7.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- pypi: https://files.pythonhosted.org/packages/a3/bb/bbae36d06c0fd670e8373da67096cd57058b57c9bad7d92969b5e3b730af/scooby-0.11.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a3/bb/bbae36d06c0fd670e8373da67096cd57058b57c9bad7d92969b5e3b730af/scooby-0.11.0-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/83/11/00d3c3dfc25ad54e731d91449895a79e4bf2384dc3ac01809010ba88f6d5/seaborn-0.13.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/83/11/00d3c3dfc25ad54e731d91449895a79e4bf2384dc3ac01809010ba88f6d5/seaborn-0.13.2-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/ca/63/2c6daf59d86b1c30600bff679d039f57fd1932af82c43c0bde1cbc55e8d4/sentry_sdk-2.52.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/47/d4/2fdf854bc3b9c7f55219678f812600a20a138af2dd847d99004994eada8f/sentry_sdk-2.53.0-py2.py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/6b/6a/c006de5df0e0f4850aa94019df1f79bf6a5342fa851ca85e4728691fd0c4/shap-0.50.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/6b/6a/c006de5df0e0f4850aa94019df1f79bf6a5342fa851ca85e4728691fd0c4/shap-0.50.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
- pypi: https://files.pythonhosted.org/packages/f2/a2/83fc37e2a58090e3d2ff79175a95493c664bcd0b653dd75cb9134645a4e5/shapely-2.1.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl - pypi: https://files.pythonhosted.org/packages/f2/a2/83fc37e2a58090e3d2ff79175a95493c664bcd0b653dd75cb9134645a4e5/shapely-2.1.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
- pypi: https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl
@ -535,9 +536,9 @@ environments:
- pypi: https://files.pythonhosted.org/packages/02/be/5d2d47b1fb58943194fb59dcf222f7c4e35122ec0ffe8c36e18b5d728f0b/tblib-3.2.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/02/be/5d2d47b1fb58943194fb59dcf222f7c4e35122ec0ffe8c36e18b5d728f0b/tblib-3.2.2-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/e0/1d/b5d63f1a6b824282b57f7b581810d20b7a28ca951f2d5b59f1eb0782c12b/tensorboardx-2.6.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e0/1d/b5d63f1a6b824282b57f7b581810d20b7a28ca951f2d5b59f1eb0782c12b/tensorboardx-2.6.4-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/9c/78/96ddb99933e11d91bc6e05edae23d2687e44213066bcbaca338898c73c47/textual-7.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d3/be/e191c2a15da20530fde03564564e3e4b4220eb9d687d4014957e5c6a5e85/textual-8.0.0-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/45/ef/e7fca88074cb0aa1c1a23195470b4549492c2797fe7dc9ff79a85500153a/thinc-8.3.10-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl - pypi: https://files.pythonhosted.org/packages/45/ef/e7fca88074cb0aa1c1a23195470b4549492c2797fe7dc9ff79a85500153a/thinc-8.3.10-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
- pypi: https://files.pythonhosted.org/packages/09/19/529b28ca338c5a88315e71e672badc85eef89460c248c4164f6ce058f8c7/tifffile-2026.1.28-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/48/06/a8e97165d82f866a40117f213d2f8a32f297c9c76ec9c16a1a2c680e0f59/tifffile-2026.2.16-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/2e/76/932be4b50ef6ccedf9d3c6639b056a967a86258c6d9200643f01269211ca/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/2e/76/932be4b50ef6ccedf9d3c6639b056a967a86258c6d9200643f01269211ca/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- pypi: https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/fb/12/5911ae3eeec47800503a238d971e51722ccea5feb8569b735184d5fcdbc0/toolz-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fb/12/5911ae3eeec47800503a238d971e51722ccea5feb8569b735184d5fcdbc0/toolz-1.1.0-py3-none-any.whl
@ -549,20 +550,20 @@ environments:
- pypi: https://files.pythonhosted.org/packages/8d/c0/fdf9d3ee103ce66a55f0532835ad5e154226c5222423c6636ba049dc42fc/traittypes-0.2.3-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8d/c0/fdf9d3ee103ce66a55f0532835ad5e154226c5222423c6636ba049dc42fc/traittypes-0.2.3-py2.py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/03/b8/e484ef633af3887baeeb4b6ad12743363af7cce68ae51e938e00aaa0529d/transformers-4.57.6-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/03/b8/e484ef633af3887baeeb4b6ad12743363af7cce68ae51e938e00aaa0529d/transformers-4.57.6-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/74/18/8dd4fe6df1fd66f3e83b4798eddb1d8482d9d9b105f25099b76703402ebb/ty-0.0.11-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/74/18/8dd4fe6df1fd66f3e83b4798eddb1d8482d9d9b105f25099b76703402ebb/ty-0.0.11-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- pypi: https://files.pythonhosted.org/packages/7a/ed/d6fca788b51d0d4640c4bc82d0e85bad4b49809bca36bf4af01b4dcb66a7/typer-0.23.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/85/d0/4da85c2a45054bb661993c93524138ace4956cb075a7ae0c9d1deadc331b/typer-0.24.0-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/07/3e/ba3a222c80ee070d9497ece3e1fe77253c142925dd4c90f04278aac0a9eb/typer_slim-0.23.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a7/24/5480c20380dfd18cf33d14784096dca45a24eae6102e91d49a718d3b6855/typer_slim-0.24.0-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/e7/c1/56ef16bf5dcd255155cc736d276efa6ae0a5c26fd685e28f0412a4013c01/types_pytz-2025.2.0.20251108-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e7/c1/56ef16bf5dcd255155cc736d276efa6ae0a5c26fd685e28f0412a4013c01/types_pytz-2025.2.0.20251108-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/d6/32/48209716f9715d77f1bce084ad74c5d3cfcf41fd78d0c7e7dbe4829cfa3a/ultraplot-1.72.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/36/48/33f00ffd1c62ca4e66f91024049107b7b372fda7bbe4d20e6a492a39ff02/ultraplot-2.0.1-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/a9/99/3ae339466c9183ea5b8ae87b34c0b897eda475d2aec2307cae60e5cd4f29/uritemplate-4.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a9/99/3ae339466c9183ea5b8ae87b34c0b897eda475d2aec2307cae60e5cd4f29/uritemplate-4.2.0-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/3d/d8/2083a1daa7439a66f3a48589a57d576aa117726762618f6bb09fe3798796/uvicorn-0.40.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/83/e4/d04a086285c20886c0daad0e026f250869201013d18f81d9ff5eada73a88/uvicorn-0.41.0-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/15/c0/0be24758891ef825f2065cd5db8741aaddabe3e248ee6acc5e8a80f04005/uvloop-0.22.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/15/c0/0be24758891ef825f2065cd5db8741aaddabe3e248ee6acc5e8a80f04005/uvloop-0.22.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
- pypi: https://files.pythonhosted.org/packages/e6/9f/ca52771fe972e0dcc5167fedb609940e01516066938ff2ee28b273ae4f29/vega_datasets-0.9.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e6/9f/ca52771fe972e0dcc5167fedb609940e01516066938ff2ee28b273ae4f29/vega_datasets-0.9.0-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/04/d5/81d1403788f072e7d0e2b2fe539a0ae4410f27886ff52df094e5348c99ea/vegafusion-2.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/04/d5/81d1403788f072e7d0e2b2fe539a0ae4410f27886ff52df094e5348c99ea/vegafusion-2.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- pypi: https://files.pythonhosted.org/packages/6a/2a/dc2228b2888f51192c7dc766106cd475f1b768c10caaf9727659726f7391/virtualenv-20.36.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/6a/2a/dc2228b2888f51192c7dc766106cd475f1b768c10caaf9727659726f7391/virtualenv-20.36.1-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/a0/18/88e02899b72fa8273ffb32bde12b0e5776ee0fd9fb29559a49c48ec4c5fa/vl_convert_python-1.9.0.post1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/a0/18/88e02899b72fa8273ffb32bde12b0e5776ee0fd9fb29559a49c48ec4c5fa/vl_convert_python-1.9.0.post1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- pypi: https://files.pythonhosted.org/packages/70/c8/1b758bd903afee000f023cd03f335ff328a21b3914f9f9deda49b1e57723/wandb-0.24.2-py3-none-manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/de/91/ec9465d014cfd199c5b2083d271d31b3c2aedeae66f3d8a0712f7f54bdf3/wandb-0.25.0-py3-none-manylinux_2_28_x86_64.whl
- pypi: https://files.pythonhosted.org/packages/06/7c/34330a89da55610daa5f245ddce5aab81244321101614751e7537f125133/wasabi-1.1.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/06/7c/34330a89da55610daa5f245ddce5aab81244321101614751e7537f125133/wasabi-1.1.3-py3-none-any.whl
- pypi: https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl
- pypi: https://files.pythonhosted.org/packages/62/da/def65b170a3815af7bd40a3e7010bf6ab53089ef1b75d05dd5385b87cf08/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/62/da/def65b170a3815af7bd40a3e7010bf6ab53089ef1b75d05dd5385b87cf08/watchfiles-1.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
@ -931,10 +932,10 @@ packages:
- astropy[dev] ; extra == 'dev-all' - astropy[dev] ; extra == 'dev-all'
- astropy[test-all] ; extra == 'dev-all' - astropy[test-all] ; extra == 'dev-all'
requires_python: '>=3.11' requires_python: '>=3.11'
- pypi: https://files.pythonhosted.org/packages/4e/67/6af8b422c04dec79c908cf60fdcd4725c3c112b2a058087c4ff58284a142/astropy_iers_data-0.2026.2.9.0.50.33-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/49/94/dcdac330d2c26776956555610ef584147584acc6b060e451aa65dd9142d9/astropy_iers_data-0.2026.2.16.0.48.25-py3-none-any.whl
name: astropy-iers-data name: astropy-iers-data
version: 0.2026.2.9.0.50.33 version: 0.2026.2.16.0.48.25
sha256: ac01dede0240499b23c2b89fdc93093500336197c5c794e6a01173cfd78a7620 sha256: 180d1c3f59d18aa616345560799c2d88ec6e5164b8c45c746380acf892946136
requires_dist: requires_dist:
- pytest ; extra == 'docs' - pytest ; extra == 'docs'
- hypothesis ; extra == 'test' - hypothesis ; extra == 'test'
@ -1523,6 +1524,13 @@ packages:
- html5lib ; extra == 'html5lib' - html5lib ; extra == 'html5lib'
- lxml ; extra == 'lxml' - lxml ; extra == 'lxml'
requires_python: '>=3.7.0' requires_python: '>=3.7.0'
- pypi: https://files.pythonhosted.org/packages/0b/c7/b2e7aca3de8981f4ecb6ab1e0334c3c4a512e5e9898b57b3d8734b086da7/biopython-1.86-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
name: biopython
version: '1.86'
sha256: 593ec6a2a4fedec08ddcee1a8a0e0b0ed56835b2714904b352ec4a93d5b9d973
requires_dist:
- numpy
requires_python: '>=3.10'
- pypi: https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl
name: blinker name: blinker
version: 1.9.0 version: 1.9.0
@ -1685,15 +1693,15 @@ packages:
- zipp>=0.5 ; python_full_version < '3.8' - zipp>=0.5 ; python_full_version < '3.8'
- typing-extensions>=3.6.4 ; python_full_version < '3.8' - typing-extensions>=3.6.4 ; python_full_version < '3.8'
requires_python: '>=3.6' requires_python: '>=3.6'
- pypi: https://files.pythonhosted.org/packages/0c/4b/d04e067df4401902cb2249df241bc1502bf90e990c6a3da5f82ba7de60fa/catboost-1.2.8-cp313-cp313-manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/e7/07/893b53c492fc2c827d0c6de5fe4d47cd016c57596b1f7318cc14cf57121f/catboost-1.2.9-cp313-cp313-manylinux2014_x86_64.whl
name: catboost name: catboost
version: 1.2.8 version: 1.2.9
sha256: 8d2b58781c7ff2f974bde857da0d10d867366979193a4e7052746330a8b76b55 sha256: 46a34a5f241c85f3184ca6fd7c3de338f2db8d6daf3ac05f81411f366e4387c8
requires_dist: requires_dist:
- graphviz - graphviz
- matplotlib - matplotlib
- numpy>=1.16.0,<3.0 - numpy>=1.16.0,<3.0
- pandas>=0.24 - pandas>=0.24,<4.0
- scipy - scipy
- plotly - plotly
- six - six
@ -2401,10 +2409,10 @@ packages:
- pytest-cov ; extra == 'tests' - pytest-cov ; extra == 'tests'
- pytest-xdist ; extra == 'tests' - pytest-xdist ; extra == 'tests'
requires_python: '>=3.8' requires_python: '>=3.8'
- pypi: https://files.pythonhosted.org/packages/2b/03/f906829bcfcbb945f19d6a64240ffb66a31d69ca5533e95882f0efc9c13c/cyclopts-4.5.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/3a/1f/d8bce383a90d8a6a11033327777afa4d4d611ec11869284adb6f48152906/cyclopts-4.5.3-py3-none-any.whl
name: cyclopts name: cyclopts
version: 4.5.2 version: 4.5.3
sha256: ee56ee23c2c81abc34b66b5aa8fd2698ca699740054e84e534449ec3eb7f944d sha256: 50af3085bb15d4a6f2582dd383dad5e4ba6a0d4d4c64ee63326d881a752a6919
requires_dist: requires_dist:
- attrs>=23.1.0 - attrs>=23.1.0
- docstring-parser>=0.15,<4.0 - docstring-parser>=0.15,<4.0
@ -2587,10 +2595,10 @@ packages:
- pyarrow ; extra == 'all' - pyarrow ; extra == 'all'
- adbc-driver-manager ; extra == 'all' - adbc-driver-manager ; extra == 'all'
requires_python: '>=3.9.0' requires_python: '>=3.9.0'
- pypi: https://files.pythonhosted.org/packages/c2/0f/875b6df73f884062f3bd7d62a2fb9bfc1d07d1c93a611e999401c5b10ca0/earthengine_api-1.7.13-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fd/62/d5aa7b3a3e637def1df38ac114dc04f042489cd22210ffc6cd03e259f87a/earthengine_api-1.7.14-py3-none-any.whl
name: earthengine-api name: earthengine-api
version: 1.7.13 version: 1.7.14
sha256: 32a24b6003287f71afb24e2cee7718296f8d82778488b88c1e760279c7e47840 sha256: 35cad802047117193931596c0b79a41569db0b65013fc468990d8d8410cd8967
requires_dist: requires_dist:
- google-cloud-storage - google-cloud-storage
- google-api-python-client>=1.12.1 - google-api-python-client>=1.12.1
@ -2766,13 +2774,11 @@ packages:
- numpy>=1.25.0,<3.0 - numpy>=1.25.0,<3.0
- packaging - packaging
requires_python: '>=3.9,<3.15' requires_python: '>=3.9,<3.15'
- pypi: https://files.pythonhosted.org/packages/c7/7d/74dd43d58f37584b32f0d781c8dbea9a286ee73e90393394e70569d4f254/fastai-2.8.6-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/49/92/9429cce6bd4048cec9e4c2458c6bdb56144327afe1e7f29341f807d97dca/fastai-2.8.7-py3-none-any.whl
name: fastai name: fastai
version: 2.8.6 version: 2.8.7
sha256: 6dcaa2e0f9d1cc6a1bd462d38f907ab908e09b9070542fee7b271018c2a2e0da sha256: 840145fe563bed47d35fb5da47121f9749b9ae7deca1a7f31189b045a6a72d9d
requires_dist: requires_dist:
- pip
- packaging
- fastdownload>=0.0.5,<2 - fastdownload>=0.0.5,<2
- fastcore>=1.8.0 - fastcore>=1.8.0
- fasttransform>=0.0.2 - fasttransform>=0.0.2
@ -2789,7 +2795,7 @@ packages:
- packaging - packaging
- plum-dispatch - plum-dispatch
- cloudpickle - cloudpickle
- torch>=1.10,<2.10 - torch>=1.10,<3
- nbdev ; extra == 'dev' - nbdev ; extra == 'dev'
- ipywidgets ; extra == 'dev' - ipywidgets ; extra == 'dev'
- lightning ; extra == 'dev' - lightning ; extra == 'dev'
@ -2821,10 +2827,10 @@ packages:
requires_dist: requires_dist:
- numpy>=2 - numpy>=2
requires_python: '>=3' requires_python: '>=3'
- pypi: https://files.pythonhosted.org/packages/ea/d6/bb13c44b5863c0be7a27ef02982eca88f50d717549df1979e85942292239/fastcore-1.12.12-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d0/c0/b7fa771dda08001eb004112114094370d6b94b857ed902a32472ed74a8fe/fastcore-1.12.14-py3-none-any.whl
name: fastcore name: fastcore
version: 1.12.12 version: 1.12.14
sha256: bb1a3a3accd62a72bad56af974e0617af078316be5bb5dcc8763b8244c197fa8 sha256: 19e5adcee3af6f357af4f66954e17f335f208bb9cb422dcdef03d2e9d586eca3
requires_dist: requires_dist:
- numpy ; extra == 'dev' - numpy ; extra == 'dev'
- nbdev>=0.2.39 ; extra == 'dev' - nbdev>=0.2.39 ; extra == 'dev'
@ -2868,13 +2874,14 @@ packages:
- apswutils>=0.1.2 - apswutils>=0.1.2
- graphviz ; extra == 'dev' - graphviz ; extra == 'dev'
requires_python: '>=3.10' requires_python: '>=3.10'
- pypi: https://files.pythonhosted.org/packages/79/45/4aa502bbda9b63c792463c3466a2c5ef3c0830935f81906043f66b2b6c74/fastprogress-1.1.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/da/8e/4ffb242418e2924ef3216b712f1382d4369a5f494c30052c3ac8dfb757d9/fastprogress-1.1.5-py3-none-any.whl
name: fastprogress name: fastprogress
version: 1.1.3 version: 1.1.5
sha256: b7ad6a1a589407174ceaa3368c212bf13136548f9b4a85d3f6c6e489289ffdad sha256: 7763ba4d87d60f51550ac07425f0308e58fd0e450e4404a9a8d7e1e1191f8e44
requires_dist: requires_dist:
- fastcore>=1.10.0 - fastcore>=1.10.0
- python-fasthtml>=0.12.34 - python-fasthtml>=0.12.34
- numpy ; extra == 'dev'
requires_python: '>=3.10' requires_python: '>=3.10'
- conda: https://conda.anaconda.org/conda-forge/linux-64/fastrlock-0.8.3-py313h5d5ffb9_2.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/fastrlock-0.8.3-py313h5d5ffb9_2.conda
sha256: 30498ed45133f457fd9ed14d5fac6512347f05d11fe1ed89842c7dfdb516f78f sha256: 30498ed45133f457fd9ed14d5fac6512347f05d11fe1ed89842c7dfdb516f78f
@ -6832,15 +6839,10 @@ packages:
- trove-classifiers>=2024.10.12 ; extra == 'tests' - trove-classifiers>=2024.10.12 ; extra == 'tests'
- defusedxml ; extra == 'xmp' - defusedxml ; extra == 'xmp'
requires_python: '>=3.10' requires_python: '>=3.10'
- pypi: https://files.pythonhosted.org/packages/de/f0/c81e05b613866b76d2d1066490adf1a3dbc4ee9d9c839961c3fc8a6997af/pip-26.0.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/48/31/05e764397056194206169869b50cf2fee4dbbbc71b344705b9c0d878d4d8/platformdirs-4.9.2-py3-none-any.whl
name: pip
version: 26.0.1
sha256: bdb1b08f4274833d62c1aa29e20907365a2ceb950410df15fc9521bad440122b
requires_python: '>=3.9'
- pypi: https://files.pythonhosted.org/packages/da/10/1b0dcf51427326f70e50d98df21b18c228117a743a1fc515a42f8dc7d342/platformdirs-4.6.0-py3-none-any.whl
name: platformdirs name: platformdirs
version: 4.6.0 version: 4.9.2
sha256: dd7f808d828e1764a22ebff09e60f175ee3c41876606a6132a688d809c7c9c73 sha256: 9170634f126f8efdae22fb58ae8a0eaa86f38365bc57897a6c4f781d1f5875bd
requires_python: '>=3.10' requires_python: '>=3.10'
- pypi: https://files.pythonhosted.org/packages/8a/67/f95b5460f127840310d2187f916cf0023b5875c0717fdf893f71e1325e87/plotly-6.5.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8a/67/f95b5460f127840310d2187f916cf0023b5875c0717fdf893f71e1325e87/plotly-6.5.2-py3-none-any.whl
name: plotly name: plotly
@ -7179,6 +7181,17 @@ packages:
- pkg:pypi/pybind11-global?source=hash-mapping - pkg:pypi/pybind11-global?source=hash-mapping
size: 228871 size: 228871
timestamp: 1755953338243 timestamp: 1755953338243
- pypi: https://files.pythonhosted.org/packages/35/ef/a0090b20af352b9e8ca7b5ccef81940df63ba15cf5c66baf5c6145620537/pycirclize-1.10.1-py3-none-any.whl
name: pycirclize
version: 1.10.1
sha256: fc571b0223195b651edd22011963628bddd92861a4053526b31035bb3347f43e
requires_dist:
- biopython>=1.80
- matplotlib>=3.6.3
- numpy>=1.21
- pandas>=1.3.5
- ipympl>=0.9.7 ; extra == 'tooltip'
requires_python: '>=3.10'
- pypi: https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl
name: pycparser name: pycparser
version: '3.0' version: '3.0'
@ -7213,10 +7226,10 @@ packages:
requires_dist: requires_dist:
- typing-extensions>=4.14.1 - typing-extensions>=4.14.1
requires_python: '>=3.9' requires_python: '>=3.9'
- pypi: https://files.pythonhosted.org/packages/c1/60/5d4751ba3f4a40a6891f24eec885f51afd78d208498268c734e256fb13c4/pydantic_settings-2.12.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b0/1a/dd1b9d7e627486cf8e7523d09b70010e05a4bc41414f4ae6ce184cf0afb6/pydantic_settings-2.13.0-py3-none-any.whl
name: pydantic-settings name: pydantic-settings
version: 2.12.0 version: 2.13.0
sha256: fddb9fd99a5b18da837b29710391e945b1e30c135477f484084ee513adb93809 sha256: d67b576fff39cd086b595441bf9c75d4193ca9c0ed643b90360694d0f1240246
requires_dist: requires_dist:
- pydantic>=2.7.0 - pydantic>=2.7.0
- python-dotenv>=0.21.0 - python-dotenv>=0.21.0
@ -7506,10 +7519,10 @@ packages:
requires_dist: requires_dist:
- click>=5.0 ; extra == 'cli' - click>=5.0 ; extra == 'cli'
requires_python: '>=3.9' requires_python: '>=3.9'
- pypi: https://files.pythonhosted.org/packages/22/da/e890190fd9b3bd465c796a341fb24cbb1b0f9d831f511d21db9faf056e32/python_fasthtml-0.12.41-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d8/83/9a9188aad05b3fe84d3f163e3978458e95d6db0991de614501a5473fe6c7/python_fasthtml-0.12.42-py3-none-any.whl
name: python-fasthtml name: python-fasthtml
version: 0.12.41 version: 0.12.42
sha256: fc0a1b7735bfd591076b5dd7b6af8050e76ba1604fa5ad9d250aec6f5a69af93 sha256: d74742012a9696a9fcd0c5dfcaa20b39ef751d29b2e1fb119c83568f7a0c9234
requires_dist: requires_dist:
- fastcore>=1.10.0 - fastcore>=1.10.0
- python-dateutil - python-dateutil
@ -8353,10 +8366,10 @@ packages:
- scipy>=1.7 ; extra == 'stats' - scipy>=1.7 ; extra == 'stats'
- statsmodels>=0.12 ; extra == 'stats' - statsmodels>=0.12 ; extra == 'stats'
requires_python: '>=3.8' requires_python: '>=3.8'
- pypi: https://files.pythonhosted.org/packages/ca/63/2c6daf59d86b1c30600bff679d039f57fd1932af82c43c0bde1cbc55e8d4/sentry_sdk-2.52.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/47/d4/2fdf854bc3b9c7f55219678f812600a20a138af2dd847d99004994eada8f/sentry_sdk-2.53.0-py2.py3-none-any.whl
name: sentry-sdk name: sentry-sdk
version: 2.52.0 version: 2.53.0
sha256: 931c8f86169fc6f2752cb5c4e6480f0d516112e78750c312e081ababecbaf2ed sha256: 46e1ed8d84355ae54406c924f6b290c3d61f4048625989a723fd622aab838899
requires_dist: requires_dist:
- urllib3>=1.26.11 - urllib3>=1.26.11
- certifi - certifi
@ -8940,10 +8953,10 @@ packages:
- packaging - packaging
- protobuf>=3.20 - protobuf>=3.20
requires_python: '>=3.9' requires_python: '>=3.9'
- pypi: https://files.pythonhosted.org/packages/9c/78/96ddb99933e11d91bc6e05edae23d2687e44213066bcbaca338898c73c47/textual-7.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d3/be/e191c2a15da20530fde03564564e3e4b4220eb9d687d4014957e5c6a5e85/textual-8.0.0-py3-none-any.whl
name: textual name: textual
version: 7.5.0 version: 8.0.0
sha256: 849dfee9d705eab3b2d07b33152b7bd74fb1f5056e002873cc448bce500c6374 sha256: 8908f4ebe93a6b4f77ca7262197784a52162bc88b05f4ecf50ac93a92d49bb8f
requires_dist: requires_dist:
- markdown-it-py[linkify]>=2.1.0 - markdown-it-py[linkify]>=2.1.0
- mdit-py-plugins - mdit-py-plugins
@ -9024,10 +9037,10 @@ packages:
- pkg:pypi/threadpoolctl?source=hash-mapping - pkg:pypi/threadpoolctl?source=hash-mapping
size: 23869 size: 23869
timestamp: 1741878358548 timestamp: 1741878358548
- pypi: https://files.pythonhosted.org/packages/09/19/529b28ca338c5a88315e71e672badc85eef89460c248c4164f6ce058f8c7/tifffile-2026.1.28-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/48/06/a8e97165d82f866a40117f213d2f8a32f297c9c76ec9c16a1a2c680e0f59/tifffile-2026.2.16-py3-none-any.whl
name: tifffile name: tifffile
version: 2026.1.28 version: 2026.2.16
sha256: 45b08a19cf603dd99952eff54a61519626a1912e4e2a4d355f05938fe4a6e9fd sha256: ea76cb4d8aa290f7f164840dfe4e244d104bd90c84d5ee1e6de6d84fd4745a48
requires_dist: requires_dist:
- numpy - numpy
- imagecodecs>=2025.11.11 ; extra == 'codecs' - imagecodecs>=2025.11.11 ; extra == 'codecs'
@ -9823,23 +9836,23 @@ packages:
version: 0.0.11 version: 0.0.11
sha256: 25f88e8789072830348cb59b761d5ced70642ed5600673b4bf6a849af71eca8b sha256: 25f88e8789072830348cb59b761d5ced70642ed5600673b4bf6a849af71eca8b
requires_python: '>=3.8' requires_python: '>=3.8'
- pypi: https://files.pythonhosted.org/packages/7a/ed/d6fca788b51d0d4640c4bc82d0e85bad4b49809bca36bf4af01b4dcb66a7/typer-0.23.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/85/d0/4da85c2a45054bb661993c93524138ace4956cb075a7ae0c9d1deadc331b/typer-0.24.0-py3-none-any.whl
name: typer name: typer
version: 0.23.0 version: 0.24.0
sha256: 79f4bc262b6c37872091072a3cb7cb6d7d79ee98c0c658b4364bdcde3c42c913 sha256: 5fc435a9c8356f6160ed6e85a6301fdd6e3d8b2851da502050d1f92c5e9eddc8
requires_dist: requires_dist:
- click>=8.0.0 - click>=8.2.1
- shellingham>=1.3.0 - shellingham>=1.3.0
- rich>=10.11.0 - rich>=12.3.0
- annotated-doc>=0.0.2 - annotated-doc>=0.0.2
requires_python: '>=3.9' requires_python: '>=3.10'
- pypi: https://files.pythonhosted.org/packages/07/3e/ba3a222c80ee070d9497ece3e1fe77253c142925dd4c90f04278aac0a9eb/typer_slim-0.23.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a7/24/5480c20380dfd18cf33d14784096dca45a24eae6102e91d49a718d3b6855/typer_slim-0.24.0-py3-none-any.whl
name: typer-slim name: typer-slim
version: 0.23.0 version: 0.24.0
sha256: 1d693daf22d998a7b1edab8413cdcb8af07254154ce3956c1664dc11b01e2f8b sha256: d5d7ee1ee2834d5020c7c616ed5e0d0f29b9a4b1dd283bdebae198ec09778d0e
requires_dist: requires_dist:
- typer>=0.23.0 - typer>=0.24.0
requires_python: '>=3.9' requires_python: '>=3.10'
- pypi: https://files.pythonhosted.org/packages/e7/c1/56ef16bf5dcd255155cc736d276efa6ae0a5c26fd685e28f0412a4013c01/types_pytz-2025.2.0.20251108-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e7/c1/56ef16bf5dcd255155cc736d276efa6ae0a5c26fd685e28f0412a4013c01/types_pytz-2025.2.0.20251108-py3-none-any.whl
name: types-pytz name: types-pytz
version: 2025.2.0.20251108 version: 2025.2.0.20251108
@ -9924,15 +9937,31 @@ packages:
license: BSD-3-Clause license: BSD-3-Clause
size: 508347 size: 508347
timestamp: 1765407086135 timestamp: 1765407086135
- pypi: https://files.pythonhosted.org/packages/d6/32/48209716f9715d77f1bce084ad74c5d3cfcf41fd78d0c7e7dbe4829cfa3a/ultraplot-1.72.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/36/48/33f00ffd1c62ca4e66f91024049107b7b372fda7bbe4d20e6a492a39ff02/ultraplot-2.0.1-py3-none-any.whl
name: ultraplot name: ultraplot
version: 1.72.0 version: 2.0.1
sha256: dc276064791661018311923bb5bf3cd541b79399682e48de1b88d8556053ae2d sha256: ba2f1ab04d3fea82165facf9434e43054f4b22cae101c36a8e4f0176017d4e09
requires_dist: requires_dist:
- numpy>=1.26.0 - numpy>=1.26.0
- matplotlib>=3.9,<3.11 - matplotlib>=3.9,<3.11
- pycirclize>=1.10.1
- typing-extensions ; python_full_version < '3.12' - typing-extensions ; python_full_version < '3.12'
requires_python: '>=3.10,<3.14' - jupyter ; extra == 'docs'
- jupytext ; extra == 'docs'
- lxml-html-clean ; extra == 'docs'
- m2r2 ; extra == 'docs'
- mpltern ; extra == 'docs'
- nbsphinx ; extra == 'docs'
- sphinx ; extra == 'docs'
- sphinx-autoapi ; extra == 'docs'
- sphinx-automodapi ; extra == 'docs'
- sphinx-copybutton ; extra == 'docs'
- sphinx-design ; extra == 'docs'
- sphinx-gallery ; extra == 'docs'
- shibuya ; extra == 'docs'
- sphinx-sitemap ; extra == 'docs'
- typing-extensions ; extra == 'docs'
requires_python: '>=3.10,<3.15'
- pypi: https://files.pythonhosted.org/packages/a9/99/3ae339466c9183ea5b8ae87b34c0b897eda475d2aec2307cae60e5cd4f29/uritemplate-4.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a9/99/3ae339466c9183ea5b8ae87b34c0b897eda475d2aec2307cae60e5cd4f29/uritemplate-4.2.0-py3-none-any.whl
name: uritemplate name: uritemplate
version: 4.2.0 version: 4.2.0
@ -9949,10 +9978,10 @@ packages:
- pysocks>=1.5.6,!=1.5.7,<2.0 ; extra == 'socks' - pysocks>=1.5.6,!=1.5.7,<2.0 ; extra == 'socks'
- backports-zstd>=1.0.0 ; python_full_version < '3.14' and extra == 'zstd' - backports-zstd>=1.0.0 ; python_full_version < '3.14' and extra == 'zstd'
requires_python: '>=3.9' requires_python: '>=3.9'
- pypi: https://files.pythonhosted.org/packages/3d/d8/2083a1daa7439a66f3a48589a57d576aa117726762618f6bb09fe3798796/uvicorn-0.40.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/83/e4/d04a086285c20886c0daad0e026f250869201013d18f81d9ff5eada73a88/uvicorn-0.41.0-py3-none-any.whl
name: uvicorn name: uvicorn
version: 0.40.0 version: 0.41.0
sha256: c6c8f55bc8bf13eb6fa9ff87ad62308bbbc33d0b67f84293151efe87e0d5f2ee sha256: 29e35b1d2c36a04b9e180d4007ede3bcb32a85fbdfd6c6aeb3f26839de088187
requires_dist: requires_dist:
- click>=7.0 - click>=7.0
- h11>=0.8 - h11>=0.8
@ -9962,7 +9991,7 @@ packages:
- python-dotenv>=0.13 ; extra == 'standard' - python-dotenv>=0.13 ; extra == 'standard'
- pyyaml>=5.1 ; extra == 'standard' - pyyaml>=5.1 ; extra == 'standard'
- uvloop>=0.15.1 ; platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32' and extra == 'standard' - uvloop>=0.15.1 ; platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32' and extra == 'standard'
- watchfiles>=0.13 ; extra == 'standard' - watchfiles>=0.20 ; extra == 'standard'
- websockets>=10.4 ; extra == 'standard' - websockets>=10.4 ; extra == 'standard'
requires_python: '>=3.10' requires_python: '>=3.10'
- pypi: https://files.pythonhosted.org/packages/15/c0/0be24758891ef825f2065cd5db8741aaddabe3e248ee6acc5e8a80f04005/uvloop-0.22.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/15/c0/0be24758891ef825f2065cd5db8741aaddabe3e248ee6acc5e8a80f04005/uvloop-0.22.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
@ -10034,17 +10063,16 @@ packages:
version: 1.9.0.post1 version: 1.9.0.post1
sha256: 3c1558fa0055e88c465bd3d71760cde9fa2c94a95f776a0ef9178252fd820b1f sha256: 3c1558fa0055e88c465bd3d71760cde9fa2c94a95f776a0ef9178252fd820b1f
requires_python: '>=3.7' requires_python: '>=3.7'
- pypi: https://files.pythonhosted.org/packages/70/c8/1b758bd903afee000f023cd03f335ff328a21b3914f9f9deda49b1e57723/wandb-0.24.2-py3-none-manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/de/91/ec9465d014cfd199c5b2083d271d31b3c2aedeae66f3d8a0712f7f54bdf3/wandb-0.25.0-py3-none-manylinux_2_28_x86_64.whl
name: wandb name: wandb
version: 0.24.2 version: 0.25.0
sha256: 38661c666e70d7e1f460fc0a0edab8a393eaaa5f8773c17be534961a7022779d sha256: 6c4c38077836f9b7569a35b0e1dcf1f0c43616fcd936d182f475edbfea063665
requires_dist: requires_dist:
- click>=8.0.1 - click>=8.0.1
- eval-type-backport ; python_full_version < '3.10' - eval-type-backport ; python_full_version < '3.10'
- gitpython>=1.0.0,!=3.1.29 - gitpython>=1.0.0,!=3.1.29
- packaging - packaging
- platformdirs - platformdirs
- protobuf>=3.12.0,!=4.21.0,!=5.28.0,<7 ; python_full_version < '3.9' and sys_platform == 'linux'
- protobuf>=3.15.0,!=4.21.0,!=5.28.0,<7 ; python_full_version == '3.9.*' and sys_platform == 'linux' - protobuf>=3.15.0,!=4.21.0,!=5.28.0,<7 ; python_full_version == '3.9.*' and sys_platform == 'linux'
- protobuf>=3.19.0,!=4.21.0,!=5.28.0,<7 ; python_full_version >= '3.10' and sys_platform == 'linux' - protobuf>=3.19.0,!=4.21.0,!=5.28.0,<7 ; python_full_version >= '3.10' and sys_platform == 'linux'
- protobuf>=3.19.0,!=4.21.0,!=5.28.0,<7 ; sys_platform != 'linux' - protobuf>=3.19.0,!=4.21.0,!=5.28.0,<7 ; sys_platform != 'linux'
@ -10103,7 +10131,7 @@ packages:
- orjson ; extra == 'perf' - orjson ; extra == 'perf'
- sweeps>=0.2.0 ; extra == 'sweeps' - sweeps>=0.2.0 ; extra == 'sweeps'
- wandb-workspaces ; extra == 'workspaces' - wandb-workspaces ; extra == 'workspaces'
requires_python: '>=3.8' requires_python: '>=3.9'
- pypi: https://files.pythonhosted.org/packages/06/7c/34330a89da55610daa5f245ddce5aab81244321101614751e7537f125133/wasabi-1.1.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/06/7c/34330a89da55610daa5f245ddce5aab81244321101614751e7537f125133/wasabi-1.1.3-py3-none-any.whl
name: wasabi name: wasabi
version: 1.1.3 version: 1.1.3

View file

@ -0,0 +1,460 @@
"""Plots for visualizing model inference results."""
import geopandas as gpd
import matplotlib.colors as mcolors
import numpy as np
import pandas as pd
import plotly.graph_objects as go
import pydeck as pdk
from entropice.dashboard.utils.colors import get_cmap, get_palette, hex_to_rgb
from entropice.dashboard.utils.geometry import fix_hex_geometry
from entropice.utils.types import Task
def create_inference_map(
predictions_gdf: gpd.GeoDataFrame,
task: Task,
make_3d_map: bool,
) -> pdk.Deck:
"""Create a spatial distribution map for model predictions.
Args:
predictions_gdf: GeoDataFrame with columns ['cell_id', 'predicted', 'geometry']
task: Task type (binary, count_regimes, density_regimes, count, density)
make_3d_map: Whether to render the map in 3D (extruded) or 2D
Returns:
pdk.Deck: A PyDeck map visualization of the predictions
"""
# Subsample if too many cells for performance
n_cells = len(predictions_gdf)
if n_cells > 50000:
predictions_gdf = predictions_gdf.sample(n=50000, random_state=42)
# Create a copy to avoid modifying the original
gdf = predictions_gdf.copy()
# Convert to WGS84 for pydeck
if gdf.crs is not None:
gdf = gdf.to_crs("EPSG:4326")
# Fix antimeridian issues for hex cells
gdf["geometry"] = gdf["geometry"].apply(fix_hex_geometry)
# Determine if classification or regression
classification_tasks: list[Task] = ["binary", "count_regimes", "density_regimes"]
is_classification = task in classification_tasks
if is_classification:
# Convert to categorical if needed
if gdf["predicted"].dtype != "category":
gdf["predicted"] = pd.Categorical(gdf["predicted"])
# Get categories and assign colors
categories = gdf["predicted"].cat.categories.tolist()
n_categories = len(categories)
colors = get_palette(task, n_categories + 2)[1:-1] # Avoid too light/dark colors
# Create category to color mapping
category_colors = {cat: colors[i] for i, cat in enumerate(categories)}
# Assign colors to each row based on predicted category
rgb_colors = []
for cat in gdf["predicted"]:
color = category_colors[cat]
rgb_colors.append(hex_to_rgb(mcolors.to_hex(color)))
gdf["fill_color"] = rgb_colors
# For elevation in 3D, use category index normalized
if n_categories > 1:
gdf["elevation"] = gdf["predicted"].cat.codes / (n_categories - 1)
else:
gdf["elevation"] = 0.5
# Display value is the category name
gdf["display_value"] = gdf["predicted"].astype(str)
else:
# Regression task - use continuous colormap
cmap = get_cmap(task)
# Get prediction values
values = gdf["predicted"].to_numpy()
# Normalize using percentiles to avoid outliers
vmin, vmax = np.nanpercentile(values, [2, 98])
if vmax > vmin:
normalized_values = (np.clip(values, vmin, vmax) - vmin) / (vmax - vmin)
else:
normalized_values = np.full_like(values, 0.5)
# Map normalized values to colors
colors = [cmap(val) for val in normalized_values]
rgb_colors = [hex_to_rgb(mcolors.to_hex(color)) for color in colors]
gdf["fill_color"] = rgb_colors
# Use normalized values for elevation
gdf["elevation"] = normalized_values
# Display value is the actual prediction (rounded)
gdf["display_value"] = gdf["predicted"].round(3).astype(str)
# Convert to GeoJSON format
geojson_data = []
for _, row in gdf.iterrows():
geojson_data.append(
{
"type": "Feature",
"geometry": row["geometry"].__geo_interface__,
"properties": {
"fill_color": row["fill_color"],
"elevation": row["elevation"],
"predicted": row["display_value"],
},
}
)
# Create pydeck layer
layer = pdk.Layer(
"GeoJsonLayer",
geojson_data,
opacity=0.7,
stroked=True,
filled=True,
extruded=make_3d_map,
wireframe=False,
get_fill_color="properties.fill_color",
get_line_color=[80, 80, 80],
line_width_min_pixels=0.5,
get_elevation="properties.elevation" if make_3d_map else 0,
elevation_scale=500000,
pickable=True,
)
# Set initial view state
view_state = pdk.ViewState(
latitude=70,
longitude=0,
zoom=2 if not make_3d_map else 1.5,
pitch=0 if not make_3d_map else 45,
)
# Build tooltip HTML
tooltip_html = "<b>Predicted:</b> {predicted}"
# Create deck
deck = pdk.Deck(
layers=[layer],
initial_view_state=view_state,
tooltip={
"html": tooltip_html,
"style": {"backgroundColor": "steelblue", "color": "white"},
},
map_style="https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json",
)
return deck
def create_prediction_distribution_plot(
predictions_gdf: gpd.GeoDataFrame,
task: Task,
) -> go.Figure:
"""Create a distribution plot for predictions.
For classification tasks, shows a bar chart of class counts.
For regression tasks, shows a histogram of predicted values.
Args:
predictions_gdf: GeoDataFrame with 'predicted' column
task: Task type
Returns:
Plotly Figure with distribution plot
"""
classification_tasks: list[Task] = ["binary", "count_regimes", "density_regimes"]
is_classification = task in classification_tasks
fig = go.Figure()
if is_classification:
# Bar chart for classification
# Convert to categorical if needed
if predictions_gdf["predicted"].dtype != "category":
predictions_gdf["predicted"] = pd.Categorical(predictions_gdf["predicted"])
categories = predictions_gdf["predicted"].cat.categories.tolist()
counts = predictions_gdf["predicted"].value_counts().reindex(categories, fill_value=0)
# Get colors
n_categories = len(categories)
colors = get_palette(task, n_categories + 2)[1:-1]
fig.add_trace(
go.Bar(
x=categories,
y=counts.to_numpy(),
marker_color=colors,
text=counts.to_numpy(),
textposition="outside",
textfont={"size": 12},
hovertemplate="<b>%{x}</b><br>Count: %{y}<br>Percentage: %{customdata:.1%}<extra></extra>",
customdata=counts.to_numpy() / counts.sum(),
)
)
fig.update_layout(
title=f"Predicted Class Distribution ({task.replace('_', ' ').title()})",
xaxis_title="Predicted Class",
yaxis_title="Count",
height=500,
showlegend=False,
)
fig.update_xaxes(tickangle=-45)
else:
# Histogram for regression
values = predictions_gdf["predicted"].to_numpy()
# Remove NaN values
values = values[~np.isnan(values)]
# Create histogram
fig.add_trace(
go.Histogram(
x=values,
nbinsx=50,
marker_color=mcolors.to_hex(get_cmap(task)(0.6)),
opacity=0.7,
hovertemplate="<b>Range:</b> %{x}<br><b>Count:</b> %{y}<extra></extra>",
)
)
# Add statistical lines
mean_val = np.mean(values)
median_val = np.median(values)
fig.add_vline(
x=mean_val,
line_dash="dash",
line_color="red",
annotation_text=f"Mean: {mean_val:.3f}",
annotation_position="top",
)
fig.add_vline(
x=median_val,
line_dash="dot",
line_color="green",
annotation_text=f"Median: {median_val:.3f}",
annotation_position="bottom right",
)
fig.update_layout(
title=f"Predicted Value Distribution ({task.replace('_', ' ').title()})",
xaxis_title=f"Predicted {task.capitalize()}",
yaxis_title="Count",
height=500,
showlegend=False,
)
return fig
def create_prediction_statistics_plot(
predictions_gdf: gpd.GeoDataFrame,
task: Task,
) -> go.Figure:
"""Create a plot showing key statistics about the predictions.
Args:
predictions_gdf: GeoDataFrame with 'predicted' column
task: Task type
Returns:
Plotly Figure with statistics
"""
classification_tasks: list[Task] = ["binary", "count_regimes", "density_regimes"]
is_classification = task in classification_tasks
if is_classification:
# Classification statistics: class proportions
# Convert to categorical if needed
if predictions_gdf["predicted"].dtype != "category":
predictions_gdf["predicted"] = pd.Categorical(predictions_gdf["predicted"])
categories = predictions_gdf["predicted"].cat.categories.tolist()
counts = predictions_gdf["predicted"].value_counts().reindex(categories, fill_value=0)
proportions = counts / counts.sum()
# Get colors
n_categories = len(categories)
colors = get_palette(task, n_categories + 2)[1:-1]
fig = go.Figure()
fig.add_trace(
go.Bar(
x=categories,
y=proportions.to_numpy() * 100, # Convert to percentage
marker_color=colors,
text=[f"{p:.1%}" for p in proportions.to_numpy()],
textposition="outside",
hovertemplate="<b>%{x}</b><br>Proportion: %{y:.1f}%<extra></extra>",
)
)
fig.update_layout(
title="Predicted Class Proportions",
xaxis_title="Predicted Class",
yaxis_title="Proportion (%)",
height=400,
showlegend=False,
)
fig.update_xaxes(tickangle=-45)
else:
# Regression statistics: box plot with quartiles
values = predictions_gdf["predicted"].to_numpy()
values = values[~np.isnan(values)]
fig = go.Figure()
fig.add_trace(
go.Box(
y=values,
name="Predictions",
marker_color=mcolors.to_hex(get_cmap(task)(0.6)),
boxmean="sd", # Show mean and standard deviation
hovertemplate="<b>Value:</b> %{y:.3f}<extra></extra>",
)
)
# Calculate statistics
stats = pd.Series(values).describe()
# Add annotation with statistics
stats_text = (
f"<b>Statistics</b><br>"
f"Count: {int(stats['count'])}<br>"
f"Mean: {stats['mean']:.3f}<br>"
f"Std: {stats['std']:.3f}<br>"
f"Min: {stats['min']:.3f}<br>"
f"25%: {stats['25%']:.3f}<br>"
f"50%: {stats['50%']:.3f}<br>"
f"75%: {stats['75%']:.3f}<br>"
f"Max: {stats['max']:.3f}"
)
fig.add_annotation(
text=stats_text,
xref="paper",
yref="paper",
x=1.15,
y=0.5,
showarrow=False,
align="left",
bgcolor="rgba(255, 255, 255, 0.8)",
bordercolor="black",
borderwidth=1,
)
fig.update_layout(
title=f"Prediction Statistics ({task.replace('_', ' ').title()})",
yaxis_title=f"Predicted {task.capitalize()}",
height=500,
showlegend=False,
margin={"r": 200}, # Make room for stats annotation
)
return fig
def create_coverage_statistics_table(
predictions_gdf: gpd.GeoDataFrame, task: Task, grid_gdf: gpd.GeoDataFrame | None = None
) -> pd.DataFrame:
"""Create a summary table of prediction coverage statistics.
Args:
predictions_gdf: GeoDataFrame with predictions
task: Task type
grid_gdf: Optional GeoDataFrame with cell_id and land_area columns for RTS area calculations
Returns:
DataFrame with coverage statistics
"""
classification_tasks: list[Task] = ["binary", "count_regimes", "density_regimes"]
is_classification = task in classification_tasks
stats = {
"Total Cells": len(predictions_gdf),
"Non-null Predictions": predictions_gdf["predicted"].notna().sum(),
"Null Predictions": predictions_gdf["predicted"].isna().sum(),
}
# Calculate RTS-affected area if grid_gdf is provided
if grid_gdf is not None:
# Merge with grid to get land areas
merged = predictions_gdf.merge(grid_gdf[["cell_id", "land_area"]], on="cell_id", how="left")
if is_classification:
# Convert to categorical if needed
if merged["predicted"].dtype != "category":
merged["predicted"] = pd.Categorical(merged["predicted"])
categories = merged["predicted"].cat.categories.tolist()
# For classification: sum areas where RTS are expected (non-zero classes)
# Assuming first category is "no RTS" (0 or similar)
rts_mask = merged["predicted"].notna()
if len(categories) > 1:
# Exclude the first category (assumed to be "no RTS")
rts_mask = rts_mask & (merged["predicted"] != categories[0])
rts_area_km2 = merged.loc[rts_mask, "land_area"].sum() / 1e6 # Convert m² to km²
stats["RTS-Affected Area (km²)"] = f"{rts_area_km2:,.2f}"
elif task == "count":
# For count: sum areas where count > 0
rts_mask = (merged["predicted"].notna()) & (merged["predicted"] > 0)
rts_area_km2 = merged.loc[rts_mask, "land_area"].sum() / 1e6 # Convert m² to km²
stats["RTS-Affected Area (km²)"] = f"{rts_area_km2:,.2f}"
elif task == "density":
# For density: multiply predicted density by area
# Density is typically RTS/km², so multiply by area in km²
merged["rts_area"] = merged["predicted"] * merged["land_area"] / 1e6 # density * area_km2
total_rts_area = merged["rts_area"].sum()
stats["Total RTS Area (km²)"] = f"{total_rts_area:,.2f}"
if is_classification:
# Add class counts
# Convert to categorical if needed
if predictions_gdf["predicted"].dtype != "category":
predictions_gdf["predicted"] = pd.Categorical(predictions_gdf["predicted"])
categories = predictions_gdf["predicted"].cat.categories.tolist()
for cat in categories:
count = (predictions_gdf["predicted"] == cat).sum()
stats[f"Class '{cat}' Count"] = count
stats[f"Class '{cat}' Proportion"] = f"{count / len(predictions_gdf):.2%}"
else:
# Add regression statistics
values = predictions_gdf["predicted"].dropna()
if len(values) > 0:
stats["Mean"] = f"{values.mean():.4f}"
stats["Median"] = f"{values.median():.4f}"
stats["Std Dev"] = f"{values.std():.4f}"
stats["Min"] = f"{values.min():.4f}"
stats["Max"] = f"{values.max():.4f}"
# Convert to DataFrame
df = pd.DataFrame(list(stats.items()), columns=["Statistic", "Value"])
return df

View file

@ -0,0 +1,106 @@
"""Sections for the inference page."""
import geopandas as gpd
import streamlit as st
from entropice.dashboard.plots.inference import (
create_coverage_statistics_table,
create_inference_map,
create_prediction_distribution_plot,
create_prediction_statistics_plot,
)
from entropice.utils.types import Task
def render_inference_map_section(predictions_gdf: gpd.GeoDataFrame, task: Task) -> None:
"""Render the inference map section.
Args:
predictions_gdf: GeoDataFrame with predictions and geometries
task: Task type
"""
st.subheader("📍 Spatial Prediction Map")
st.markdown(
"""
Interactive map showing model predictions across the Arctic region.
Toggle 3D mode to see predictions as elevated terrain.
"""
)
# 3D toggle
col1, col2 = st.columns([1, 4])
with col1:
make_3d = st.checkbox("3D View", value=False, key="inference_map_3d")
with col2:
if make_3d:
st.info("🎨 Height represents prediction magnitude. Rotate and tilt the map to explore!")
# Create and display map
with st.spinner("Generating map..."):
deck = create_inference_map(predictions_gdf, task, make_3d)
st.pydeck_chart(deck)
def render_prediction_statistics_section(
predictions_gdf: gpd.GeoDataFrame, task: Task, grid_gdf: gpd.GeoDataFrame | None = None
) -> None:
"""Render the prediction statistics section.
Args:
predictions_gdf: GeoDataFrame with predictions
task: Task type
grid_gdf: Optional GeoDataFrame with cell_id and land_area for RTS area calculations
"""
st.subheader("📊 Prediction Statistics")
# Create two columns for statistics
col1, col2 = st.columns(2)
with col1:
st.markdown("#### Coverage Statistics")
# Create statistics table
stats_df = create_coverage_statistics_table(predictions_gdf, task, grid_gdf)
st.dataframe(stats_df, hide_index=True, width="stretch")
with col2:
st.markdown("#### Statistical Summary")
# Create statistics plot (box plot for regression, proportions for classification)
fig = create_prediction_statistics_plot(predictions_gdf, task)
st.plotly_chart(fig, width="stretch")
def render_prediction_distribution_section(predictions_gdf: gpd.GeoDataFrame, task: Task) -> None:
"""Render the prediction distribution section.
Args:
predictions_gdf: GeoDataFrame with predictions
task: Task type
"""
classification_tasks: list[Task] = ["binary", "count_regimes", "density_regimes"]
is_classification = task in classification_tasks
if is_classification:
st.subheader("📈 Class Distribution")
st.markdown(
"""
Distribution of predicted classes across all grid cells.
Shows the count and proportion of each predicted class.
"""
)
else:
st.subheader("📈 Value Distribution")
st.markdown(
"""
Distribution of predicted values across all grid cells.
Histogram shows the frequency of predictions in different value ranges.
"""
)
# Create and display distribution plot
fig = create_prediction_distribution_plot(predictions_gdf, task)
st.plotly_chart(fig, width="stretch")

View file

@ -1,8 +1,15 @@
"""Inference page: Visualization of model inference results across the study region.""" """Inference page: Visualization of model inference results across the study region."""
import geopandas as gpd
import streamlit as st import streamlit as st
from stopuhr import stopwatch from stopuhr import stopwatch
import entropice.utils.paths
from entropice.dashboard.sections.inference import (
render_inference_map_section,
render_prediction_distribution_section,
render_prediction_statistics_section,
)
from entropice.dashboard.utils.loaders import TrainingResult, load_all_training_results from entropice.dashboard.utils.loaders import TrainingResult, load_all_training_results
@ -77,15 +84,27 @@ def render_inference_page():
# Main content area # Main content area
# Load predictions # Load predictions
with st.spinner("Loading inference results..."): with st.spinner("Loading inference results..."):
# Columns: Index(['cell_id', 'predicted', 'geometry'], dtype='object') # Columns: ['cell_id', 'predicted', 'geometry']
predictions_gdf = selected_result.run.predictions predictions_gdf = selected_result.run.predictions
task = selected_result.run.task task = selected_result.run.task
# Reading the data takes for the largest grids ~1.7s
gridfile = entropice.utils.paths.get_grid_file(
selected_result.run.dataset.grid, selected_result.run.dataset.level
)
grid_gdf = gpd.read_parquet(gridfile, columns=["cell_id", "land_area", "geometry"])
# TODO: Implement the sections # Section 1: Spatial Map
# Map, optionally 3D render_inference_map_section(predictions_gdf, task)
# Some statistics about the predictions
# Class Distribution for classification tasks
# Distribution of predicted values for regression tasks
st.balloons() st.divider()
# Section 2: Prediction Statistics
render_prediction_statistics_section(predictions_gdf, task, grid_gdf)
st.divider()
# Section 3: Distribution Analysis
render_prediction_distribution_section(predictions_gdf, task)
st.success("✅ Inference visualization complete!")
stopwatch.summary() stopwatch.summary()

View file

@ -11,30 +11,186 @@ from entropice.ml.dataset import DatasetEnsemble
from entropice.ml.hpsearchcv import RunSettings as HPOCVRunSettings from entropice.ml.hpsearchcv import RunSettings as HPOCVRunSettings
from entropice.ml.hpsearchcv import hpsearch_cv from entropice.ml.hpsearchcv import hpsearch_cv
from entropice.utils.paths import RESULTS_DIR from entropice.utils.paths import RESULTS_DIR
from entropice.utils.types import Grid, Model, TargetDataset, Task from entropice.utils.types import Grid, L2SourceDataset, Model, TargetDataset, Task
cli = cyclopts.App("entropice-feature-importance") cli = cyclopts.App("entropice-feature-importance")
DEV = False
EXPERIMENT_NAME = "feature_importance_era5-shoulder_arcticdem-v2" EXPERIMENT_NAME = "feature_importance_era5-shoulder_arcticdem-v2"
if DEV:
EXPERIMENT_NAME = "tobis-final-tests" all_features = None
univariate_features = [
"x",
"y",
"era5_freezing_days_AMJ",
"era5_freezing_days_JAS",
"era5_freezing_days_trend_JAS",
"era5_freezing_degree_days_AMJ",
"era5_freezing_degree_days_JAS",
"era5_freezing_degree_days_JFM",
"era5_freezing_degree_days_trend_JAS",
"era5_freezing_degree_days_trend_JFM",
"era5_freezing_degree_days_trend_OND",
"era5_precipitation_occurrences_AMJ",
"era5_precipitation_occurrences_OND",
"era5_sf_JAS",
"era5_snowc_mean_trend_JAS",
"era5_snowfall_occurrences_JAS",
"era5_snowfall_occurrences_trend_JAS",
"era5_sshf_JFM",
"era5_sshf_OND",
"era5_t2m_avg_AMJ",
"era5_t2m_avg_JAS",
"era5_t2m_avg_JFM",
"era5_t2m_avg_trend_JFM",
"era5_t2m_avg_trend_OND",
"era5_t2m_max_AMJ",
"era5_t2m_max_JAS",
"era5_t2m_max_JFM",
"era5_t2m_max_OND",
"era5_t2m_max_trend_OND",
"era5_t2m_mean_AMJ",
"era5_t2m_mean_JAS",
"era5_t2m_mean_JFM",
"era5_t2m_mean_trend_JFM",
"era5_t2m_mean_trend_OND",
"era5_t2m_min_AMJ",
"era5_t2m_min_trend_JAS",
"era5_t2m_min_trend_JFM",
"era5_t2m_range_AMJ",
"era5_t2m_range_JAS",
"era5_t2m_skew_JAS",
"era5_thawing_days_AMJ",
"era5_thawing_days_JAS",
"era5_thawing_days_trend_JAS",
"era5_thawing_degree_days_AMJ",
"era5_thawing_degree_days_JAS",
"era5_tp_AMJ",
"era5_tp_JAS",
]
cluster_features = [
"cell_area",
"water_area",
"x",
"y",
"arcticdem_aspect_median",
"arcticdem_curvature_median",
"arcticdem_dem_median",
"arcticdem_slope_median",
"era5_effective_snow_depth_trend_AMJ",
"era5_effective_snow_depth_trend_JAS",
"era5_effective_snow_depth_trend_JFM",
"era5_effective_snow_depth_trend_OND",
"era5_freezing_days_AMJ",
"era5_freezing_days_JAS",
"era5_freezing_days_JFM",
"era5_freezing_days_OND",
"era5_freezing_days_trend_AMJ",
"era5_freezing_days_trend_OND",
"era5_freezing_degree_days_trend_AMJ",
"era5_freezing_degree_days_trend_JFM",
"era5_freezing_degree_days_trend_OND",
"era5_lblt_max_JAS",
"era5_lblt_max_trend_AMJ",
"era5_lblt_max_trend_JAS",
"era5_lblt_max_trend_JFM",
"era5_lblt_max_trend_OND",
"era5_precipitation_occurrences_AMJ",
"era5_precipitation_occurrences_JFM",
"era5_precipitation_occurrences_trend_AMJ",
"era5_precipitation_occurrences_trend_JAS",
"era5_precipitation_occurrences_trend_JFM",
"era5_precipitation_occurrences_trend_OND",
"era5_sf_AMJ",
"era5_sf_trend_AMJ",
"era5_sf_trend_JAS",
"era5_snowc_mean_JFM",
"era5_snowc_mean_trend_AMJ",
"era5_snowc_mean_trend_OND",
"era5_sshf_AMJ",
"era5_sshf_JFM",
"era5_sshf_trend_AMJ",
"era5_sshf_trend_JFM",
"era5_t2m_avg_trend_AMJ",
"era5_t2m_avg_trend_JAS",
"era5_t2m_max_AMJ",
"era5_t2m_max_trend_JAS",
"era5_t2m_max_trend_JFM",
"era5_t2m_max_trend_OND",
"era5_t2m_min_JFM",
"era5_t2m_min_trend_OND",
"era5_t2m_range_JFM",
"era5_t2m_range_trend_AMJ",
"era5_t2m_range_trend_JFM",
"era5_t2m_skew_trend_AMJ",
"era5_t2m_skew_trend_JAS",
"era5_t2m_skew_trend_JFM",
"era5_t2m_skew_trend_OND",
]
@cli.default @cli.default
def main(grid: Grid, target: TargetDataset, selection: Literal["none", "cluster", "univariate"] = "none"): def main(grid: Grid, target: TargetDataset, selection: Literal["none", "cluster", "univariate"] = "none"):
"""Feature Importance Experiment.""" """Feature Importance Experiment."""
experiment_name = EXPERIMENT_NAME
if selection != "none":
experiment_name += f"_{selection=}"
levels = [3, 4, 5, 6] if grid == "hex" else [6, 7, 8, 9, 10] levels = [3, 4, 5, 6] if grid == "hex" else [6, 7, 8, 9, 10]
if DEV:
levels = [3, 6] if grid == "hex" else [6, 10]
for level in levels: for level in levels:
print(f"Running feature importance experiment for {grid} grid at level {level}...") print(f"Running feature importance experiment for {grid} grid at level {level}...")
members: list[L2SourceDataset] = ["ArcticDEM", "ERA5-shoulder"]
dimension_filters = {"ArcticDEM": {"aggregations": ["median"]}} dimension_filters = {"ArcticDEM": {"aggregations": ["median"]}}
if (grid == "hex" and level in [3, 4]) or (grid == "healpix" and level in [6, 7]): is_era5_median_grid = (grid == "hex" and level in [3, 4]) or (grid == "healpix" and level in [6, 7])
is_era5_mean_grid = (grid == "hex" and level in [5]) or (grid == "healpix" and level in [8, 9])
if is_era5_median_grid:
dimension_filters["ERA5-shoulder"] = {"aggregations": ["median"]} dimension_filters["ERA5-shoulder"] = {"aggregations": ["median"]}
feature_filters = {
"none": all_features,
"cluster": cluster_features,
"univariate": univariate_features,
}[selection]
if feature_filters is not None:
if not any(f.startswith("arcticdem") for f in feature_filters):
dimension_filters.pop("ArcticDEM", None)
members.remove("ArcticDEM")
if not any(f.startswith("era5") for f in feature_filters):
dimension_filters.pop("ERA5-shoulder", None)
members.remove("ERA5-shoulder")
elif is_era5_median_grid:
def _add_median(feature: str) -> str:
if not feature.startswith("era5"):
return feature
return (
feature.replace("JAS", "median_JAS")
.replace("AMJ", "median_AMJ")
.replace("JFM", "median_JFM")
.replace("OND", "median_OND")
)
feature_filters = [_add_median(f) for f in feature_filters]
elif is_era5_mean_grid:
def _add_mean(feature: str) -> str:
if not feature.startswith("era5"):
return feature
return (
feature.replace("JAS", "mean_JAS")
.replace("AMJ", "mean_AMJ")
.replace("JFM", "mean_JFM")
.replace("OND", "mean_OND")
)
feature_filters = [_add_mean(f) for f in feature_filters]
dataset_ensemble = DatasetEnsemble( dataset_ensemble = DatasetEnsemble(
grid=grid, level=level, members=["ArcticDEM", "ERA5-shoulder"], dimension_filters=dimension_filters grid=grid,
level=level,
members=members,
dimension_filters=dimension_filters,
post_merge_filters=feature_filters,
) )
for task in cast(list[Task], ["binary", "density"]): for task in cast(list[Task], ["binary", "density"]):
@ -42,11 +198,7 @@ def main(grid: Grid, target: TargetDataset, selection: Literal["none", "cluster"
# AutoGluon # AutoGluon
time_limit = 30 * 60 # 30 minutes time_limit = 30 * 60 # 30 minutes
if DEV:
time_limit = 2 * 60 # 2 minutes
presets = "extreme" presets = "extreme"
if DEV:
presets = "medium"
settings = AutoGluonRunSettings( settings = AutoGluonRunSettings(
time_limit=time_limit, time_limit=time_limit,
presets=presets, presets=presets,
@ -54,7 +206,7 @@ def main(grid: Grid, target: TargetDataset, selection: Literal["none", "cluster"
task=task, task=task,
target=target, target=target,
) )
train_autogluon(dataset_ensemble, settings, experiment=EXPERIMENT_NAME) train_autogluon(dataset_ensemble, settings, experiment=experiment_name)
# HPOCV # HPOCV
splitter = "stratified_shuffle" if task == "binary" else "kfold" splitter = "stratified_shuffle" if task == "binary" else "kfold"
@ -69,10 +221,7 @@ def main(grid: Grid, target: TargetDataset, selection: Literal["none", "cluster"
"rf": 100, # RF is slow, so we reduce the number of iterations "rf": 100, # RF is slow, so we reduce the number of iterations
"knn": 40, # kNN hpspace is small, so we reduce the number of iterations "knn": 40, # kNN hpspace is small, so we reduce the number of iterations
}[model] }[model]
if DEV:
n_iter = 3
scaler = "standard" if model in ["espa", "knn"] else "none" scaler = "standard" if model in ["espa", "knn"] else "none"
normalize = scaler != "none"
settings = HPOCVRunSettings( settings = HPOCVRunSettings(
n_iter=n_iter, n_iter=n_iter,
task=task, task=task,
@ -80,13 +229,13 @@ def main(grid: Grid, target: TargetDataset, selection: Literal["none", "cluster"
splitter=splitter, splitter=splitter,
model=model, model=model,
scaler=scaler, scaler=scaler,
normalize=normalize, normalize=False,
) )
hpsearch_cv(dataset_ensemble, settings, experiment=EXPERIMENT_NAME) hpsearch_cv(dataset_ensemble, settings, experiment=experiment_name)
stopwatch.summary() stopwatch.summary()
times = stopwatch.export() times = stopwatch.export()
times.to_parquet(RESULTS_DIR / EXPERIMENT_NAME / f"training_times_{target}_{grid}.parquet") times.to_parquet(RESULTS_DIR / experiment_name / f"training_times_{target}_{grid}.parquet")
print("Done.") print("Done.")

View file

@ -15,7 +15,7 @@ from entropice.utils.types import Grid, Model, TargetDataset, Task
cli = cyclopts.App("entropice-feature-importance") cli = cyclopts.App("entropice-feature-importance")
EXPERIMENT_NAME = "feature_importance_era5-shoulder_arcticdem-v2" EXPERIMENT_NAME = "feature_importance_alphaearth"
@cli.default @cli.default

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -8,7 +8,3 @@ external sources into the Entropice system:
- arcticdem: Terrain data from ArcticDEM - arcticdem: Terrain data from ArcticDEM
- alphaearth: Satellite image embeddings from AlphaEarth/Google Earth Engine - alphaearth: Satellite image embeddings from AlphaEarth/Google Earth Engine
""" """
from . import alphaearth, arcticdem, darts, era5
__all__ = ["alphaearth", "arcticdem", "darts", "era5"]

View file

@ -6,7 +6,3 @@ This package contains modules for machine learning workflows:
- training: Model training with eSPA, XGBoost, Random Forest, KNN - training: Model training with eSPA, XGBoost, Random Forest, KNN
- inference: Batch prediction pipeline for trained classifiers - inference: Batch prediction pipeline for trained classifiers
""" """
from . import autogluon, dataset, hpsearchcv, inference
__all__ = ["autogluon", "dataset", "hpsearchcv", "inference", "inference"]

View file

@ -298,6 +298,7 @@ class DatasetEnsemble:
# ?: We can't use L2SourceDataset as types here because cyclopts can't handle Literals as dict keys # ?: We can't use L2SourceDataset as types here because cyclopts can't handle Literals as dict keys
dimension_filters: dict[str, dict[str, list]] = field(default_factory=dict) dimension_filters: dict[str, dict[str, list]] = field(default_factory=dict)
variable_filters: dict[str, list[str]] = field(default_factory=dict) variable_filters: dict[str, list[str]] = field(default_factory=dict)
post_merge_filters: list[str] | None = None
def __post_init__(self): def __post_init__(self):
# Validate filters # Validate filters
@ -325,6 +326,15 @@ class DatasetEnsemble:
valid = {"x", "y", "cell_area", "land_area", "water_area", "land_ratio"} valid = {"x", "y", "cell_area", "land_area", "water_area", "land_ratio"}
assert len(filtered - valid) == 0 assert len(filtered - valid) == 0
if self.post_merge_filters is not None:
assert len(self.post_merge_filters) >= 1, "Post-merge filters must be a list with one or more entries."
assert "geometry" not in self.post_merge_filters, "Filtering on 'geometry' is not supported."
assert "cell_id" not in self.post_merge_filters, "Filtering on 'cell_id' is not supported."
print(
"Warning: Post-merge filters are not checked for validity!"
" Please ensure that they are valid columns in the final merged dataset."
)
def __hash__(self): def __hash__(self):
return int(self.id(), 16) return int(self.id(), 16)
@ -349,10 +359,20 @@ class DatasetEnsemble:
@cache @cache
def read_grid(self) -> gpd.GeoDataFrame: def read_grid(self) -> gpd.GeoDataFrame:
"""Load the grid dataframe and enrich it with lat-lon information.""" """Load the grid dataframe and enrich it with lat-lon information."""
# Define required columns that must always be included
required_columns = ["cell_id", "geometry"]
# Determine columns to load based on variable filters
if "Grid" in self.variable_filters: if "Grid" in self.variable_filters:
columns_to_load = self.variable_filters["Grid"] + ["cell_id", "geometry"] columns_to_load = list(set(self.variable_filters["Grid"] + required_columns))
else: else:
columns_to_load = ["cell_id", "geometry", "cell_area", "land_area", "water_area", "land_ratio", "x", "y"] default_grid_columns = ["cell_area", "land_area", "water_area", "land_ratio", "x", "y"]
columns_to_load = required_columns + default_grid_columns
# Apply post-merge filters if specified
if self.post_merge_filters is not None:
allowed_columns = set(self.post_merge_filters + required_columns)
columns_to_load = list(set(columns_to_load) & allowed_columns)
# Reading the data takes for the largest grids ~1.7s # Reading the data takes for the largest grids ~1.7s
gridfile = entropice.utils.paths.get_grid_file(self.grid, self.level) gridfile = entropice.utils.paths.get_grid_file(self.grid, self.level)
@ -557,6 +577,10 @@ class DatasetEnsemble:
raise NotImplementedError(f"Member {member} not implemented.") raise NotImplementedError(f"Member {member} not implemented.")
with stopwatch("Joining datasets"): with stopwatch("Joining datasets"):
dataset = dataset.join(member_dfs) dataset = dataset.join(member_dfs)
if self.post_merge_filters is not None:
dataset = dataset[list(set(self.post_merge_filters) & set(dataset.columns))]
print(f"Prepared dataset with {len(dataset)} samples and {len(dataset.columns)} features.") print(f"Prepared dataset with {len(dataset)} samples and {len(dataset.columns)} features.")
if cache_mode in ["read", "overwrite"]: if cache_mode in ["read", "overwrite"]:

View file

@ -266,6 +266,7 @@ def _compute_shap_explanation(model: Model, best_estimator: Pipeline, training_d
feature_names=training_data.feature_names, feature_names=training_data.feature_names,
output_names=training_data.target_labels, output_names=training_data.target_labels,
) )
explain_kwargs = {}
case "rf": case "rf":
masker = shap.maskers.Independent(data=training_data.X.as_numpy().train) masker = shap.maskers.Independent(data=training_data.X.as_numpy().train)
explainer = TreeExplainer( explainer = TreeExplainer(
@ -273,8 +274,10 @@ def _compute_shap_explanation(model: Model, best_estimator: Pipeline, training_d
data=masker, data=masker,
feature_names=training_data.feature_names, feature_names=training_data.feature_names,
) )
explain_kwargs = {"check_additivity": False} # Additivity does not hold for RF, see
case "xgboost": case "xgboost":
explainer = TreeExplainer(best_estimator.named_steps["model"], feature_names=training_data.feature_names) explainer = TreeExplainer(best_estimator.named_steps["model"], feature_names=training_data.feature_names)
explain_kwargs = {"check_additivity": False} # Additivity does not hold for XGBoost, see
case _: case _:
raise ValueError(f"Unknown model: {model}") raise ValueError(f"Unknown model: {model}")
@ -288,7 +291,7 @@ def _compute_shap_explanation(model: Model, best_estimator: Pipeline, training_d
samples = best_estimator.named_steps["scaler"].transform(samples) samples = best_estimator.named_steps["scaler"].transform(samples)
if "normalizer" in best_estimator.named_steps: if "normalizer" in best_estimator.named_steps:
samples = best_estimator.named_steps["normalizer"].transform(samples) samples = best_estimator.named_steps["normalizer"].transform(samples)
explanation = explainer(samples) explanation = explainer(samples, **explain_kwargs)
return explanation return explanation

View file

@ -7,7 +7,3 @@ This package contains modules for spatial data processing and grid-based operati
- watermask: Ocean masking utilities - watermask: Ocean masking utilities
- xvec: Extended vector operations for xarray - xvec: Extended vector operations for xarray
""" """
from . import aggregators, grids, watermask, xvec
__all__ = ["aggregators", "grids", "watermask", "xvec"]

View file

@ -5,7 +5,3 @@ This package contains utility modules used across the Entropice system:
- paths: Centralized path management and configuration - paths: Centralized path management and configuration
- codecs: Custom codecs for data serialization - codecs: Custom codecs for data serialization
""" """
from . import codecs, paths
__all__ = ["codecs", "paths"]

View file

@ -149,9 +149,44 @@ class Training:
else: else:
return None return None
def to_record(self) -> dict[str, Any]:
"""Convert the training run to a dictionary record for easy creation of DataFrames."""
train_metrics = {f"train_{k}": v for k, v in self.get_metrics_from_split("train").items()}
test_metrics = {f"test_{k}": v for k, v in self.get_metrics_from_split("test").items()}
complete_metrics = {f"complete_{k}": v for k, v in self.get_metrics_from_split("complete").items()}
return {
"path": self.path,
"dataset": f"{self.dataset.grid}-{self.dataset.level}{self.dataset.members}",
"grid": self.dataset.grid,
"level": self.dataset.level,
"members": self.dataset.members,
"method": type(self.method).__name__,
"task": self.task,
"target": self.target,
"model_type": self.model_type,
"run": self,
**train_metrics,
**test_metrics,
**complete_metrics,
}
def get_metrics_from_split(self, split: Literal["train", "test", "complete"]) -> dict[str, float]: def get_metrics_from_split(self, split: Literal["train", "test", "complete"]) -> dict[str, float]:
"""Get a dictionary of metric names and values for the specified split.""" """Get a dictionary of metric names and values for the specified split."""
return self.metrics[self.metrics["split"] == split].set_index("metric")["score"].to_dict() # ty:ignore[invalid-return-type] metrics_df = self.metrics[self.metrics["split"] == split].copy()
# If regression task and HPOCV: remove all "neg_" from the metric names
# If regression task and AutoML: negate all pot. neg metrics to be consistent with HPOCV
if self.task not in ["binary", "count_regimes", "density_regimes"]:
if self.method_type == "HPOCV":
metrics_df["metric"] = metrics_df["metric"].str.replace("neg_", "", regex=False)
elif self.method_type == "AutoML":
neg_metrics = [
"root_mean_squared_error",
"mean_squared_error",
"mean_absolute_error",
"median_absolute_error",
]
metrics_df.loc[metrics_df["metric"].isin(neg_metrics), "score"] *= -1
return metrics_df.set_index("metric")["score"].to_dict() # ty:ignore[invalid-return-type]
def save(self): def save(self):
"""Save the training results to the specified path.""" """Save the training results to the specified path."""
@ -221,6 +256,10 @@ class Training:
target = config["target"] target = config["target"]
model_type = config["model_type"] model_type = config["model_type"]
# Legacy support for old config files
if "add_lonlat" in config["dataset"].keys():
config["dataset"].pop("add_lonlat")
dataset = DatasetEnsemble(**config["dataset"]) dataset = DatasetEnsemble(**config["dataset"])
method_type = config["method_type"] method_type = config["method_type"]