diff --git a/pixi.lock b/pixi.lock index 6900a66..d84af50 100644 --- a/pixi.lock +++ b/pixi.lock @@ -40,17 +40,22 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda + - pypi: https://files.pythonhosted.org/packages/6d/f4/5a7d76dc844d3ff8ed1f1a043158aa393794aebb787d3e2f8c0fe87f674f/aiobotocore-3.8.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a1/7e/6815aab7d3a56610891c76ef79095677b8b5be6646aaf00f69b221765021/aiohttp-3.13.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/10/a1/510b0a7fadc6f43a6ce50152e69dbd86415240835868bb0bd9b5b88b1e06/aioitertools-0.13.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/4c/f4/4d0193dc5bab3af74e9560a8b45830d88ac707467d15ceff7e3df17adc41/anndata-0.12.10-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a0/d3/54cd560804a8c2b898824778e86c13c2a14600bc83532a9c4f69f2f469c3/array_api_compat-1.14.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/2d/6a/885bc91484e1aa8f618f6f0228d76d0e67000b0fdd6090673b777e311913/asciitree-0.3.3.tar.gz - pypi: https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/0e/f2/4bd8f2f419088feb3ce55f0ca91040ff902f402edfd197450b20a2e1d533/botocore-1.43.46-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/06/f3/39cf3367b8107baa44f861dc802cbf16263c945b62d8265d36034fc07bea/cachetools-7.0.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/03/f4/44d3b830a20e89ff82a3134912d9a1cf6084d64f3b95dcad40f74449a654/charset_normalizer-3.4.5-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/1b/24/e95471ae93c08d3606c9c7343cf65d490f154daa88b50581957a0aa780f4/colorcet-3.2.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/5f/4b/6157f24ca425b89fe2eb7e7be642375711ab671135be21e6faa100f7448c/contourpy-1.3.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/66/d5/bd4c03e9516d3cf788a270debe28d687e5c48b13a9931599bbddf01de302/cuda_bindings-12.9.6-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/92/de/8ca2b613042550dcf9ef50c596c8b1f602afda92cf9032ac28a73f6ee410/cuda_pathfinder-1.4.2-py3-none-any.whl @@ -67,23 +72,26 @@ environments: - pypi: https://pypi.nvidia.com/dask-cuda/dask_cuda-24.10.0-py3-none-any.whl - pypi: https://pypi.nvidia.com/dask-cudf-cu12/dask_cudf_cu12-24.10.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f6/11/d758ed9f1e9d6917402c475a8512b0a0204873226479d47cc440e50404ec/dask_expr-1.1.14-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/3f/5b/15d6d6ff8697b188787609be059fe4f07f99fc00f43f68e9e1540fa8733e/dask_image-2026.5.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/cb/41/247627c8b9fef5c605d00546b85771a8fe42975b9616a557cead5468789b/datashader-0.19.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/84/d0/205d54408c08b13550c733c4b85429e7ead111c7f0014309637425520a9a/deprecated-1.3.1-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a0/15/3746074e6a20e87de78c61fe8eb63a70ad01cf37f0ef1a8611fd7f9e5701/distributed-2024.9.0-py3-none-any.whl - pypi: https://pypi.nvidia.com/distributed-ucxx-cu12/distributed_ucxx_cu12-0.40.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/55/e2/2537ebcff11c1ee1ff17d8d0b6f4db75873e3b0fb32c2d4a2ee31ecb310a/docstring_parser-0.17.0-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/51/ac/e5d886f892666d2d1e5cb8c1a41146e1d79ae8896477b1153a21711d3b44/fasteners-0.20-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/01/e2/5e5515562b2e9a56d84659377176aef7345da2c3c22909a1897fe27e14dd/fastrlock-0.8.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/a4/a5/842ae8f0c08b61d6484b52f99a03510a3a72d23141942d216ebe81fefbce/filelock-3.25.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8a/d7/8e4845993ee233c2023d11babe9b3dae7d30333da1d792eeccebcb77baab/fonttools-4.62.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl - pypi: https://files.pythonhosted.org/packages/11/b1/71a477adc7c36e5fb628245dfbdea2166feae310757dea848d02bd0689fd/frozenlist-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl - pypi: https://files.pythonhosted.org/packages/e6/ab/fb21f4c939bb440104cc2b396d3be1d9b7a9fd3c6c2a53d98c45b3d7c954/fsspec-2026.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/3c/78/6a04792ace63a93e162f1305392d500ae8ddcb620e7eb88a22fd622b35bb/geopandas-1.1.3-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f6/fd/33aa4ec62b290477181c55bb1c9302c9698c58c0ce9a6ab4874abc8b0d60/google_crc32c-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl - pypi: https://files.pythonhosted.org/packages/52/a0/c1f604538ff6db22a0690be2dc44ab59178e115f63c917794e529356ab23/h5py-3.16.0-cp311-cp311-manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/49/fa/391e437a34e55095173dca5f24070d89cbc233ff85bf1c29c93248c6588d/imageio-2.37.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl - pypi: https://download.pytorch.org/whl/jinja2-3.1.6-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/7b/91/984aca2ec129e2757d1e4e3c81c3fcda9d0f85b74670a094cc443d9ee949/joblib-1.5.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/80/46/bddc13df6c2a40741e0cc7865bb1c9ed4796b6760bd04ce5fae3928ef917/kiwisolver-1.5.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl - pypi: https://files.pythonhosted.org/packages/8a/a1/8d812e53a5da1687abb10445275d41a8b13adb781bbf7196ddbcf8d88505/lazy_loader-0.5-py3-none-any.whl @@ -97,22 +105,24 @@ environments: - pypi: https://files.pythonhosted.org/packages/12/b5/99cf8772fdd846c07da4fd70f07812a3c8fd17ea2409522c946bb0f2b277/llvmlite-0.46.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl - pypi: https://files.pythonhosted.org/packages/db/bc/83e112abc66cd466c6b83f99118035867cecd41802f8d044638aa78a106e/locket-1.0.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/30/ac/0273f6fcb5f42e314c6d8cd99effae6a5354604d461b8d392b5ec9530a54/markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://download.pytorch.org/whl/markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/8f/a0/7024215e95d456de5883e6732e708d8187d9753a21d32f8ddb3befc0c445/matplotlib-3.10.8-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/da/e0/6cc2e852837cd6086fe7d8406af4294e66827a60a4cf60b86575a4a65ca8/msgpack-1.1.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/5a/56/21b27c560c13822ed93133f08aa6372c53a8e067f11fbed37b4adcdac922/multidict-6.7.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/51/c0/00c9809d8b9346eb238a6bbd5f83e846a4ce4503da94a4c08cb7284c325b/multipledispatch-1.0.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/4f/02/eff2e0a291201b70f5c342a8dac0ec67c75aa912af50a999054b99755832/multiscale_spatial_image-2.0.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ef/82/7a9d0550484a62c6da82858ee9419f3dd1ccc9aa1c26a1e43da3ecd20b0d/natsort-8.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/19/16/aa6e3ba3cd45435c117d1101b278b646444ed05b7c712af631b91353f573/numba-0.64.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/54/4b/195ac84cc8f6077b4f0f421e8daee21b7f1bd88cb7716414234379fe68ec/numcodecs-0.16.5-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/a6/a8/908a226632ffabf19caf8c99f1b2898f2f22aac02795a6fe9d018fd6d9dd/numcodecs-0.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/3a/d0/edc009c27b406c4f9cbc79274d6e46d634d139075492ad055e3d68445925/numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://pypi.nvidia.com/nvidia-cublas-cu12/nvidia_cublas_cu12-12.1.3.1-py3-none-manylinux1_x86_64.whl - pypi: https://pypi.nvidia.com/nvidia-cuda-cupti-cu12/nvidia_cuda_cupti_cu12-12.1.105-py3-none-manylinux1_x86_64.whl - pypi: https://pypi.nvidia.com/nvidia-cuda-nvrtc-cu12/nvidia_cuda_nvrtc_cu12-12.1.105-py3-none-manylinux1_x86_64.whl - pypi: https://pypi.nvidia.com/nvidia-cuda-runtime-cu12/nvidia_cuda_runtime_cu12-12.1.105-py3-none-manylinux1_x86_64.whl - - pypi: https://download.pytorch.org/whl/cu121/nvidia_cudnn_cu12-9.1.0.70-py3-none-manylinux2014_x86_64.whl + - pypi: https://download.pytorch.org/whl/cu124/nvidia_cudnn_cu12-9.1.0.70-py3-none-manylinux2014_x86_64.whl - pypi: https://pypi.nvidia.com/nvidia-cufft-cu12/nvidia_cufft_cu12-11.0.2.54-py3-none-manylinux1_x86_64.whl - pypi: https://pypi.nvidia.com/nvidia-curand-cu12/nvidia_curand_cu12-10.3.2.106-py3-none-manylinux1_x86_64.whl - pypi: https://pypi.nvidia.com/nvidia-cusolver-cu12/nvidia_cusolver_cu12-11.4.5.107-py3-none-manylinux1_x86_64.whl @@ -121,17 +131,23 @@ environments: - pypi: https://pypi.nvidia.com/nvidia-nvjitlink-cu12/nvidia_nvjitlink_cu12-12.9.86-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl - pypi: https://pypi.nvidia.com/nvidia-nvtx-cu12/nvidia_nvtx_cu12-12.1.105-py3-none-manylinux1_x86_64.whl - pypi: https://pypi.nvidia.com/nvtx/nvtx-0.2.14-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/24/c8/35ac60b20eccccf84638a872c3b4ebefad46b20f87540ca17a37908b1db6/ome_zarr-0.11.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/2c/8b/90eb44a40476fa0e71e05a0283947cfd74a5d36121a11d926ad6f3193cc4/opencv_python-4.11.0.86-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - pypi: https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fc/a5/4d82be566f069d7a9a702dcdf6f9106df0e0b042e738043c0cc7ddd7e3f6/pandas-2.2.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/ac/37/1351bbfabbacbe92cd38774f8779ff680fab48c36b5fed9bcfe0c160009c/param-2.4.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/71/e7/40fb618334dcdf7c5a316c0e7343c5cd82d3d866edc100d98e29bc945ecd/partd-1.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f1/70/ba4b949bdc0490ab78d545459acd7702b211dfccf7eb89bbc1060f52818d/patsy-1.0.2-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a2/c8/46dfeac5825e600579157eea177be43e2f7ff4a99da9d0d0a49533509ac5/pillow-12.1.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/b8/02/5bf3639f5b77e9b183011c08541c5039ba3d04f5316c70312b48a8e003a9/pims-0.7.tar.gz + - pypi: https://files.pythonhosted.org/packages/28/be/0ff05fcd2938fb58ad9219bd54135968342d214737e012d62d43f06a2dd6/platformdirs-4.11.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a7/f8/fad8470d9701c1b208cc24919a661efdf565373e77e7d06400642a759285/polars-1.39.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/cf/60/c0d0b6720437685223457242a79f6bba443485ca85928645786479ebed86/polars_runtime_32-1.39.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/2a/2d/d4bf65e47cea8ff2c794a600c4fd1273a7902f268757c531e0ee9f18aa58/pooch-1.9.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/52/6a/57f43e054fb3d3a56ac9fc532bc684fc6169a26c75c353e65425b3e56eef/propcache-0.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/b5/70/5d8df3b09e25bce090399cf48e452d25c935ab72dad19406c77f4e828045/psutil-7.2.2-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/4c/21/9ca93b84b92ef927814cb7ba37f0774a484c849d58f0b692b16af8eebcfb/pyarrow-17.0.0-cp311-cp311-manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/8c/b2/23f4032cd1c9744aa8e9ecda43cd4d755fcb209f7f40fae035248f31a679/pyct-0.6.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl - pypi: https://pypi.nvidia.com/pylibcudf-cu12/pylibcudf_cu12-24.10.1-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl - pypi: https://pypi.nvidia.com/pylibcugraph-cu12/pylibcugraph_cu12-24.10.0-cp311-cp311-manylinux_2_28_x86_64.whl @@ -152,40 +168,50 @@ environments: - pypi: https://files.pythonhosted.org/packages/14/25/b208c5683343959b670dc001595f2f3737e051da617f66c31f7c4fa93abc/rich-14.3.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/13/2f/b4530fbf948867702d0a3f27de4a6aab1d156f406d72852ab902c4d04de9/rich_rst-1.3.2-py3-none-any.whl - pypi: https://pypi.nvidia.com/rmm-cu12/rmm_cu12-24.10.0-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/57/e1/64c264db50b68de8a438b60ceeb921b2f22da3ebb7ad6255150225d0beac/s3fs-2026.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/32/e9/c1d43543da87cd27e8e2a74db85cf0b6c5cff2d5f04a86bd584d2fbc2bb0/scanpy-1.11.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a5/2a/e71c1a7d90e70da67b88ccc609bd6ae54798d5847369b15d3a8052232f9d/scikit_image-0.26.0-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/36/4d/4a67f30778a45d542bbea5db2dbfa1e9e100bf9ba64aefe34215ba9f11f6/scikit_learn-1.8.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/09/7d/af933f0f6e0767995b4e2d705a0665e454d1c19402aa7e895de3951ebb04/scipy-1.17.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/83/11/00d3c3dfc25ad54e731d91449895a79e4bf2384dc3ac01809010ba88f6d5/seaborn-0.13.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/44/7c/64d18f2374e19ba9bee52dee885ec81f808a1863ed0995495b83319b88bc/session_info2-0.4-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/13/02/58b0b8d9c17c93ab6340edd8b7308c0c5a5b81f94ce65705819b7416dba5/shapely-2.1.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl - pypi: https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e8/ae/fa6cd331b364ad2bbc31652d025f5747d89cbb75576733dfdf8efe3e4d62/slicerator-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/b9/c1/16eb09d03eb7096b901e816dc93f53819f83b867c7d5dbb075f837d0120b/spatial_image-1.2.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/14/96/015832d04de478b5ccf089fd259bff58adcff195cf27fec29b2bed307a46/spatialdata-0.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/40/c6/9ae8e9b0721e9b6eb5f340c3a0ce8cd7cce4f66e03dd81f80d60f111987f/statsmodels-0.14.6-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/b2/fe/81695a1aa331a842b582453b605175f419fe8540355886031328089d840a/sympy-1.13.1-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/32/d5/f9a850d79b0851d1d4ef6456097579a9005b31fea68726a4ae5f2d82ddd9/threadpoolctl-3.6.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/1a/e4/e804505f87627cd8cdae9c010c47c4485fd8c1ce31a7dd0ab7fcc4707377/tifffile-2026.3.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fb/12/5911ae3eeec47800503a238d971e51722ccea5feb8569b735184d5fcdbc0/toolz-1.1.0-py3-none-any.whl - - pypi: https://download.pytorch.org/whl/cu121/torch-2.5.1%2Bcu121-cp311-cp311-linux_x86_64.whl + - pypi: https://download-r2.pytorch.org/whl/cu121/torch-2.5.1%2Bcu121-cp311-cp311-linux_x86_64.whl - pypi: https://files.pythonhosted.org/packages/1e/d3/4dffd7300500465e0b4a2ae917dcb2ce771de0b9a772670365799a27c024/torch_geometric-2.7.0-py3-none-any.whl - pypi: https://data.pyg.org/whl/torch-2.5.0%2Bcu121/torch_scatter-2.1.2%2Bpt25cu121-cp311-cp311-linux_x86_64.whl - pypi: https://data.pyg.org/whl/torch-2.5.0%2Bcu121/torch_sparse-0.6.18%2Bpt25cu121-cp311-cp311-linux_x86_64.whl - pypi: https://files.pythonhosted.org/packages/c3/a2/c7f6ebf546f8f644edf0f999aa98ece106986a77a7b922316bf6414ff825/torchmetrics-1.9.0-py3-none-any.whl - - pypi: https://download.pytorch.org/whl/cu121/torchvision-0.20.1%2Bcu121-cp311-cp311-linux_x86_64.whl + - pypi: https://download-r2.pytorch.org/whl/cu121/torchvision-0.20.1%2Bcu121-cp311-cp311-linux_x86_64.whl - pypi: https://files.pythonhosted.org/packages/b2/04/7b5705d5b3c0fab088f434f9c83edac1573830ca49ccf29fb83bf7178eec/tornado-6.5.5-cp39-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl - pypi: https://files.pythonhosted.org/packages/16/e1/3079a9ff9b8e11b846c6ac5c8b5bfb7ff225eee721825310c91b3b50304f/tqdm-4.67.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/42/0e/c9aecfed527ef6bff91ea51036cfcf4b6f6218bc6f507cdf4dff0bb2c81f/treelite-4.3.0-py3-none-manylinux2014_x86_64.whl - - pypi: https://download.pytorch.org/whl/triton-3.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: https://download.pytorch.org/whl/typing_extensions-4.15.0-py3-none-any.whl + - pypi: https://download-r2.pytorch.org/whl/triton-3.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl - pypi: https://pypi.nvidia.com/ucx-py-cu12/ucx_py_cu12-0.40.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl - pypi: https://pypi.nvidia.com/ucxx-cu12/ucxx_cu12-0.40.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/43/d2/fcf7192dd1cd8c090b6cfd53fa223c4fb2887a17c47e06bc356d44f40dfb/umap_learn-0.5.11-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/71/71/4cd2151a236f44a6e2dd4ed8011838d7ba0be3d656c8bafdfc65a2ed1917/wrapt-2.3.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/40/ed/1c4631ad5909487ea8907cd326d9855c2207d790e3936e77bda48173b8be/xarray-2024.11.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/aa/7b/9adbd82e2b7b8571da23856a890324b42cfbc38ae0ceac2177e5256f7216/xarray_dataclasses-1.9.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/a9/6d/f585a27b380ee987619b5617c0ca672a71a4345b67cfedbb6299750ce845/xarray_schema-0.0.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/61/ee/9d0bb9f1bbaf347efe2ca6ad7bae259d6ed9e7a2b4441bd16b88723145a1/xarray_spatial-0.5.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a5/86/cf2c0321dc3940a7aa73076f4fd677a0fb3e405cb297ead7d864fd90847e/xxhash-3.6.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl - pypi: https://files.pythonhosted.org/packages/9a/64/c53487d9f4968045b8afa51aed7ca44f58b2589e772f32745f3744476c82/yarl-1.23.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/44/15/bb13b4913ef95ad5448490821eee4671d0e67673342e4d4070854e5fe081/zarr-3.1.5-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/5e/d8/9ffd8c237b3559945bb52103cf0eed64ea098f7b7f573f8d2962ef27b4b2/zarr-2.18.7-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/80/ab/11a76c1e2126084fde2639514f24e6111b789b0bfa4fc6264a8975c7e1f1/zict-3.0.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl - pypi: ./ @@ -303,6 +329,21 @@ packages: purls: [] size: 28948 timestamp: 1770939786096 +- pypi: https://files.pythonhosted.org/packages/6d/f4/5a7d76dc844d3ff8ed1f1a043158aa393794aebb787d3e2f8c0fe87f674f/aiobotocore-3.8.0-py3-none-any.whl + name: aiobotocore + version: 3.8.0 + sha256: 8bc605132cadfe844a3f334635a0a64fa5e360a4a206e915d99d53db5b6deeba + requires_dist: + - aiohttp>=3.12.0,<4.0.0 + - aioitertools>=0.5.1,<1.0.0 + - botocore>=1.43.3,<1.43.47 + - python-dateutil>=2.1,<3.0.0 + - jmespath>=0.7.1,<2.0.0 + - multidict>=6.0.0,<7.0.0 + - typing-extensions>=4.14.0,<5.0.0 ; python_full_version < '3.11' + - wrapt>=1.10.10,<3.0.0 + - httpx>=0.25.1,<0.29 ; extra == 'httpx' + requires_python: '>=3.10' - pypi: https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl name: aiohappyeyeballs version: 2.6.1 @@ -326,6 +367,13 @@ packages: - brotlicffi>=1.2 ; platform_python_implementation != 'CPython' and extra == 'speedups' - backports-zstd ; python_full_version < '3.14' and platform_python_implementation == 'CPython' and extra == 'speedups' requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/10/a1/510b0a7fadc6f43a6ce50152e69dbd86415240835868bb0bd9b5b88b1e06/aioitertools-0.13.0-py3-none-any.whl + name: aioitertools + version: 0.13.0 + sha256: 0be0292b856f08dfac90e31f4739432f4cb6d7520ab9eb73e143f4f2fa5259be + requires_dist: + - typing-extensions>=4.0 ; python_full_version < '3.10' + requires_python: '>=3.9' - pypi: https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl name: aiosignal version: 1.4.0 @@ -442,11 +490,25 @@ packages: - torch ; extra == 'dev' - sparse>=0.15.1 ; extra == 'dev' requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/2d/6a/885bc91484e1aa8f618f6f0228d76d0e67000b0fdd6090673b777e311913/asciitree-0.3.3.tar.gz + name: asciitree + version: 0.3.3 + sha256: 4aa4b9b649f85e3fcb343363d97564aa1fb62e249677f2e18a96765145cc0f6e - pypi: https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl name: attrs version: 25.4.0 sha256: adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373 requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/0e/f2/4bd8f2f419088feb3ce55f0ca91040ff902f402edfd197450b20a2e1d533/botocore-1.43.46-py3-none-any.whl + name: botocore + version: 1.43.46 + sha256: cb673891e623ae6e6a1bf24d94ef169504f3eb02584adb5d5bee2f6aae819b60 + requires_dist: + - jmespath>=0.7.1,<2.0.0 + - python-dateutil>=2.1,<3.0.0 + - urllib3>=1.25.4,!=2.2.0,<3 + - awscrt==0.32.2 ; extra == 'crt' + requires_python: '>=3.10' - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda sha256: 0b75d45f0bba3e95dc693336fa51f40ea28c980131fec438afb7ce6118ed05f6 md5: d2ffd7602c02f2b316fd921d39876885 @@ -494,6 +556,31 @@ packages: version: 3.1.2 sha256: 9acb47f6afd73f60dc1df93bb801b472f05ff42fa6c84167d25cb206be1fbf4a requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/1b/24/e95471ae93c08d3606c9c7343cf65d490f154daa88b50581957a0aa780f4/colorcet-3.2.1-py3-none-any.whl + name: colorcet + version: 3.2.1 + sha256: 3f6fde13cef2169222dd5fe2a2bf847c02d644470fdf167ed566f6421df470f7 + requires_dist: + - pre-commit ; extra == 'tests' + - pytest>=2.8.5 ; extra == 'tests' + - pytest-cov ; extra == 'tests' + - packaging ; extra == 'tests' + - colorcet[tests] ; extra == 'tests-extra' + - pytest-mpl ; extra == 'tests-extra' + - numpy ; extra == 'examples' + - holoviews ; extra == 'examples' + - matplotlib ; extra == 'examples' + - bokeh ; extra == 'examples' + - colorcet[examples] ; extra == 'tests-examples' + - nbval ; extra == 'tests-examples' + - colorcet[examples] ; extra == 'doc' + - nbsite>=0.8.4 ; extra == 'doc' + - sphinx-copybutton ; extra == 'doc' + - colorcet[tests] ; extra == 'all' + - colorcet[tests-extra] ; extra == 'all' + - colorcet[examples] ; extra == 'all' + - colorcet[doc] ; extra == 'all' + requires_python: '>=3.10' - pypi: https://files.pythonhosted.org/packages/5f/4b/6157f24ca425b89fe2eb7e7be642375711ab671135be21e6faa100f7448c/contourpy-1.3.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl name: contourpy version: 1.3.3 @@ -886,6 +973,60 @@ packages: - crick ; extra == 'analyze' - distributed ; extra == 'analyze' requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/3f/5b/15d6d6ff8697b188787609be059fe4f07f99fc00f43f68e9e1540fa8733e/dask_image-2026.5.0-py3-none-any.whl + name: dask-image + version: 2026.5.0 + sha256: acf86cd7f0f1e97804198d30b7cc931efd29f9dec86c65ec004b50405c3f5227 + requires_dist: + - dask[array]>=2024.4.1 + - numpy>=1.18 + - scipy>=1.7.0 + - pims>=0.4.1 + - tifffile>=2020.10.1 + - dask[dataframe]>=2024.4.1 ; extra == 'dataframe' + - pandas>=2.0.0 ; extra == 'dataframe' + - build>=1.2.1 ; extra == 'test' + - coverage>=7.2.1 ; extra == 'test' + - flake8>=6.0.0 ; extra == 'test' + - flake8-pyproject ; extra == 'test' + - pytest>=7.2.2 ; extra == 'test' + - pytest-cov>=4.0.0 ; extra == 'test' + - pytest-flake8>=1.1.1 ; extra == 'test' + - pytest-timeout>=2.3.1 ; extra == 'test' + - twine>=3.1.1 ; extra == 'test' + - cupy>=9.0.0 ; extra == 'gpu' + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/cb/41/247627c8b9fef5c605d00546b85771a8fe42975b9616a557cead5468789b/datashader-0.19.1-py3-none-any.whl + name: datashader + version: 0.19.1 + sha256: 7ce7154ff3ed070607f429355f57002fee5a17964e47c0b6447eeafe8cef9c82 + requires_dist: + - colorcet + - multipledispatch + - numba + - numpy + - packaging + - pandas + - param + - pyct + - requests + - scipy + - toolz + - xarray + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/84/d0/205d54408c08b13550c733c4b85429e7ead111c7f0014309637425520a9a/deprecated-1.3.1-py2.py3-none-any.whl + name: deprecated + version: 1.3.1 + sha256: 597bfef186b6f60181535a29fbe44865ce137a5079f295b479886c82729d5f3f + requires_dist: + - wrapt>=1.10,<3 + - inspect2 ; python_full_version < '3' + - tox ; extra == 'dev' + - pytest ; extra == 'dev' + - pytest-cov ; extra == 'dev' + - bump2version<1 ; extra == 'dev' + - setuptools ; python_full_version >= '3.12' and extra == 'dev' + requires_python: '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*' - pypi: https://files.pythonhosted.org/packages/a0/15/3746074e6a20e87de78c61fe8eb63a70ad01cf37f0ef1a8611fd7f9e5701/distributed-2024.9.0-py3-none-any.whl name: distributed version: 2024.9.0 @@ -953,6 +1094,11 @@ packages: - pytest ; extra == 'test' - cloudpickle ; extra == 'test' requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/51/ac/e5d886f892666d2d1e5cb8c1a41146e1d79ae8896477b1153a21711d3b44/fasteners-0.20-py3-none-any.whl + name: fasteners + version: '0.20' + sha256: 9422c40d1e350e4259f509fb2e608d6bc43c0136f79a00db1b49046029d0b3b7 + requires_python: '>=3.6' - pypi: https://files.pythonhosted.org/packages/01/e2/5e5515562b2e9a56d84659377176aef7345da2c3c22909a1897fe27e14dd/fastrlock-0.8.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl name: fastrlock version: 0.8.3 @@ -1398,6 +1544,11 @@ packages: - markupsafe>=2.0 - babel>=2.7 ; extra == 'i18n' requires_python: '>=3.7' +- pypi: https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl + name: jmespath + version: 1.1.0 + sha256: a5663118de4908c91729bea0acadca56526eb2698e83de10cd116ae0f4e97c64 + requires_python: '>=3.9' - pypi: https://files.pythonhosted.org/packages/7b/91/984aca2ec129e2757d1e4e3c81c3fcda9d0f85b74670a094cc443d9ee949/joblib-1.5.3-py3-none-any.whl name: joblib version: 1.5.3 @@ -1906,10 +2057,9 @@ packages: - pytest-regressions ; extra == 'testing' - requests ; extra == 'testing' requires_python: '>=3.10' -- pypi: https://files.pythonhosted.org/packages/30/ac/0273f6fcb5f42e314c6d8cd99effae6a5354604d461b8d392b5ec9530a54/markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl +- pypi: https://download.pytorch.org/whl/markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl name: markupsafe version: 3.0.3 - sha256: 0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf requires_python: '>=3.9' - pypi: https://files.pythonhosted.org/packages/8f/a0/7024215e95d456de5883e6732e708d8187d9753a21d32f8ddb3befc0c445/matplotlib-3.10.8-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl name: matplotlib @@ -1960,6 +2110,38 @@ packages: requires_dist: - typing-extensions>=4.1.0 ; python_full_version < '3.11' requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/51/c0/00c9809d8b9346eb238a6bbd5f83e846a4ce4503da94a4c08cb7284c325b/multipledispatch-1.0.0-py3-none-any.whl + name: multipledispatch + version: 1.0.0 + sha256: 0c53cd8b077546da4e48869f49b13164bebafd0c2a5afceb6bb6a316e7fb46e4 +- pypi: https://files.pythonhosted.org/packages/4f/02/eff2e0a291201b70f5c342a8dac0ec67c75aa912af50a999054b99755832/multiscale_spatial_image-2.0.2-py3-none-any.whl + name: multiscale-spatial-image + version: 2.0.2 + sha256: 0c25fe7d743293bec06811ccd19842c0998dcdb99b58a0102116340d97d7dfcc + requires_dist: + - dask + - numpy + - python-dateutil + - spatial-image>=0.2.1 + - xarray>=2024.10.0 + - zarr + - dask-image ; extra == 'dask-image' + - pyimagej ; extra == 'imagej' + - itk-filtering>=5.3.0 ; extra == 'itk' + - matplotlib>=3.9.2,<4 ; extra == 'notebooks' + - ome-types>=0.5.1.post1,<0.6 ; extra == 'notebooks' + - tqdm>=4.66.4,<5 ; extra == 'notebooks' + - dask-image ; extra == 'test' + - fsspec ; extra == 'test' + - ipfsspec ; extra == 'test' + - itk-filtering>=5.3.0 ; extra == 'test' + - jsonschema ; extra == 'test' + - nbmake ; extra == 'test' + - pooch ; extra == 'test' + - pytest ; extra == 'test' + - pytest-mypy ; extra == 'test' + - urllib3 ; extra == 'test' + requires_python: '>=3.10,<3.13' - pypi: https://files.pythonhosted.org/packages/ef/82/7a9d0550484a62c6da82858ee9419f3dd1ccc9aa1c26a1e43da3ecd20b0d/natsort-8.4.0-py3-none-any.whl name: natsort version: 8.4.0 @@ -2029,6 +2211,26 @@ packages: - llvmlite>=0.46.0.dev0,<0.47 - numpy>=1.22,<2.5 requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/a6/a8/908a226632ffabf19caf8c99f1b2898f2f22aac02795a6fe9d018fd6d9dd/numcodecs-0.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + name: numcodecs + version: 0.15.1 + sha256: cdfaef9f5f2ed8f65858db801f1953f1007c9613ee490a1c56233cd78b505ed5 + requires_dist: + - numpy>=1.24 + - deprecated + - sphinx ; extra == 'docs' + - sphinx-issues ; extra == 'docs' + - pydata-sphinx-theme ; extra == 'docs' + - numpydoc ; extra == 'docs' + - coverage ; extra == 'test' + - pytest ; extra == 'test' + - pytest-cov ; extra == 'test' + - importlib-metadata ; extra == 'test-extras' + - msgpack ; extra == 'msgpack' + - zfpy>=1.0.0 ; extra == 'zfpy' + - pcodec>=0.3,<0.4 ; extra == 'pcodec' + - crc32c>=2.7 ; extra == 'crc32c' + requires_python: '>=3.11' - pypi: https://files.pythonhosted.org/packages/54/4b/195ac84cc8f6077b4f0f421e8daee21b7f1bd88cb7716414234379fe68ec/numcodecs-0.16.5-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl name: numcodecs version: 0.16.5 @@ -2082,7 +2284,7 @@ packages: version: 12.1.105 sha256: 6e258468ddf5796e25f1dc591a31029fa317d97a0a94ed93468fc86301d61e40 requires_python: '>=3' -- pypi: https://download.pytorch.org/whl/cu121/nvidia_cudnn_cu12-9.1.0.70-py3-none-manylinux2014_x86_64.whl +- pypi: https://download.pytorch.org/whl/cu124/nvidia_cudnn_cu12-9.1.0.70-py3-none-manylinux2014_x86_64.whl name: nvidia-cudnn-cu12 version: 9.1.0.70 sha256: 165764f44ef8c61fcdfdfdbe769d687e06374059fbb388b6c89ecb0e28793a6f @@ -2140,6 +2342,21 @@ packages: - setuptools ; extra == 'test' - sphinx ; extra == 'docs' - nvidia-sphinx-theme ; extra == 'docs' +- pypi: https://files.pythonhosted.org/packages/24/c8/35ac60b20eccccf84638a872c3b4ebefad46b20f87540ca17a37908b1db6/ome_zarr-0.11.1-py3-none-any.whl + name: ome-zarr + version: 0.11.1 + sha256: e8ffc93de78558be990ed3b1b2b186b97ca0c7eb2cb460a7cffb861f4f13a8f1 + requires_dist: + - numpy + - dask + - zarr>=2.8.1,<3 + - fsspec[s3]>=0.8,!=2021.7.0,!=2023.9.0 + - aiohttp<4 + - requests + - scikit-image + - toolz + - pytest ; extra == 'tests' + requires_python: '>3.10' - pypi: https://files.pythonhosted.org/packages/2c/8b/90eb44a40476fa0e71e05a0283947cfd74a5d36121a11d926ad6f3193cc4/opencv_python-4.11.0.86-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl name: opencv-python version: 4.11.0.86 @@ -2363,6 +2580,73 @@ packages: - xlsxwriter>=3.0.5 ; extra == 'all' - zstandard>=0.19.0 ; extra == 'all' requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/ac/37/1351bbfabbacbe92cd38774f8779ff680fab48c36b5fed9bcfe0c160009c/param-2.4.1-py3-none-any.whl + name: param + version: 2.4.1 + sha256: 6cdc0869b3ade232fc6d01691223cf86c2bdb53a6d5ba67a33dba838d8b8cf4c + requires_dist: + - aiohttp ; extra == 'all' + - cloudpickle ; extra == 'all' + - gmpy2 ; extra == 'all' + - ipython ; extra == 'all' + - jsonschema ; extra == 'all' + - nbval ; extra == 'all' + - nest-asyncio ; extra == 'all' + - numpy ; extra == 'all' + - odfpy ; extra == 'all' + - openpyxl ; extra == 'all' + - pandas ; extra == 'all' + - panel ; extra == 'all' + - pyarrow ; extra == 'all' + - pytest ; extra == 'all' + - pytest-asyncio ; extra == 'all' + - pytest-cov ; extra == 'all' + - pytest-xdist ; extra == 'all' + - tables ; extra == 'all' + - xlrd ; extra == 'all' + - aiohttp ; extra == 'examples' + - pandas ; extra == 'examples' + - panel ; extra == 'examples' + - pytest ; extra == 'tests' + - pytest-asyncio ; extra == 'tests' + - pytest-cov ; extra == 'tests' + - odfpy ; extra == 'tests-deser' + - openpyxl ; extra == 'tests-deser' + - pyarrow ; extra == 'tests-deser' + - tables ; extra == 'tests-deser' + - xlrd ; extra == 'tests-deser' + - aiohttp ; extra == 'tests-examples' + - nbval ; extra == 'tests-examples' + - pandas ; extra == 'tests-examples' + - panel ; extra == 'tests-examples' + - pytest ; extra == 'tests-examples' + - pytest-asyncio ; extra == 'tests-examples' + - pytest-xdist ; extra == 'tests-examples' + - aiohttp ; extra == 'tests-full' + - cloudpickle ; extra == 'tests-full' + - gmpy2 ; extra == 'tests-full' + - ipython ; extra == 'tests-full' + - jsonschema ; extra == 'tests-full' + - nbval ; extra == 'tests-full' + - nest-asyncio ; extra == 'tests-full' + - numpy ; extra == 'tests-full' + - odfpy ; extra == 'tests-full' + - openpyxl ; extra == 'tests-full' + - pandas ; extra == 'tests-full' + - panel ; extra == 'tests-full' + - pyarrow ; extra == 'tests-full' + - pytest ; extra == 'tests-full' + - pytest-asyncio ; extra == 'tests-full' + - pytest-cov ; extra == 'tests-full' + - pytest-xdist ; extra == 'tests-full' + - tables ; extra == 'tests-full' + - xlrd ; extra == 'tests-full' + - cloudpickle ; extra == 'tests-pypy' + - ipython ; extra == 'tests-pypy' + - jsonschema ; extra == 'tests-pypy' + - nest-asyncio ; extra == 'tests-pypy' + - numpy ; extra == 'tests-pypy' + requires_python: '>=3.10' - pypi: https://files.pythonhosted.org/packages/71/e7/40fb618334dcdf7c5a316c0e7343c5cd82d3d866edc100d98e29bc945ecd/partd-1.4.2-py3-none-any.whl name: partd version: 1.4.2 @@ -2417,6 +2701,22 @@ packages: - trove-classifiers>=2024.10.12 ; extra == 'tests' - defusedxml ; extra == 'xmp' requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/b8/02/5bf3639f5b77e9b183011c08541c5039ba3d04f5316c70312b48a8e003a9/pims-0.7.tar.gz + name: pims + version: '0.7' + sha256: 55907a4c301256086d2aa4e34a5361b9109f24e375c2071e1117b9491e82946b + requires_dist: + - imageio + - numpy>=1.19 + - packaging + - slicerator>=0.9.8 + - tifffile + requires_python: '>=3.7' +- pypi: https://files.pythonhosted.org/packages/28/be/0ff05fcd2938fb58ad9219bd54135968342d214737e012d62d43f06a2dd6/platformdirs-4.11.4-py3-none-any.whl + name: platformdirs + version: 4.11.4 + sha256: e34ff91a24bcddc6d939b878bdf3f5c437c9c46fe9e212b1bf455fdf1ee57586 + requires_python: '>=3.10' - pypi: https://files.pythonhosted.org/packages/0a/49/737c1a6273c585719858261753da0b688454d1b634438ccba8a9c4eb5aab/polars-1.38.1-py3-none-any.whl name: polars version: 1.38.1 @@ -2501,6 +2801,20 @@ packages: version: 1.39.0 sha256: b82c872b25ef6628462f90f1b6b3950779aee36889e83b3693d0a69684d3d86a requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/2a/2d/d4bf65e47cea8ff2c794a600c4fd1273a7902f268757c531e0ee9f18aa58/pooch-1.9.0-py3-none-any.whl + name: pooch + version: 1.9.0 + sha256: f265597baa9f760d25ceb29d0beb8186c243d6607b0f60b83ecf14078dbc703b + requires_dist: + - platformdirs>=2.5.0 + - packaging>=20.0 + - requests>=2.19.0 + - tqdm>=4.41.0,<5.0.0 ; extra == 'progress' + - paramiko>=2.7.0 ; extra == 'sftp' + - xxhash>=1.4.3 ; extra == 'xxhash' + - pytest-httpserver ; extra == 'test' + - pytest-localftpserver ; extra == 'test' + requires_python: '>=3.9' - pypi: https://files.pythonhosted.org/packages/52/6a/57f43e054fb3d3a56ac9fc532bc684fc6169a26c75c353e65425b3e56eef/propcache-0.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl name: propcache version: 0.4.1 @@ -2567,6 +2881,16 @@ packages: version: 23.0.1 sha256: 26d50dee49d741ac0e82185033488d28d35be4d763ae6f321f97d1140eb7a0e9 requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/8c/b2/23f4032cd1c9744aa8e9ecda43cd4d755fcb209f7f40fae035248f31a679/pyct-0.6.0-py3-none-any.whl + name: pyct + version: 0.6.0 + sha256: cfaded7289fca72ddf6579b81459e3ec8db323a508e61c49aa318ee3cd6ff160 + requires_dist: + - param>=1.7.0 + - pyyaml ; extra == 'cmd' + - requests ; extra == 'cmd' + - pytest ; extra == 'tests' + requires_python: '>=3.8' - pypi: https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl name: pygments version: 2.19.2 @@ -2903,6 +3227,15 @@ packages: - pytest ; extra == 'test' - pytest-cov ; extra == 'test' requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/57/e1/64c264db50b68de8a438b60ceeb921b2f22da3ebb7ad6255150225d0beac/s3fs-2026.2.0-py3-none-any.whl + name: s3fs + version: 2026.2.0 + sha256: 65198835b86b1d5771112b0085d1da52a6ede36508b1aaa6cae2aedc765dfe10 + requires_dist: + - aiobotocore>=2.19.0,<4.0.0 + - fsspec==2026.2.0 + - aiohttp!=4.0.0a0,!=4.0.0a1 + requires_python: '>=3.10' - pypi: https://files.pythonhosted.org/packages/32/e9/c1d43543da87cd27e8e2a74db85cf0b6c5cff2d5f04a86bd584d2fbc2bb0/scanpy-1.11.5-py3-none-any.whl name: scanpy version: 1.11.5 @@ -3196,8 +3529,8 @@ packages: requires_python: '>=3.8' - pypi: ./ name: segger - version: 0.1.0 - sha256: 800a085c1d8e3c13b06804ff039a14bc4f9789fe51414139e12b0dfc7505ad3d + version: 0.2.0 + sha256: 90ad8c33bbab808b877deb569839bcb2b1f7bbc6ef01866f717b08989ee9bea3 requires_dist: - anndata - cyclopts @@ -3214,6 +3547,7 @@ packages: - scikit-image - scikit-learn - tifffile + - tqdm requires_python: '>=3.11' - pypi: https://files.pythonhosted.org/packages/44/7c/64d18f2374e19ba9bee52dee885ec81f808a1863ed0995495b83319b88bc/session_info2-0.4-py3-none-any.whl name: session-info2 @@ -3243,6 +3577,63 @@ packages: - pytest-subprocess ; extra == 'test' - testing-common-database ; extra == 'test' requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl + name: setuptools + version: 81.0.0 + sha256: fdd925d5c5d9f62e4b74b30d6dd7828ce236fd6ed998a08d81de62ce5a6310d6 + requires_dist: + - pytest>=6,!=8.1.* ; extra == 'test' + - virtualenv>=13.0.0 ; extra == 'test' + - wheel>=0.44.0 ; extra == 'test' + - pip>=19.1 ; extra == 'test' + - packaging>=24.2 ; extra == 'test' + - jaraco-envs>=2.2 ; extra == 'test' + - pytest-xdist>=3 ; extra == 'test' + - jaraco-path>=3.7.2 ; extra == 'test' + - build[virtualenv]>=1.0.3 ; extra == 'test' + - filelock>=3.4.0 ; extra == 'test' + - ini2toml[lite]>=0.14 ; extra == 'test' + - tomli-w>=1.0.0 ; extra == 'test' + - pytest-timeout ; extra == 'test' + - pytest-perf ; sys_platform != 'cygwin' and extra == 'test' + - jaraco-develop>=7.21 ; python_full_version >= '3.9' and sys_platform != 'cygwin' and extra == 'test' + - pytest-home>=0.5 ; extra == 'test' + - pytest-subprocess ; extra == 'test' + - pyproject-hooks!=1.1 ; extra == 'test' + - jaraco-test>=5.5 ; extra == 'test' + - sphinx>=3.5 ; extra == 'doc' + - jaraco-packaging>=9.3 ; extra == 'doc' + - rst-linker>=1.9 ; extra == 'doc' + - furo ; extra == 'doc' + - sphinx-lint ; extra == 'doc' + - jaraco-tidelift>=1.4 ; extra == 'doc' + - pygments-github-lexers==0.0.5 ; extra == 'doc' + - sphinx-favicon ; extra == 'doc' + - sphinx-inline-tabs ; extra == 'doc' + - sphinx-reredirects ; extra == 'doc' + - sphinxcontrib-towncrier ; extra == 'doc' + - sphinx-notfound-page>=1,<2 ; extra == 'doc' + - pyproject-hooks!=1.1 ; extra == 'doc' + - towncrier<24.7 ; extra == 'doc' + - packaging>=24.2 ; extra == 'core' + - more-itertools>=8.8 ; extra == 'core' + - jaraco-text>=3.7 ; extra == 'core' + - importlib-metadata>=6 ; python_full_version < '3.10' and extra == 'core' + - tomli>=2.0.1 ; python_full_version < '3.11' and extra == 'core' + - wheel>=0.43.0 ; extra == 'core' + - platformdirs>=4.2.2 ; extra == 'core' + - jaraco-functools>=4 ; extra == 'core' + - more-itertools ; extra == 'core' + - pytest-checkdocs>=2.4 ; extra == 'check' + - pytest-ruff>=0.2.1 ; sys_platform != 'cygwin' and extra == 'check' + - ruff>=0.13.0 ; sys_platform != 'cygwin' and extra == 'check' + - pytest-cov ; extra == 'cover' + - pytest-enabler>=2.2 ; extra == 'enabler' + - pytest-mypy ; extra == 'type' + - mypy==1.18.* ; extra == 'type' + - importlib-metadata>=7.0.2 ; python_full_version < '3.10' and extra == 'type' + - jaraco-develop>=7.21 ; sys_platform != 'cygwin' and extra == 'type' + requires_python: '>=3.9' - pypi: https://files.pythonhosted.org/packages/13/02/58b0b8d9c17c93ab6340edd8b7308c0c5a5b81f94ce65705819b7416dba5/shapely-2.1.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl name: shapely version: 2.1.2 @@ -3263,10 +3654,75 @@ packages: version: 1.17.0 sha256: 4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274 requires_python: '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*' +- pypi: https://files.pythonhosted.org/packages/e8/ae/fa6cd331b364ad2bbc31652d025f5747d89cbb75576733dfdf8efe3e4d62/slicerator-1.1.0-py3-none-any.whl + name: slicerator + version: 1.1.0 + sha256: 167668d48c6d3a5ba0bd3d54b2688e81ee267dc20aef299e547d711e6f3c441a - pypi: https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl name: sortedcontainers version: 2.4.0 sha256: a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0 +- pypi: https://files.pythonhosted.org/packages/b9/c1/16eb09d03eb7096b901e816dc93f53819f83b867c7d5dbb075f837d0120b/spatial_image-1.2.1-py3-none-any.whl + name: spatial-image + version: 1.2.1 + sha256: 312c7f289284ed7f72eae50ca1b29b25b74db73f6daff745666af5ec27ad5436 + requires_dist: + - numpy + - xarray-dataclasses + - xarray>=2024.10.0 + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/14/96/015832d04de478b5ccf089fd259bff58adcff195cf27fec29b2bed307a46/spatialdata-0.4.0-py3-none-any.whl + name: spatialdata + version: 0.4.0 + sha256: f0a3f76efda57a221a775686a4d376093bfea560492697f40820eb3ec6d6ea89 + requires_dist: + - anndata>=0.9.1 + - click + - dask-image + - dask>=2024.4.1,<=2024.11.2 + - fsspec + - geopandas>=0.14 + - multiscale-spatial-image>=2.0.2 + - networkx + - numba>=0.55.0 + - numpy + - ome-zarr>=0.8.4 + - pandas + - pooch + - pyarrow + - rich + - scikit-image + - scipy + - setuptools + - shapely>=2.0.1 + - spatial-image>=1.1.0 + - typing-extensions>=4.8.0 + - xarray-dataclasses>=1.8.0 + - xarray-schema + - xarray-spatial>=0.3.5 + - xarray>=2024.10.0 + - zarr<3 + - asv ; extra == 'benchmark' + - bump2version ; extra == 'dev' + - ipython>=8.6.0 ; extra == 'docs' + - myst-nb ; extra == 'docs' + - sphinx-autobuild ; extra == 'docs' + - sphinx-autodoc-typehints ; extra == 'docs' + - sphinx-book-theme>=1.0.0 ; extra == 'docs' + - sphinx-copybutton ; extra == 'docs' + - sphinx-design ; extra == 'docs' + - sphinx-pytest ; extra == 'docs' + - sphinx>=4.5 ; extra == 'docs' + - sphinxcontrib-bibtex>=1.0.0 ; extra == 'docs' + - napari-spatialdata[all] ; extra == 'extra' + - spatialdata-io ; extra == 'extra' + - spatialdata-plot ; extra == 'extra' + - pytest ; extra == 'test' + - pytest-cov ; extra == 'test' + - pytest-mock ; extra == 'test' + - torch ; extra == 'test' + - torch ; extra == 'torch' + requires_python: '>=3.10,<3.13' - pypi: https://files.pythonhosted.org/packages/40/c6/9ae8e9b0721e9b6eb5f340c3a0ce8cd7cce4f66e03dd81f80d60f111987f/statsmodels-0.14.6-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl name: statsmodels version: 0.14.6 @@ -3377,7 +3833,7 @@ packages: version: 1.1.0 sha256: 15ccc861ac51c53696de0a5d6d4607f99c210739caf987b5d2054f3efed429d8 requires_python: '>=3.9' -- pypi: https://download.pytorch.org/whl/cu121/torch-2.5.1%2Bcu121-cp311-cp311-linux_x86_64.whl +- pypi: https://download-r2.pytorch.org/whl/cu121/torch-2.5.1%2Bcu121-cp311-cp311-linux_x86_64.whl name: torch version: 2.5.1+cu121 sha256: c8ab8c92eab928a93c483f83ca8c63f13dafc10fc93ad90ed2dcb7c82ea50410 @@ -3633,7 +4089,7 @@ packages: - kornia>=0.6.7 ; extra == 'dev' - statsmodels>0.13.5 ; extra == 'dev' requires_python: '>=3.10' -- pypi: https://download.pytorch.org/whl/cu121/torchvision-0.20.1%2Bcu121-cp311-cp311-linux_x86_64.whl +- pypi: https://download-r2.pytorch.org/whl/cu121/torchvision-0.20.1%2Bcu121-cp311-cp311-linux_x86_64.whl name: torchvision version: 0.20.1+cu121 sha256: 237609a3551c2b68f32bcd3f3875dca93836010d83922ef2f3bd3a7540caee58 @@ -3680,7 +4136,7 @@ packages: - pytest ; extra == 'testing' - scikit-learn ; extra == 'testing' requires_python: '>=3.8' -- pypi: https://download.pytorch.org/whl/triton-3.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl +- pypi: https://download-r2.pytorch.org/whl/triton-3.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl name: triton version: 3.1.0 sha256: 0f34f6e7885d1bf0eaaf7ba875a5f0ce6f3c13ba98f9503651c1e6dc6757ed5c @@ -3698,10 +4154,6 @@ packages: - matplotlib ; extra == 'tutorials' - pandas ; extra == 'tutorials' - tabulate ; extra == 'tutorials' -- pypi: https://download.pytorch.org/whl/typing_extensions-4.15.0-py3-none-any.whl - name: typing-extensions - version: 4.15.0 - requires_python: '>=3.9' - pypi: https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl name: typing-extensions version: 4.15.0 @@ -3790,6 +4242,111 @@ packages: - pysocks>=1.5.6,!=1.5.7,<2.0 ; extra == 'socks' - backports-zstd>=1.0.0 ; python_full_version < '3.14' and extra == 'zstd' requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/71/71/4cd2151a236f44a6e2dd4ed8011838d7ba0be3d656c8bafdfc65a2ed1917/wrapt-2.3.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl + name: wrapt + version: 2.3.0 + sha256: fc648a335d7e01adb3640b25f02fd0ea05886cf04d0af7f4ee902bc7b5e466e8 + requires_dist: + - pytest ; extra == 'dev' + - setuptools ; extra == 'dev' + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/40/ed/1c4631ad5909487ea8907cd326d9855c2207d790e3936e77bda48173b8be/xarray-2024.11.0-py3-none-any.whl + name: xarray + version: 2024.11.0 + sha256: 6ee94f63ddcbdd0cf3909d1177f78cdac756640279c0e32ae36819a89cdaba37 + requires_dist: + - numpy>=1.24 + - packaging>=23.2 + - pandas>=2.1 + - scipy ; extra == 'accel' + - bottleneck ; extra == 'accel' + - numbagg ; extra == 'accel' + - numba>=0.54 ; extra == 'accel' + - flox ; extra == 'accel' + - opt-einsum ; extra == 'accel' + - xarray[accel,etc,io,parallel,viz] ; extra == 'complete' + - hypothesis ; extra == 'dev' + - jinja2 ; extra == 'dev' + - mypy ; extra == 'dev' + - pre-commit ; extra == 'dev' + - pytest ; extra == 'dev' + - pytest-cov ; extra == 'dev' + - pytest-env ; extra == 'dev' + - pytest-xdist ; extra == 'dev' + - pytest-timeout ; extra == 'dev' + - ruff ; extra == 'dev' + - sphinx ; extra == 'dev' + - sphinx-autosummary-accessors ; extra == 'dev' + - xarray[complete] ; extra == 'dev' + - netcdf4 ; extra == 'io' + - h5netcdf ; extra == 'io' + - scipy ; extra == 'io' + - pydap ; python_full_version < '3.10' and extra == 'io' + - zarr ; extra == 'io' + - fsspec ; extra == 'io' + - cftime ; extra == 'io' + - pooch ; extra == 'io' + - sparse ; extra == 'etc' + - dask[complete] ; extra == 'parallel' + - cartopy ; extra == 'viz' + - matplotlib ; extra == 'viz' + - nc-time-axis ; extra == 'viz' + - seaborn ; extra == 'viz' + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/aa/7b/9adbd82e2b7b8571da23856a890324b42cfbc38ae0ceac2177e5256f7216/xarray_dataclasses-1.9.1-py3-none-any.whl + name: xarray-dataclasses + version: 1.9.1 + sha256: 3590556ef795ebbb33908b484a58311192d880cbb511666fe4c354569c3c468f + requires_dist: + - numpy>=1.22,<1.25 ; python_full_version == '3.8.*' + - numpy>=1.22,<3.0 ; python_full_version >= '3.9' and python_full_version < '3.14' + - typing-extensions>=4.0,<5.0 + - xarray>=2022.3,<2023.2 ; python_full_version == '3.8.*' + - xarray>=2022.3,<2025.0 ; python_full_version >= '3.9' and python_full_version < '3.14' + requires_python: '>=3.8,<3.14' +- pypi: https://files.pythonhosted.org/packages/a9/6d/f585a27b380ee987619b5617c0ca672a71a4345b67cfedbb6299750ce845/xarray_schema-0.0.3-py3-none-any.whl + name: xarray-schema + version: 0.0.3 + sha256: aa6f856626b2e100213ba290407797464608b2555bb8e0b26093a97fe1ba38ce + requires_dist: + - xarray>=0.16 + - numpy>=1.21 + requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/61/ee/9d0bb9f1bbaf347efe2ca6ad7bae259d6ed9e7a2b4441bd16b88723145a1/xarray_spatial-0.5.3-py3-none-any.whl + name: xarray-spatial + version: 0.5.3 + sha256: 84f5a3e07a1ac3212bcfff3c4677daa3c529a533f1493eb555f8e498b7d9746e + requires_dist: + - datashader>=0.15.0 + - numba + - xarray + - numpy + - dask[dataframe] ; extra == 'doc' + - geopandas ; extra == 'doc' + - jinja2>=2.11 ; extra == 'doc' + - ipykernel ; extra == 'doc' + - matplotlib ; extra == 'doc' + - nbsphinx ; extra == 'doc' + - numpydoc ; extra == 'doc' + - pandoc ; extra == 'doc' + - pydata-sphinx-theme ; extra == 'doc' + - sphinx ; extra == 'doc' + - sphinx-panels ; extra == 'doc' + - sphinx-rtd-theme ; extra == 'doc' + - awkward>=1.4 ; extra == 'optional' + - geopandas ; extra == 'optional' + - shapely ; extra == 'optional' + - spatialpandas ; extra == 'optional' + - rtxpy ; extra == 'optional' + - flake8 ; extra == 'tests' + - isort ; extra == 'tests' + - noise>=1.2.2 ; extra == 'tests' + - dask ; extra == 'tests' + - pyarrow ; extra == 'tests' + - pytest ; extra == 'tests' + - pytest-cov ; extra == 'tests' + - scipy ; extra == 'tests' + requires_python: '>=3.8' - pypi: https://files.pythonhosted.org/packages/a5/86/cf2c0321dc3940a7aa73076f4fd677a0fb3e405cb297ead7d864fd90847e/xxhash-3.6.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl name: xxhash version: 3.6.0 @@ -3804,6 +4361,28 @@ packages: - multidict>=4.0 - propcache>=0.2.1 requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/5e/d8/9ffd8c237b3559945bb52103cf0eed64ea098f7b7f573f8d2962ef27b4b2/zarr-2.18.7-py3-none-any.whl + name: zarr + version: 2.18.7 + sha256: ac3dc4033e9ae4e9d7b5e27c97ea3eaf1003cc0a07f010bd83d5134bf8c4b223 + requires_dist: + - asciitree + - numpy>=1.24 + - fasteners ; sys_platform != 'emscripten' + - numcodecs>=0.10.0,!=0.14.0,!=0.14.1,<0.16 + - notebook ; extra == 'jupyter' + - ipytree>=0.2.2 ; extra == 'jupyter' + - ipywidgets>=8.0.0 ; extra == 'jupyter' + - sphinx ; extra == 'docs' + - sphinx-automodapi ; extra == 'docs' + - sphinx-design ; extra == 'docs' + - sphinx-issues ; extra == 'docs' + - sphinx-copybutton ; extra == 'docs' + - pydata-sphinx-theme ; extra == 'docs' + - numpydoc ; extra == 'docs' + - numcodecs[msgpack]!=0.14.0,!=0.14.1,<0.16 ; extra == 'docs' + - pytest-doctestplus ; extra == 'docs' + requires_python: '>=3.11' - pypi: https://files.pythonhosted.org/packages/44/15/bb13b4913ef95ad5448490821eee4671d0e67673342e4d4070854e5fe081/zarr-3.1.5-py3-none-any.whl name: zarr version: 3.1.5 diff --git a/pixi.toml b/pixi.toml index b27ccad..7d048d2 100644 --- a/pixi.toml +++ b/pixi.toml @@ -37,9 +37,11 @@ cudf-cu12 = "==24.10.*" cuml-cu12 = "==24.10.*" cugraph-cu12 = "==24.10.*" cupy-cuda12x = ">=12.2,<13.0" +spatialdata = ">=0.4.0, <0.5" +setuptools = ">=81.0.0, <82" [tool.uv.extra-build-dependencies] torch-scatter = ["torch"] [environments] -cuda121 = ["cuda121"] \ No newline at end of file +cuda121 = ["cuda121"] diff --git a/src/segger/__init__.py b/src/segger/__init__.py index 67cb121..a4ef99d 100644 --- a/src/segger/__init__.py +++ b/src/segger/__init__.py @@ -1,6 +1,11 @@ import logging import os from pathlib import Path + +import dask + +dask.config.set({"dataframe.query-planning": False}) # spatialdata doesn't yet support dask-expr; must be set before cudf pulls in dask.dataframe + import cupy as cp import torch import rmm diff --git a/src/segger/cli/export.py b/src/segger/cli/export.py index 7d0b6a8..8bbdfdf 100644 --- a/src/segger/cli/export.py +++ b/src/segger/cli/export.py @@ -1,104 +1,270 @@ """``segger export``: write a segger segmentation as scverse-compatible files. -One command writes the chosen SpatialData elements: ``anndata`` the cell by gene table -(``adata.h5ad``), ``transcripts`` the assigned transcripts/points (``transcripts.parquet``), -and ``boundaries`` one polygon per cell/shapes (``cell_boundaries.parquet``). Default: anndata + boundaries. +Example usage: + # save anndata and boundaries + segger export anndata \ + -s $PATH_OUTPUT/segger_segmentation.parquet \ + -o $PATH_OUTPUT/adata_export + + # save spatialdata - adds elements directly to an existing sdata object, no -o needed + segger export spatialdata \ + -s $PATH_OUTPUT/segger_segmentation.parquet \ + --sdata $PATH_INPUT/sdata.zarr """ from __future__ import annotations from pathlib import Path from typing import Annotated, Literal, Optional - from cyclopts import Parameter, Group, validators +import polars as pl +from ..io import StandardTranscriptFields + _group_io = Group(name="I/O", sort_key=0) _group_opts = Group(name="Options", sort_key=1) -_Element = Literal["anndata", "transcripts", "boundaries"] +_Element = Literal["anndata", "transcripts", "boundaries", "spatialdata"] _DEFAULT_ELEMENTS = ("anndata", "boundaries") _Seg = Annotated[Path, Parameter(alias="-s", group=_group_io, validator=validators.Path(exists=True, dir_okay=False))] -_Source = Annotated[Path, Parameter(alias="-i", group=_group_io, validator=validators.Path(exists=True, dir_okay=True))] -_Out = Annotated[Path, Parameter(alias="-o", group=_group_io)] +_Source = Annotated[ + Optional[Path], + Parameter( + alias="-i", + group=_group_io, + validator=validators.Path(exists=True, dir_okay=True), + help="Source transcripts directory. Only needed for segger v0.2.0 (before x/y/feature_name were included in outputs).", + ), +] +_Out = Annotated[ + Optional[Path], + Parameter(alias="-o", group=_group_io, help="Required unless the only element being exported is 'spatialdata'."), +] +_Sdata = Annotated[ + Optional[Path], + Parameter( + alias="--sdata", + group=_group_io, + validator=validators.Path(exists=True, dir_okay=True), + help="Existing SpatialData Zarr store to add elements to in place (required for 'spatialdata').", + ), +] _IncludeAll = Annotated[ bool, - Parameter(group=_group_opts, help="Keep every cell-assigned transcript, ignoring the similarity threshold."), + Parameter(group=_group_opts, help="Keep every transcript in the segmentation output, not just the ones segger's 'filtered' flag marked as kept."), +] +_SdataTranscriptsName = Annotated[ + str, + Parameter( + group=_group_opts, + help="Name of the existing points element in --sdata to append segger's columns to.", + ), ] -_MinSim = Annotated[ - Optional[float], +_SdataCellBoundariesName = Annotated[ + str, Parameter( group=_group_opts, - validator=validators.Number(gte=0, lte=1), - help="Fixed similarity threshold (0-1), overriding the per-gene threshold from segmentation.", + help="Name of the shapes element segger's cell boundaries are written to " + "(avoids colliding with an existing same-named element, e.g. from the raw Xenium sdata).", ), ] -_MinTx = Annotated[ +_SdataTableName = Annotated[ + str, + Parameter( + group=_group_opts, + help="Name of the table element segger's AnnData is written to.", + ), +] +_MinCounts = Annotated[ int, Parameter( group=_group_opts, - validator=validators.Number(gte=0), - help="Minimum number of assigned transcripts a cell must have to be included.", + help="Drop cells with fewer than this many assigned transcripts from the table/anndata " + "(must be >= 3 for spatialdata, since boundaries need >= 3 points).", ), ] -def _load_assigned( +# -- LOAD TRANSCRIPTS -- +def load_transcripts( segmentation_path: Path, - source_path: Path, include_all_transcripts: bool, - min_similarity: Optional[float], - min_transcripts: int = 10, -) -> "pl.DataFrame": - """Join predictions onto source transcripts; return the kept tx (row_index/segger_cell_id/feature_name/x/y).""" - import polars as pl - - from ..io import StandardTranscriptFields, get_preprocessor + source_path: Path = None, +): + # read transcripts + tx = pl.read_parquet(segmentation_path) + # check if legacy result (before v0.2.0) std = StandardTranscriptFields() - seg = pl.read_parquet(segmentation_path) - if "segger_cell_id" not in seg.columns: - raise ValueError(f"No 'segger_cell_id' column in {segmentation_path}.") - - tx = get_preprocessor(source_path).transcripts - if isinstance(tx, pl.LazyFrame): - tx = tx.collect() - - pred_cols = [c for c in (std.row_index, "segger_cell_id", "segger_similarity", "similarity_threshold") if c in seg.columns] - merged = tx.join(seg.select(pred_cols), on=std.row_index, how="left") - - has_assignment = pl.col("segger_cell_id").is_not_null() - if include_all_transcripts: - keep = has_assignment - elif min_similarity is not None: - if "segger_similarity" not in merged.columns: - raise ValueError("--min-similarity needs a 'segger_similarity' column in the segmentation file.") - keep = has_assignment & (pl.col("segger_similarity") >= min_similarity) - elif {"segger_similarity", "similarity_threshold"} <= set(merged.columns): - keep = has_assignment & (pl.col("segger_similarity") >= pl.col("similarity_threshold")) - else: - keep = has_assignment + if not {std.x, std.y, std.feature, "filtered"} <= set(tx.columns): + tx = _legacy_join(tx, source_path=source_path, std=std) - assigned = merged.filter(keep).select( + # subset + coord_cols = [pl.col(std.x).alias("x"), pl.col(std.y).alias("y")] + if std.z in tx.columns: + coord_cols.append(pl.col(std.z).alias("z")) + + # filter + kept = tx.filter(pl.col("filtered")) if not include_all_transcripts else tx + + # select + assigned = kept.select( pl.col(std.row_index), pl.col("segger_cell_id").cast(pl.String), pl.col(std.feature).alias("feature_name"), - pl.col(std.x).alias("x"), - pl.col(std.y).alias("y"), + *coord_cols, + ) + + return assigned, tx + + +def _legacy_join(tx: "pl.DataFrame", source_path: Optional[Path], std) -> "pl.DataFrame": + """Join x/y/feature_name onto a segmentation output written before they were included inline.""" + if source_path is None: + raise ValueError("This segmentation output predates inline x/y/feature_name; pass -i/--source-path to join them from the source transcripts.") + + from ..io import get_preprocessor + + # load and merge + tx_all = get_preprocessor(source_path).transcripts + pred_cols = [c for c in (std.row_index, "segger_cell_id", "segger_similarity", "similarity_threshold") if c in tx.columns] + tx = tx.select(pred_cols).join(tx_all, on=std.row_index, how="left") + + # add "filtered" + tx = tx.with_columns(( + (pl.col("segger_cell_id").is_not_null()) & (pl.col("segger_similarity") >= pl.col("similarity_threshold")) + ).alias("filtered")) + + # if "converged" exists, also require this to be true + if "converged" in tx.columns: + tx = tx.with_columns( + (pl.col("filtered") & pl.col("converged")).alias("filtered") + ) + + return tx + +# -- Spatial Data Support +def _check_sdata_elements( + sdata, + transcripts_element: str, + cell_boundaries_element: str, + table_element: str, + ) -> None: + """Fail fast if the transcripts element is missing, or any target element name already exists.""" + if transcripts_element not in sdata.points: + raise KeyError(f"{transcripts_element!r} not found in sdata.points; pass --sdata-transcripts-name to point at the right one.") + if cell_boundaries_element in sdata.shapes: + raise FileExistsError(f"{cell_boundaries_element!r} already exists in sdata.shapes; pass --sdata-cell-boundaries-name to specify a different name.") + if table_element in sdata.tables: + raise FileExistsError(f"{table_element!r} already exists in sdata.tables; pass --sdata-table-name to specify a different name.") + + + +def _merge_sdata_transcripts(sdata_tx: "dd.DataFrame", tx: "pl.DataFrame", row_index: str) -> "dd.DataFrame": + """Segger's per-transcript outputs, joined onto the existing (dask-backed) transcripts table. Stays lazy throughout.""" + + # rename; these names are hardcoded. make sure to update this if any name should change going forward + map_columns = { + "segger_cell_id": "segger_cell_id", + "segger_similarity": "segger_similarity", + "similarity_threshold": "segger_similarity_threshold", + "converged": "segger_converged", + "filtered": "segger_filtered", + } + + # rename + tx = tx.rename(map_columns).select(row_index, *map_columns.values()).to_pandas() + + # sdata_tx has no row_index column; construct it + sdata_tx = sdata_tx.assign(**{row_index: 1}) + sdata_tx[row_index] = sdata_tx[row_index].cumsum() - 1 + + # delete existing (overwrite is not exactly silent - export would stop if boundaries or table already exists) + sdata_tx = sdata_tx.drop(columns=[col for col in map_columns.values() if col in sdata_tx.columns]) + + # merge (tx is small enough to broadcast onto every partition; no shuffle needed) + sdata_tx = sdata_tx.merge(tx, on=row_index, how="left") + sdata_tx["segger_seen"] = sdata_tx["segger_filtered"].notnull() + + # row_index is only a join key; drop it from the output + sdata_tx = sdata_tx.drop(columns=[row_index]) + + return sdata_tx + +def _write_to_sdata( + sdata, + tx: "pl.DataFrame", + gdf: "gpd.GeoDataFrame", + adata: "AnnData", + transcripts_element: str = "transcripts", + cell_boundaries_element: str = "cell_boundaries_segger", + table_element: str = "table_segger", +) -> None: + """Append segger's columns to the existing transcripts element, and add its boundaries/table elements to the given SpatialData store.""" + from spatialdata.models import PointsModel, ShapesModel, TableModel + from spatialdata.transformations import get_transformation + + # get current transcripts + base_transcripts = sdata.points[transcripts_element] + attrs = base_transcripts.attrs.get("spatialdata_attrs", {}) + transformations = get_transformation(base_transcripts, get_all=True) + + # new element fully in memory, required for overwriting + tx = _merge_sdata_transcripts(base_transcripts, tx, "row_index").compute().reset_index(drop=True) + + coordinates = {"x": "x", "y": "y"} + if "z" in tx.columns: + coordinates["z"] = "z" + + # build the new (in-memory, unbacked) elements + new_transcripts = PointsModel.parse( + tx, + coordinates=coordinates, + feature_key=attrs.get("feature_key"), + instance_key=attrs.get("instance_key"), + transformations=transformations, ) + new_boundaries = ShapesModel.parse(gdf, transformations=transformations) + new_table = TableModel.parse(adata) - if min_transcripts > 0: - assigned = assigned.filter(pl.len().over("segger_cell_id") >= min_transcripts) + # SpatialData can't overwrite (#520). Do 1) backup, 2) drop in-memory handles, 3) delete original, 4) write new elements, 5) drop backup + # 1 backup + backup_element = f"{transcripts_element}_backup" + sdata[backup_element] = base_transcripts + sdata.write_element([backup_element]) - return assigned + # 2 detach in-memory + del sdata.points[backup_element] + sdata[transcripts_element] = new_transcripts + sdata[cell_boundaries_element] = new_boundaries + sdata[table_element] = new_table + + # 3 4 delete and write + print(f"Writing {transcripts_element}, {cell_boundaries_element}, {table_element} to {sdata.path}...") + try: + sdata.delete_element_from_disk(transcripts_element) + sdata.write_element([transcripts_element, cell_boundaries_element, table_element]) + except Exception: + print( + f"Write failed. The original {transcripts_element!r} is preserved on disk as " + f"{backup_element!r}; restore it from there." + ) + raise + else: + # delete backup + sdata.delete_element_from_disk(backup_element) + if sdata.has_consolidated_metadata(): + sdata.write_consolidated_metadata() def export( *elements: Annotated[_Element, Parameter(help="Elements to write (default: anndata boundaries).")], segmentation_path: _Seg, - source_path: _Source, - output_directory: _Out, + output_directory: _Out = None, + source_path: _Source = None, + sdata_path: _Sdata = None, method: Annotated[ Literal["delaunay", "convex_hull"], Parameter(group=_group_opts, help="Cell-polygon method for boundaries."), @@ -106,31 +272,75 @@ def export( chaikin_iterations: Annotated[ int, Parameter(group=_group_opts, help="Chaikin corner-cutting iterations to round boundaries (0 disables).") ] = 0, - include_all_transcripts: _IncludeAll = False, - min_similarity: _MinSim = None, - min_transcripts: _MinTx = 10, + include_all_transcripts: _IncludeAll = True, + sdata_transcripts_name: _SdataTranscriptsName = "transcripts", + sdata_cell_boundaries_name: _SdataCellBoundariesName = "cell_boundaries_segger", + sdata_table_name: _SdataTableName = "table_segger", + min_counts: _MinCounts = 10, ): - """Write a segger segmentation as scverse SpatialData elements (anndata, transcripts, boundaries).""" + """Write a segger segmentation as scverse SpatialData elements (anndata, transcripts, boundaries, spatialdata).""" selected = elements or _DEFAULT_ELEMENTS - assigned = _load_assigned(segmentation_path, source_path, include_all_transcripts, min_similarity, min_transcripts) - output_directory.mkdir(parents=True, exist_ok=True) + sdata = None + if "spatialdata" in selected: + if min_counts < 3: + # cell boundaries need >= 3 transcripts to form a polygon; a lower table cutoff leaves cells without one + raise ValueError("--min-counts must be >= 3 for spatialdata: boundaries need >= 3 transcripts to form a polygon.") + if sdata_path is None: + raise ValueError("--sdata is required when exporting 'spatialdata'.") + import spatialdata as sd + sdata = sd.read_zarr(sdata_path) + _check_sdata_elements(sdata, sdata_transcripts_name, sdata_cell_boundaries_name, sdata_table_name) + + if set(selected) - {"spatialdata"} and output_directory is None: + raise ValueError("-o/--output-directory is required unless the only element being exported is 'spatialdata'.") + + # load tx + assigned, tx = load_transcripts(segmentation_path, include_all_transcripts, source_path) + if output_directory is not None: + output_directory.mkdir(parents=True, exist_ok=True) + + # compute outputs gdf = None - if "boundaries" in selected: + if "boundaries" in selected or "spatialdata" in selected: from ..export import generate_boundaries - gdf = generate_boundaries(assigned, cell_id="segger_cell_id", method=method, smoothing=chaikin_iterations) + + adata = None + if "anndata" in selected or "spatialdata" in selected: + from ..export import build_anndata + adata = build_anndata( + assigned, + cell_id="segger_cell_id", + z="z", + area=gdf.geometry.area if gdf is not None else None, + region=sdata_cell_boundaries_name, + min_counts=min_counts, + ) + # keep only cells that produced a boundary polygon, so the table annotates only real shapes + if gdf is not None: + adata = adata[adata.obs_names.isin(gdf.index)].copy() + + # save outputs + if "transcripts" in selected: + assigned.write_parquet(output_directory / "transcripts.parquet") + print(f"Wrote {assigned.height} assigned transcripts: {output_directory / 'transcripts.parquet'}") + + if "boundaries" in selected: gdf.to_parquet(output_directory / "cell_boundaries.parquet") print(f"Wrote {len(gdf)} {method} cell boundaries: {output_directory / 'cell_boundaries.parquet'}") if "anndata" in selected: - from ..export import build_anndata - - # Use the exported polygon areas so obs["area"] matches the boundaries; omitted otherwise. - adata = build_anndata(assigned, cell_id="segger_cell_id", area=gdf.geometry.area if gdf is not None else None) adata.write_h5ad(output_directory / "adata.h5ad") print(f"Wrote AnnData ({adata.n_obs} cells x {adata.n_vars} genes): {output_directory / 'adata.h5ad'}") - if "transcripts" in selected: - assigned.write_parquet(output_directory / "transcripts.parquet") - print(f"Wrote {assigned.height} assigned transcripts: {output_directory / 'transcripts.parquet'}") + if "spatialdata" in selected: + _write_to_sdata( + sdata, + tx, + gdf, + adata, + transcripts_element=sdata_transcripts_name, + cell_boundaries_element=sdata_cell_boundaries_name, + table_element=sdata_table_name, + ) diff --git a/src/segger/data/writer.py b/src/segger/data/writer.py index dfc1139..7f62be5 100644 --- a/src/segger/data/writer.py +++ b/src/segger/data/writer.py @@ -110,6 +110,10 @@ def write_anndata( tx_fields = TrainingTranscriptFields() tx = trainer.datamodule.tx + coordinate_columns = [tx_fields.x, tx_fields.y] + if tx_fields.z in tx.columns: + coordinate_columns.append(tx_fields.z) + transcripts = ( segmentation .filter( @@ -118,8 +122,7 @@ def write_anndata( .join( tx.select([ tx_fields.row_index, - tx_fields.x, - tx_fields.y, + *coordinate_columns, tx_fields.feature, ]), on=tx_fields.row_index, @@ -132,8 +135,7 @@ def write_anndata( "segger_cell_id", "segger_similarity", "similarity_threshold", - tx_fields.x, - tx_fields.y, + *coordinate_columns, ]) ) @@ -142,7 +144,7 @@ def write_anndata( feature_column="segger_gene", cell_id_column="segger_cell_id", score_column="segger_similarity", - coordinate_columns=[tx_fields.x, tx_fields.y], + coordinate_columns=coordinate_columns, ) adata.write_h5ad(self.output_directory / 'segger_anndata.h5ad') diff --git a/src/segger/export/anndata_writer.py b/src/segger/export/anndata_writer.py index b957e56..e9d3989 100644 --- a/src/segger/export/anndata_writer.py +++ b/src/segger/export/anndata_writer.py @@ -15,19 +15,25 @@ def build_anndata( feature: str = "feature_name", x: str = "x", y: str = "y", + z: Optional[str] = None, region: str = "cell_boundaries", area: Optional[pd.Series] = None, + min_counts: int = 1, ) -> AnnData: """Cell x gene table built on :func:`anndata_from_transcripts`, with the SpatialData link added. - ``obs`` is indexed by the cell id; centroids land in ``obsm["spatial"]`` and the table-to-shapes - link in ``uns["spatialdata_attrs"]``. ``area`` (a per-cell Series, e.g. the exported boundary - polygon areas) is written to ``obs["area"]`` when given. + ``obs`` is indexed by cell id, with centroids in ``obsm["spatial"]`` (3D if ``z`` is given and + present) and the table-to-shapes link in ``uns["spatialdata_attrs"]``. ``area``, when given, is + written to ``obs["area"]``. """ from ..data.utils.anndata import anndata_from_transcripts + coordinate_columns = [x, y] + if z is not None and z in assigned.columns: + coordinate_columns.append(z) + adata = anndata_from_transcripts( - assigned, feature_column=feature, cell_id_column=cell_id, coordinate_columns=[x, y] + assigned, feature_column=feature, cell_id_column=cell_id, coordinate_columns=coordinate_columns ) if "X_spatial" in adata.obsm: adata.obsm["spatial"] = adata.obsm.pop("X_spatial") @@ -37,6 +43,9 @@ def build_anndata( if area is not None: adata.obs["area"] = pd.Series(area).reindex(adata.obs_names).to_numpy() + if min_counts > 1: + adata = adata[adata.obs["n_transcripts"] >= min_counts].copy() + # SpatialData link: region/instance_key obs columns plus the attrs that join table to shapes. adata.obs["region"] = pd.Categorical([region] * adata.n_obs, categories=[region]) adata.obs["cell_id"] = adata.obs_names.to_numpy() diff --git a/src/segger/export/boundary.py b/src/segger/export/boundary.py index 65ea72b..3307d90 100644 --- a/src/segger/export/boundary.py +++ b/src/segger/export/boundary.py @@ -7,6 +7,8 @@ from __future__ import annotations +import os +from concurrent.futures import ProcessPoolExecutor from typing import Literal, Optional, Union import geopandas as gpd @@ -184,6 +186,13 @@ def cell_boundary( return poly +def _build_one_boundary(inputs: tuple) -> tuple: + """Run ``cell_boundary`` for one cell; returns (cell_id, n_transcripts, geometry).""" + cid, pts, method, smoothing, connectivity = inputs + geom = cell_boundary(pts, method=method, smoothing=smoothing, connectivity=connectivity) + return str(cid), len(pts), geom + + def generate_boundaries( transcripts: Union[pl.DataFrame, pd.DataFrame], cell_id: str = "cell_id", @@ -203,14 +212,20 @@ def generate_boundaries( n_groups = grouped.ngroups groups = ((cid, g[[x, y]].to_numpy()) for cid, g in grouped) - ids, n_tx, geoms = [], [], [] - for cid, pts in tqdm(groups, total=n_groups, desc="Building cell boundaries"): - ids.append(str(cid)) - n_tx.append(len(pts)) - geoms.append(cell_boundary(pts, method=method, smoothing=smoothing, connectivity=connectivity)) + inputs = [(cid, pts, method, smoothing, connectivity) for cid, pts in groups] + + n_workers = max(len(os.sched_getaffinity(0)) - 1, 1) + with ProcessPoolExecutor(max_workers=n_workers) as pool: + results = list( + tqdm( + pool.map(_build_one_boundary, inputs, chunksize=10), + total=n_groups, + desc="Building cell boundaries", + ) + ) + ids, n_tx, geoms = map(list, zip(*results)) if results else ([], [], []) - # Output the SpatialData instance key as "cell_id" regardless of the input column name. Keep it as - # a column too: geoparquet drops a named index, and it must match the table instance key to join. + # Output the SpatialData instance key as "cell_id" regardless of the input column name. gdf = gpd.GeoDataFrame( {"cell_id": ids, "n_transcripts": n_tx}, geometry=geoms, index=pd.Index(ids, name="cell_id") ) diff --git a/src/segger/io/fields.py b/src/segger/io/fields.py index 8dc30a9..315965c 100644 --- a/src/segger/io/fields.py +++ b/src/segger/io/fields.py @@ -107,6 +107,7 @@ class StandardTranscriptFields: row_index: str = 'row_index' x: str = 'x' y: str = 'y' + z: str = 'z' feature: str = 'feature_name' cell_id: str = 'cell_id' compartment: str = 'cell_compartment'