diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 837d87c..b53e40d 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -1,5 +1,9 @@ name: Run Pytest and Codecov with Hatch +permissions: + id-token: write + contents: read + on: push: branches: @@ -19,8 +23,8 @@ jobs: - name: Run pytest and generate coverage report run: docker run --rm -e HATCH_ENV=test -v "${{ github.workspace }}:/app" myapp:hatch cov - name: Upload coverage report to Codecov - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v4 with: - token: ${{ secrets.CODECOV_TOKEN }} + use_oidc: true fail_ci_if_error: true - files: ${{ github.workspace }}/.coverage \ No newline at end of file + files: ${{ github.workspace }}/coverage.xml diff --git a/README.md b/README.md index 589f4dd..8c833c4 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,42 @@ -TODO: this readme -================= -for more info goto: https://lavlab-python-utils.readthedocs.io/en/latest/ -python3 -m unittest -TODO: convention documentation. -TODO: pyXNAT support \ No newline at end of file +# LavLab Python Utils + +[![Documentation Status](https://readthedocs.org/projects/lavlab-python-utils/badge/?version=stable)](https://lavlab-python-utils.readthedocs.io/stable) +[![GitHub release](https://img.shields.io/github/v/release/laviolette-lab/lavlab-python-utils.svg)](https://github.com/laviolette-lab/lavlab-python-utils/releases) +[![Build Status](https://github.com/laviolette-lab/lavlab-python-utils/actions/workflows/pylint.yml/badge.svg)](https://github.com/laviolette-lab/lavlab-python-utils/actions) +[![Coverage Status](https://img.shields.io/codecov/c/github/laviolette-lab/lavlab-python-utils.svg)](https://codecov.io/gh/laviolette-lab/lavlab-python-utils) + +Welcome to the **LavLab Python Utils** repository! This library is a collection of Python utilities developed by the LaViolette Lab to support our research in RadioPathomics and digital pathology. + + + +## Overview + +LavLab Python Utils is designed to streamline common tasks in our research workflow, including data preprocessing, analysis, and visualization. Our goal is to provide a set of tools that are easy to use, well-documented, and performant. + +## Features + +- **Data Processing:** Functions to handle various data formats used in our research, including DICOM, NIfTI, and more. +- **Visualization:** Tools to create publication-quality plots and visualizations. +- **Integration:** Seamless integration with other tools and services used in our lab. + +## Installation + +You can install LavLab Python Utils via pip: + +```bash +python3 -m pip install https://github.com/laviolette-lab/lavlab-python-utils/releases/latest/download/lavlab_python_utils-latest-py3-none-any.whl +# optional install targets, must install wheel from github using command above first! +python3 -m pip install 'lavlab-python-utils[all]' +``` + +## Documentation + +Comprehensive documentation is available on [Read the Docs](https://lavlab-python-utils.readthedocs.io/stable/). This includes detailed API references, usage examples, and tutorials. + +## Contributing + +We welcome contributions from the community! If you are interested in contributing, please read our [contributing guide]([CONTRIBUTING.md](https://lavlab-python-utils.readthedocs.io/stable/contributing/)) and check out our [open issues](https://github.com/laviolette-lab/lavlab-python-utils/issues). + +--- + +Thank you for using LavLab Python Utils! We hope you find it useful in your research. diff --git a/docs/installation.md b/docs/installation.md index 3d25607..91c7352 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -2,11 +2,20 @@ ## Using latest wheel -You can install the latest release from GitHub: +You can install the latest release from GitHub, once installed you can get the optional dependencies: ```sh python3 -m pip install https://github.com/laviolette-lab/lavlab-python-utils/releases/latest/download/lavlab_python_utils-latest-py3-none-any.whl +# optional install targets, must install wheel from github using command above first! +python3 -m pip install 'lavlab-python-utils[all]' ``` +We support the following install targets: +* omero + * installs omero-py for omero api access +* jupyter + * installs dash for performant image viewing +* all + * installs all optional dependencies ## Using versioned wheel @@ -22,4 +31,4 @@ Install using pip+git: ```sh python3 -m pip install git+https://github.com/laviolette-lab/lavlab-python-utils.git -``` \ No newline at end of file +``` diff --git a/logo.webp b/logo.webp new file mode 100644 index 0000000..7b3491b Binary files /dev/null and b/logo.webp differ diff --git a/pyproject.toml b/pyproject.toml index 398357c..6d4608d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -53,6 +53,9 @@ jupyter = [ "dash-slicer", "dash-bootstrap-components" ] +all = [ + "lavlab-python-utils[omero, jupyter]" +] [project.entry-points."lavlab_python_utils.service_providers"] OMERO = "lavlab.omero:OmeroServiceProvider" @@ -98,7 +101,7 @@ dependencies = [ ] [tool.hatch.envs.test.scripts] test = "pytest {args:test}" -cov = "pytest --cov=src --cov-report=term-missing {args:test}" +cov = "pytest --cov=src --cov-report=xml {args:test}" [tool.hatch.envs.lint] features = [ "omero", "jupyter" ] @@ -163,4 +166,4 @@ module = [ "omero", "scipy" ] -ignore_missing_imports = true \ No newline at end of file +ignore_missing_imports = true diff --git a/requirements/requirements-docs.txt b/requirements/requirements-docs.txt index 9459fe3..35c391c 100644 --- a/requirements/requirements-docs.txt +++ b/requirements/requirements-docs.txt @@ -8,6 +8,7 @@ # - mkdocs-minify-plugin # - mkdocs-material-extensions # - mkdocs-git-revision-date-localized-plugin +# - highdicom # - keyring # - matplotlib # - nibabel @@ -512,6 +513,10 @@ h11==0.14.0 \ --hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \ --hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761 # via httpcore +highdicom==0.22.0 \ + --hash=sha256:2f9c7f468924afafb57d49a24c3c96477fe4c5d1e8b6849097d193f00eab6cda \ + --hash=sha256:62442fb9e77c05489c8ff99e6a30ed88fa03842a1fb70616dcf934fe4e3b1ca3 + # via hatch.envs.docs htmlmin2==0.1.13 \ --hash=sha256:75609f2a42e64f7ce57dbff28a39890363bde9e7e5885db633317efbdf8c79a2 # via mkdocs-minify-plugin @@ -1058,6 +1063,7 @@ numpy==1.26.4 \ # via # contourpy # dash-slicer + # highdicom # imageio # matplotlib # nibabel @@ -1181,10 +1187,48 @@ pillow==10.3.0 \ --hash=sha256:ff61bfd9253c3915e6d41c651d5f962da23eda633cf02262990094a18a55371a # via # dash-slicer + # highdicom # imageio # matplotlib # omero-py + # pillow-jpls # scikit-image +pillow-jpls==1.3.2 \ + --hash=sha256:0307b8506862892139a8ce3c63f34e7fd6dfed59bd6c96b677dcf7e03df815a4 \ + --hash=sha256:058e8ad9fce542673703ae1032dc3f4fa3aaf39a8114ce087bce0bcb3a684d95 \ + --hash=sha256:0eadbab278b1c54d6fa79085e0331e0db8799813e7009a6709bce4ad484e0711 \ + --hash=sha256:20fb78195f70ace9cdfd863cb5b3e76d9c9d2ad20aab1b4c87c0bad9aab90563 \ + --hash=sha256:28bdb039cddb68933024330453c2692c6c595e546d0ce9305217413045fca8d4 \ + --hash=sha256:2d1a223a842dd97e3af324e80d07d4dbb9aa19ccab3b46b1c39e2ea231e7dd00 \ + --hash=sha256:34a8d6783a46f8f41c7c4dcd0235b3c0a893818492e8f2500b4a4e70886b5959 \ + --hash=sha256:3aa7e3e48f5e29c22f565e677e27d029e3a302cf56b98c1115835f7c08875453 \ + --hash=sha256:4125954831a91f1f6484f21ef6e521ca214955322e207abb487ebb7cb7ad1b21 \ + --hash=sha256:463ee0eb8c6004fbca535f044b8f7969fa324c2ea4d992158f8bad0ff8ca91dc \ + --hash=sha256:5a87864a95f0e36b32908f12251b5e8b7fa14551a89f27c916cc0e69fdc3382f \ + --hash=sha256:5f87c1cef6de984f07c08d34a84e35e69643d3bc6a3e39241089f4be38f864da \ + --hash=sha256:6bbb20d063fc9efe2474ba7594f203288e5bab75b0cfca32d2d4432fb9053de3 \ + --hash=sha256:7610b9aad5295eb6adc2e658df0dd995b38fef7d4c72c4ef63c1977989f5e701 \ + --hash=sha256:85a42e28cac15b9e25a65588a68a1ba65ed5334a7f7a9b57bcab1223ddf65dae \ + --hash=sha256:8a6c1e8c76b94620e0070948b91771461f7d49cc6be2575e233f6056ffe1ec26 \ + --hash=sha256:8b4740afc7555fb7bce95d6c507069fc0cc9800892e336dba18c5302ef7364a5 \ + --hash=sha256:91553669c4ecaf92ffa53426870190cb1b5bdf2795cddbeac1ae6fc3120c939a \ + --hash=sha256:97d3265f8fcdd2add41a4ca49f464fd6e0982c0225ecbc80f30175fa04ce4e3c \ + --hash=sha256:99a4c3598cf0a82885e3691307fd222b763c69c5b4a15223998679377247bc50 \ + --hash=sha256:9cb643dd50c8fa848c16fe5e41350049ca762499e22cf5fb4cd5f67ae2c027d1 \ + --hash=sha256:a0e04d6ca24dea9763a544518fc06c737499ab9075d216776b86e054be83599c \ + --hash=sha256:a1f1d47544bf824a6262678e5884815f6a2df8cef410bcd9365e213450a4853e \ + --hash=sha256:a79106cc1094385ac1d8670a3bb4d5fe67a7e49d405673d241bf19535d557318 \ + --hash=sha256:ac607508232cdafb09e77f5280211e25d7678152edb0885f0dd374e0b651e2c2 \ + --hash=sha256:ad0afb2c1676bc7d1618cf3837e9fc58997c8f0527464d9f524c19a36d666ce9 \ + --hash=sha256:c822fafda531bc047068663722f86fb67083b572957b38fbc818b6339a817302 \ + --hash=sha256:d1a00f77bd2d33a93082b9496c6891151fed1e1e1b915b60bdcad5f28085a9fc \ + --hash=sha256:d64f4df3c385466aa897a1c70ffe4ecf91c611ca77f524321ddaf3969daede92 \ + --hash=sha256:dea160c6e100b05c896a8434b0b9021870d7c4b055051ec637536437df218da6 \ + --hash=sha256:e837011ad129ff9d2f0c17087856eeb493b208816f41ef82daa21d7cd21fcd53 \ + --hash=sha256:f1ea5f90a3e30e12a5844e850393ee43acc281712bca97fd6545252d652c6f0e \ + --hash=sha256:f346cc2f957c7b726266d46749028832351599a737bb27671eda5853784d02c3 \ + --hash=sha256:f8956774bb9bc23aa85df733b21eaf128c1e115feedf6f37d88c1955d52c444d + # via highdicom platformdirs==4.2.0 \ --hash=sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068 \ --hash=sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768 @@ -1249,7 +1293,9 @@ pycparser==2.22 \ pydicom==2.4.4 \ --hash=sha256:90b4801d851ce65be3df520e16bbfa3d6c767cf2a3a3b1c18f6780e6b670b87a \ --hash=sha256:f9f8e19b78525be57aa6384484298833e4d06ac1d6226c79459131ddb0bd7c42 - # via hatch.envs.docs + # via + # hatch.envs.docs + # highdicom pygments==2.17.2 \ --hash=sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c \ --hash=sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367 diff --git a/requirements/requirements-lint.txt b/requirements/requirements-lint.txt index 7795f26..54d69e9 100644 --- a/requirements/requirements-lint.txt +++ b/requirements/requirements-lint.txt @@ -5,6 +5,7 @@ # - pytest # - pylint # - black +# - highdicom # - keyring # - matplotlib # - nibabel @@ -512,6 +513,10 @@ h11==0.14.0 \ --hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \ --hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761 # via httpcore +highdicom==0.22.0 \ + --hash=sha256:2f9c7f468924afafb57d49a24c3c96477fe4c5d1e8b6849097d193f00eab6cda \ + --hash=sha256:62442fb9e77c05489c8ff99e6a30ed88fa03842a1fb70616dcf934fe4e3b1ca3 + # via hatch.envs.lint httpcore==1.0.5 \ --hash=sha256:34a38e2f9291467ee3b44e89dd52615370e152954ba21721378a87b2960f7a61 \ --hash=sha256:421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5 @@ -1007,6 +1012,7 @@ numpy==1.26.4 \ # via # contourpy # dash-slicer + # highdicom # imageio # matplotlib # nibabel @@ -1128,10 +1134,48 @@ pillow==10.3.0 \ --hash=sha256:ff61bfd9253c3915e6d41c651d5f962da23eda633cf02262990094a18a55371a # via # dash-slicer + # highdicom # imageio # matplotlib # omero-py + # pillow-jpls # scikit-image +pillow-jpls==1.3.2 \ + --hash=sha256:0307b8506862892139a8ce3c63f34e7fd6dfed59bd6c96b677dcf7e03df815a4 \ + --hash=sha256:058e8ad9fce542673703ae1032dc3f4fa3aaf39a8114ce087bce0bcb3a684d95 \ + --hash=sha256:0eadbab278b1c54d6fa79085e0331e0db8799813e7009a6709bce4ad484e0711 \ + --hash=sha256:20fb78195f70ace9cdfd863cb5b3e76d9c9d2ad20aab1b4c87c0bad9aab90563 \ + --hash=sha256:28bdb039cddb68933024330453c2692c6c595e546d0ce9305217413045fca8d4 \ + --hash=sha256:2d1a223a842dd97e3af324e80d07d4dbb9aa19ccab3b46b1c39e2ea231e7dd00 \ + --hash=sha256:34a8d6783a46f8f41c7c4dcd0235b3c0a893818492e8f2500b4a4e70886b5959 \ + --hash=sha256:3aa7e3e48f5e29c22f565e677e27d029e3a302cf56b98c1115835f7c08875453 \ + --hash=sha256:4125954831a91f1f6484f21ef6e521ca214955322e207abb487ebb7cb7ad1b21 \ + --hash=sha256:463ee0eb8c6004fbca535f044b8f7969fa324c2ea4d992158f8bad0ff8ca91dc \ + --hash=sha256:5a87864a95f0e36b32908f12251b5e8b7fa14551a89f27c916cc0e69fdc3382f \ + --hash=sha256:5f87c1cef6de984f07c08d34a84e35e69643d3bc6a3e39241089f4be38f864da \ + --hash=sha256:6bbb20d063fc9efe2474ba7594f203288e5bab75b0cfca32d2d4432fb9053de3 \ + --hash=sha256:7610b9aad5295eb6adc2e658df0dd995b38fef7d4c72c4ef63c1977989f5e701 \ + --hash=sha256:85a42e28cac15b9e25a65588a68a1ba65ed5334a7f7a9b57bcab1223ddf65dae \ + --hash=sha256:8a6c1e8c76b94620e0070948b91771461f7d49cc6be2575e233f6056ffe1ec26 \ + --hash=sha256:8b4740afc7555fb7bce95d6c507069fc0cc9800892e336dba18c5302ef7364a5 \ + --hash=sha256:91553669c4ecaf92ffa53426870190cb1b5bdf2795cddbeac1ae6fc3120c939a \ + --hash=sha256:97d3265f8fcdd2add41a4ca49f464fd6e0982c0225ecbc80f30175fa04ce4e3c \ + --hash=sha256:99a4c3598cf0a82885e3691307fd222b763c69c5b4a15223998679377247bc50 \ + --hash=sha256:9cb643dd50c8fa848c16fe5e41350049ca762499e22cf5fb4cd5f67ae2c027d1 \ + --hash=sha256:a0e04d6ca24dea9763a544518fc06c737499ab9075d216776b86e054be83599c \ + --hash=sha256:a1f1d47544bf824a6262678e5884815f6a2df8cef410bcd9365e213450a4853e \ + --hash=sha256:a79106cc1094385ac1d8670a3bb4d5fe67a7e49d405673d241bf19535d557318 \ + --hash=sha256:ac607508232cdafb09e77f5280211e25d7678152edb0885f0dd374e0b651e2c2 \ + --hash=sha256:ad0afb2c1676bc7d1618cf3837e9fc58997c8f0527464d9f524c19a36d666ce9 \ + --hash=sha256:c822fafda531bc047068663722f86fb67083b572957b38fbc818b6339a817302 \ + --hash=sha256:d1a00f77bd2d33a93082b9496c6891151fed1e1e1b915b60bdcad5f28085a9fc \ + --hash=sha256:d64f4df3c385466aa897a1c70ffe4ecf91c611ca77f524321ddaf3969daede92 \ + --hash=sha256:dea160c6e100b05c896a8434b0b9021870d7c4b055051ec637536437df218da6 \ + --hash=sha256:e837011ad129ff9d2f0c17087856eeb493b208816f41ef82daa21d7cd21fcd53 \ + --hash=sha256:f1ea5f90a3e30e12a5844e850393ee43acc281712bca97fd6545252d652c6f0e \ + --hash=sha256:f346cc2f957c7b726266d46749028832351599a737bb27671eda5853784d02c3 \ + --hash=sha256:f8956774bb9bc23aa85df733b21eaf128c1e115feedf6f37d88c1955d52c444d + # via highdicom platformdirs==4.2.0 \ --hash=sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068 \ --hash=sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768 @@ -1200,7 +1244,9 @@ pycparser==2.22 \ pydicom==2.4.4 \ --hash=sha256:90b4801d851ce65be3df520e16bbfa3d6c767cf2a3a3b1c18f6780e6b670b87a \ --hash=sha256:f9f8e19b78525be57aa6384484298833e4d06ac1d6226c79459131ddb0bd7c42 - # via hatch.envs.lint + # via + # hatch.envs.lint + # highdicom pygments==2.18.0 \ --hash=sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199 \ --hash=sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a diff --git a/requirements/requirements-test.txt b/requirements/requirements-test.txt index d661e94..4a92111 100644 --- a/requirements/requirements-test.txt +++ b/requirements/requirements-test.txt @@ -7,6 +7,7 @@ # - pytest-asyncio # - coverage[toml]>=6.2 # - pydicom-data +# - highdicom # - keyring # - matplotlib # - nibabel @@ -536,6 +537,10 @@ h11==0.14.0 \ --hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \ --hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761 # via httpcore +highdicom==0.22.0 \ + --hash=sha256:2f9c7f468924afafb57d49a24c3c96477fe4c5d1e8b6849097d193f00eab6cda \ + --hash=sha256:62442fb9e77c05489c8ff99e6a30ed88fa03842a1fb70616dcf934fe4e3b1ca3 + # via hatch.envs.test httpcore==1.0.5 \ --hash=sha256:34a38e2f9291467ee3b44e89dd52615370e152954ba21721378a87b2960f7a61 \ --hash=sha256:421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5 @@ -1019,6 +1024,7 @@ numpy==1.26.4 \ # via # contourpy # dash-slicer + # highdicom # imageio # matplotlib # nibabel @@ -1135,10 +1141,48 @@ pillow==10.3.0 \ --hash=sha256:ff61bfd9253c3915e6d41c651d5f962da23eda633cf02262990094a18a55371a # via # dash-slicer + # highdicom # imageio # matplotlib # omero-py + # pillow-jpls # scikit-image +pillow-jpls==1.3.2 \ + --hash=sha256:0307b8506862892139a8ce3c63f34e7fd6dfed59bd6c96b677dcf7e03df815a4 \ + --hash=sha256:058e8ad9fce542673703ae1032dc3f4fa3aaf39a8114ce087bce0bcb3a684d95 \ + --hash=sha256:0eadbab278b1c54d6fa79085e0331e0db8799813e7009a6709bce4ad484e0711 \ + --hash=sha256:20fb78195f70ace9cdfd863cb5b3e76d9c9d2ad20aab1b4c87c0bad9aab90563 \ + --hash=sha256:28bdb039cddb68933024330453c2692c6c595e546d0ce9305217413045fca8d4 \ + --hash=sha256:2d1a223a842dd97e3af324e80d07d4dbb9aa19ccab3b46b1c39e2ea231e7dd00 \ + --hash=sha256:34a8d6783a46f8f41c7c4dcd0235b3c0a893818492e8f2500b4a4e70886b5959 \ + --hash=sha256:3aa7e3e48f5e29c22f565e677e27d029e3a302cf56b98c1115835f7c08875453 \ + --hash=sha256:4125954831a91f1f6484f21ef6e521ca214955322e207abb487ebb7cb7ad1b21 \ + --hash=sha256:463ee0eb8c6004fbca535f044b8f7969fa324c2ea4d992158f8bad0ff8ca91dc \ + --hash=sha256:5a87864a95f0e36b32908f12251b5e8b7fa14551a89f27c916cc0e69fdc3382f \ + --hash=sha256:5f87c1cef6de984f07c08d34a84e35e69643d3bc6a3e39241089f4be38f864da \ + --hash=sha256:6bbb20d063fc9efe2474ba7594f203288e5bab75b0cfca32d2d4432fb9053de3 \ + --hash=sha256:7610b9aad5295eb6adc2e658df0dd995b38fef7d4c72c4ef63c1977989f5e701 \ + --hash=sha256:85a42e28cac15b9e25a65588a68a1ba65ed5334a7f7a9b57bcab1223ddf65dae \ + --hash=sha256:8a6c1e8c76b94620e0070948b91771461f7d49cc6be2575e233f6056ffe1ec26 \ + --hash=sha256:8b4740afc7555fb7bce95d6c507069fc0cc9800892e336dba18c5302ef7364a5 \ + --hash=sha256:91553669c4ecaf92ffa53426870190cb1b5bdf2795cddbeac1ae6fc3120c939a \ + --hash=sha256:97d3265f8fcdd2add41a4ca49f464fd6e0982c0225ecbc80f30175fa04ce4e3c \ + --hash=sha256:99a4c3598cf0a82885e3691307fd222b763c69c5b4a15223998679377247bc50 \ + --hash=sha256:9cb643dd50c8fa848c16fe5e41350049ca762499e22cf5fb4cd5f67ae2c027d1 \ + --hash=sha256:a0e04d6ca24dea9763a544518fc06c737499ab9075d216776b86e054be83599c \ + --hash=sha256:a1f1d47544bf824a6262678e5884815f6a2df8cef410bcd9365e213450a4853e \ + --hash=sha256:a79106cc1094385ac1d8670a3bb4d5fe67a7e49d405673d241bf19535d557318 \ + --hash=sha256:ac607508232cdafb09e77f5280211e25d7678152edb0885f0dd374e0b651e2c2 \ + --hash=sha256:ad0afb2c1676bc7d1618cf3837e9fc58997c8f0527464d9f524c19a36d666ce9 \ + --hash=sha256:c822fafda531bc047068663722f86fb67083b572957b38fbc818b6339a817302 \ + --hash=sha256:d1a00f77bd2d33a93082b9496c6891151fed1e1e1b915b60bdcad5f28085a9fc \ + --hash=sha256:d64f4df3c385466aa897a1c70ffe4ecf91c611ca77f524321ddaf3969daede92 \ + --hash=sha256:dea160c6e100b05c896a8434b0b9021870d7c4b055051ec637536437df218da6 \ + --hash=sha256:e837011ad129ff9d2f0c17087856eeb493b208816f41ef82daa21d7cd21fcd53 \ + --hash=sha256:f1ea5f90a3e30e12a5844e850393ee43acc281712bca97fd6545252d652c6f0e \ + --hash=sha256:f346cc2f957c7b726266d46749028832351599a737bb27671eda5853784d02c3 \ + --hash=sha256:f8956774bb9bc23aa85df733b21eaf128c1e115feedf6f37d88c1955d52c444d + # via highdicom platformdirs==4.2.2 \ --hash=sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee \ --hash=sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3 @@ -1204,7 +1248,9 @@ pycparser==2.22 \ pydicom==2.4.4 \ --hash=sha256:90b4801d851ce65be3df520e16bbfa3d6c767cf2a3a3b1c18f6780e6b670b87a \ --hash=sha256:f9f8e19b78525be57aa6384484298833e4d06ac1d6226c79459131ddb0bd7c42 - # via hatch.envs.test + # via + # hatch.envs.test + # highdicom pydicom-data==1.0.0 \ --hash=sha256:622ac97265f1d91f76b5120b5bd6eb0f57737c392ef863b72c71779c91e33637 \ --hash=sha256:93f2094f219b6fec1e6dbed2e5039fb879272f678646a351b46172f6d0bf110f diff --git a/requirements/requirements-types.txt b/requirements/requirements-types.txt index a186773..aedb4d6 100644 --- a/requirements/requirements-types.txt +++ b/requirements/requirements-types.txt @@ -2,6 +2,7 @@ # This file is autogenerated by hatch-pip-compile with Python 3.11 # # - mypy>=1.0.0 +# - highdicom # - keyring # - matplotlib # - nibabel @@ -475,6 +476,10 @@ h11==0.14.0 \ --hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \ --hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761 # via httpcore +highdicom==0.22.0 \ + --hash=sha256:2f9c7f468924afafb57d49a24c3c96477fe4c5d1e8b6849097d193f00eab6cda \ + --hash=sha256:62442fb9e77c05489c8ff99e6a30ed88fa03842a1fb70616dcf934fe4e3b1ca3 + # via hatch.envs.types httpcore==1.0.5 \ --hash=sha256:34a38e2f9291467ee3b44e89dd52615370e152954ba21721378a87b2960f7a61 \ --hash=sha256:421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5 @@ -988,6 +993,7 @@ numpy==1.26.4 \ # via # contourpy # dash-slicer + # highdicom # imageio # matplotlib # nibabel @@ -1103,10 +1109,48 @@ pillow==10.3.0 \ --hash=sha256:ff61bfd9253c3915e6d41c651d5f962da23eda633cf02262990094a18a55371a # via # dash-slicer + # highdicom # imageio # matplotlib # omero-py + # pillow-jpls # scikit-image +pillow-jpls==1.3.2 \ + --hash=sha256:0307b8506862892139a8ce3c63f34e7fd6dfed59bd6c96b677dcf7e03df815a4 \ + --hash=sha256:058e8ad9fce542673703ae1032dc3f4fa3aaf39a8114ce087bce0bcb3a684d95 \ + --hash=sha256:0eadbab278b1c54d6fa79085e0331e0db8799813e7009a6709bce4ad484e0711 \ + --hash=sha256:20fb78195f70ace9cdfd863cb5b3e76d9c9d2ad20aab1b4c87c0bad9aab90563 \ + --hash=sha256:28bdb039cddb68933024330453c2692c6c595e546d0ce9305217413045fca8d4 \ + --hash=sha256:2d1a223a842dd97e3af324e80d07d4dbb9aa19ccab3b46b1c39e2ea231e7dd00 \ + --hash=sha256:34a8d6783a46f8f41c7c4dcd0235b3c0a893818492e8f2500b4a4e70886b5959 \ + --hash=sha256:3aa7e3e48f5e29c22f565e677e27d029e3a302cf56b98c1115835f7c08875453 \ + --hash=sha256:4125954831a91f1f6484f21ef6e521ca214955322e207abb487ebb7cb7ad1b21 \ + --hash=sha256:463ee0eb8c6004fbca535f044b8f7969fa324c2ea4d992158f8bad0ff8ca91dc \ + --hash=sha256:5a87864a95f0e36b32908f12251b5e8b7fa14551a89f27c916cc0e69fdc3382f \ + --hash=sha256:5f87c1cef6de984f07c08d34a84e35e69643d3bc6a3e39241089f4be38f864da \ + --hash=sha256:6bbb20d063fc9efe2474ba7594f203288e5bab75b0cfca32d2d4432fb9053de3 \ + --hash=sha256:7610b9aad5295eb6adc2e658df0dd995b38fef7d4c72c4ef63c1977989f5e701 \ + --hash=sha256:85a42e28cac15b9e25a65588a68a1ba65ed5334a7f7a9b57bcab1223ddf65dae \ + --hash=sha256:8a6c1e8c76b94620e0070948b91771461f7d49cc6be2575e233f6056ffe1ec26 \ + --hash=sha256:8b4740afc7555fb7bce95d6c507069fc0cc9800892e336dba18c5302ef7364a5 \ + --hash=sha256:91553669c4ecaf92ffa53426870190cb1b5bdf2795cddbeac1ae6fc3120c939a \ + --hash=sha256:97d3265f8fcdd2add41a4ca49f464fd6e0982c0225ecbc80f30175fa04ce4e3c \ + --hash=sha256:99a4c3598cf0a82885e3691307fd222b763c69c5b4a15223998679377247bc50 \ + --hash=sha256:9cb643dd50c8fa848c16fe5e41350049ca762499e22cf5fb4cd5f67ae2c027d1 \ + --hash=sha256:a0e04d6ca24dea9763a544518fc06c737499ab9075d216776b86e054be83599c \ + --hash=sha256:a1f1d47544bf824a6262678e5884815f6a2df8cef410bcd9365e213450a4853e \ + --hash=sha256:a79106cc1094385ac1d8670a3bb4d5fe67a7e49d405673d241bf19535d557318 \ + --hash=sha256:ac607508232cdafb09e77f5280211e25d7678152edb0885f0dd374e0b651e2c2 \ + --hash=sha256:ad0afb2c1676bc7d1618cf3837e9fc58997c8f0527464d9f524c19a36d666ce9 \ + --hash=sha256:c822fafda531bc047068663722f86fb67083b572957b38fbc818b6339a817302 \ + --hash=sha256:d1a00f77bd2d33a93082b9496c6891151fed1e1e1b915b60bdcad5f28085a9fc \ + --hash=sha256:d64f4df3c385466aa897a1c70ffe4ecf91c611ca77f524321ddaf3969daede92 \ + --hash=sha256:dea160c6e100b05c896a8434b0b9021870d7c4b055051ec637536437df218da6 \ + --hash=sha256:e837011ad129ff9d2f0c17087856eeb493b208816f41ef82daa21d7cd21fcd53 \ + --hash=sha256:f1ea5f90a3e30e12a5844e850393ee43acc281712bca97fd6545252d652c6f0e \ + --hash=sha256:f346cc2f957c7b726266d46749028832351599a737bb27671eda5853784d02c3 \ + --hash=sha256:f8956774bb9bc23aa85df733b21eaf128c1e115feedf6f37d88c1955d52c444d + # via highdicom platformdirs==4.2.2 \ --hash=sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee \ --hash=sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3 @@ -1168,7 +1212,9 @@ pycparser==2.22 \ pydicom==2.4.4 \ --hash=sha256:90b4801d851ce65be3df520e16bbfa3d6c767cf2a3a3b1c18f6780e6b670b87a \ --hash=sha256:f9f8e19b78525be57aa6384484298833e4d06ac1d6226c79459131ddb0bd7c42 - # via hatch.envs.types + # via + # hatch.envs.types + # highdicom pygments==2.18.0 \ --hash=sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199 \ --hash=sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a diff --git a/src/lavlab/__about__.py b/src/lavlab/__about__.py index 5d7ef5a..19d1c8e 100644 --- a/src/lavlab/__about__.py +++ b/src/lavlab/__about__.py @@ -1,3 +1,3 @@ """Hatch Version Info""" -version = "1.4.0-alpha.1" # pylint: disable=C0103 +version = "1.3.1" # pylint: disable=C0103 diff --git a/src/lavlab/imsuite.py b/src/lavlab/imsuite.py index 747def6..d7400cf 100644 --- a/src/lavlab/imsuite.py +++ b/src/lavlab/imsuite.py @@ -668,7 +668,7 @@ def imhist(img_arr: np.ndarray, bins=256) -> None: def imcomplement(img_arr: np.ndarray) -> np.ndarray: """Generates the image's complement (inverts the image). - + Parameters ---------- img_arr : np.ndarray @@ -679,7 +679,23 @@ def imcomplement(img_arr: np.ndarray) -> np.ndarray: np.ndarray Inverted image. """ - return ~img_arr + # Handle uint8 directly + if img_arr.dtype == np.uint8: + return ~img_arr + + min_val = np.min(img_arr) + max_val = np.max(img_arr) + + # Handle range [0, 1] + if max_val <= 1 and min_val >= 0: + return 1 - img_arr + + # Handle range [-1, 1] + if max_val <= 1 and min_val >= -1: + return -img_arr + + # Generalized case + return min_val + max_val - img_arr def edge(img_arr: np.ndarray, method: str = "SOBEL", **kwargs) -> np.ndarray: diff --git a/src/lavlab/omero/tiles.py b/src/lavlab/omero/tiles.py index 5477907..62dc7ca 100644 --- a/src/lavlab/omero/tiles.py +++ b/src/lavlab/omero/tiles.py @@ -21,7 +21,7 @@ def get_tiles( # pylint: disable=R0914 ) -> Generator[ tuple[np.ndarray, tuple[int, int, int, tuple[int, int, int, int]]], None, None ]: - """Pull tiles from omero faster using a ThreadPoolExecutor! + """Pull tiles from omero faster using a ThreadPoolExecutor and executor.map! Parameters ---------- @@ -46,49 +46,37 @@ def get_tiles( # pylint: disable=R0914 conn = img._conn # pylint: disable=W0212 local = threading.local() - def work(pix_id, zct, coord, res_lvl, rps_bypass): - """runs inside a threadpool to get multiple tiles at a time""" + def work(args): + """Runs inside a thread pool to get multiple tiles at a time.""" + pix_id, zct, coord, res_lvl, rps_bypass = args if getattr(local, "rps", None) is None: - # need to prepare a thread-specific rps + # Need to prepare a thread-specific rps local.rps = conn.c.sf.createRawPixelsStore() local.rps.setPixelsId(pix_id, rps_bypass) if res_lvl is None: res_lvl = local.rps.getResolutionLevels() res_lvl -= 1 local.rps.setResolutionLevel(res_lvl) - return local.rps.getTile(*zct, *coord), (*zct, coord) + raw_data = local.rps.getTile(*zct, *coord) + return raw_data, (*zct, coord) def cleanup(): - """cleans out the raw pixels stores after work is done""" + """Cleans out the raw pixels stores after work is done.""" if hasattr(local, "rps"): local.rps.close() delattr(local, "rps") - futures = [ - tpe.submit( - work, - img.getPrimaryPixels().getId(), - (z, c, t), - coord, - res_lvl, - rps_bypass, - ) - for z, c, t, coord in tiles - ] try: - for future in as_completed(futures): - raw_data, (z, c, t, coord) = future.result() - processed_data = np.frombuffer(raw_data, dtype=np.uint8).reshape( - coord[3], coord[2] - ) + # Use executor.map for streamlined processing + pix_id = img.getPrimaryPixels().getId() + args_iter = ((pix_id, (z, c, t), coord, res_lvl, rps_bypass) for z, c, t, coord in tiles) + for raw_data, (z, c, t, coord) in tpe.map(work, args_iter): + processed_data = np.frombuffer(raw_data, dtype=np.uint8).reshape(coord[3], coord[2]) yield processed_data, (z, c, t, coord) finally: - futures = [ - tpe.submit(cleanup) - for x in range(tpe._max_workers) # pylint: disable=W0212 - ] # pylint: disable=W0212 - for future in as_completed(futures): - future.result() + # Cleanup resources + for _ in range(tpe._max_workers): # pylint: disable=W0212 + cleanup() def create_tile_list_2d( # pylint: disable=R0913