├── .github └── workflows │ ├── build_book.yml │ └── test_and_deploy.yml ├── .gitignore ├── .napari └── config.yml ├── .pre-commit-config.yaml ├── CITATION.cff ├── LICENSE ├── MANIFEST.in ├── README.md ├── codecov.yml ├── docs ├── _config.yml ├── _toc.yml ├── api.rst ├── clusters-plotter-demo.gif ├── contributing │ └── new_algorithm.md ├── examples │ ├── imgs │ │ ├── sample_data_bbbc1.gif │ │ ├── sample_data_cells3d.gif │ │ ├── sample_data_skan_skeleton.gif │ │ └── sample_data_tgmm.gif │ └── sample_data.md ├── intro.md ├── logo.png ├── requirements.txt └── usage │ ├── clustering_widget.md │ ├── dimensionality_reduction_widget.md │ ├── imgs │ ├── Zeichnung.svg │ ├── clustering_overview1.png │ ├── clustering_overview1_annotated.png │ ├── clustering_overview2.png │ ├── clustering_overview3.png │ ├── clustering_visualization1.png │ ├── dimensionality_reduction_overview1.png │ ├── dimensionality_reduction_overview1_annotated.png │ ├── dimensionality_reduction_overview2.png │ ├── dimensionality_reduction_visualize1.png │ ├── dimensionality_reduction_visualize2.png │ ├── feature_immediacy3.gif │ ├── features_immediacy1.gif │ ├── features_immediacy2.gif │ ├── layer_demo_tracks.gif │ ├── plotter_overview1.png │ ├── plotter_overview1_annotated.png │ ├── plotter_overview2.png │ ├── plotter_overview3.png │ ├── plotter_overview3_annotated.png │ ├── selecting_features1.gif │ ├── selecting_layers1.png │ ├── selecting_layers1_annotated.png │ ├── selecting_layers2.png │ ├── selecting_layers3.gif │ ├── selecting_layers4.png │ ├── selecting_layers4_annotated.png │ └── selecting_layers5.png │ ├── overview.md │ └── plotter_widget.md ├── notebooks ├── demo_biological_data.ipynb ├── demo_new_plotter.ipynb ├── demo_new_reduction.ipynb └── demo_shapes_clustering.ipynb ├── pyproject.toml ├── src └── napari_clusters_plotter │ ├── __init__.py │ ├── _algorithm_widget.py │ ├── _algorithms.py │ ├── _dim_reduction_and_clustering.py │ ├── _new_plotter_widget.py │ ├── _sample_data.py │ ├── _tests │ ├── __init__.py │ ├── test_dimensionality_reduction.py │ ├── test_layers.py │ ├── test_plotter.py │ └── test_sample_data.py │ ├── _version.py │ ├── napari.yaml │ ├── plotter_inputs.ui │ └── sample_data │ ├── BBBC007_v1_images │ ├── A9 │ │ ├── A9 p10d.tif │ │ ├── A9 p10d_features.csv │ │ ├── A9 p10d_labels.tif │ │ ├── A9 p5d.tif │ │ ├── A9 p5d_features.csv │ │ ├── A9 p5d_labels.tif │ │ ├── A9 p7d.tif │ │ ├── A9 p7d_features.csv │ │ ├── A9 p7d_labels.tif │ │ ├── A9 p9d.tif │ │ ├── A9 p9d_features.csv │ │ └── A9 p9d_labels.tif │ ├── data_source.txt │ ├── f96 (17) │ │ ├── 17P1_POS0006_D_1UL.tif │ │ ├── 17P1_POS0006_D_1UL_features.csv │ │ ├── 17P1_POS0006_D_1UL_labels.tif │ │ ├── 17P1_POS0007_D_1UL.tif │ │ ├── 17P1_POS0007_D_1UL_features.csv │ │ ├── 17P1_POS0007_D_1UL_labels.tif │ │ ├── 17P1_POS0011_D_1UL.tif │ │ ├── 17P1_POS0011_D_1UL_features.csv │ │ ├── 17P1_POS0011_D_1UL_labels.tif │ │ ├── 17P1_POS0013_D_1UL.tif │ │ ├── 17P1_POS0013_D_1UL_features.csv │ │ ├── 17P1_POS0013_D_1UL_labels.tif │ │ ├── 17P1_POS0014_D_1UL.tif │ │ ├── 17P1_POS0014_D_1UL_features.csv │ │ └── 17P1_POS0014_D_1UL_labels.tif │ └── f9620 │ │ ├── 20P1_POS0002_D_1UL_labels.tif │ │ ├── 20P1_POS0005_D_1UL.tif │ │ ├── 20P1_POS0005_D_1UL_features.csv │ │ ├── 20P1_POS0005_D_1UL_labels.tif │ │ ├── 20P1_POS0007_D_1UL.tif │ │ ├── 20P1_POS0007_D_1UL_features.csv │ │ ├── 20P1_POS0007_D_1UL_labels.tif │ │ ├── 20P1_POS0008_D_1UL.tif │ │ ├── 20P1_POS0008_D_1UL_features.csv │ │ ├── 20P1_POS0008_D_1UL_labels.tif │ │ ├── 20P1_POS0010_D_1UL.tif │ │ ├── 20P1_POS0010_D_1UL_features.csv │ │ ├── 20P1_POS0010_D_1UL_labels.tif │ │ ├── 20P1_POS0011_D_1UL.tif │ │ ├── 20P1_POS0011_D_1UL_features.csv │ │ └── 20P1_POS0011_D_1UL_labels.tif │ ├── cells3d │ ├── faces.txt │ ├── nucleus.tif │ ├── signature.csv │ └── vertices.txt │ ├── shapes_skeleton │ ├── all_paths.csv │ ├── blobs.tif │ └── skeleton_features.csv │ └── tracking_data │ ├── LICENSE │ ├── README.md │ ├── tgmm-mini-spot.csv │ ├── tgmm-mini-tracks-layer-data.csv │ ├── tgmm-mini.csv │ └── tgmm-mini.tif └── tox.ini /.github/workflows/build_book.yml: -------------------------------------------------------------------------------- 1 | name: deploy-book 2 | 3 | # Run this when the master or main branch changes 4 | on: 5 | push: 6 | branches: 7 | - master 8 | - main 9 | # If your git repository has the Jupyter Book within some-subfolder next to 10 | # unrelated files, you can make this run only if a file within that specific 11 | # folder has been modified. 12 | # 13 | # paths: 14 | # - some-subfolder/** 15 | 16 | # This job installs dependencies, builds the book, and pushes it to `gh-pages` 17 | jobs: 18 | deploy-book: 19 | runs-on: ubuntu-latest 20 | permissions: 21 | pages: write 22 | id-token: write 23 | steps: 24 | - uses: actions/checkout@v4 25 | 26 | # Install dependencies 27 | - name: Set up Python 3.11 28 | uses: actions/setup-python@v5 29 | with: 30 | python-version: '3.11' 31 | cache: pip # Implicitly uses requirements.txt for cache key 32 | 33 | - name: Install dependencies 34 | run: pip install -r docs/requirements.txt 35 | 36 | # (optional) Cache your executed notebooks between runs 37 | # if you have config: 38 | # execute: 39 | # execute_notebooks: cache 40 | - name: cache executed notebooks 41 | uses: actions/cache@v4 42 | with: 43 | path: _build/.jupyter_cache 44 | key: jupyter-book-cache-${{ hashFiles('docs/requirements.txt') }} 45 | 46 | # Build the book 47 | - name: Build the book 48 | run: | 49 | jupyter-book build ./docs/ 50 | 51 | # Upload the book's HTML as an artifact 52 | - name: Upload artifact 53 | uses: actions/upload-pages-artifact@v3 54 | with: 55 | path: "docs/_build/html" 56 | 57 | # Deploy the book's HTML to GitHub Pages 58 | - name: Deploy to GitHub Pages 59 | id: deployment 60 | uses: actions/deploy-pages@v4 61 | -------------------------------------------------------------------------------- /.github/workflows/test_and_deploy.yml: -------------------------------------------------------------------------------- 1 | # This workflows will upload a Python Package using Twine when a release is created 2 | # For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries 3 | 4 | name: tests 5 | 6 | on: 7 | push: 8 | branches: 9 | - master 10 | - main 11 | tags: 12 | - "*" # Push events with any tag 13 | pull_request: 14 | branches: 15 | - master 16 | - main 17 | workflow_dispatch: 18 | 19 | jobs: 20 | test: 21 | name: ${{ matrix.platform }} py${{ matrix.python-version }} 22 | runs-on: ${{ matrix.platform }} 23 | strategy: 24 | matrix: 25 | platform: [ubuntu-latest, windows-latest, macos-latest] # macos-latest (disabled, see related issue) 26 | python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] 27 | 28 | steps: 29 | - uses: actions/checkout@v3 30 | 31 | - name: Set up Python ${{ matrix.python-version }} 32 | uses: actions/setup-python@v4 33 | with: 34 | python-version: ${{ matrix.python-version }} 35 | 36 | # these libraries enable testing on Qt on linux 37 | - uses: tlambert03/setup-qt-libs@v1 38 | 39 | # strategy borrowed from vispy for installing opengl libs on windows 40 | - name: Install Windows OpenGL 41 | if: runner.os == 'Windows' 42 | run: | 43 | git clone --depth 1 https://github.com/pyvista/gl-ci-helpers.git 44 | powershell gl-ci-helpers/appveyor/install_opengl.ps1 45 | 46 | # note: if you need dependencies from conda, considering using 47 | # setup-miniconda: https://github.com/conda-incubator/setup-miniconda 48 | # and 49 | # tox-conda: https://github.com/tox-dev/tox-conda 50 | - name: Install dependencies 51 | run: | 52 | python -m pip install --upgrade pip 53 | python -m pip install setuptools tox tox-gh-actions 54 | 55 | # this runs the platform-specific tests declared in tox.ini 56 | - name: Test with tox 57 | uses: aganders3/headless-gui@v2 58 | with: 59 | run: python -m tox 60 | env: 61 | PLATFORM: ${{ matrix.platform }} 62 | 63 | - name: Coverage 64 | uses: codecov/codecov-action@v3 65 | 66 | deploy: 67 | # this will run when you have tagged a commit, 68 | # and requires that you have put your twine API key in your 69 | # github secrets (see readme for details) 70 | needs: [test] 71 | runs-on: ubuntu-latest 72 | if: contains(github.ref, 'tags') 73 | steps: 74 | - uses: actions/checkout@v3 75 | - name: Set up Python 76 | uses: actions/setup-python@v4 77 | with: 78 | python-version: "3.x" 79 | - name: Install dependencies 80 | run: | 81 | python -m pip install --upgrade pip 82 | pip install -U setuptools setuptools_scm wheel twine build 83 | - name: Build and publish 84 | env: 85 | TWINE_USERNAME: __token__ 86 | TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }} 87 | run: | 88 | git tag 89 | python -m build . 90 | twine upload dist/* 91 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | .hypothesis/ 47 | .napari_cache 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | local_settings.py 56 | 57 | # Flask instance folder 58 | instance/ 59 | 60 | # Sphinx documentation 61 | docs/_build/ 62 | 63 | # MkDocs documentation 64 | /site/ 65 | 66 | # PyBuilder 67 | target/ 68 | 69 | # IPython Notebook 70 | .ipynb_checkpoints 71 | 72 | # pyenv 73 | .python-version 74 | 75 | # OS 76 | .DS_Store 77 | 78 | # written by setuptools_scm 79 | */_version.py 80 | 81 | # PyBuilder 82 | .idea 83 | venv/ 84 | -------------------------------------------------------------------------------- /.napari/config.yml: -------------------------------------------------------------------------------- 1 | # Add labels from the EDAM Bioimaging ontology 2 | labels: 3 | ontology: EDAM-BIOIMAGING:alpha06 4 | terms: 5 | - 2D image 6 | - 3D image 7 | - Unsupervised learning 8 | - Clustering 9 | - Centroid-based clustering 10 | - Hierarchical clustering 11 | - Visualisation 12 | - Plotting 13 | - Object feature extraction 14 | - Shape features extraction 15 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v4.5.0 4 | hooks: 5 | - id: check-docstring-first 6 | - id: end-of-file-fixer 7 | - id: trailing-whitespace 8 | exclude: ^\.napari-hub/.* 9 | - id: check-yaml # checks for correct yaml syntax for github actions ex. 10 | - repo: https://github.com/astral-sh/ruff-pre-commit 11 | rev: v0.3.4 12 | hooks: 13 | - id: ruff 14 | - repo: https://github.com/psf/black 15 | rev: 24.3.0 16 | hooks: 17 | - id: black 18 | - repo: https://github.com/tlambert03/napari-plugin-checks 19 | rev: v0.3.0 20 | hooks: 21 | - id: napari-plugin-checks 22 | -------------------------------------------------------------------------------- /CITATION.cff: -------------------------------------------------------------------------------- 1 | cff-version: 1.2.0 2 | title: napari-clusters-plotter 3 | message: "If you use this software, please cite it using the metadata from this file." 4 | abstract: "A plugin to use with napari for clustering objects according to their properties." 5 | type: software 6 | authors: 7 | - given-names: Laura 8 | family-names: Zigutyte 9 | email: zigutyte@gmail.com 10 | - given-names: Ryan 11 | family-names: Savill 12 | - given-names: Johannes 13 | family-names: Müller 14 | - given-names: Marcelo 15 | family-names: Zoccoler 16 | - given-names: Thorsten 17 | family-names: Wagner 18 | email: thorsten.wagner@mpi-dortmund.mpg.de 19 | - given-names: Robert 20 | family-names: Haase 21 | email: robert.haase@tu-dresden.de 22 | version: 0.7.1 23 | date-released: 2023-05-01 24 | identifiers: 25 | - description: This is the collection of archived snapshots of all versions of napari-clusters-plotter 26 | type: doi 27 | value: "10.5281/zenodo.5884657" 28 | - description: This is the archived snapshot of version 0.7.1 of napari-clusters-plotter 29 | type: doi 30 | value: "10.5281/zenodo.7882626" 31 | - description: This is the archived snapshot of version 0.7.0 of napari-clusters-plotter 32 | type: doi 33 | value: "10.5281/zenodo.7879227" 34 | - description: This is the archived snapshot of version 0.6.2 of napari-clusters-plotter 35 | type: doi 36 | value: "10.5281/zenodo.7745633" 37 | - description: This is the archived snapshot of version 0.6.1 of napari-clusters-plotter 38 | type: doi 39 | value: "10.5281/zenodo.7646982" 40 | - description: This is the archived snapshot of version 0.5.1 of napari-clusters-plotter 41 | type: doi 42 | value: "10.5281/zenodo.6620442" 43 | - description: This is the archived snapshot of version 0.5.0 of napari-clusters-plotter 44 | type: doi 45 | value: "10.5281/zenodo.6520216" 46 | - description: This is the archived snapshot of version 0.4.0 of napari-clusters-plotter 47 | type: doi 48 | value: "10.5281/zenodo.6483425" 49 | - description: This is the archived snapshot of version 0.3.0 of napari-clusters-plotter 50 | type: doi 51 | value: "10.5281/zenodo.6412049" 52 | - description: This is the archived snapshot of version 0.2.2 of napari-clusters-plotter 53 | type: doi 54 | value: "10.5281/zenodo.5884658" 55 | license: BSD-3-Clause 56 | repository-code: https://github.com/BiAPoL/napari-clusters-plotter 57 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2022, DFG Cluster of Excellence "Physics of Life" TU Dresden: Robert Haase, Laura Zigutyte, Marcello Zoccoler, Ryan Savill, Johannes Müller and Max Planck Institute of Molecular Physiology Dortmund: Thorsten Wagner 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of napari-clusters-plotter nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE 2 | include README.md 3 | include requirements.txt 4 | 5 | recursive-include src/napari-clusters-plotter/sample_data * 6 | 7 | recursive-exclude * __pycache__ 8 | recursive-exclude * *.py[co] 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # napari-clusters-plotter 2 | 3 | [![License](https://img.shields.io/pypi/l/napari-clusters-plotter.svg?color=green)](https://github.com/lazigu/napari-clusters-plotter/raw/master/LICENSE) 4 | [![PyPI](https://img.shields.io/pypi/v/napari-clusters-plotter.svg?color=green)](https://pypi.org/project/napari-clusters-plotter) 5 | [![Python Version](https://img.shields.io/pypi/pyversions/napari-clusters-plotter.svg?color=green)](https://python.org) 6 | [![Anaconda-Server Badge](https://anaconda.org/conda-forge/napari-clusters-plotter/badges/version.svg)](https://anaconda.org/conda-forge/napari-clusters-plotter) 7 | [![tests](https://github.com/BiAPoL/napari-clusters-plotter/actions/workflows/test_and_deploy.yml/badge.svg)](https://github.com/BiAPoL/napari-clusters-plotter/actions/workflows/test_and_deploy.yml) 8 | [![codecov](https://codecov.io/gh/BiAPoL/napari-clusters-plotter/branch/main/graph/badge.svg?token=R6W2KO1NJ8)](https://codecov.io/gh/BiAPoL/napari-clusters-plotter) 9 | [![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://github.com/pre-commit/pre-commit) 10 | [![Anaconda-Server Badge](https://anaconda.org/conda-forge/napari-clusters-plotter/badges/downloads.svg)](https://anaconda.org/conda-forge/napari-clusters-plotter) 11 | [![napari hub](https://img.shields.io/endpoint?url=https://api.napari-hub.org/shields/napari-clusters-plotter)](https://www.napari-hub.org/plugins/napari-clusters-plotter) 12 | [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.7011471.svg)](https://doi.org/10.5281/zenodo.7011471) 13 | 14 | A napari-plugin for clustering objects according to their properties. 15 | 16 | ## [Documentation](https://biapol.github.io/napari-clusters-plotter/) 17 | 18 | The documentation for the napari-clusters-plotter is available under the above link. 19 | 20 | ## License 21 | 22 | Distributed under the terms of the [BSD-3] license, 23 | "napari-clusters-plotter" is free and open source software 24 | 25 | ## Acknowledgements 26 | This project was supported by the Deutsche Forschungsgemeinschaft under Germany’s Excellence Strategy – EXC2068 - Cluster of Excellence "Physics of Life" of TU Dresden. 27 | This project has been made possible in part by grant number [2021-240341 (Napari plugin accelerator grant)](https://chanzuckerberg.com/science/programs-resources/imaging/napari/improving-image-processing/) from the Chan Zuckerberg Initiative DAF, an advised fund of the Silicon Valley Community Foundation. 28 | 29 | ## Issues 30 | 31 | If you encounter any problems, please [file an issue](https://github.com/BiAPoL/napari-clusters-plotter/issues) along 32 | with a detailed description. 33 | 34 | [napari]: https://github.com/napari/napari 35 | [Cookiecutter]: https://github.com/audreyr/cookiecutter 36 | [@napari]: https://github.com/napari 37 | [MIT]: http://opensource.org/licenses/MIT 38 | [BSD-3]: http://opensource.org/licenses/BSD-3-Clause 39 | [GNU GPL v3.0]: http://www.gnu.org/licenses/gpl-3.0.txt 40 | [GNU LGPL v3.0]: http://www.gnu.org/licenses/lgpl-3.0.txt 41 | [Apache Software License 2.0]: http://www.apache.org/licenses/LICENSE-2.0 42 | [Mozilla Public License 2.0]: https://www.mozilla.org/media/MPL/2.0/index.txt 43 | [cookiecutter-napari-plugin]: https://github.com/napari/cookiecutter-napari-plugin 44 | 45 | [napari]: https://github.com/napari/napari 46 | [pytest]: https://docs.pytest.org/en/7.0.x/ 47 | [pip]: https://pypi.org/project/pip/ 48 | [PyPI]: https://pypi.org/ 49 | [conda]: https://docs.conda.io/projects/conda/en/latest/ 50 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | status: 3 | project: 4 | default: 5 | target: auto 6 | threshold: 5% # allow for 5% reduction of coverage without failing 7 | patch: 8 | default: 9 | target: 0% 10 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | # Book settings 2 | # Learn more at https://jupyterbook.org/customize/config.html 3 | # Comprehensive example: https://github.com/executablebooks/jupyter-book/blob/master/docs/_config.yml 4 | 5 | title: napari-clusters-plotter 6 | author: Laura Zigutyte, Ryan Savill, Marcelo Zoccoler, Johannes Soltwedel, Thorsten Wagner, Robert Haase 7 | logo: logo.png 8 | 9 | # Force re-execution of notebooks on each build. 10 | # See https://jupyterbook.org/content/execute.html 11 | execute: 12 | execute_notebooks: off 13 | 14 | # Define the name of the latex output file for PDF builds 15 | latex: 16 | latex_documents: 17 | targetname: book.tex 18 | 19 | # Add a bibtex file so that we can create citations 20 | #bibtex_bibfiles: 21 | # - references.bib 22 | 23 | # Information about where the book exists on the web 24 | repository: 25 | url: https://github.com/BiAPoL/napari-clusters-plotter # Online location of your book 26 | path_to_book: docs # Optional path to your book, relative to the repository root 27 | branch: main # Which branch of the repository should be used when creating links (optional) 28 | 29 | # Add GitHub buttons to your book 30 | # See https://jupyterbook.org/customize/config.html#add-a-link-to-your-repository 31 | html: 32 | use_issues_button: true 33 | use_repository_button: true 34 | 35 | 36 | 37 | sphinx: 38 | extra_extensions: 39 | - sphinx.ext.autosummary 40 | - sphinx.ext.autodoc 41 | - sphinx.ext.napoleon # Enable support for NumPy and Google style docstrings 42 | - sphinx.ext.intersphinx 43 | - sphinx_inline_tabs 44 | - sphinx_proof 45 | - sphinx_examples 46 | 47 | config: 48 | add_module_names: True 49 | autosummary_generate: True 50 | -------------------------------------------------------------------------------- /docs/_toc.yml: -------------------------------------------------------------------------------- 1 | # Table of contents 2 | # Learn more at https://jupyterbook.org/customize/toc.html 3 | 4 | format: jb-book 5 | root: intro 6 | parts: 7 | - caption: Usage 8 | chapters: 9 | - file: usage/overview 10 | - file: usage/plotter_widget 11 | - file: usage/dimensionality_reduction_widget 12 | - file: usage/clustering_widget 13 | 14 | - caption: Examples 15 | chapters: 16 | - file: examples/sample_data 17 | - caption: Contributing 18 | chapters: 19 | - file: contributing/new_algorithm 20 | - caption: API 21 | chapters: 22 | - file: api 23 | -------------------------------------------------------------------------------- /docs/api.rst: -------------------------------------------------------------------------------- 1 | `Widgets` 2 | ========= 3 | 4 | .. automodule:: napari_clusters_plotter.PlotterWidget 5 | :members: 6 | 7 | .. automodule:: napari_clusters_plotter.DimensionalityReductionWidget 8 | :members: 9 | 10 | .. automodule:: napari_clusters_plotter.ClusteringWidget 11 | :members: 12 | -------------------------------------------------------------------------------- /docs/clusters-plotter-demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/docs/clusters-plotter-demo.gif -------------------------------------------------------------------------------- /docs/contributing/new_algorithm.md: -------------------------------------------------------------------------------- 1 | # Contributing a new algorithm 2 | 3 | If you want to make a new clustering or dimensionality reduction algorithm available in the napari-clusters-plotter, please follow a few guidelines and specifications. First, fork the repository and create yourself a different branch to work on. AOnce this is set up, you can find all implemented allgorithms under `src/napari_clusters_plotter/algorithms.py`, where you can add your algorithm, too. 4 | 5 | ## New dimensionality reduction algorithm 6 | 7 | If you want to add your algorithm there, please make sure that it adheres to the following syntax: 8 | 9 | ```python 10 | def reduce_my_algorithm( 11 | data: pd.DataFrame, 12 | your_int_algorithm_parameter: int = 2, 13 | your_float_algorithm_parameter: float = 0.1, 14 | scale: bool = True 15 | ) -> FunctionWorker[pd.DataFrame]: 16 | """ 17 | Reduce the data using my algorithm 18 | """ 19 | 20 | @thread_worker(progress=True) 21 | def _reduce_my_algorithm( 22 | data: pd.DataFrame, 23 | your_int_algorithm_parameter: int, 24 | your_float_algorithm_parameter: float, 25 | scale: bool 26 | ) -> FunctionWorker[pd.DataFrame]: 27 | import your_module 28 | from sklearn.preprocessing import StandardScaler 29 | 30 | # Keep this code 31 | non_nan_data = data.dropna() 32 | 33 | if scale: 34 | preprocessed = StandardScaler().fit_transform(non_nan_data.values) 35 | else: 36 | preprocessed = non_nan_data.values 37 | 38 | # << FunctionWorker[pd.Series]: 116 | """ 117 | Cluster the data using Spectral Clustering 118 | """ 119 | 120 | @thread_worker(progress=True) 121 | def _cluster_method( 122 | data: pd.DataFrame, some_parameter: int, scale: bool 123 | ) -> pd.Series: 124 | from module import MyClusteringAlgorithm 125 | 126 | # Remove NaN rows 127 | non_nan_data = data.dropna() 128 | 129 | if scale: 130 | preprocessed = StandardScaler().fit_transform(non_nan_data) 131 | else: 132 | preprocessed = non_nan_data.values 133 | 134 | # Perform Spectral Clustering (+1 to start clusters from 1) 135 | clusterer = MyClusteringAlgorithm(some_parameter=some_parameter) 136 | clusters = clusterer.fit_predict(preprocessed) + 1 137 | 138 | # Add NaN rows back 139 | result = pd.Series(index=data.index, dtype=int) 140 | result.loc[non_nan_data.index] = clusters 141 | 142 | return result 143 | 144 | return _cluster_method(data, n_clusters, scale) 145 | ``` 146 | -------------------------------------------------------------------------------- /docs/examples/imgs/sample_data_bbbc1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/docs/examples/imgs/sample_data_bbbc1.gif -------------------------------------------------------------------------------- /docs/examples/imgs/sample_data_cells3d.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/docs/examples/imgs/sample_data_cells3d.gif -------------------------------------------------------------------------------- /docs/examples/imgs/sample_data_skan_skeleton.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/docs/examples/imgs/sample_data_skan_skeleton.gif -------------------------------------------------------------------------------- /docs/examples/imgs/sample_data_tgmm.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/docs/examples/imgs/sample_data_tgmm.gif -------------------------------------------------------------------------------- /docs/examples/sample_data.md: -------------------------------------------------------------------------------- 1 | # Sample data 2 | 3 | The napari-clusters-plotter comes with a number of sample data files for you to test and play with the functionality of the plugin. Here we list where these sample data have been taken from and how to load them into napari. 4 | 5 | ## Labels: BBBC1-Data 6 | 7 | For demo raw image and segmentations as label images, we used image set BBBC007v1 image set version 1 (Jones et al., Proc. ICCV Workshop on Computer Vision for Biomedical Image Applications, 2005), available from the [Broad Bioimage Benchmark Collection](https://bbbc.broadinstitute.org/BBBC007) [Ljosa et al., Nature Methods, 2012]. Images were cropped with a 340x340 window size and converted to 16-bit format. The segmentations have been created using the voronoi-otsu-algorithm from [napari-segment-things-with-blobs-and-membranes](https://github.com/haesleinhuepf/napari-segment-blobs-and-things-with-membranes). The dataset includes several images and their corresponding segmentations side-by-side in the napari viewer. 8 | 9 | ![BBBC1 dataset overview](./imgs/sample_data_bbbc1.gif) 10 | 11 | The dataset is available in the napari viewer under `File > Open Sample > napari clusters plotter > BBBC 1 dataset & segmentations` 12 | 13 | ## Surface: Cells3d curvatures 14 | 15 | For surface (aka mesh) data, we segmented and converted a piece of the [scikit-image cells3d example dataset](https://scikit-image.org/docs/stable/api/skimage.data.html#skimage.data.cells3d). The data were converted according to [this notebook](https://github.com/haesleinhuepf/napari-process-points-and-surfaces/blob/main/docs/demo.ipynb) from the [napari-process-points-and-surfaces](https://github.com/haesleinhuepf/napari-process-points-and-surfaces) plugin. The dataset includes a raw image of a mitotic cell and its corresponding surface mesh. Mean and Gaussian curvatures have been measured on the surface with the [patch-fitting algorithm](https://campaslab.github.io/napari-stress/05_API/measurements.html#napari_stress.measurements.calculate_patch_fitted_curvature_on_surface) taken from the [napari-stress plugin](https://github.com/campaslab/napari-stress) 16 | 17 | ![Cells3d dataset overview](./imgs/sample_data_cells3d.gif) 18 | 19 | The dataset is available in the napari viewer under `File > Open Sample > napari clusters plotter > Cells3D mitotic nucleus surface curvatures` 20 | 21 | ## Tracks: tgmm-mini labels and tracks 22 | 23 | For tracking data, we provide the tgmm-mini dataset which includes segmented nuclei that are tracked over time and label-matched so that nuclei retain their label over time. It has been derived from [tgmm-mini](https://github.com/mastodon-sc/mastodon-example-data/tree/master/tgmm-mini) using [Fiji](https://fiji.sc/) with the [Mastodon](https://mastodon.readthedocs.io/en/latest/) and the [Mastodon-Deep-Lineage](https://mastodon.readthedocs.io/en/latest/docs/partC/mastodon_deep_lineage.html) plugin. 24 | 25 | The data is licensed under the conditions in [LICENSE](../../src/napari_clusters_plotter/sample_data/tracking_data/LICENSE). 26 | 27 | ![TGMM mini dataset overview](./imgs/sample_data_tgmm.gif) 28 | 29 | The dataset is available in the napari viewer under `File > Open Sample > napari clusters plotter > TGMM mini dataset (tracks and segmentations)` 30 | 31 | ## Shapes: Skan skeleton 32 | 33 | For shapes data, we provide a set of skeleton paths that were determined from a [random dataset](https://scikit-image.org/docs/stable/api/skimage.data.html#skimage.data.binary_blobs) using the [skan library](https://skeleton-analysis.org/stable/) according to [this workflow](https://skeleton-analysis.org/stable/examples/visualizing_3d_skeletons.html). 34 | 35 | ![Skan skeleton](./imgs/sample_data_skan_skeleton.gif) 36 | 37 | The dataset is available in the napari viewer under `File > Open Sample > napari clusters plotter > Skan skeleton dataset(labels and paths)` 38 | -------------------------------------------------------------------------------- /docs/intro.md: -------------------------------------------------------------------------------- 1 | (intro)= 2 | 3 | # napari-clusters-plotter 4 | 5 | Welcome to the documentation pages of the napari-clusters-plotter. The clusters-plotter is designed to provide an easy, interactive interface for state-of-the-art tools for unsupervised machine learning in biological contexts. 6 | 7 | 8 | ![Clusters-plotter demo](clusters-plotter-demo.gif) 9 | 10 | ## Installation 11 | 12 | * Make sure you have Python in your computer, e.g. download [miniforge](https://github.com/conda-forge/miniforge). 13 | 14 | * Create a new environment, for example, like this: 15 | 16 | ``` 17 | mamba create --name clusters-plotter python=3.12 18 | ``` 19 | 20 | If you never used mamba/conda environments before, take a look at [this blog post](https://biapol.github.io/blog/mara_lampert/getting_started_with_mambaforge_and_python/readme.html). 21 | 22 | * **Activate** the new environment with `mamba`: 23 | 24 | ``` 25 | mamba activate clusters-plotter 26 | ``` 27 | 28 | * Install [napari](https://napari.org/stable/), e.g. via `mamba`: 29 | 30 | ``` 31 | mamba install -c conda-forge napari pyqt 32 | ``` 33 | 34 | Afterwards, install `napari-clusters-plotter` via `pip`: 35 | 36 | ``` 37 | pip install napari-clusters-plotter 38 | ``` 39 | 40 | To install latest development version : 41 | 42 | ``` 43 | pip install git+https://github.com/BiAPoL/napari-clusters-plotter.git 44 | ``` 45 | 46 | ## Table of Contents 47 | 48 | Here is an automatically generated Table of Contents: 49 | 50 | ```{tableofcontents} 51 | ``` 52 | 53 | [github]: https://github.com/BiAPoL/napari-clusters-plotter "GitHub source code repository for this project" 54 | [tutorial]: https://docs.readthedocs.io/en/stable/tutorial/index.html "Official Read the Docs Tutorial" 55 | [jb-docs]: https://jupyterbook.org/en/stable/ "Official Jupyter Book documentation" 56 | -------------------------------------------------------------------------------- /docs/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/docs/logo.png -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | sphinx-inline-tabs 2 | sphinx-proof 3 | sphinx-examples 4 | jupyter-book 5 | -------------------------------------------------------------------------------- /docs/usage/clustering_widget.md: -------------------------------------------------------------------------------- 1 | (widget:clustering)= 2 | # Clustering 3 | 4 | [Clustering](https://en.wikipedia.org/wiki/Cluster_analysis) is an unsupervised machine-learning technique to assign or detect groups among a group of objects according to provided features. This clustering can be done irrespective of the dimensionality of the feature space. The napari-clusters-plotter provides the following clustering algorithms: 5 | 6 | - [KMEANS: K-means clustering](https://scikit-learn.org/stable/modules/generated/sklearn.cluster.KMeans.html) 7 | - [HDBSCAN: Hierarchical density-based patial clustering of applications with noise](https://scikit-learn.org/stable/modules/generated/sklearn.cluster.HDBSCAN.html) 8 | - [Gaussian Mixture](https://scikit-learn.org/stable/modules/generated/sklearn.mixture.GaussianMixture.html) 9 | - [Spectral Clustering](https://scikit-learn.org/stable/modules/generated/sklearn.cluster.SpectralClustering.html) 10 | 11 | ## Widget overview 12 | 13 | The functionality of the clustering widget is available to you as follows: 14 | 15 | ![Clustering widget overview](./imgs/clustering_overview1_annotated.png) 16 | 17 | 1. List of features that should be forwarded to the clustering algorithm 18 | 2. Selected algorithm for clustering (see available algorithms above) 19 | 3. Input parameters for selected algorithm (will change upon selecting different algorithm) 20 | 4. `Run` button - executes the algorithm. 21 | 22 | ## Running clustering 23 | 24 | Similar to the [Dimensionality Reduction Widget](widget:dimensionality_reduction), the functionality of the Clustering Widget mirrors the [Plotter Widget](widget:plotter) to a large degree. To select features for clustering, simply select the layer with the features of interest in the napari layer list on the left. The available features are then automatically listed in the list of available features. For simmplicity, we use the `BBBC1 dataset & segmentations` dataset in this demo, too. While the clustering *can* be applied to any set of features, we aere applying it to a pre-computed, low-dimensional representation of the data. In this example, a UMAP reduction was used. 25 | 26 | To run the algorithm, simply select the layer and the respective features and hit the `Run` button: 27 | 28 | ![Selecting features for clustering](./imgs/clustering_overview2.png) 29 | 30 | To visualize the result of the clustering, simply re-open the Plotter Widget. The results of the clustering algorithm are now available as a new categorical feature (marked in orange) in the `Hue` column: 31 | 32 | ![Visualizing clustering results](./imgs/clustering_overview3.png) 33 | 34 | ```{note} 35 | You *can* edit the result of the clustering algorithm in the Plotter Widget. To do so, select the result of the clustering in the `Hue` column and start drawing. This will **overwrite your previous manual selection** and replace it with the new, edited clustering result 36 | ``` 37 | 38 | ## Cross-layer clustering 39 | 40 | Finally, similar to the Plotter & Dimensionality Reduction Widget, the Clustering Widget also supports applying the available algorithms across several layers. To make use of this feature, simply select multiple layers. The feature list will then automatically be populated with features that are common to all selected layers. The limitations here are the same as for the [Plotter Widget](widget:plotter) and the [Dimensionality reduction widget](widget:dimensionality_reduction). 41 | 42 | ![Reslts of cross-layer clustering](./imgs/clustering_visualization1.png) 43 | -------------------------------------------------------------------------------- /docs/usage/dimensionality_reduction_widget.md: -------------------------------------------------------------------------------- 1 | (widget:dimensionality_reduction)= 2 | # Dimensionality reduction 3 | 4 | [Dimensionality reduction](https://en.wikipedia.org/wiki/Dimensionality_reduction) is an unsupervised machine-learning technique to project high-dimensional feature spaces into lower dimensions, where we can introspect them easier. The napari-clusters-plotter currently supports the following algorithms for dimensionality reduction: 5 | 6 | - [UMAP: Uniform manifold approximation and projection](https://umap-learn.readthedocs.io/en/latest/) 7 | - [t-SNE: t-stochastic neighborhood embedding](https://scikit-learn.org/stable/modules/generated/sklearn.manifold.TSNE.html) 8 | - [PCA: Principal component analysis](https://scikit-learn.org/stable/modules/generated/sklearn.decomposition.PCA.html) 9 | 10 | The `Clustering Widget` is available in the napari viewer like this: 11 | 12 | - `Plugins > napari clusters plotter > Dimensionality Reduction` 13 | 14 | ## Widget overview 15 | 16 | The functionality of the dimensionality reduction widget is available to you as follows: 17 | 18 | ![Dimensionality reduction widget overview](./imgs/dimensionality_reduction_overview1_annotated.png) 19 | 20 | 1. List of features that should be forwarded to the dimensionality reduction algorithm 21 | 2. Selected algorithm for reduction (see available algorithms above) 22 | 3. Input parameters for selected algorithm (will change upon selecting different algorithm) 23 | 4. `Run` button - executes the algorithm. 24 | 25 | ## Running dimensionality reduction 26 | 27 | The functionality of the dimensionality reduction widget mirrors the [Plotter Widget](widget:plotter) to a large degree. To select features for dimensionality reduction, simply select the layer with the features of interest in the napari layer list on the left. The available features are then automatically listed in the list of available features. 28 | 29 | Finally, to run the selected algorithm (by default PCA), select the features you want to forward to the algorithm as shown below and hit the `Run` button. 30 | 31 | ![Selecting features for dimensionality reduction](./imgs/dimensionality_reduction_overview2.png) 32 | 33 | To visualize the result of the dimensionality reduction, simply re-open the Plotter Widget. The results of the dimensionality reduction algorithm have now been appended to the list of features for visualization: 34 | 35 | ![Visualize dimensionality reduction result](./imgs/dimensionality_reduction_visualize1.png) 36 | 37 | ## Cross-layer dimensionality reduction 38 | 39 | Similar to the plotter widget, the dimensionality reduction widget also supports applying the available algorithms across several layers. To make use of this feature, simply select multiple layers. The feature list will then automatically be populated with features that are common to all selected layers. The limitations here are the same as for the Plotter Widget: 40 | 41 | - Only features common to all selected layers are eligible for cross-layer dimensionality reduction 42 | - Selecting layers of different kinds yields an error message 43 | 44 | Depending on the chosen algorithm, the results of the dimensionality reduction algorithm are appended to the features table with an acronym that indicates the used algorithm (i.e., `UMAP0` and `UMAP1` for UMAP, etc). Selecting these features shows the result of the reduction algorithm: 45 | 46 | ![Dimensionality reduction result](./imgs/dimensionality_reduction_visualize2.png) 47 | -------------------------------------------------------------------------------- /docs/usage/imgs/clustering_overview1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/docs/usage/imgs/clustering_overview1.png -------------------------------------------------------------------------------- /docs/usage/imgs/clustering_overview1_annotated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/docs/usage/imgs/clustering_overview1_annotated.png -------------------------------------------------------------------------------- /docs/usage/imgs/clustering_overview2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/docs/usage/imgs/clustering_overview2.png -------------------------------------------------------------------------------- /docs/usage/imgs/clustering_overview3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/docs/usage/imgs/clustering_overview3.png -------------------------------------------------------------------------------- /docs/usage/imgs/clustering_visualization1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/docs/usage/imgs/clustering_visualization1.png -------------------------------------------------------------------------------- /docs/usage/imgs/dimensionality_reduction_overview1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/docs/usage/imgs/dimensionality_reduction_overview1.png -------------------------------------------------------------------------------- /docs/usage/imgs/dimensionality_reduction_overview1_annotated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/docs/usage/imgs/dimensionality_reduction_overview1_annotated.png -------------------------------------------------------------------------------- /docs/usage/imgs/dimensionality_reduction_overview2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/docs/usage/imgs/dimensionality_reduction_overview2.png -------------------------------------------------------------------------------- /docs/usage/imgs/dimensionality_reduction_visualize1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/docs/usage/imgs/dimensionality_reduction_visualize1.png -------------------------------------------------------------------------------- /docs/usage/imgs/dimensionality_reduction_visualize2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/docs/usage/imgs/dimensionality_reduction_visualize2.png -------------------------------------------------------------------------------- /docs/usage/imgs/feature_immediacy3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/docs/usage/imgs/feature_immediacy3.gif -------------------------------------------------------------------------------- /docs/usage/imgs/features_immediacy1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/docs/usage/imgs/features_immediacy1.gif -------------------------------------------------------------------------------- /docs/usage/imgs/features_immediacy2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/docs/usage/imgs/features_immediacy2.gif -------------------------------------------------------------------------------- /docs/usage/imgs/layer_demo_tracks.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/docs/usage/imgs/layer_demo_tracks.gif -------------------------------------------------------------------------------- /docs/usage/imgs/plotter_overview1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/docs/usage/imgs/plotter_overview1.png -------------------------------------------------------------------------------- /docs/usage/imgs/plotter_overview1_annotated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/docs/usage/imgs/plotter_overview1_annotated.png -------------------------------------------------------------------------------- /docs/usage/imgs/plotter_overview2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/docs/usage/imgs/plotter_overview2.png -------------------------------------------------------------------------------- /docs/usage/imgs/plotter_overview3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/docs/usage/imgs/plotter_overview3.png -------------------------------------------------------------------------------- /docs/usage/imgs/plotter_overview3_annotated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/docs/usage/imgs/plotter_overview3_annotated.png -------------------------------------------------------------------------------- /docs/usage/imgs/selecting_features1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/docs/usage/imgs/selecting_features1.gif -------------------------------------------------------------------------------- /docs/usage/imgs/selecting_layers1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/docs/usage/imgs/selecting_layers1.png -------------------------------------------------------------------------------- /docs/usage/imgs/selecting_layers1_annotated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/docs/usage/imgs/selecting_layers1_annotated.png -------------------------------------------------------------------------------- /docs/usage/imgs/selecting_layers2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/docs/usage/imgs/selecting_layers2.png -------------------------------------------------------------------------------- /docs/usage/imgs/selecting_layers3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/docs/usage/imgs/selecting_layers3.gif -------------------------------------------------------------------------------- /docs/usage/imgs/selecting_layers4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/docs/usage/imgs/selecting_layers4.png -------------------------------------------------------------------------------- /docs/usage/imgs/selecting_layers4_annotated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/docs/usage/imgs/selecting_layers4_annotated.png -------------------------------------------------------------------------------- /docs/usage/imgs/selecting_layers5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/docs/usage/imgs/selecting_layers5.png -------------------------------------------------------------------------------- /docs/usage/overview.md: -------------------------------------------------------------------------------- 1 | # Features 2 | 3 | The napari-clusters-plotter provides a number of features, which shall be briefly described here. The three key components of the plugin are the [Plotter Widget](widget:plotter), the [dimensionality reduction widget](widget:dimensionality_reduction) and the [clustering widget](widget:clustering). It is immportant to understand, that all of these plugins operate almost exclusively on the `features` that are attached to supported napari layers. 4 | 5 | ## Supported layers 6 | 7 | The clusters plotter currently supports the following layers: 8 | 9 | - Labels layers 10 | - Points layers 11 | - Surface layers 12 | - Vectors layers 13 | - Shapes layers 14 | - Tracks layers 15 | 16 | 17 | It is important to understand that while the these layer types are all supported, the cluster plotter functionality depends entirely on the attached features, as written above. For a napari layer, the features are attached to a layer as an attribute (`layer.feature`). By default, it is simply a [pandas dataframe](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.html) where each row refers to a single item in the respective layer. For the different layers, these correspond to: 18 | 19 | - Labels: One row for one object with the same label 20 | - Points: One row for each point 21 | - Vectors: One row for each vector 22 | - Shapes: One row for each shape 23 | - Surface: One row for each vertex of the surface (face or edge features are not supported) 24 | - Tracks: One row for every vertex in a tracking graph (coming soon) 25 | 26 | ## Selection persistence 27 | 28 | When you draw a manual selection of data points, the selection is stored so that you can later return to it. As all clusters-plotter functionality also works across multiple layers, you can make selections on individual layers and later pool them together: 29 | 30 | ![Persistence of selected features](./imgs/features_immediacy2.gif) 31 | 32 | In combination with the dimensionality reduction and clustering algorithms, this gives you an easy to way to track how different algorithm parameters change outcomes and track these changes with respect to your data. Of course, cluster selection (manual or by algorithm) persist during such changes . 33 | 34 | ![Cluster persistence during algorithm change](./imgs/feature_immediacy3.gif) 35 | 36 | ## Feature maps 37 | 38 | The drawing of the plotted data is triggered whenever the data in the `layer.features` attribute has been updated. This gives trise to a few cool use cases of the clusters plotter. One of them is the simple generation of feature maps directly on top of an existing layer: 39 | 40 | ![Feature map generation](./imgs/features_immediacy1.gif) 41 | -------------------------------------------------------------------------------- /docs/usage/plotter_widget.md: -------------------------------------------------------------------------------- 1 | (widget:plotter)= 2 | # Plotting 3 | 4 | The plotter widget is the heart of the napari-clusters-plotter. To open it, open a napari viewer and find the Plotter Widget either under 5 | 6 | - `Layers > Visualize > Plot & select features (napari-clusters-plotter)` 7 | - `Plugins > napari-clusters-plotter > Plot & select features (napari-clusters-plotter)` 8 | 9 | ## Widget overview 10 | 11 | The core functionality of the plugin is available to you directly upon opening it: 12 | 13 | ![Plugin functionality overview](./imgs/plotter_overview1_annotated.png) 14 | 15 | 1. Standard [matplotlib toolbar](https://matplotlib.org/3.2.2/users/navigation_toolbar.html): Reset, Undo/Redo, Pan, Zoom, other plot properties & export 16 | 2. Tools to select points on the canvas: 17 | - Lasso selector 18 | - Ellipse selector (drag and drop, confirm with rightclick) 19 | - Rectangle selector (drag & drop, confirm with right-click) 20 | 3. Selected cluster index: Depending on which color/number is selected here, regions in the plot will be counted as members of this cluster group and highlighted accordingly 21 | 4. Show/Hide: Show or hide the selected points or histogram bins on the canvas. 22 | 5. Canvas: Features will be visualized here 23 | 6. What feature to plot on the x-axis and y-axis, respectively. The `Hue` dropdown controls the coloring of the data on the canvas, categorical features are highlighted in orange. 24 | 7. Reset button: Resets all drawn clusters 25 | 26 | ![Advanced settings](./imgs/plotter_overview3_annotated.png) 27 | 28 | Under the `Advanced Options` tab, you have access to some more customization options for the visualization: 29 | 30 | 8. Change the colormap for the chosen overlay color. If a layer is colored by a non-categorical feature, this determines the colormap for the depiction. Only enabled if a non-categorical feature is selected in the `Hue` dropdown. 31 | 9. Apply a log-scale to the chosen feature 32 | 10. Switch plot type between `SCATTER` and `HISTOGRAM2D` 33 | 11. Colorap for 2D histogram (only enabled if `HISTOGRAM2D` is selected in 10.) 34 | 12. Change the size of the bins (only enabled if `HISTOGRAM2D` is selected in 10.) 35 | 36 | ## Visualizing layer features 37 | 38 | In order to visualize features from a dataset, you can load some of the sample data which accompanies the napari-clusters-plotter. You find the sample datasets under `File > Open Sample > napari-clusters-plotter > ...`. In this tutorial, we will use the `BBBC1 dataset & segmentations` dataset, (Jones et al., Proc. ICCV Workshop on Computer Vision for Biomedical Image Applications, 2005), available from the Broad Bioimage Benchmark Collection [Ljosa et al., Nature Methods, 2012] ([Link to data source](https://bbbc.broadinstitute.org/BBBC007)) 39 | 40 | The `features` of a [Labels layer](https://napari.org/stable/howtos/layers/labels.html) can be loaded into the Plotter Widget **simply by selecting it in the layer list** on the left: 41 | 42 | ![Selecting layer features](./imgs/selecting_layers1_annotated.png) 43 | 44 | The dropdown menus for `x-axis`, `y-axis` and `Hue` are then automatically populated with all available features. The features will be drawn as soon as you make the first change to the selected features. By default, the `MANUAL_CLUSTER_ID` is selected as the `Hue` value. This features stores all the drawn/selected items. 45 | 46 | ![Selecting layer features: defaults](./imgs/selecting_layers2.png) 47 | 48 | For Label layers, we can observe that the initial random label colors are retained by default (i.e., the selection overlay is invisible by default): 49 | 50 | ![Invisible overlay for labels](./imgs/selecting_layers5.png) 51 | 52 | When we start drawing or untoggle the visibility button, we see the respective items showing up in the color we selected as cluster index (see above). If we want to reset the selection, we can press the `Reset` button. For `Labels` data, the color will revert back to the default (random colors) as soon as the layer is unselected. To retain the cluster selection, simply keep the layer selected in the napari layer list. 53 | 54 | ![Drawing and reseting colors](./imgs/selecting_layers3.gif) 55 | 56 | ## Cross-layer visualization 57 | 58 | A key feature of the napari-clusters-plotter is that you can select *multiple layers of the same type* and explore their features with the Plotter Widget. To do so, simply select multiple layers in the layer list of napari. Again, the aforementioned sample dataset (`BBBC1 dataset & segmentations`) is suitable to give this a try. 59 | 60 | ![Cross-layer visualization](./imgs/selecting_layers4_annotated.png) 61 | 62 | There are two things to keep in mind here: 63 | 64 | - The features available for visualization is the *intersection of all features* that are common to all selected layers. If a feature `feature_x` is not present in all selected layers, it will not be available for visualization. 65 | - Only features from the same layer type can be compared. If mixed layer types (e.g., `Labels` and `Points`) are selected, the drawing will fail. 66 | 67 | ## Visualizing non-categorical features 68 | 69 | So far, the `Hue` selector was always set to `MANUAL_CLUSTER_ID`, which is by design a *categorical* column. However, the napari-clusters-plotter supports visualizing any feature as the `Hue` parameter. If this is done, the points are colored according to the selected feature and each point's color will be project on the respective object in the napari viewport. In essence, this creates feature maps for each feature you select: 70 | 71 | ![Selecting features as hue](./imgs/selecting_features1.gif) 72 | -------------------------------------------------------------------------------- /notebooks/demo_biological_data.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 3, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import glob\n", 10 | "import pandas as pd\n", 11 | "from pathlib import Path\n", 12 | "import numpy as np\n", 13 | "from skimage import io, measure\n", 14 | "\n", 15 | "import napari\n", 16 | "import napari_clusters_plotter as ncp\n", 17 | "import napari_segment_blobs_and_things_with_membranes as nsbatwm" 18 | ] 19 | }, 20 | { 21 | "cell_type": "code", 22 | "execution_count": 2, 23 | "metadata": {}, 24 | "outputs": [ 25 | { 26 | "name": "stdout", 27 | "output_type": "stream", 28 | "text": [ 29 | "Assistant skips harvesting pyclesperanto as it's not installed.\n" 30 | ] 31 | } 32 | ], 33 | "source": [ 34 | "viewer = napari.Viewer()" 35 | ] 36 | }, 37 | { 38 | "cell_type": "code", 39 | "execution_count": 5, 40 | "metadata": {}, 41 | "outputs": [], 42 | "source": [ 43 | "sample_dataset = ncp.bbbc_1_dataset()\n", 44 | "for sample in sample_dataset:\n", 45 | " layer = napari.layers.Layer.create(sample[0], sample[1], sample[2])\n", 46 | " viewer.add_layer(layer)" 47 | ] 48 | }, 49 | { 50 | "cell_type": "code", 51 | "execution_count": 6, 52 | "metadata": {}, 53 | "outputs": [ 54 | { 55 | "name": "stderr", 56 | "output_type": "stream", 57 | "text": [ 58 | "c:\\Users\\johamuel\\AppData\\Local\\mambaforge\\envs\\clusters-plotter-dev\\lib\\site-packages\\napari_matplotlib\\base.py:46: FutureWarning: The `as_dict` kwarg has been deprecated since Napari 0.5.0 and will be removed in future version. You can use `get_theme(...).to_rgb_dict()`\n", 59 | " get_theme(napari_viewer.theme, as_dict=False)\n", 60 | "c:\\Users\\johamuel\\AppData\\Local\\mambaforge\\envs\\clusters-plotter-dev\\lib\\site-packages\\napari_matplotlib\\base.py:101: FutureWarning: The `as_dict` kwarg has been deprecated since Napari 0.5.0 and will be removed in future version. You can use `get_theme(...).to_rgb_dict()`\n", 61 | " theme = napari.utils.theme.get_theme(self.viewer.theme, as_dict=False)\n" 62 | ] 63 | }, 64 | { 65 | "data": { 66 | "text/plain": [ 67 | "" 68 | ] 69 | }, 70 | "execution_count": 6, 71 | "metadata": {}, 72 | "output_type": "execute_result" 73 | } 74 | ], 75 | "source": [ 76 | "plotter_widget = ncp.PlotterWidget(viewer)\n", 77 | "viewer.window.add_dock_widget(plotter_widget, area='right')" 78 | ] 79 | }, 80 | { 81 | "cell_type": "code", 82 | "execution_count": null, 83 | "metadata": {}, 84 | "outputs": [], 85 | "source": [] 86 | } 87 | ], 88 | "metadata": { 89 | "kernelspec": { 90 | "display_name": "clusters-plotter", 91 | "language": "python", 92 | "name": "python3" 93 | }, 94 | "language_info": { 95 | "codemirror_mode": { 96 | "name": "ipython", 97 | "version": 3 98 | }, 99 | "file_extension": ".py", 100 | "mimetype": "text/x-python", 101 | "name": "python", 102 | "nbconvert_exporter": "python", 103 | "pygments_lexer": "ipython3", 104 | "version": "3.9.19" 105 | } 106 | }, 107 | "nbformat": 4, 108 | "nbformat_minor": 2 109 | } 110 | -------------------------------------------------------------------------------- /notebooks/demo_new_plotter.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import napari\n", 10 | "from napari_clusters_plotter._new_plotter_widget import PlotterWidget\n", 11 | "\n", 12 | "from skimage import morphology, measure, data\n", 13 | "import numpy as np\n", 14 | "import pandas as pd" 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": 2, 20 | "metadata": {}, 21 | "outputs": [ 22 | { 23 | "name": "stderr", 24 | "output_type": "stream", 25 | "text": [ 26 | "WARNING: QWindowsWindow::setGeometry: Unable to set geometry 3440x1377+640+280 (frame: 3456x1416+632+249) on QWidgetWindow/\"_QtMainWindowClassWindow\" on \"\\\\.\\DISPLAY1\". Resulting geometry: 1924x1061+640+280 (frame: 1940x1100+632+249) margins: 8, 31, 8, 8 minimum size: 385x501 MINMAXINFO(maxSize=POINT(x=0, y=0), maxpos=POINT(x=0, y=0), maxtrack=POINT(x=0, y=0), mintrack=POINT(x=401, y=540)))\n" 27 | ] 28 | } 29 | ], 30 | "source": [ 31 | "viewer = napari.Viewer()" 32 | ] 33 | }, 34 | { 35 | "cell_type": "markdown", 36 | "metadata": {}, 37 | "source": [ 38 | "## Points demo" 39 | ] 40 | }, 41 | { 42 | "cell_type": "code", 43 | "execution_count": 3, 44 | "metadata": {}, 45 | "outputs": [ 46 | { 47 | "data": { 48 | "text/plain": [ 49 | "" 50 | ] 51 | }, 52 | "execution_count": 3, 53 | "metadata": {}, 54 | "output_type": "execute_result" 55 | } 56 | ], 57 | "source": [ 58 | "viewer.layers.clear()\n", 59 | "\n", 60 | "n_samples = 100\n", 61 | "loc = 5\n", 62 | "n_timeframes = 5\n", 63 | "frame = np.arange(n_timeframes).repeat(n_samples//n_timeframes)\n", 64 | "# make some random points with random features\n", 65 | "points = np.random.random((n_samples, 4))\n", 66 | "points2 = np.random.random((n_samples-1, 4))\n", 67 | "\n", 68 | "points[:, 0] = frame\n", 69 | "points2[:, 0] = frame[:-1]\n", 70 | "\n", 71 | "features = pd.DataFrame({\n", 72 | " 'frame': frame,\n", 73 | " 'feature1': np.random.normal(size=n_samples, loc=loc),\n", 74 | " 'feature2': np.random.normal(size=n_samples, loc=loc),\n", 75 | " 'feature3': np.random.normal(size=n_samples, loc=loc),\n", 76 | " 'feature4': np.random.normal(size=n_samples, loc=loc),})\n", 77 | "\n", 78 | "features2 = pd.DataFrame({\n", 79 | " 'frame': frame[:-1],\n", 80 | " 'feature2': np.random.normal(size=n_samples-1, loc=-loc),\n", 81 | " 'feature3': np.random.normal(size=n_samples-1, loc=-loc),\n", 82 | " 'feature4': np.random.normal(size=n_samples-1, loc=-loc),})\n", 83 | "\n", 84 | "layer = napari.layers.Points(points, features=features, size=0.1, blending='translucent_no_depth')\n", 85 | "layer2 = napari.layers.Points(points2, features=features2, size=0.1, translate=(0, 0, 2), blending='translucent_no_depth')\n", 86 | "viewer.layers.clear()\n", 87 | "viewer.add_layer(layer)\n", 88 | "viewer.add_layer(layer2)\n" 89 | ] 90 | }, 91 | { 92 | "cell_type": "code", 93 | "execution_count": 4, 94 | "metadata": {}, 95 | "outputs": [ 96 | { 97 | "name": "stderr", 98 | "output_type": "stream", 99 | "text": [ 100 | "c:\\Users\\johamuel\\AppData\\Local\\miniforge3\\envs\\clusters-plotter\\Lib\\site-packages\\biaplotter\\colormap.py:34: UserWarning: Categorical colormap detected. Setting categorical=True. If the colormap is continuous, set categorical=False explicitly.\n", 101 | " warnings.warn(\n" 102 | ] 103 | }, 104 | { 105 | "data": { 106 | "text/plain": [ 107 | "" 108 | ] 109 | }, 110 | "execution_count": 4, 111 | "metadata": {}, 112 | "output_type": "execute_result" 113 | } 114 | ], 115 | "source": [ 116 | "plotter_widget = PlotterWidget(viewer)\n", 117 | "viewer.window.add_dock_widget(plotter_widget, area='right')" 118 | ] 119 | }, 120 | { 121 | "cell_type": "markdown", 122 | "metadata": {}, 123 | "source": [ 124 | "## Surface demo" 125 | ] 126 | }, 127 | { 128 | "cell_type": "code", 129 | "execution_count": 5, 130 | "metadata": {}, 131 | "outputs": [], 132 | "source": [ 133 | "faces = np.random.randint(0, 100, (100, 3))\n", 134 | "\n", 135 | "surface_layer = viewer.add_surface((points, faces), name='surface')\n", 136 | "surface_layer.features = features" 137 | ] 138 | }, 139 | { 140 | "cell_type": "markdown", 141 | "metadata": {}, 142 | "source": [ 143 | "## Labels demo" 144 | ] 145 | }, 146 | { 147 | "cell_type": "code", 148 | "execution_count": 6, 149 | "metadata": {}, 150 | "outputs": [ 151 | { 152 | "name": "stderr", 153 | "output_type": "stream", 154 | "text": [ 155 | "c:\\Users\\johan\\mambaforge\\envs\\clusters-plotter\\lib\\site-packages\\napari\\utils\\colormaps\\colormap.py:435: UserWarning: color_dict did not provide a default color. Missing keys will be transparent. To provide a default color, use the key `None`, or provide a defaultdict instance.\n", 156 | " warn(\n", 157 | "c:\\Users\\johan\\mambaforge\\envs\\clusters-plotter\\lib\\site-packages\\napari\\utils\\colormaps\\colormap.py:435: UserWarning: color_dict did not provide a default color. Missing keys will be transparent. To provide a default color, use the key `None`, or provide a defaultdict instance.\n", 158 | " warn(\n" 159 | ] 160 | }, 161 | { 162 | "data": { 163 | "text/plain": [ 164 | "" 165 | ] 166 | }, 167 | "execution_count": 6, 168 | "metadata": {}, 169 | "output_type": "execute_result" 170 | } 171 | ], 172 | "source": [ 173 | "binary_image = data.binary_blobs(length=128, n_dim=3, volume_fraction=0.1)\n", 174 | "label_image = measure.label(binary_image)\n", 175 | "features = pd.DataFrame({\n", 176 | " 'feature1': np.random.random(label_image.max() + 1),\n", 177 | " 'feature2': np.random.random(label_image.max() + 1),\n", 178 | " 'feature3': np.random.random(label_image.max() + 1),\n", 179 | "})\n", 180 | "\n", 181 | "viewer.add_labels(label_image, name='labels', features=features)" 182 | ] 183 | }, 184 | { 185 | "cell_type": "markdown", 186 | "metadata": {}, 187 | "source": [ 188 | "## Vectors demo" 189 | ] 190 | }, 191 | { 192 | "cell_type": "code", 193 | "execution_count": 10, 194 | "metadata": {}, 195 | "outputs": [ 196 | { 197 | "data": { 198 | "text/plain": [ 199 | "" 200 | ] 201 | }, 202 | "execution_count": 10, 203 | "metadata": {}, 204 | "output_type": "execute_result" 205 | } 206 | ], 207 | "source": [ 208 | "points_direction = np.random.normal(size=points.shape) * 100\n", 209 | "vectors = np.stack([points*100, points_direction], axis=1)\n", 210 | "\n", 211 | "viewer.add_vectors(vectors, name='vectors', features=features, vector_style='arrow')" 212 | ] 213 | }, 214 | { 215 | "cell_type": "code", 216 | "execution_count": null, 217 | "metadata": {}, 218 | "outputs": [], 219 | "source": [] 220 | } 221 | ], 222 | "metadata": { 223 | "kernelspec": { 224 | "display_name": "clusters-plotter", 225 | "language": "python", 226 | "name": "python3" 227 | }, 228 | "language_info": { 229 | "codemirror_mode": { 230 | "name": "ipython", 231 | "version": 3 232 | }, 233 | "file_extension": ".py", 234 | "mimetype": "text/x-python", 235 | "name": "python", 236 | "nbconvert_exporter": "python", 237 | "pygments_lexer": "ipython3", 238 | "version": "3.12.9" 239 | } 240 | }, 241 | "nbformat": 4, 242 | "nbformat_minor": 2 243 | } 244 | -------------------------------------------------------------------------------- /notebooks/demo_shapes_clustering.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import glob\n", 10 | "import pandas as pd\n", 11 | "from pathlib import Path\n", 12 | "import numpy as np\n", 13 | "from skimage import io, measure\n", 14 | "\n", 15 | "import napari\n", 16 | "import napari_clusters_plotter as ncp\n", 17 | "import napari_segment_blobs_and_things_with_membranes as nsbatwm" 18 | ] 19 | }, 20 | { 21 | "cell_type": "code", 22 | "execution_count": 2, 23 | "metadata": {}, 24 | "outputs": [ 25 | { 26 | "name": "stderr", 27 | "output_type": "stream", 28 | "text": [ 29 | "napari.manifest -> 'napari-vedo-bridge' could not be imported: The name field in the manifest ('napari-clusters-plotter') must match the package name ('napari-vedo-bridge')\n" 30 | ] 31 | }, 32 | { 33 | "name": "stdout", 34 | "output_type": "stream", 35 | "text": [ 36 | "Assistant skips harvesting pyclesperanto as it's not installed.\n" 37 | ] 38 | } 39 | ], 40 | "source": [ 41 | "viewer = napari.Viewer()" 42 | ] 43 | }, 44 | { 45 | "cell_type": "code", 46 | "execution_count": 3, 47 | "metadata": {}, 48 | "outputs": [], 49 | "source": [ 50 | "# random centers\n", 51 | "box_centers = np.random.random((20, 2)) * 1000\n", 52 | "box_widths = np.random.random((20)) * 100\n", 53 | "box_heights = np.random.random((20)) * 100\n", 54 | "features = pd.DataFrame({'box_widths': box_widths, 'box_heights': box_heights})\n", 55 | "features['area'] = features['box_widths'] * features['box_heights']\n", 56 | "\n", 57 | "boxes = []\n", 58 | "\n", 59 | "for i in range(20):\n", 60 | " corners = np.array([[box_centers[i, 0] - box_widths[i] / 2, box_centers[i, 1] - box_heights[i] / 2],\n", 61 | " [box_centers[i, 0] + box_widths[i] / 2, box_centers[i, 1] - box_heights[i] / 2],\n", 62 | " [box_centers[i, 0] + box_widths[i] / 2, box_centers[i, 1] + box_heights[i] / 2],\n", 63 | " [box_centers[i, 0] - box_widths[i] / 2, box_centers[i, 1] + box_heights[i] / 2]])\n", 64 | " boxes.append(corners)" 65 | ] 66 | }, 67 | { 68 | "cell_type": "code", 69 | "execution_count": 4, 70 | "metadata": {}, 71 | "outputs": [ 72 | { 73 | "data": { 74 | "text/plain": [ 75 | "" 76 | ] 77 | }, 78 | "execution_count": 4, 79 | "metadata": {}, 80 | "output_type": "execute_result" 81 | } 82 | ], 83 | "source": [ 84 | "viewer.layers.clear()\n", 85 | "viewer.add_shapes(boxes, shape_type='polygon', edge_color='blue', face_color='area', opacity=0.6, features=features)" 86 | ] 87 | }, 88 | { 89 | "cell_type": "code", 90 | "execution_count": 5, 91 | "metadata": {}, 92 | "outputs": [ 93 | { 94 | "data": { 95 | "text/plain": [ 96 | "" 97 | ] 98 | }, 99 | "execution_count": 5, 100 | "metadata": {}, 101 | "output_type": "execute_result" 102 | } 103 | ], 104 | "source": [ 105 | "plotter_widget = ncp.PlotterWidget(viewer)\n", 106 | "viewer.window.add_dock_widget(plotter_widget, area='right')" 107 | ] 108 | }, 109 | { 110 | "cell_type": "code", 111 | "execution_count": null, 112 | "metadata": {}, 113 | "outputs": [], 114 | "source": [] 115 | } 116 | ], 117 | "metadata": { 118 | "kernelspec": { 119 | "display_name": "clusters-plotter", 120 | "language": "python", 121 | "name": "python3" 122 | }, 123 | "language_info": { 124 | "codemirror_mode": { 125 | "name": "ipython", 126 | "version": 3 127 | }, 128 | "file_extension": ".py", 129 | "mimetype": "text/x-python", 130 | "name": "python", 131 | "nbconvert_exporter": "python", 132 | "pygments_lexer": "ipython3", 133 | "version": "3.9.19" 134 | } 135 | }, 136 | "nbformat": 4, 137 | "nbformat_minor": 2 138 | } 139 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "napari-clusters-plotter" 3 | dynamic = ["version"] 4 | description = "A plugin to use with napari for clustering objects according to their properties" 5 | readme = "README.md" 6 | license = {file = "LICENSE"} 7 | authors = [ 8 | {name = "Laura Zigutyte"}, 9 | {name = "Ryan Savill"}, 10 | {name = "Johannes Soltwedel", email = "johannes_richard.soltwedel@tu-dresden.de"}, 11 | {name = "Marcelo Zoccoler"}, 12 | {name = "Thorsten Wagner"}, 13 | {name = "Robert Haase"} 14 | ] 15 | classifiers = [ 16 | "Development Status :: 2 - Pre-Alpha", 17 | "Framework :: napari", 18 | "Intended Audience :: Developers", 19 | "License :: OSI Approved :: BSD License", 20 | "Operating System :: OS Independent", 21 | "Programming Language :: Python", 22 | "Programming Language :: Python :: 3", 23 | "Programming Language :: Python :: 3 :: Only", 24 | "Programming Language :: Python :: 3.8", 25 | "Programming Language :: Python :: 3.9", 26 | "Programming Language :: Python :: 3.10", 27 | "Topic :: Scientific/Engineering :: Image Processing", 28 | ] 29 | requires-python = ">=3.9" 30 | dependencies = [ 31 | "numpy", 32 | "magicgui", 33 | "qtpy", 34 | "napari", 35 | "npe2", 36 | "scikit-learn", 37 | "pandas", 38 | "umap-learn", 39 | "scikit-image", 40 | "scipy", 41 | "biaplotter>=0.3.1", 42 | "imagecodecs" 43 | ] 44 | 45 | 46 | [project.optional-dependencies] 47 | testing = [ 48 | "tox", 49 | "pytest", # https://docs.pytest.org/en/latest/contents.html 50 | "pytest-cov", # https://pytest-cov.readthedocs.io/en/latest/ 51 | "pytest-qt", # https://pytest-qt.readthedocs.io/en/latest/ 52 | "napari", 53 | "pyqt5", 54 | ] 55 | 56 | [project.entry-points."napari.manifest"] 57 | "napari-clusters-plotter" = "napari_clusters_plotter:napari.yaml" 58 | 59 | [project.urls] 60 | "Bug Tracker" = "https://github.com/BiAPoL/napari-clusters-plotter/issues" 61 | "Documentation" = "https://github.com/BiAPoL/napari-clusters-plotter" 62 | "Source Code" = "https://github.com/BiAPoL/napari-clusters-plotter" 63 | "User Support" = "https://github.com/BiAPoL/napari-clusters-plotter/issues" 64 | 65 | [build-system] 66 | requires = ["setuptools>=42.0.0", "wheel", "setuptools_scm"] 67 | build-backend = "setuptools.build_meta" 68 | 69 | [tool.setuptools] 70 | include-package-data = true 71 | 72 | [tool.setuptools.packages.find] 73 | where = ["src"] 74 | 75 | [tool.setuptools.package-data] 76 | "*" = ["*.yaml"] 77 | 78 | [tool.setuptools_scm] 79 | write_to = "src/napari_clusters_plotter/_version.py" 80 | fallback_version = "0.0.1+nogit" 81 | 82 | [tool.black] 83 | line-length = 79 84 | target-version = ['py38', 'py39', 'py310'] 85 | 86 | [tool.ruff] 87 | line-length = 79 88 | lint.select = [ 89 | "E", "F", "W", #flake8 90 | "UP", # pyupgrade 91 | "I", # isort 92 | "BLE", # flake8-blind-exception 93 | "B", # flake8-bugbear 94 | "A", # flake8-builtins 95 | "C4", # flake8-comprehensions 96 | "ISC", # flake8-implicit-str-concat 97 | "G", # flake8-logging-format 98 | "PIE", # flake8-pie 99 | "SIM", # flake8-simplify 100 | ] 101 | lint.ignore = [ 102 | "E501", # line too long. let black handle this 103 | "UP006", "UP007", # type annotation. As using magicgui require runtime type annotation then we disable this. 104 | "SIM117", # flake8-simplify - some of merged with statements are not looking great with black, re-enable after drop python 3.9 105 | ] 106 | 107 | exclude = [ 108 | ".bzr", 109 | ".direnv", 110 | ".eggs", 111 | ".git", 112 | ".mypy_cache", 113 | ".pants.d", 114 | ".ruff_cache", 115 | ".svn", 116 | ".tox", 117 | ".venv", 118 | "__pypackages__", 119 | "_build", 120 | "buck-out", 121 | "build", 122 | "dist", 123 | "node_modules", 124 | "venv", 125 | "*vendored*", 126 | "*_vendor*", 127 | ] 128 | 129 | target-version = "py38" 130 | fix = true 131 | -------------------------------------------------------------------------------- /src/napari_clusters_plotter/__init__.py: -------------------------------------------------------------------------------- 1 | try: 2 | from ._version import version as __version__ 3 | except ImportError: 4 | __version__ = "unknown" 5 | 6 | from ._dim_reduction_and_clustering import ( 7 | ClusteringWidget, 8 | DimensionalityReductionWidget, 9 | ) 10 | from ._new_plotter_widget import PlotterWidget 11 | from ._sample_data import ( 12 | bbbc_1_dataset, 13 | cells3d_curvatures, 14 | skan_skeleton, 15 | tgmm_mini_dataset, 16 | ) 17 | 18 | __all__ = [ 19 | "PlotterWidget", 20 | "DimensionalityReductionWidget", 21 | "ClusteringWidget", 22 | "bbbc_1_dataset", 23 | "tgmm_mini_dataset", 24 | "cells3d_curvatures", 25 | "skan_skeleton", 26 | ] 27 | -------------------------------------------------------------------------------- /src/napari_clusters_plotter/_algorithm_widget.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | 3 | import pandas as pd 4 | from magicgui import magic_factory 5 | from magicgui.widgets import Label 6 | from napari.layers import ( 7 | Labels, 8 | Points, 9 | Shapes, 10 | Surface, 11 | Tracks, 12 | Vectors, 13 | ) 14 | from qtpy.QtCore import Qt 15 | from qtpy.QtWidgets import ( 16 | QAbstractItemView, 17 | QComboBox, 18 | QLabel, 19 | QListWidget, 20 | QVBoxLayout, 21 | QWidget, 22 | ) 23 | 24 | 25 | class BaseWidget(QWidget): 26 | 27 | input_layer_types = [Labels, Points, Surface, Vectors, Shapes, Tracks] 28 | 29 | def __init__(self, napari_viewer): 30 | super().__init__() 31 | 32 | self.viewer = napari_viewer 33 | self.layers = [] 34 | 35 | def _get_features(self): 36 | features = pd.DataFrame() 37 | for layer in self.layers: 38 | _features = layer.features[self.common_columns].copy() 39 | 40 | # Add layer name as a categorical column 41 | _features["layer"] = layer.name 42 | _features["layer"] = _features["layer"].astype("category") 43 | features = pd.concat([features, _features], axis=0) 44 | 45 | # make sure that MANUAL_CLUSTER_ID is always categorical 46 | if "MANUAL_CLUSTER_ID" in features.columns: 47 | features["MANUAL_CLUSTER_ID"] = features[ 48 | "MANUAL_CLUSTER_ID" 49 | ].astype("category") 50 | return features.reset_index(drop=True) 51 | 52 | def _clean_up(self): 53 | """Determines what happens in case of no layer selected""" 54 | 55 | raise NotImplementedError( 56 | "This function should be implemented in the subclass." 57 | ) 58 | 59 | @property 60 | def common_columns(self): 61 | if len(self.layers) == 0: 62 | return [] 63 | common_columns = [ 64 | list(layer.features.columns) for layer in self.layers 65 | ] 66 | common_columns = list(set.intersection(*map(set, common_columns))) 67 | return common_columns 68 | 69 | @property 70 | def categorical_columns(self): 71 | if len(self.layers) == 0: 72 | return [] 73 | return self._get_features().select_dtypes(include="category").columns 74 | 75 | @property 76 | def n_selected_layers(self) -> int: 77 | """ 78 | Number of currently selected layers. 79 | """ 80 | return len(list(self.viewer.layers.selection)) 81 | 82 | def get_valid_layers(self): 83 | """ 84 | Check if the currently selected layers are of the correct type. 85 | """ 86 | return [ 87 | layer 88 | for layer in self.viewer.layers.selection 89 | if type(layer) in self.input_layer_types 90 | ] 91 | 92 | 93 | class AlgorithmWidgetBase(BaseWidget): 94 | def __init__(self, napari_viewer, algorithms, label_text, combo_box_items): 95 | super().__init__(napari_viewer) 96 | 97 | self.selected_algorithm_widget = None 98 | self.worker = None 99 | 100 | # Add label and list to put in the features to be reduced 101 | self.label_features = QLabel(label_text) 102 | self.feature_selection_widget = QListWidget() 103 | self.feature_selection_widget.setSelectionMode( 104 | QAbstractItemView.ExtendedSelection 105 | ) 106 | 107 | # Add combobox with algorithm options 108 | self.label_algorithm = QLabel( 109 | f"Select {label_text.split(' ')[-2]} algorithm:" 110 | ) 111 | self.algorithm_selection = QComboBox() 112 | self.algorithm_selection.addItems(combo_box_items) 113 | 114 | # Add layout and combobox 115 | self.layout = QVBoxLayout() 116 | self.layout.addWidget(self.label_features) 117 | self.layout.addWidget(self.feature_selection_widget) 118 | self.layout.addWidget(self.label_algorithm) 119 | self.layout.addWidget(self.algorithm_selection) 120 | self.setLayout(self.layout) 121 | 122 | self.algorithms = algorithms 123 | 124 | self._on_algorithm_changed(0) 125 | self._on_update_layer_selection(None) 126 | self._setup_callbacks() 127 | 128 | def _setup_callbacks(self): 129 | self.viewer.layers.selection.events.changed.connect( 130 | self._on_update_layer_selection 131 | ) 132 | self.algorithm_selection.currentIndexChanged.connect( 133 | self._on_algorithm_changed 134 | ) 135 | self.feature_selection_widget.itemSelectionChanged.connect( 136 | self._update_features 137 | ) 138 | 139 | def _update_features(self): 140 | """ 141 | Update the features to be used in the selected algorithm. Called when 142 | the user selects a different set of features. 143 | """ 144 | selected_columns = [ 145 | item.text() 146 | for item in self.feature_selection_widget.selectedItems() 147 | ] 148 | features = self._get_features()[selected_columns] 149 | 150 | if self.selected_algorithm_widget is not None: 151 | self.selected_algorithm_widget.data.value = features 152 | 153 | return features 154 | 155 | def _wait_for_finish(self, worker): 156 | # escape empty input data 157 | if self.selected_algorithm_widget.data.value.empty: 158 | warnings.warn( 159 | "No features selected. Please select features before running the algorithm.", 160 | stacklevel=1, 161 | ) 162 | return 163 | self.worker = worker 164 | self.worker.start() 165 | self.worker.returned.connect(self._process_result) 166 | 167 | def _process_result(self, result): 168 | raise NotImplementedError("Subclasses should implement this method.") 169 | 170 | def _on_algorithm_changed(self, index): 171 | if self.selected_algorithm_widget is not None: 172 | self.layout.removeWidget(self.selected_algorithm_widget.native) 173 | self.selected_algorithm_widget.native.deleteLater() 174 | 175 | algorithm = self.algorithm_selection.currentText() 176 | widget_factory = magic_factory( 177 | self.algorithms[algorithm]["callback"], 178 | call_button="Run", 179 | widget_init=lambda widget: self._on_init_algorithm(widget), 180 | ) 181 | self.selected_algorithm_widget = widget_factory() 182 | self.selected_algorithm_widget.native_parent_changed.emit(self) 183 | self.selected_algorithm_widget.called.connect(self._wait_for_finish) 184 | self.layout.addWidget(self.selected_algorithm_widget.native) 185 | 186 | self._update_features() 187 | 188 | def _on_init_algorithm(self, widget): 189 | """ 190 | Add a label with the documentation link to the algorithm widget. 191 | 192 | Taken from https://github.com/guiwitz/napari-skimage/blob/main/src/napari_skimage/skimage_detection_widget.py 193 | 194 | Parameters 195 | ---------- 196 | widget : magicgui.widgets.Widget 197 | The widget to add the label to. 198 | """ 199 | label_widget = Label(value="") 200 | 201 | algorithm = self.algorithms[self.algorithm_selection.currentText()] 202 | 203 | label_widget.value = ( 204 | f'Doc pages: {algorithm["doc_url"]}' 206 | ) 207 | label_widget.native.setTextFormat(Qt.RichText) 208 | label_widget.native.setTextInteractionFlags(Qt.TextBrowserInteraction) 209 | label_widget.native.setOpenExternalLinks(True) 210 | widget.extend([label_widget]) 211 | 212 | def _on_update_layer_selection(self, layer): 213 | self.layers = self.get_valid_layers() 214 | if len(self.layers) == 0: 215 | self._clean_up() 216 | return 217 | 218 | # don't do anything if no layer is selected 219 | if self.n_selected_layers == 0: 220 | self._clean_up() 221 | return 222 | 223 | features_to_add = self._get_features()[self.common_columns] 224 | column_strings = [ 225 | algo["column_string"] for algo in self.algorithms.values() 226 | ] 227 | features_to_add = features_to_add.drop( 228 | columns=[ 229 | col 230 | for col in features_to_add.columns 231 | if any(col.startswith(s) for s in column_strings) 232 | ] 233 | ) 234 | self.feature_selection_widget.clear() 235 | self.feature_selection_widget.addItems(sorted(features_to_add.columns)) 236 | self._update_features() 237 | 238 | def _clean_up(self): 239 | """ 240 | Clean up the widget when it is closed. 241 | """ 242 | 243 | # block signals for feature selection 244 | self.feature_selection_widget.blockSignals(True) 245 | self.feature_selection_widget.clear() 246 | self.feature_selection_widget.blockSignals(False) 247 | 248 | @property 249 | def selected_algorithm(self): 250 | return self.algorithm_selection.currentText() 251 | -------------------------------------------------------------------------------- /src/napari_clusters_plotter/_algorithms.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | from napari.qt.threading import FunctionWorker, thread_worker 3 | 4 | 5 | def reduce_pca( 6 | data: pd.DataFrame, n_components: int = 2, scale: bool = True 7 | ) -> FunctionWorker[pd.DataFrame]: 8 | """ 9 | Reduce the data using PCA 10 | """ 11 | 12 | @thread_worker(progress=True) 13 | def _reduce_pca( 14 | data: pd.DataFrame, n_components: int, scale: bool 15 | ) -> FunctionWorker[pd.DataFrame]: 16 | from sklearn.decomposition import PCA 17 | from sklearn.preprocessing import StandardScaler 18 | 19 | # Remove NaN rows 20 | non_nan_data = data.dropna() 21 | 22 | if scale: 23 | preprocessed = StandardScaler().fit_transform(non_nan_data.values) 24 | else: 25 | preprocessed = non_nan_data.values 26 | 27 | pca = PCA(n_components=n_components) 28 | pca.fit(preprocessed) 29 | reduced_data = pca.transform(preprocessed) 30 | 31 | # Add NaN rows back 32 | result = pd.DataFrame(index=data.index, columns=range(n_components)) 33 | result.loc[non_nan_data.index] = reduced_data 34 | 35 | return result 36 | 37 | return _reduce_pca(data, n_components, scale) 38 | 39 | 40 | def reduce_tsne( 41 | data: pd.DataFrame, 42 | n_components: int = 2, 43 | perplexity: float = 30, 44 | scale: bool = True, 45 | ) -> FunctionWorker[pd.DataFrame]: 46 | """ 47 | Reduce the data using t-SNE 48 | """ 49 | 50 | @thread_worker(progress=True) 51 | def _reduce_tsne( 52 | data: pd.DataFrame, n_components: int, perplexity: float, scale: bool 53 | ) -> pd.DataFrame: 54 | from sklearn.manifold import TSNE 55 | from sklearn.preprocessing import StandardScaler 56 | 57 | # Remove NaN rows 58 | non_nan_data = data.dropna() 59 | 60 | if scale: 61 | preprocessed = StandardScaler().fit_transform(non_nan_data) 62 | else: 63 | preprocessed = non_nan_data.values 64 | tsne = TSNE(n_components=n_components, perplexity=perplexity) 65 | reduced_data = tsne.fit_transform(preprocessed) 66 | 67 | # Add NaN rows back 68 | result = pd.DataFrame(index=data.index, columns=range(n_components)) 69 | result.loc[non_nan_data.index] = reduced_data 70 | 71 | return result 72 | 73 | return _reduce_tsne(data, n_components, perplexity, scale) 74 | 75 | 76 | def reduce_umap( 77 | data: pd.DataFrame, 78 | n_components: int = 2, 79 | n_neighbors: int = 30, 80 | scale: bool = True, 81 | ) -> FunctionWorker[pd.DataFrame]: 82 | """ 83 | Reduce the data using UMAP 84 | """ 85 | 86 | @thread_worker(progress=True) 87 | def _reduce_umap( 88 | data: pd.DataFrame, n_components: int, n_neighbors: int, scale: bool 89 | ) -> pd.DataFrame: 90 | import umap 91 | from sklearn.preprocessing import StandardScaler 92 | 93 | # Remove NaN rows 94 | non_nan_data = data.dropna() 95 | 96 | if scale: 97 | preprocessed = StandardScaler().fit_transform(non_nan_data) 98 | else: 99 | preprocessed = non_nan_data.values 100 | 101 | reducer = umap.UMAP(n_components=n_components, n_neighbors=n_neighbors) 102 | reduced_data = reducer.fit_transform(preprocessed) 103 | 104 | # Add NaN rows back 105 | result = pd.DataFrame(index=data.index, columns=range(n_components)) 106 | result.loc[non_nan_data.index] = reduced_data 107 | 108 | return result 109 | 110 | return _reduce_umap(data, n_components, n_neighbors, scale) 111 | 112 | 113 | def cluster_kmeans( 114 | data: pd.DataFrame, n_clusters: int = 3, scale: bool = True 115 | ) -> FunctionWorker[pd.Series]: 116 | """ 117 | Cluster the data using KMeans 118 | """ 119 | 120 | @thread_worker(progress=True) 121 | def _cluster_kmeans( 122 | data: pd.DataFrame, n_clusters: int, scale: bool 123 | ) -> pd.Series: 124 | from sklearn.cluster import KMeans 125 | from sklearn.preprocessing import StandardScaler 126 | 127 | # Remove NaN rows 128 | non_nan_data = data.dropna() 129 | 130 | if scale: 131 | preprocessed = StandardScaler().fit_transform(non_nan_data) 132 | else: 133 | preprocessed = non_nan_data.values 134 | 135 | # Perform KMeans clustering (+1 to start clusters from 1) 136 | kmeans = KMeans(n_clusters=n_clusters) 137 | clusters = kmeans.fit_predict(preprocessed) + 1 138 | 139 | # Add NaN rows back 140 | result = pd.Series(index=data.index, dtype=int) 141 | result.loc[non_nan_data.index] = clusters 142 | 143 | return result 144 | 145 | return _cluster_kmeans(data, n_clusters, scale) 146 | 147 | 148 | def cluster_hdbscan( 149 | data: pd.DataFrame, 150 | min_cluster_size: int = 5, 151 | min_samples: int = 5, 152 | scale: bool = True, 153 | ) -> FunctionWorker[pd.Series]: 154 | """ 155 | Cluster the data using HDBSCAN 156 | """ 157 | 158 | @thread_worker(progress=True) 159 | def _cluster_hdbscan( 160 | data: pd.DataFrame, 161 | min_cluster_size: int, 162 | min_samples: int, 163 | scale: bool, 164 | ) -> pd.Series: 165 | from sklearn.cluster import HDBSCAN 166 | from sklearn.preprocessing import StandardScaler 167 | 168 | # Remove NaN rows 169 | non_nan_data = data.dropna() 170 | 171 | if scale: 172 | preprocessed = StandardScaler().fit_transform(non_nan_data) 173 | else: 174 | preprocessed = non_nan_data.values 175 | 176 | # Perform HDBSCAN clustering (+1 to start clusters from 1) 177 | clusterer = HDBSCAN( 178 | min_cluster_size=min_cluster_size, min_samples=min_samples 179 | ) 180 | clusters = clusterer.fit_predict(preprocessed) + 1 181 | 182 | # Add NaN rows back 183 | result = pd.Series(index=data.index, dtype=int) 184 | result.loc[non_nan_data.index] = clusters 185 | 186 | return result 187 | 188 | return _cluster_hdbscan(data, min_cluster_size, min_samples, scale) 189 | 190 | 191 | def cluster_gaussian_mixture( 192 | data: pd.DataFrame, n_components: int = 3, scale: bool = True 193 | ) -> FunctionWorker[pd.Series]: 194 | """ 195 | Cluster the data using Gaussian Mixture 196 | """ 197 | 198 | @thread_worker(progress=True) 199 | def _cluster_gaussian_mixture( 200 | data: pd.DataFrame, n_components: int, scale: bool 201 | ) -> pd.Series: 202 | from sklearn.mixture import GaussianMixture 203 | from sklearn.preprocessing import StandardScaler 204 | 205 | # Remove NaN rows 206 | non_nan_data = data.dropna() 207 | 208 | if scale: 209 | preprocessed = StandardScaler().fit_transform(non_nan_data) 210 | else: 211 | preprocessed = non_nan_data.values 212 | 213 | # Perform Gaussian Mixture clustering (+1 to start clusters from 1) 214 | gmm = GaussianMixture(n_components=n_components) 215 | clusters = gmm.fit_predict(preprocessed) + 1 216 | 217 | # Add NaN rows back 218 | result = pd.Series(index=data.index, dtype=int) 219 | result.loc[non_nan_data.index] = clusters 220 | 221 | return result 222 | 223 | return _cluster_gaussian_mixture(data, n_components, scale) 224 | 225 | 226 | def cluster_spectral( 227 | data: pd.DataFrame, n_clusters: int = 3, scale: bool = True 228 | ) -> FunctionWorker[pd.Series]: 229 | """ 230 | Cluster the data using Spectral Clustering 231 | """ 232 | 233 | @thread_worker(progress=True) 234 | def _cluster_spectral( 235 | data: pd.DataFrame, n_clusters: int, scale: bool 236 | ) -> pd.Series: 237 | from sklearn.cluster import SpectralClustering 238 | from sklearn.preprocessing import StandardScaler 239 | 240 | # Remove NaN rows 241 | non_nan_data = data.dropna() 242 | 243 | if scale: 244 | preprocessed = StandardScaler().fit_transform(non_nan_data) 245 | else: 246 | preprocessed = non_nan_data.values 247 | 248 | # Perform Spectral Clustering (+1 to start clusters from 1) 249 | clusterer = SpectralClustering(n_clusters=n_clusters) 250 | clusters = clusterer.fit_predict(preprocessed) + 1 251 | 252 | # Add NaN rows back 253 | result = pd.Series(index=data.index, dtype=int) 254 | result.loc[non_nan_data.index] = clusters 255 | 256 | return result 257 | 258 | return _cluster_spectral(data, n_clusters, scale) 259 | -------------------------------------------------------------------------------- /src/napari_clusters_plotter/_dim_reduction_and_clustering.py: -------------------------------------------------------------------------------- 1 | import napari 2 | import pandas as pd 3 | 4 | from ._algorithm_widget import AlgorithmWidgetBase 5 | from ._algorithms import ( 6 | cluster_gaussian_mixture, 7 | cluster_hdbscan, 8 | cluster_kmeans, 9 | cluster_spectral, 10 | reduce_pca, 11 | reduce_tsne, 12 | reduce_umap, 13 | ) 14 | 15 | 16 | class ClusteringWidget(AlgorithmWidgetBase): 17 | algorithms = { 18 | "KMeans": { 19 | "callback": cluster_kmeans, 20 | "column_string": "KMeans", 21 | "doc_url": "https://scikit-learn.org/stable/modules/generated/sklearn.cluster.KMeans.html", 22 | }, 23 | "HDBSCAN": { 24 | "callback": cluster_hdbscan, 25 | "column_string": "HDBSCAN", 26 | "doc_url": "https://hdbscan.readthedocs.io/en/latest/how_hdbscan_works.html", 27 | }, 28 | "Gaussian Mixture": { 29 | "callback": cluster_gaussian_mixture, 30 | "column_string": "Gaussian Mixture", 31 | "doc_url": "https://scikit-learn.org/stable/modules/generated/sklearn.mixture.GaussianMixture.html", 32 | }, 33 | "Spectral": { 34 | "callback": cluster_spectral, 35 | "column_string": "Spectral", 36 | "doc_url": "https://scikit-learn.org/stable/modules/generated/sklearn.cluster.SpectralClustering.html", 37 | }, 38 | } 39 | 40 | def __init__(self, napari_viewer: napari.Viewer): 41 | super().__init__( 42 | napari_viewer, 43 | ClusteringWidget.algorithms, 44 | "Features to cluster:", 45 | ["KMeans", "HDBSCAN", "Gaussian Mixture", "Spectral"], 46 | ) 47 | 48 | def _process_result(self, result): 49 | """ 50 | Process the result of the clustering algorithm and update the layer 51 | """ 52 | 53 | column_name = self.algorithms[self.selected_algorithm]["column_string"] 54 | features_clustered = pd.DataFrame(result, columns=[column_name]) 55 | features_clustered[column_name] = features_clustered[ 56 | column_name 57 | ].astype("category") 58 | features_clustered["layer"] = self._get_features()["layer"] 59 | 60 | for layer in self.layers: 61 | current_features = layer.features 62 | 63 | # add the columns to the features 64 | layer_feature_subset = features_clustered[ 65 | features_clustered["layer"] == layer.name 66 | ] 67 | current_features[column_name] = layer_feature_subset[ 68 | column_name 69 | ].values 70 | 71 | # overwrite the features to trigger the features changed signal 72 | layer.features = current_features 73 | 74 | 75 | class DimensionalityReductionWidget(AlgorithmWidgetBase): 76 | algorithms = { 77 | "PCA": { 78 | "callback": reduce_pca, 79 | "column_string": "PC", 80 | "doc_url": "https://scikit-learn.org/stable/modules/generated/sklearn.decomposition.PCA.html", 81 | }, 82 | "t-SNE": { 83 | "callback": reduce_tsne, 84 | "column_string": "t-SNE", 85 | "doc_url": "https://scikit-learn.org/stable/modules/generated/sklearn.manifold.TSNE.html", 86 | }, 87 | "UMAP": { 88 | "callback": reduce_umap, 89 | "column_string": "UMAP", 90 | "doc_url": "https://umap-learn.readthedocs.io/en/latest/", 91 | }, 92 | } 93 | 94 | def __init__(self, napari_viewer: napari.Viewer): 95 | super().__init__( 96 | napari_viewer, 97 | DimensionalityReductionWidget.algorithms, 98 | "Features to reduce:", 99 | ["PCA", "t-SNE", "UMAP"], 100 | ) 101 | 102 | def _process_result(self, result: pd.DataFrame): 103 | """ 104 | Process result of dimensionality reduction algorithm and update layer 105 | """ 106 | column_names = [ 107 | f"{self.algorithms[self.selected_algorithm]['column_string']}{i}" 108 | for i in range(result.shape[1]) 109 | ] 110 | result.columns = column_names 111 | result["layer"] = self._get_features()["layer"].values 112 | 113 | for layer in self.layers: 114 | current_features = layer.features 115 | for column in column_names: 116 | layer_feature_subset = result[result["layer"] == layer.name] 117 | 118 | # add the columns to the features 119 | current_features[column] = layer_feature_subset[column].values 120 | 121 | # overwrite the features to trigger the features changed signal 122 | layer.features = current_features 123 | -------------------------------------------------------------------------------- /src/napari_clusters_plotter/_sample_data.py: -------------------------------------------------------------------------------- 1 | import glob 2 | import os 3 | from pathlib import Path 4 | from typing import List 5 | 6 | 7 | def skan_skeleton() -> List["LayerData"]: # noqa: F821 8 | import pandas as pd 9 | from skimage.io import imread 10 | 11 | paths_data = Path(__file__).parent / "sample_data" / "shapes_skeleton" 12 | df_paths = pd.read_csv( 13 | paths_data / Path("all_paths.csv"), 14 | ) 15 | df_features = pd.read_csv( 16 | paths_data / Path("skeleton_features.csv"), 17 | index_col="Unnamed: 0", # Adjusted to match the CSV structure 18 | ) 19 | 20 | # skeleton_id column should be categorical 21 | categorical_columns = [ 22 | "skeleton_id", 23 | "node_id_src", 24 | "branch_type", 25 | "path_id", 26 | "random_path_id", 27 | ] 28 | for feature in categorical_columns: 29 | df_features[feature] = df_features[feature].astype("category") 30 | 31 | list_of_paths = [] 32 | shape_types = [] 33 | for _, group in list(df_paths.groupby("index")): 34 | list_of_paths.append(group[["axis-0", "axis-1", "axis-2"]].values) 35 | shape_types.append(group["shape-type"].values[0]) 36 | 37 | layer_paths = ( 38 | list_of_paths, 39 | { 40 | "name": "shapes_skeleton", 41 | "shape_type": shape_types, 42 | "features": df_features, 43 | "edge_width": 0.25, 44 | "blending": "translucent", 45 | }, 46 | "shapes", 47 | ) 48 | 49 | layer_blobs = ( 50 | imread(paths_data / Path("blobs.tif")), 51 | { 52 | "name": "binary blobs", 53 | "opacity": 0.5, 54 | "blending": "additive", 55 | }, 56 | "labels", 57 | ) 58 | 59 | return [layer_paths, layer_blobs] 60 | 61 | 62 | def tgmm_mini_dataset() -> List["LayerData"]: # noqa: F821 63 | import pandas as pd 64 | from skimage.io import imread 65 | 66 | path = Path(__file__).parent / "sample_data" / "tracking_data" 67 | data = pd.read_csv(path / Path("tgmm-mini-tracks-layer-data.csv")) 68 | features = pd.read_csv( 69 | path / Path("tgmm-mini-spot.csv"), 70 | skiprows=[1, 2], 71 | low_memory=False, 72 | encoding="utf-8", 73 | ) 74 | 75 | categorical_columns = [ 76 | "Label", 77 | "ID", 78 | "Branch spot ID", 79 | "Spot track ID", 80 | ] 81 | for feature in categorical_columns: 82 | features[feature] = features[feature].astype("category") 83 | tracking_label_image = imread(path / Path("tgmm-mini.tif")) 84 | 85 | layer_data_tuple_tracks = ( 86 | data, 87 | { 88 | "name": "tgmm-mini-tracks", 89 | "features": features, 90 | "scale": [5, 1, 1], 91 | }, 92 | "tracks", 93 | ) 94 | 95 | layer_data_tuple_labels = ( 96 | tracking_label_image, 97 | { 98 | "name": "tgmm-mini-labels", 99 | "features": features, 100 | "scale": [5, 1, 1], 101 | }, 102 | "labels", 103 | ) 104 | 105 | return [layer_data_tuple_tracks, layer_data_tuple_labels] 106 | 107 | 108 | def bbbc_1_dataset() -> List["LayerData"]: # noqa: F821 109 | import napari 110 | import pandas as pd 111 | from skimage import io 112 | 113 | # get path of this file 114 | path = Path(__file__).parent / "sample_data" / "BBBC007_v1_images" 115 | 116 | tif_files = glob.glob( 117 | os.path.join(str(path), "**", "*.tif"), recursive=True 118 | ) 119 | raw_images = [f for f in tif_files if "labels" not in f] 120 | layers = [] 121 | 122 | for raw_image_filename in raw_images: 123 | 124 | label_filename = raw_image_filename.replace(".tif", "_labels.tif") 125 | feature_filename = raw_image_filename.replace(".tif", "_features.csv") 126 | image = io.imread(raw_image_filename) 127 | labels = io.imread(label_filename) 128 | 129 | features = pd.read_csv(feature_filename) 130 | 131 | ldtuple_image = ( 132 | image, 133 | { 134 | "name": Path(raw_image_filename).stem, 135 | }, 136 | "image", 137 | ) 138 | 139 | ldtuple_labels = ( 140 | labels, 141 | { 142 | "name": Path(raw_image_filename).stem + "_labels", 143 | "features": features, 144 | }, 145 | "labels", 146 | ) 147 | 148 | layers.append(ldtuple_image) 149 | layers.append(ldtuple_labels) 150 | 151 | viewer = napari.current_viewer() 152 | viewer.grid.enabled = True 153 | viewer.grid.stride = 2 154 | 155 | return layers 156 | 157 | 158 | def cells3d_curvatures() -> List["LayerData"]: # noqa: F821 159 | import numpy as np 160 | import pandas as pd 161 | from skimage import io 162 | 163 | path = Path(__file__).parent / "sample_data" / "cells3d" 164 | 165 | # load data 166 | vertices = np.loadtxt(path / "vertices.txt") 167 | faces = np.loadtxt(path / "faces.txt").astype(int) 168 | hks = pd.read_csv(path / "signature.csv") 169 | nuclei = io.imread(path / "nucleus.tif") 170 | 171 | # create layer data tuples 172 | layer_data_surface = ( 173 | (vertices, faces), 174 | { 175 | "name": "cells_3d_mitotic_nucleus_surface_curvatures", 176 | "features": hks, 177 | }, 178 | "surface", 179 | ) 180 | 181 | layer_data_nuclei = ( 182 | nuclei, 183 | { 184 | "name": "cells_3d_nucleus", 185 | "colormap": "gray", 186 | }, 187 | "image", 188 | ) 189 | 190 | return [layer_data_nuclei, layer_data_surface] 191 | -------------------------------------------------------------------------------- /src/napari_clusters_plotter/_tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/src/napari_clusters_plotter/_tests/__init__.py -------------------------------------------------------------------------------- /src/napari_clusters_plotter/_tests/test_dimensionality_reduction.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | import pytest 4 | 5 | from napari_clusters_plotter import ( 6 | ClusteringWidget, 7 | DimensionalityReductionWidget, 8 | ) 9 | 10 | 11 | @pytest.fixture( 12 | params=[ 13 | { 14 | "widget_class": DimensionalityReductionWidget, 15 | "algorithms": ["PCA", "t-SNE", "UMAP"], 16 | }, 17 | { 18 | "widget_class": ClusteringWidget, 19 | "algorithms": ["KMeans", "HDBSCAN"], 20 | }, 21 | ] 22 | ) 23 | def widget_config(request): 24 | return request.param 25 | 26 | 27 | def create_points(n_samples=100, loc=5): 28 | from napari.layers import Points 29 | 30 | points = np.random.random((n_samples, 3)) 31 | 32 | features = pd.DataFrame( 33 | { 34 | "feature1": np.random.normal(size=n_samples, loc=loc), 35 | "feature2": np.random.normal(size=n_samples, loc=loc), 36 | "feature3": np.random.normal(size=n_samples, loc=loc), 37 | "feature4": np.random.normal(size=n_samples, loc=loc), 38 | } 39 | ) 40 | 41 | # add some NaNs 42 | features.iloc[::10] = np.nan 43 | 44 | layer = Points(points, features=features, size=0.1) 45 | 46 | return layer 47 | 48 | 49 | def test_initialization(make_napari_viewer, widget_config): 50 | viewer = make_napari_viewer() 51 | layer = create_points() 52 | viewer.add_layer(layer) 53 | 54 | count_widgets = len(viewer.window._dock_widgets) 55 | 56 | WidgetClass = widget_config["widget_class"] 57 | algorithms = widget_config["algorithms"] 58 | widget = WidgetClass(viewer) 59 | 60 | viewer.window.add_dock_widget(widget, area="right") 61 | 62 | assert widget.viewer == viewer 63 | assert len(viewer.window._dock_widgets) == count_widgets + 1 64 | for algorithm in algorithms: 65 | assert algorithm in widget.algorithms 66 | 67 | # check if the widget is properly initialized 68 | feature_selection_items = [ 69 | widget.feature_selection_widget.item(i).text() 70 | for i in range(widget.feature_selection_widget.count()) 71 | ] 72 | 73 | for feature in layer.features.columns: 74 | assert feature in widget.common_columns 75 | assert feature in feature_selection_items 76 | 77 | # check that all features are in reduce_wdiget.feature_selection_widget 78 | assert len(feature_selection_items) == len(layer.features.columns) 79 | 80 | # clear layers to make sure cleanup works 81 | viewer.layers.clear() 82 | 83 | assert widget.feature_selection_widget.count() == 0 84 | 85 | 86 | def test_layer_update(make_napari_viewer, widget_config): 87 | viewer = make_napari_viewer() 88 | # Create two random layers using the create_points fixture 89 | points_layer1 = create_points() 90 | points_layer2 = create_points() 91 | 92 | points_layer1.name = "points1" 93 | points_layer2.name = "points2" 94 | 95 | # remove one feature from the second layer 96 | points_layer2.features = points_layer2.features.drop(columns=["feature4"]) 97 | 98 | # Add the layers to the viewer 99 | viewer.add_layer(points_layer1) 100 | viewer.add_layer(points_layer2) 101 | 102 | WidgetClass = widget_config["widget_class"] 103 | widget = WidgetClass(viewer) 104 | viewer.window.add_dock_widget(widget, area="right") 105 | 106 | selection_permutations = [ 107 | [points_layer1], 108 | [points_layer2], 109 | [points_layer1, points_layer2], 110 | ] 111 | 112 | for possible_selection in selection_permutations: 113 | viewer.layers.selection = possible_selection 114 | 115 | feature_selection_items = [ 116 | widget.feature_selection_widget.item(i).text() 117 | for i in range(widget.feature_selection_widget.count()) 118 | ] 119 | 120 | for feature in widget.common_columns: 121 | # make sure common columns are in every layer 122 | assert feature in feature_selection_items 123 | for layer in possible_selection: 124 | assert feature in layer.features.columns 125 | 126 | # make sure that the name of the layer is in the collected features 127 | collected_features = widget._get_features() 128 | for layer in possible_selection: 129 | for feature in widget.common_columns: 130 | assert feature in collected_features.columns 131 | assert layer.name in collected_features["layer"].values 132 | 133 | 134 | def test_feature_update(make_napari_viewer, widget_config): 135 | viewer = make_napari_viewer() 136 | 137 | points_layer = create_points() 138 | viewer.add_layer(points_layer) 139 | 140 | WidgetClass = widget_config["widget_class"] 141 | widget = WidgetClass(viewer) 142 | viewer.window.add_dock_widget(widget, area="right") 143 | 144 | # select all possible permutations of features 145 | combinations = [ 146 | [0], 147 | [0, 1], 148 | [0, 1, 2], 149 | ] 150 | 151 | for combination in combinations: 152 | for idx in combination: 153 | # select the feature 154 | item = widget.feature_selection_widget.item(idx) 155 | item.setSelected(True) 156 | 157 | features = widget._update_features() 158 | selected_features = [ 159 | item.text() 160 | for item in widget.feature_selection_widget.selectedItems() 161 | ] 162 | for feature in features.columns: 163 | assert feature in selected_features 164 | 165 | for selected_feature in selected_features: 166 | assert selected_feature in features.columns 167 | assert selected_feature in points_layer.features.columns 168 | assert ( 169 | selected_feature 170 | in widget.selected_algorithm_widget.data.value.columns 171 | ) 172 | 173 | 174 | def test_algorithm_change(make_napari_viewer, widget_config): 175 | 176 | viewer = make_napari_viewer() 177 | 178 | points_layer = create_points() 179 | viewer.add_layer(points_layer) 180 | 181 | WidgetClass = widget_config["widget_class"] 182 | widget = WidgetClass(viewer) 183 | viewer.window.add_dock_widget(widget, area="right") 184 | 185 | # select all possible permutations of features 186 | for idx in range(widget.algorithm_selection.count()): 187 | widget.algorithm_selection.setCurrentIndex(idx) 188 | assert ( 189 | widget.selected_algorithm 190 | == widget.algorithm_selection.itemText(idx) 191 | ) 192 | 193 | 194 | def test_algorithm_execution(make_napari_viewer, qtbot, widget_config): 195 | from qtpy.QtCore import QEventLoop 196 | 197 | viewer = make_napari_viewer() 198 | 199 | layer = create_points() 200 | viewer.add_layer(layer) 201 | 202 | WidgetClass = widget_config["widget_class"] 203 | widget = WidgetClass(viewer) 204 | qtbot.addWidget(widget) 205 | 206 | # Select features in the QListWidget and the algorithm in the QComboBox 207 | widget.feature_selection_widget.selectAll() 208 | 209 | for algorithm in widget.algorithms: 210 | widget.algorithm_selection.setCurrentText(algorithm) 211 | 212 | # Create an event loop to wait for the process to finish 213 | loop = QEventLoop() 214 | 215 | # Connect the worker's finished signal to the loop quit slot 216 | def on_worker_finished(loop=loop): 217 | loop.quit() 218 | 219 | # Wait until the worker is created and then connect the finished signal 220 | def on_button_clicked(): 221 | if widget.worker: 222 | widget.worker.finished.connect(on_worker_finished) 223 | 224 | # Connect the button clicked signal to the function that will 225 | # connect the worker's finished signal 226 | widget.selected_algorithm_widget.call_button.clicked.connect( 227 | on_button_clicked 228 | ) 229 | widget.selected_algorithm_widget.call_button.clicked.emit() 230 | 231 | # Start the loop and wait for the worker to finish and the loop to quit 232 | loop.exec_() 233 | qtbot.wait(100) 234 | 235 | # Check if the results are added to the layer 236 | column_prefix = widget.algorithms[algorithm]["column_string"] 237 | for col in layer.features.columns: 238 | if col.startswith(column_prefix): 239 | break 240 | else: 241 | raise AssertionError( 242 | f"Results not found in layer features for algorithm {algorithm}" 243 | ) 244 | 245 | # if a clustering algorithm is executed, assert that the resulting 246 | # columns are of type "category" 247 | if widget_config["widget_class"] == ClusteringWidget: 248 | assert layer.features[col].dtype.name == "category" 249 | 250 | # check that there are no -1 values in the clustering results 251 | assert not any( 252 | layer.features[col] == -1 253 | ), f"-1 values found in clustering results for {algorithm}" 254 | -------------------------------------------------------------------------------- /src/napari_clusters_plotter/_tests/test_layers.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | 4 | import napari_clusters_plotter as ncp 5 | 6 | 7 | def test_shapes_layer(make_napari_viewer): 8 | 9 | # random centers 10 | box_centers = np.random.random((20, 2)) * 1000 11 | box_widths = np.random.random(20) * 100 12 | box_heights = np.random.random(20) * 100 13 | features = pd.DataFrame( 14 | {"box_widths": box_widths, "box_heights": box_heights} 15 | ) 16 | features["area"] = features["box_widths"] * features["box_heights"] 17 | 18 | boxes = [] 19 | 20 | for i in range(20): 21 | corners = np.array( 22 | [ 23 | [ 24 | box_centers[i, 0] - box_widths[i] / 2, 25 | box_centers[i, 1] - box_heights[i] / 2, 26 | ], 27 | [ 28 | box_centers[i, 0] + box_widths[i] / 2, 29 | box_centers[i, 1] - box_heights[i] / 2, 30 | ], 31 | [ 32 | box_centers[i, 0] + box_widths[i] / 2, 33 | box_centers[i, 1] + box_heights[i] / 2, 34 | ], 35 | [ 36 | box_centers[i, 0] - box_widths[i] / 2, 37 | box_centers[i, 1] + box_heights[i] / 2, 38 | ], 39 | ] 40 | ) 41 | boxes.append(corners) 42 | 43 | viewer = make_napari_viewer() 44 | viewer.add_shapes(boxes, shape_type="polygon", features=features) 45 | 46 | plotter_widget = ncp.PlotterWidget(viewer) 47 | viewer.window.add_dock_widget(plotter_widget, area="right") 48 | -------------------------------------------------------------------------------- /src/napari_clusters_plotter/_tests/test_sample_data.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | 4 | @pytest.mark.parametrize( 5 | "sample_data_function", 6 | ["bbbc1", "cells3d_curvatures", "tgmm_mini", "skan_skeleton"], 7 | ) 8 | def test_bbbc_1_sample_data(make_napari_viewer, sample_data_function): 9 | 10 | viewer = make_napari_viewer() 11 | viewer.open_sample("napari-clusters-plotter", sample_data_function) 12 | assert len(viewer.layers) > 0 13 | -------------------------------------------------------------------------------- /src/napari_clusters_plotter/_version.py: -------------------------------------------------------------------------------- 1 | # file generated by setuptools-scm 2 | # don't change, don't track in version control 3 | 4 | __all__ = ["__version__", "__version_tuple__", "version", "version_tuple"] 5 | 6 | TYPE_CHECKING = False 7 | if TYPE_CHECKING: 8 | from typing import Tuple, Union 9 | 10 | VERSION_TUPLE = Tuple[Union[int, str], ...] 11 | else: 12 | VERSION_TUPLE = object 13 | 14 | version: str 15 | __version__: str 16 | __version_tuple__: VERSION_TUPLE 17 | version_tuple: VERSION_TUPLE 18 | 19 | __version__ = version = "0.8.2.dev372+g7a6588e.d20250514" 20 | __version_tuple__ = version_tuple = (0, 8, 2, "dev372", "g7a6588e.d20250514") 21 | -------------------------------------------------------------------------------- /src/napari_clusters_plotter/napari.yaml: -------------------------------------------------------------------------------- 1 | name: napari-clusters-plotter 2 | display_name: napari clusters plotter 3 | contributions: 4 | commands: 5 | - id: napari-clusters-plotter.plotter 6 | python_name: napari_clusters_plotter:PlotterWidget 7 | title: Clusters Plotter 8 | 9 | - id: napari-clusters-plotter.Dimensionality_Reduction 10 | python_name: napari_clusters_plotter:DimensionalityReductionWidget 11 | title: Dimensionality Reduction 12 | 13 | - id: napari-clusters-plotter.Clustering 14 | python_name: napari_clusters_plotter:ClusteringWidget 15 | title: Clustering 16 | 17 | - id: napari-clusters-plotter.bbbc_sample_data 18 | python_name: napari_clusters_plotter:bbbc_1_dataset 19 | title: Load bbbc sample data 20 | - id: napari-clusters-plotter.cells3d_curvatures 21 | python_name: napari_clusters_plotter:cells3d_curvatures 22 | title: Load cells3d mitotic nucleus surface curvatures 23 | - id: napari-clusters-plotter.tgmm_mini_data 24 | python_name: napari_clusters_plotter:tgmm_mini_dataset 25 | title: Load tgmm mini dataset 26 | - id: napari-clusters-plotter.skan_skeleton 27 | python_name: napari_clusters_plotter:skan_skeleton 28 | title: Load skan skeleton dataset 29 | 30 | menus: 31 | napari/layers/visualize: 32 | - command: napari-clusters-plotter.plotter 33 | 34 | napari/layers/measure: 35 | - command: napari-clusters-plotter.Dimensionality_Reduction 36 | 37 | napari/layers/classify: 38 | - command: napari-clusters-plotter.Clustering 39 | 40 | widgets: 41 | - command: napari-clusters-plotter.plotter 42 | autogenerate: false 43 | display_name: Plot & select features 44 | - command: napari-clusters-plotter.Dimensionality_Reduction 45 | autogenerate: false 46 | display_name: Dimensionality reduction (features) 47 | - command: napari-clusters-plotter.Clustering 48 | autogenerate: false 49 | display_name: Clustering (features) 50 | 51 | sample_data: 52 | - command: napari-clusters-plotter.bbbc_sample_data 53 | key: bbbc1 54 | display_name: BBBC 1 dataset & segmentations 55 | - command: napari-clusters-plotter.tgmm_mini_data 56 | key: tgmm_mini 57 | display_name: TGMM mini dataset (tracks and segmentations) 58 | - command: napari-clusters-plotter.cells3d_curvatures 59 | key: cells3d_curvatures 60 | display_name: Cells3D mitotic nucleus surface curvatures 61 | - command: napari-clusters-plotter.skan_skeleton 62 | key: skan_skeleton 63 | display_name: Skan skeleton dataset (labels and paths) 64 | -------------------------------------------------------------------------------- /src/napari_clusters_plotter/plotter_inputs.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Form 4 | 5 | 6 | 7 | 0 8 | 0 9 | 1303 10 | 871 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 20 | 21 | 0 22 | 0 23 | 24 | 25 | 26 | 0 27 | 28 | 29 | 30 | Plotting Options 31 | 32 | 33 | 34 | 35 | 36 | y-axis 37 | 38 | 39 | 40 | 41 | 42 | 43 | Hue 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | true 57 | 58 | 59 | <html><head/><body><p>Feature used to color data</p><p>By default, <span style=" font-family:'Consolas','Courier New','monospace'; font-size:14px; color:#ce9178;">MANUAL_CLUSTER_ID</span>, which displays manual selections.</p></body></html> 60 | 61 | 62 | 63 | 64 | 65 | 66 | x-axis 67 | 68 | 69 | 70 | 71 | 72 | 73 | Clear Manual Cluster Selection 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | Here you can find advanced options for the type of plot as well as further advanced options for plotting. 82 | 83 | 84 | Advanced Options 85 | 86 | 87 | 88 | 89 | 90 | true 91 | 92 | 93 | 94 | 95 | 96 | true 97 | 98 | 99 | 100 | 101 | 102 | Colors in Log Scale 103 | 104 | 105 | 106 | 107 | 108 | 109 | <html><head/><body><p>If checked, display histogram colors and overlay colors in log scale.</p><p>To enale this, select a HISTOGRAM2D in the <span style=" font-weight:600;">Plotting Type</span> Combobox.</p></body></html> 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | true 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | Plotting Type 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | <html><head/><body><p>Continuous colormap to display a feature as colors over plotted data.</p><p>Use the eye button in the plotter controls to hide/show the overlay colors.</p><p>To enale this, select a non-categorical feature in the <span style=" font-weight:600;">Hue</span> Combobox.</p></body></html> 149 | 150 | 151 | 152 | 153 | 154 | 155 | Overlay Colormap 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | true 166 | 167 | 168 | 169 | 170 | 171 | Number of Bins 172 | 173 | 174 | 175 | 176 | 177 | 178 | true 179 | 180 | 181 | 182 | 183 | 184 | true 185 | 186 | 187 | Auto 188 | 189 | 190 | true 191 | 192 | 193 | 194 | 195 | 196 | 197 | false 198 | 199 | 200 | 1 201 | 202 | 203 | 10000 204 | 205 | 206 | 20 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | Histogram Colormap 223 | 224 | 225 | 226 | 227 | 228 | 229 | <html><head/><body><p>Continuous colormap to display the histogram data (not the colors overlay).</p></body></html> 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | false 240 | 241 | 242 | 243 | 244 | 245 | Hide non-selected clusters 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | Qt::Vertical 267 | 268 | 269 | 270 | 20 271 | 40 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | hue_box 280 | y_axis_box 281 | x_axis_box 282 | 283 | 284 | 285 | 286 | -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/BBBC007_v1_images/A9/A9 p10d.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/src/napari_clusters_plotter/sample_data/BBBC007_v1_images/A9/A9 p10d.tif -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/BBBC007_v1_images/A9/A9 p10d_labels.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/src/napari_clusters_plotter/sample_data/BBBC007_v1_images/A9/A9 p10d_labels.tif -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/BBBC007_v1_images/A9/A9 p5d.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/src/napari_clusters_plotter/sample_data/BBBC007_v1_images/A9/A9 p5d.tif -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/BBBC007_v1_images/A9/A9 p5d_labels.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/src/napari_clusters_plotter/sample_data/BBBC007_v1_images/A9/A9 p5d_labels.tif -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/BBBC007_v1_images/A9/A9 p7d.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/src/napari_clusters_plotter/sample_data/BBBC007_v1_images/A9/A9 p7d.tif -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/BBBC007_v1_images/A9/A9 p7d_labels.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/src/napari_clusters_plotter/sample_data/BBBC007_v1_images/A9/A9 p7d_labels.tif -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/BBBC007_v1_images/A9/A9 p9d.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/src/napari_clusters_plotter/sample_data/BBBC007_v1_images/A9/A9 p9d.tif -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/BBBC007_v1_images/A9/A9 p9d_labels.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/src/napari_clusters_plotter/sample_data/BBBC007_v1_images/A9/A9 p9d_labels.tif -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/BBBC007_v1_images/data_source.txt: -------------------------------------------------------------------------------- 1 | We used image set BBBC007v1 image set version 1 (Jones et al., Proc. ICCV Workshop on Computer Vision for Biomedical Image Applications, 2005), available from the Broad Bioimage Benchmark Collection [Ljosa et al., Nature Methods, 2012]. 2 | 3 | Some images (17P1_POS0006_D_1UL, 17P1_POS0014_D_1UL, 20P1_POS0005_D_1UL, 20P1_POS0010_D_1UL, 20P1_POS0011_D_1UL) were converted from RGB to grayscale (8-bit). 4 | 5 | Link: https://bbbc.broadinstitute.org/BBBC007 6 | -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f96 (17)/17P1_POS0006_D_1UL.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f96 (17)/17P1_POS0006_D_1UL.tif -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f96 (17)/17P1_POS0006_D_1UL_features.csv: -------------------------------------------------------------------------------- 1 | label,area_filled,perimeter,axis_major_length,axis_minor_length,eccentricity,area,intensity_mean,intensity_max,intensity_min 2 | 1,29.0,18.863961030678926,7.853436897338211,4.935022236649111,0.7778983506301059,29.0,58.724137931034484,67.0,49.0 3 | 2,32.0,24.242640687119284,12.953143085278311,3.1741863858801147,0.9695100778153846,32.0,73.34375,118.0,40.0 4 | 3,316.0,65.11269837220809,22.94785673587347,17.64278455558406,0.6394645523780353,316.0,95.33227848101266,248.0,22.0 5 | 4,258.0,60.2842712474619,22.477334668569057,14.716400471677105,0.7558699598237298,258.0,113.58527131782945,204.0,19.0 6 | 5,59.0,32.27817459305202,15.198124697479766,5.328296994078263,0.9365293784749327,59.0,80.88135593220339,162.0,35.0 7 | 6,304.0,64.5269119345812,20.664762535888837,18.92458332112656,0.40165736274171154,304.0,87.46381578947368,253.0,30.0 8 | 7,163.0,55.8700576850888,20.473009100130877,11.368904921092499,0.8316421884304861,163.0,59.2760736196319,93.0,30.0 9 | 8,124.0,39.21320343559643,13.875408413141749,11.3834222690182,0.5717861839807512,124.0,95.93548387096774,155.0,28.0 10 | 9,478.0,80.18376618407356,26.77755138633069,22.845603154860928,0.5216452037834255,478.0,96.25313807531381,179.0,36.0 11 | 10,71.0,29.556349186104043,10.023724984880703,9.048539011179736,0.4302448743816973,71.0,85.63380281690141,130.0,40.0 12 | 11,164.0,46.04163056034262,16.096068031713997,13.052581948588621,0.5851606096900837,164.0,71.5548780487805,120.0,35.0 13 | 12,298.0,62.2842712474619,21.505940339917686,17.774346499391573,0.562958100100281,298.0,97.74161073825503,186.0,26.0 14 | 13,313.0,65.698484809835,22.993029643370495,17.593870262703756,0.6438131083978549,313.0,82.42172523961662,198.0,25.0 15 | 14,332.0,67.11269837220809,23.793097584045256,17.84581765016302,0.6613904322607078,332.0,88.68072289156626,146.0,31.0 16 | 15,314.0,67.11269837220809,22.96536448887688,18.12776568736901,0.6139403724874952,314.0,72.36942675159236,123.0,27.0 17 | 16,295.0,63.941125496954285,23.009684634005783,16.727150088200542,0.6866784391451113,295.0,96.03050847457627,224.0,27.0 18 | 17,143.0,41.798989873223334,14.533636076866449,12.50519323752038,0.5095667101153286,143.0,98.55944055944056,183.0,27.0 19 | 18,134.0,40.384776310850235,13.955227541656615,12.216821730447567,0.483345327984947,134.0,82.80597014925372,137.0,40.0 20 | 19,285.0,60.8700576850888,21.209893913012767,17.114853633933393,0.5906500485882875,285.0,99.08070175438597,182.0,28.0 21 | 20,20.0,13.65685424949238,6.0,4.09878030638384,0.7302967433402214,20.0,67.3,94.0,52.0 22 | 21,177.0,48.2842712474619,16.874259109060045,13.570843858275088,0.5943134990376142,177.0,76.71186440677967,139.0,30.0 23 | 22,265.0,58.8700576850888,19.682826088949593,17.18116022649597,0.487897220522837,265.0,99.12830188679246,173.0,28.0 24 | 23,272.0,67.59797974644667,26.637560109534927,13.327411214516118,0.8658382486643851,272.0,108.86029411764706,247.0,23.0 25 | 24,282.0,61.698484809834994,21.055571609893452,17.456866151949036,0.5591220502833156,282.0,87.7517730496454,161.0,35.0 26 | 25,287.0,63.4558441227157,21.357056533309443,17.379091500815107,0.5812290324932629,287.0,70.46341463414635,132.0,35.0 27 | 26,313.0,63.698484809834994,22.095742769704824,18.092367616930737,0.5740547733996865,313.0,85.10862619808307,145.0,34.0 28 | 27,281.0,60.04163056034261,19.328001836719643,18.608377433617072,0.2703297994203861,281.0,95.68327402135232,192.0,26.0 29 | 28,293.0,61.941125496954285,20.645017488979104,18.210853967694117,0.4710727111192103,293.0,94.62457337883959,171.0,26.0 30 | 29,278.0,59.698484809834994,19.326952768107315,18.336493224029628,0.3160203223900904,278.0,95.82014388489209,159.0,33.0 31 | 30,169.0,46.62741699796952,16.42577493551992,13.129403495165006,0.6009093980773081,169.0,72.1301775147929,108.0,42.0 32 | 31,146.0,42.62741699796952,14.043337067082488,13.295546184627876,0.32196610086092886,146.0,69.88356164383562,102.0,42.0 33 | 32,214.0,54.38477631085023,18.15432137252512,15.874908491609458,0.48512933901342997,214.0,85.0,180.0,22.0 34 | 33,159.0,49.55634918610404,19.99572544122407,10.494430428019347,0.8512047900866054,159.0,89.87421383647799,169.0,35.0 35 | -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f96 (17)/17P1_POS0006_D_1UL_labels.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f96 (17)/17P1_POS0006_D_1UL_labels.tif -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f96 (17)/17P1_POS0007_D_1UL.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f96 (17)/17P1_POS0007_D_1UL.tif -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f96 (17)/17P1_POS0007_D_1UL_features.csv: -------------------------------------------------------------------------------- 1 | label,area_filled,perimeter,axis_major_length,axis_minor_length,eccentricity,area,intensity_mean,intensity_max,intensity_min 2 | 1,14.0,14.414213562373096,8.246211251235321,1.9794866372215747,0.97076101630644,14.0,74.21428571428571,89.0,59.0 3 | 2,226.0,55.798989873223334,18.48492704082718,16.226430798065454,0.4789914339783646,226.0,108.84513274336283,209.0,37.0 4 | 3,83.0,35.89949493661167,15.108542753227468,7.366140382217728,0.8730961632404963,83.0,88.12048192771084,169.0,37.0 5 | 4,236.0,56.87005768508881,19.04776862920078,16.32433338409757,0.5152818603294829,236.0,77.73305084745763,125.0,41.0 6 | 5,258.0,57.45584412271571,20.426963897139593,16.119166916283113,0.6142490516739021,258.0,104.37596899224806,218.0,36.0 7 | 6,141.0,40.970562748477136,13.389950714690624,13.380210337307481,0.03813593557981585,141.0,74.44680851063829,102.0,45.0 8 | 7,163.0,46.62741699796952,16.593487414863198,12.760650549119823,0.6392300205152683,163.0,74.71779141104294,147.0,38.0 9 | 8,132.0,40.62741699796952,14.12404130713554,11.932776848108844,0.5349942439544312,132.0,88.12878787878788,164.0,36.0 10 | 9,227.0,53.79898987322333,19.105955557064096,15.263266815738822,0.6014973160404392,227.0,125.08370044052863,247.0,27.0 11 | 10,102.0,39.31370849898476,15.872129652347825,8.658597438567906,0.8380964399128614,102.0,87.92156862745098,140.0,37.0 12 | 11,256.0,57.698484809834994,19.288035890066404,17.002606119736036,0.47216442284915283,256.0,97.33984375,180.0,34.0 13 | 12,275.0,60.87005768508881,19.62649953480677,18.32462066788287,0.35814157570831956,275.0,95.0,191.0,31.0 14 | 13,145.0,42.384776310850235,13.829238733623953,13.428232775674012,0.23906715985586063,145.0,80.95172413793104,150.0,41.0 15 | 14,263.0,58.2842712474619,19.01806543350642,17.655582617207063,0.37168602803831297,263.0,85.72623574144487,136.0,39.0 16 | 15,278.0,61.35533905932738,21.621254129317034,16.64431268116382,0.6382700404837951,278.0,92.62230215827338,172.0,34.0 17 | 16,255.0,57.698484809834994,19.19435979259306,16.93673203489292,0.4705362419282335,255.0,95.83529411764705,201.0,39.0 18 | 17,163.0,45.21320343559643,14.977668028331571,13.968108471910929,0.36092284647202827,163.0,75.09815950920246,119.0,45.0 19 | 18,267.0,61.4558441227157,22.080416015448655,15.58851566460279,0.7082234825045493,267.0,96.53183520599251,251.0,31.0 20 | 19,310.0,65.11269837220809,23.920517253350017,16.580890829522716,0.7207779169912576,310.0,99.08387096774193,255.0,33.0 21 | 20,276.0,59.698484809834994,19.179894404979322,18.445294768342784,0.2741059664131236,276.0,106.3913043478261,195.0,33.0 22 | 21,274.0,59.11269837220809,20.513233526984646,17.010552115650874,0.5588812219095061,274.0,96.47080291970804,198.0,38.0 23 | 22,148.0,42.970562748477136,15.84780617517351,11.935105665642697,0.6578971921966663,148.0,81.01351351351352,119.0,35.0 24 | 23,75.0,35.69238815542512,15.811075005366922,6.3698976493779105,0.9152547097167153,75.0,85.2,122.0,39.0 25 | 24,269.0,59.112698372208094,19.413296708183644,17.75142307185678,0.40482296201801843,269.0,105.70260223048327,200.0,33.0 26 | 25,154.0,43.798989873223334,14.696946276739354,13.36011234915779,0.41670881989374214,154.0,89.3896103896104,192.0,40.0 27 | 26,152.0,43.79898987322333,14.859977232920507,13.045187676397395,0.4788916760642079,152.0,82.125,170.0,39.0 28 | 27,67.0,27.31370849898476,10.119262469031607,8.384297850809082,0.5599175765113138,67.0,74.40298507462687,97.0,52.0 29 | 28,148.0,42.62741699796952,14.613747538059133,12.915897706826213,0.4678302985693364,148.0,82.0,139.0,39.0 30 | 29,157.0,44.2842712474619,15.57783777802714,12.971610984356468,0.5537296633385383,157.0,77.4267515923567,118.0,40.0 31 | 30,293.0,61.11269837220809,20.115722009003413,18.619822195992505,0.378416844244657,293.0,107.6382252559727,208.0,33.0 32 | 31,795.0,129.29646455628165,50.895155063684555,22.875024837443746,0.8933035380824103,795.0,81.98238993710692,185.0,33.0 33 | 32,287.0,76.76955262170047,27.975792055578083,14.78762673809726,0.8488794286616944,287.0,91.23344947735191,184.0,28.0 34 | 33,429.0,79.59797974644667,30.21882116729518,18.437654317914703,0.7922950784844954,429.0,94.4895104895105,174.0,36.0 35 | 34,263.0,61.112698372208094,20.416617678620614,16.617012430448437,0.5810099707862236,263.0,69.77566539923954,141.0,40.0 36 | 35,281.0,63.698484809834994,23.554226838166866,15.599185615710217,0.7492679805866858,281.0,80.19217081850533,135.0,37.0 37 | 36,274.0,60.87005768508881,22.55266663671927,15.46923749115036,0.7276806185737763,274.0,109.87591240875912,224.0,34.0 38 | 37,155.0,44.62741699796952,14.934086601713771,13.267355199142498,0.45908150810354675,155.0,74.36774193548388,139.0,43.0 39 | 38,324.0,67.94112549695427,22.855847713369357,18.822653531443258,0.5672614607637757,324.0,78.1358024691358,134.0,40.0 40 | 39,510.0,83.59797974644665,29.083112898050878,22.64598747451617,0.6274405160561302,510.0,116.46078431372548,223.0,35.0 41 | 40,415.0,83.97665940288701,28.299114733152468,20.012246089519337,0.7070449307281965,415.0,97.63614457831325,231.0,34.0 42 | 41,256.0,57.698484809834994,20.226536834403873,16.156204686559384,0.60164609994963,256.0,84.03515625,164.0,36.0 43 | 42,272.0,59.11269837220809,20.288442390954298,17.106885787164412,0.5376254207710772,272.0,80.65073529411765,127.0,43.0 44 | 43,277.0,60.526911934581186,20.60144454997579,17.276212735038758,0.5447595406266308,277.0,107.84837545126354,255.0,34.0 45 | 44,198.0,54.87005768508881,18.71551686605938,13.837300437217623,0.6733222982462079,198.0,75.47474747474747,120.0,42.0 46 | 45,250.0,56.2842712474619,18.511808601389674,17.205258216763717,0.36902188491650045,250.0,91.784,188.0,45.0 47 | 46,339.0,71.35533905932738,27.826134220038142,15.88133429500443,0.8211346730388955,339.0,97.57522123893806,164.0,33.0 48 | 47,255.0,58.04163056034261,19.615155960768746,16.699866735510643,0.52455643383404,255.0,90.77254901960784,183.0,37.0 49 | 48,297.0,63.35533905932738,22.5235679864815,16.865589032180363,0.6627989600079728,297.0,105.92929292929293,222.0,36.0 50 | 49,107.0,35.798989873223334,12.728641199272161,10.694187995595563,0.5423273208953737,107.0,62.51401869158879,77.0,48.0 51 | 50,336.0,69.35533905932738,23.65482638029985,18.710458975815392,0.611843950728968,336.0,127.61309523809524,247.0,29.0 52 | 51,322.0,65.698484809835,22.546902793153475,18.45766606218175,0.5743152640393789,322.0,88.53416149068323,178.0,32.0 53 | 52,240.0,55.45584412271571,18.414500329302797,16.72251675170326,0.41871698455843337,240.0,97.59166666666667,208.0,36.0 54 | 53,307.0,63.45584412271571,21.8552732998849,17.978063953327464,0.5686260220518231,307.0,97.22475570032573,197.0,38.0 55 | 54,313.0,64.2842712474619,21.700584074319888,18.53623740316157,0.5199749697594843,313.0,105.15654952076677,197.0,34.0 56 | 55,321.0,71.11269837220809,25.89301769665064,16.356945747181403,0.7752026705660505,321.0,77.8753894080997,132.0,38.0 57 | 56,312.0,64.5269119345812,21.84970016492942,18.35371033096772,0.5425890774616867,312.0,94.85897435897436,224.0,37.0 58 | 57,316.0,63.94112549695428,21.614590137816744,18.642256732595047,0.5060828663151685,316.0,92.45253164556962,157.0,40.0 59 | 58,284.0,62.526911934581186,20.86335359669824,17.669264859033333,0.531745264790636,284.0,96.12323943661971,204.0,33.0 60 | 59,285.0,61.94112549695428,20.931046413342028,17.514281213548436,0.5475684413184597,285.0,105.26315789473684,186.0,31.0 61 | 60,305.0,64.8700576850888,20.706975688827654,19.066538804331998,0.39008573887865683,305.0,94.25573770491803,203.0,33.0 62 | 61,163.0,45.21320343559643,15.876364908106481,13.077667365528297,0.5669978837880836,163.0,99.65644171779141,181.0,33.0 63 | 62,300.0,62.2842712474619,20.238799106177357,18.936691887145535,0.35289528670976095,300.0,92.34666666666666,171.0,43.0 64 | 63,426.0,79.84062043356595,30.222822163851667,18.19985391821709,0.7983534895150651,426.0,90.26525821596245,169.0,38.0 65 | 64,293.0,61.698484809834994,21.25239538691197,17.655518933516625,0.5566392788287206,293.0,96.26962457337883,252.0,32.0 66 | 65,333.0,67.94112549695427,22.49387507032604,19.692632910802875,0.4832789032542326,333.0,86.81681681681681,201.0,36.0 67 | 66,322.0,66.8700576850888,23.283966242645636,17.84590963984238,0.6423083980302975,322.0,94.18012422360249,196.0,39.0 68 | 67,191.0,49.21320343559643,16.208465063205836,15.021487285448009,0.37563414768847603,191.0,101.08376963350786,201.0,31.0 69 | 68,421.0,80.42640687119285,32.03129758478756,17.060578398626188,0.8463531482724321,421.0,86.62470308788599,151.0,41.0 70 | 69,140.0,41.21320343559643,14.370665995536816,12.416343725017562,0.5034812625581998,140.0,83.05714285714286,126.0,41.0 71 | 70,312.0,63.698484809834994,22.019588806779197,18.15310742113727,0.565997154134222,312.0,106.65384615384616,249.0,29.0 72 | 71,242.0,57.4558441227157,21.359456330209824,14.462492671120645,0.7358908114086536,242.0,121.84297520661157,255.0,28.0 73 | 72,124.0,38.384776310850235,13.880993720028423,11.383423094878735,0.5722594459719833,124.0,69.6774193548387,92.0,47.0 74 | 73,305.0,63.941125496954285,22.69538557996777,17.487439654477306,0.6374056398755424,305.0,90.87868852459016,167.0,38.0 75 | 74,297.0,63.35533905932738,22.982210100617877,16.581141522701177,0.692438149960783,297.0,86.3063973063973,154.0,36.0 76 | 75,236.0,54.62741699796952,18.302036826604372,16.62519550791645,0.4181466724359583,236.0,79.83050847457628,141.0,43.0 77 | 76,321.0,65.94112549695427,22.40892484493232,18.49021652156838,0.5649467893933237,321.0,84.33333333333333,188.0,35.0 78 | 77,179.0,51.11269837220809,21.194660353307388,10.820388521803173,0.8598633431658818,179.0,80.15642458100558,179.0,38.0 79 | 78,288.0,61.698484809834994,19.709548444162387,18.72115941108128,0.3126989884789833,288.0,100.43402777777777,191.0,32.0 80 | 79,176.0,51.55634918610404,20.13256216022954,11.71077428067519,0.8134153867029522,176.0,82.47727272727273,150.0,45.0 81 | 80,327.0,67.59797974644667,24.156677400392727,17.545522893839095,0.6873547509865351,327.0,91.44648318042813,213.0,33.0 82 | 81,88.0,32.14213562373095,11.966320918011302,9.339849223722828,0.6251416173328838,88.0,65.42045454545455,87.0,47.0 83 | 82,299.0,62.2842712474619,20.75698302016119,18.551405522870645,0.4485796328231997,299.0,101.87959866220736,232.0,30.0 84 | 83,305.0,64.18376618407356,22.011149406488045,17.839887729461154,0.5857479944524896,305.0,87.32459016393443,150.0,42.0 85 | 84,38.0,24.485281374238568,11.235484105887215,4.510611306450524,0.9158760167816941,38.0,84.55263157894737,132.0,36.0 86 | 85,45.0,25.071067811865476,11.034792234904993,5.422156405487292,0.8709514137675363,45.0,83.35555555555555,150.0,35.0 87 | -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f96 (17)/17P1_POS0007_D_1UL_labels.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f96 (17)/17P1_POS0007_D_1UL_labels.tif -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f96 (17)/17P1_POS0011_D_1UL.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f96 (17)/17P1_POS0011_D_1UL.tif -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f96 (17)/17P1_POS0011_D_1UL_labels.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f96 (17)/17P1_POS0011_D_1UL_labels.tif -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f96 (17)/17P1_POS0013_D_1UL.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f96 (17)/17P1_POS0013_D_1UL.tif -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f96 (17)/17P1_POS0013_D_1UL_features.csv: -------------------------------------------------------------------------------- 1 | label,area_filled,perimeter,axis_major_length,axis_minor_length,eccentricity,area,intensity_mean,intensity_max,intensity_min 2 | 1,68.0,29.65685424949238,11.863528025181955,7.490059642830743,0.775496562530516,68.0,115.54411764705883,209.0,30.0 3 | 2,112.0,37.89949493661167,13.908575283414839,10.476309665040779,0.6577610532030626,112.0,96.72321428571429,159.0,32.0 4 | 3,29.0,19.656854249492383,9.216670132148066,4.112503193847125,0.8949319198853977,29.0,56.96551724137931,72.0,47.0 5 | 4,136.0,44.14213562373095,17.05310319152883,10.705622665691918,0.7783896138017923,136.0,105.63970588235294,194.0,39.0 6 | 5,272.0,60.87005768508881,22.81691209728724,15.250812044589878,0.7438024893274021,272.0,94.51470588235294,212.0,28.0 7 | 6,262.0,60.52691193458118,19.731460383992022,17.33818659824861,0.4773601784457651,262.0,103.6793893129771,214.0,28.0 8 | 7,20.0,13.65685424949238,5.215361924162119,4.795831523312719,0.3929526239966882,20.0,79.8,105.0,61.0 9 | 8,397.0,73.35533905932738,25.0883515203087,20.21333456901556,0.5923428112788612,397.0,90.8942065491184,164.0,33.0 10 | 9,246.0,56.2842712474619,19.57408275261172,16.034242716554665,0.5735696644243595,246.0,90.26016260162602,165.0,32.0 11 | 10,230.0,53.698484809834994,17.89701698903076,16.39030086601418,0.401607508829389,230.0,119.71739130434783,229.0,24.0 12 | 11,287.0,61.11269837220809,20.93650751611079,17.560588136332107,0.5445098984537792,287.0,98.71080139372822,198.0,33.0 13 | 12,283.0,59.698484809834994,20.197839998456118,17.83000107344387,0.4698097066614709,283.0,85.75971731448763,141.0,40.0 14 | 13,279.0,59.698484809834994,20.036041837646213,17.738961256831466,0.46492022531031674,279.0,99.05017921146954,208.0,32.0 15 | 14,119.0,43.31370849898476,18.54361219061249,8.5137949631364,0.8883728180365461,119.0,100.90756302521008,185.0,30.0 16 | 15,273.0,61.698484809834994,21.152297403820988,16.51904768905325,0.6245840269842522,273.0,101.79120879120879,192.0,31.0 17 | 16,272.0,60.87005768508881,21.85331679323712,15.98149265300827,0.6820479910565428,272.0,89.15808823529412,169.0,33.0 18 | 17,133.0,40.62741699796952,14.424502984247013,11.743493129991172,0.5806756042940887,133.0,98.29323308270676,176.0,33.0 19 | 18,457.0,79.94112549695427,30.558515604669285,19.190777958481803,0.7782125419382562,457.0,96.00437636761488,233.0,33.0 20 | 19,257.0,57.698484809834994,20.527802913690678,15.945545304183316,0.629774537467808,257.0,103.1011673151751,229.0,34.0 21 | 20,273.0,59.4558441227157,19.48677070329613,17.902556843958777,0.39494885257373646,273.0,97.10622710622711,194.0,33.0 22 | 21,291.0,62.52691193458118,20.74221004183561,17.956255997520827,0.5005861408197473,291.0,88.3298969072165,208.0,30.0 23 | 22,184.0,48.62741699796952,17.672560154575056,13.28407070167585,0.659530531552167,184.0,88.94565217391305,182.0,35.0 24 | 23,225.0,53.21320343559643,18.91958994430953,15.153311345519288,0.5987548707477296,225.0,94.17777777777778,162.0,34.0 25 | 24,165.0,45.21320343559643,14.980613934887428,14.029713106249966,0.35060193876499507,165.0,89.01212121212122,158.0,33.0 26 | 25,139.0,41.21320343559643,14.43165401190216,12.269113704931,0.526535759316718,139.0,76.53956834532374,111.0,45.0 27 | 26,206.0,51.21320343559643,17.724048280302423,14.812278447630009,0.5491612147583519,206.0,119.22330097087378,255.0,23.0 28 | 27,131.0,40.384776310850235,14.073468915841707,11.844949809883236,0.5400217770013721,131.0,97.50381679389314,185.0,29.0 29 | 28,138.0,42.38477631085023,14.571265582845898,12.244858855883027,0.5420552495310106,138.0,90.44927536231884,162.0,29.0 30 | 29,134.0,45.798989873223334,18.425435251546702,9.702404944076227,0.850127623344455,134.0,61.649253731343286,107.0,37.0 31 | 30,125.0,39.798989873223334,13.41592605087958,11.973790051497085,0.4510361751657572,125.0,91.08,166.0,31.0 32 | 31,281.0,60.526911934581186,19.351503623521545,18.68281919127952,0.26060559456708876,281.0,104.0,242.0,33.0 33 | 32,131.0,42.798989873223334,16.21171316589363,10.741388689984836,0.7490003297083327,131.0,74.6030534351145,126.0,31.0 34 | 33,422.0,74.76955262170047,23.499908230473558,22.920137747475408,0.2207570934161845,422.0,103.38862559241706,198.0,33.0 35 | 34,237.0,55.698484809834994,19.06779627937932,15.958166794348227,0.547329507363812,237.0,98.0295358649789,170.0,31.0 36 | 35,295.0,61.4558441227157,19.552519258100766,19.217634898512085,0.1842864796572444,295.0,99.52542372881356,216.0,34.0 37 | 36,92.0,34.14213562373095,13.094611957508192,8.970016409854473,0.7285281874038884,92.0,68.27173913043478,99.0,45.0 38 | 37,272.0,59.698484809834994,18.96079754638305,18.430684903835015,0.23480850407099782,272.0,90.75367647058823,177.0,36.0 39 | 38,298.0,63.112698372208094,22.583366735013783,16.93150437534024,0.661739998509788,298.0,80.54697986577182,168.0,34.0 40 | 39,329.0,66.52691193458118,21.69430029322881,19.40054109948879,0.4475297575216115,329.0,90.61702127659575,204.0,29.0 41 | 40,301.0,63.35533905932738,20.607633663779563,18.875895200335897,0.4012555077221437,301.0,99.51827242524917,196.0,31.0 42 | 41,167.0,50.14213562373095,19.71875869387925,11.374849455169171,0.8168471043796373,167.0,92.62275449101796,165.0,34.0 43 | 42,129.0,39.798989873223334,13.52039013286549,12.204360761890745,0.43034737330648687,129.0,78.69767441860465,124.0,37.0 44 | 43,316.0,73.42640687119285,24.396107099695573,17.554122456848905,0.6944447309999863,316.0,77.59177215189874,182.0,34.0 45 | 44,322.0,69.39087296526012,23.35887997897621,18.198410341540274,0.6269258962821146,322.0,84.94409937888199,168.0,29.0 46 | 45,387.0,75.84062043356595,26.17168781278707,19.28155032457752,0.6761835901540703,387.0,101.18087855297158,164.0,33.0 47 | 46,282.0,60.87005768508881,21.656623730581455,16.622075681534838,0.6410148353092556,282.0,100.13120567375887,177.0,29.0 48 | 47,475.0,84.32590180780451,31.981865094931106,19.293089409305203,0.7975514607338573,475.0,94.52842105263159,233.0,33.0 49 | 48,130.0,41.798989873223334,15.169229697163292,11.000119820946162,0.6885803209169158,130.0,91.8923076923077,150.0,33.0 50 | 49,267.0,59.11269837220809,20.05823239072641,16.995484266766326,0.5311031420091505,267.0,98.67790262172285,236.0,30.0 51 | 50,383.0,75.698484809835,29.84172753805656,16.537189386079948,0.8324079934387352,383.0,95.0313315926893,222.0,32.0 52 | 51,258.0,59.11269837220809,20.10580697990588,16.50122382838544,0.571331629422696,258.0,107.96899224806202,215.0,30.0 53 | 52,219.0,53.21320343559643,19.384717680195003,14.415068417893758,0.6685907520814597,219.0,92.3013698630137,181.0,37.0 54 | 53,146.0,41.798989873223334,14.141408113155684,13.140161689880765,0.36958344646966357,146.0,75.45205479452055,110.0,42.0 55 | 54,149.0,43.21320343559643,15.83207331716668,12.00066518228182,0.6522579568463254,149.0,87.8255033557047,189.0,34.0 56 | -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f96 (17)/17P1_POS0013_D_1UL_labels.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f96 (17)/17P1_POS0013_D_1UL_labels.tif -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f96 (17)/17P1_POS0014_D_1UL.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f96 (17)/17P1_POS0014_D_1UL.tif -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f96 (17)/17P1_POS0014_D_1UL_features.csv: -------------------------------------------------------------------------------- 1 | label,area_filled,perimeter,axis_major_length,axis_minor_length,eccentricity,area,intensity_mean,intensity_max,intensity_min 2 | 1,64.0,31.899494936611667,14.184742379730311,6.062831629748832,0.9040535404456704,64.0,98.390625,156.0,45.0 3 | 2,45.0,25.106601717798213,9.926295654908811,6.2926971393344395,0.7733804751562076,45.0,72.37777777777778,115.0,40.0 4 | 3,104.0,35.55634918610404,12.929582828557399,10.243507122823296,0.6101921068462771,104.0,93.15384615384616,140.0,45.0 5 | 4,161.0,48.7634559672906,16.841200138055648,12.580806106165362,0.6647953736501848,161.0,73.1055900621118,115.0,42.0 6 | 5,295.0,61.698484809834994,20.704425168393996,18.24965647456866,0.4723007070106906,295.0,152.55254237288136,255.0,27.0 7 | 6,120.0,40.04163056034261,14.147168987815304,10.88024962270715,0.6391572143323385,120.0,79.43333333333334,114.0,38.0 8 | 7,386.0,71.94112549695427,23.015824662863427,21.45154740690372,0.36236901642602043,386.0,139.1139896373057,255.0,33.0 9 | 8,182.0,48.38477631085023,16.097604029706503,14.598175539909429,0.42144506481817984,182.0,83.32417582417582,154.0,34.0 10 | 9,298.0,62.526911934581186,21.601025365230047,17.632421897531373,0.5776605660933547,298.0,131.11409395973155,255.0,27.0 11 | 10,4.0,2.0,4.47213595499958,0.0,1.0,4.0,84.25,97.0,70.0 12 | 11,231.0,56.384776310850235,18.622851096930606,16.343871616658195,0.4793486420957589,231.0,113.61904761904762,202.0,39.0 13 | 12,397.0,74.5269119345812,27.401886101518787,18.628116768214653,0.733386903708688,397.0,117.54156171284635,215.0,33.0 14 | 13,225.0,53.698484809834994,17.392078105213724,16.60134649966377,0.2980990083661266,225.0,115.15555555555555,252.0,36.0 15 | 14,251.0,56.87005768508881,18.606680167660087,17.252276453484548,0.37454499662421037,251.0,99.91235059760956,161.0,36.0 16 | 15,69.0,30.48528137423857,12.559907436762948,7.19848201841213,0.8194632210999485,69.0,65.94202898550725,91.0,48.0 17 | 16,108.0,36.97056274847714,13.814422579777757,10.030331249459481,0.6876136503349325,108.0,81.62962962962963,131.0,37.0 18 | 17,132.0,45.3492424049175,17.076125491100818,10.585350633668437,0.7846872768576126,132.0,112.65151515151516,208.0,32.0 19 | 18,257.0,61.4558441227157,21.013841354133916,15.939596284575549,0.6516399365289695,257.0,95.87548638132296,212.0,40.0 20 | 19,270.0,61.45584412271572,21.162537453847325,16.733756704720577,0.6121709574551186,270.0,108.02222222222223,187.0,29.0 21 | 20,419.0,82.08326112068522,29.87400583514346,18.243614837089353,0.7918734246863594,419.0,119.33890214797135,222.0,34.0 22 | 21,252.0,73.73401871576773,21.213116408121103,18.96862359048845,0.4476813520140676,252.0,110.0952380952381,237.0,29.0 23 | 22,277.0,59.698484809834994,20.47392781937929,17.28719417129284,0.5357894528098569,277.0,118.08303249097473,219.0,37.0 24 | 23,319.0,73.35533905932738,26.69808266595327,16.17164152980311,0.7956756258549814,319.0,107.60188087774294,219.0,34.0 25 | 24,132.0,40.384776310850235,14.498997259268114,11.589568805856043,0.6008844672235771,132.0,99.71969696969697,162.0,36.0 26 | 25,272.0,60.52691193458118,20.454161270851504,17.156090433287336,0.5445044505375463,272.0,92.47426470588235,150.0,41.0 27 | 26,249.0,56.2842712474619,19.24156820011847,16.48273259720075,0.5159460777565317,249.0,109.66666666666667,220.0,30.0 28 | 27,250.0,56.87005768508881,19.946705757104876,15.961562875842674,0.5997192649249328,250.0,109.204,204.0,43.0 29 | 28,253.0,58.2842712474619,18.825270245137606,17.19534192802477,0.4070226502214042,253.0,112.3201581027668,230.0,32.0 30 | 29,162.0,45.21320343559643,16.723974001202766,12.368308511764253,0.6730954796212648,162.0,90.27777777777777,141.0,43.0 31 | 30,154.0,50.45584412271571,15.355950139887632,13.621580987609706,0.4616626790258901,154.0,78.24025974025975,172.0,35.0 32 | 31,263.0,60.35533905932738,19.05294125533526,17.77933968024857,0.359475314691789,263.0,94.76045627376426,167.0,42.0 33 | 32,252.0,57.4558441227157,19.49981515719577,16.503222479147713,0.5326634953712371,252.0,108.93650793650794,204.0,40.0 34 | 33,141.0,41.21320343559643,13.70712888576011,13.088768663679662,0.29696716307400345,141.0,90.63120567375887,165.0,37.0 35 | 34,294.0,61.941125496954285,20.2358269329234,18.685244496213507,0.3839006675937693,294.0,93.19727891156462,150.0,43.0 36 | 35,221.0,53.45584412271571,17.46565699941349,16.15658447461036,0.3798483623913767,221.0,119.34389140271493,230.0,31.0 37 | 36,198.0,49.798989873223334,17.912256356996355,14.095001971185985,0.6170913982205207,198.0,94.12121212121212,162.0,49.0 38 | 37,238.0,54.87005768508881,18.73075951469344,16.17993330693045,0.5038070970916032,238.0,131.37394957983193,255.0,26.0 39 | 38,245.0,56.04163056034261,19.282699843531827,16.328249726749437,0.5319395321629083,245.0,106.44897959183673,222.0,43.0 40 | 39,230.0,56.04163056034261,19.65582849699757,15.109771424016712,0.6395889496939974,230.0,121.84782608695652,220.0,36.0 41 | 40,172.0,46.62741699796952,17.35214798609899,12.617550542221053,0.6864825053457176,172.0,90.18023255813954,180.0,49.0 42 | 41,245.0,57.35533905932738,19.23193046121414,16.333878124930404,0.527893817203142,245.0,111.0326530612245,208.0,34.0 43 | 42,186.0,48.04163056034262,16.54023047192569,14.32085821873242,0.5003560330607519,186.0,112.85483870967742,199.0,39.0 44 | 43,133.0,40.384776310850235,14.524764073860569,11.642898785512878,0.5978747592950389,133.0,85.8796992481203,148.0,47.0 45 | 44,247.0,56.2842712474619,17.990785138367276,17.492909863105577,0.23362783353054384,247.0,118.97165991902834,248.0,35.0 46 | 45,205.0,54.42031021678297,19.130223447180935,13.854247668623024,0.6895823168194076,205.0,95.14146341463415,162.0,36.0 47 | 46,129.0,39.79898987322333,13.749161455819253,11.93766904515231,0.49613207772593554,129.0,87.75193798449612,126.0,51.0 48 | 47,182.0,47.798989873223334,16.98537464559544,13.636875852324202,0.5961677723929633,182.0,107.34065934065934,196.0,34.0 49 | 48,167.0,45.798989873223334,16.42748520273662,12.963488459675352,0.6142209701562865,167.0,100.0119760479042,221.0,38.0 50 | 49,497.0,103.97665940288701,43.25426111442451,16.778622061473392,0.9216986024101839,497.0,111.49496981891348,204.0,37.0 51 | 50,321.0,74.76955262170047,28.73270155206121,14.977060983130224,0.85340104701441,321.0,84.88473520249221,124.0,43.0 52 | 51,257.0,57.11269837220809,18.728804313329753,17.564002796948596,0.3471572120346577,257.0,114.39299610894942,209.0,36.0 53 | 52,253.0,56.62741699796952,20.762918766576572,15.535721417612084,0.6634240657705756,253.0,104.60474308300395,160.0,42.0 54 | 53,257.0,57.698484809834994,19.419715881993913,16.92744874355033,0.49010563163738097,257.0,95.96498054474708,183.0,35.0 55 | 54,291.0,65.59797974644665,24.731999134238265,15.192721590222387,0.7890771424932203,291.0,98.36769759450172,162.0,37.0 56 | 55,256.0,58.284271247461895,18.75379814509052,17.521558608488554,0.35650381237156914,256.0,117.9609375,238.0,26.0 57 | 56,126.0,39.798989873223334,13.142779582285643,12.224449309724902,0.36723895245294264,126.0,92.65079365079364,170.0,45.0 58 | 57,281.0,61.94112549695428,22.31621742430304,16.132177498872764,0.6909627984844138,281.0,96.23843416370107,172.0,45.0 59 | 58,228.0,53.45584412271571,19.037979696561,15.253357048511822,0.5983876756001228,228.0,109.5219298245614,238.0,39.0 60 | 59,202.0,52.04163056034261,19.370007230875697,13.332092420925285,0.7254400469577726,202.0,82.73762376237623,121.0,37.0 61 | 60,257.0,60.04163056034261,20.94686614205776,15.864977511776097,0.6529610843070333,257.0,101.38910505836576,183.0,35.0 62 | 61,189.0,49.45584412271571,18.13939227418487,13.335602396018484,0.6778788768674799,189.0,90.21693121693121,134.0,46.0 63 | 62,31.0,20.449747468305834,10.22475280075362,4.036733952882332,0.9187670218954904,31.0,88.45161290322581,123.0,51.0 64 | 63,133.0,40.970562748477136,14.890686463965972,11.44363135257369,0.6398385910639034,133.0,89.65413533834587,161.0,43.0 65 | 64,239.0,55.698484809834994,19.625392072133046,15.535140197713854,0.6110607726670946,239.0,114.1213389121339,203.0,35.0 66 | 65,5.0,3.0,5.656854249492381,0.0,1.0,5.0,74.6,80.0,69.0 67 | 66,283.0,60.526911934581186,19.41641012703734,18.60352069953482,0.2863205119116588,283.0,103.68551236749117,190.0,40.0 68 | 67,259.0,59.11269837220809,20.959167433396363,15.940147267469042,0.6492987899168314,259.0,96.8030888030888,177.0,40.0 69 | 68,215.0,52.62741699796952,18.474548230884896,14.85272543130453,0.5946886719719914,215.0,101.36744186046512,154.0,32.0 70 | 69,215.0,52.04163056034261,17.32777243944999,15.79772715625267,0.4108569376896717,215.0,117.53488372093024,199.0,41.0 71 | 70,238.0,54.87005768508881,18.035539832976053,16.99602642145466,0.3345920978697794,238.0,113.75210084033614,217.0,38.0 72 | 71,260.0,58.2842712474619,19.297784353296123,17.292287626608914,0.4439000170073388,260.0,114.14615384615385,193.0,37.0 73 | 72,247.0,57.112698372208094,20.328900373618428,15.643572249204645,0.63861815879067,247.0,95.32388663967612,179.0,42.0 74 | 73,325.0,66.04163056034261,20.5830236709549,20.312571278534023,0.16157512687985373,325.0,94.06153846153846,149.0,42.0 75 | 74,275.0,61.21320343559643,20.16231466532221,17.55942344252947,0.49145467299982887,275.0,105.18545454545455,168.0,39.0 76 | 75,230.0,54.87005768508881,18.586890200985824,15.92005156891976,0.5161130862728307,230.0,114.56521739130434,193.0,35.0 77 | 76,282.0,62.2842712474619,22.055458585549076,16.51215183829901,0.6629484039633771,282.0,107.5,190.0,34.0 78 | 77,300.0,63.112698372208094,22.20918585910896,17.37963230425517,0.6225971425659244,300.0,102.88,185.0,38.0 79 | 78,257.0,56.8700576850888,19.43129127910262,16.86627098870217,0.4965722771787657,257.0,122.15175097276264,249.0,32.0 80 | 79,261.0,58.87005768508881,19.85915340876708,16.850719787302452,0.5291769615272404,261.0,120.93869731800767,246.0,33.0 81 | 80,121.0,38.384776310850235,12.882997005011402,12.014498535880273,0.36094867710105183,121.0,79.0,115.0,50.0 82 | 81,266.0,58.2842712474619,19.02605519957736,17.826998149887874,0.3493879390093692,266.0,115.703007518797,225.0,34.0 83 | 82,182.0,48.87005768508881,16.531557007151847,14.199187772159323,0.5121196452215498,182.0,85.12087912087912,149.0,0.0 84 | 83,121.0,38.384776310850235,13.870238130994688,11.10709701435825,0.5989501334173516,121.0,86.38842975206612,136.0,50.0 85 | 84,285.0,60.62741699796952,20.36561413781778,17.96564623642178,0.47095754113601435,285.0,96.0421052631579,156.0,40.0 86 | 85,221.0,53.55634918610404,17.24550817547375,16.47149178412594,0.2962262531102819,221.0,103.9502262443439,162.0,41.0 87 | 86,2.0,0.0,2.0,0.0,1.0,2.0,65.5,71.0,60.0 88 | -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f96 (17)/17P1_POS0014_D_1UL_labels.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f96 (17)/17P1_POS0014_D_1UL_labels.tif -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f9620/20P1_POS0002_D_1UL_labels.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f9620/20P1_POS0002_D_1UL_labels.tif -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f9620/20P1_POS0005_D_1UL.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f9620/20P1_POS0005_D_1UL.tif -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f9620/20P1_POS0005_D_1UL_features.csv: -------------------------------------------------------------------------------- 1 | label,area_filled,perimeter,axis_major_length,axis_minor_length,eccentricity,area,intensity_mean,intensity_max,intensity_min 2 | 1,144.0,43.55634918610404,15.582808399985465,12.068228194397822,0.6326255196538931,144.0,88.39583333333333,151.0,40.0 3 | 2,310.0,67.45584412271572,24.753906386829556,16.494643218585125,0.7456435220543799,310.0,89.84193548387097,181.0,44.0 4 | 3,245.0,54.8700576850888,18.10418764230944,17.226631721193044,0.3075637963324605,245.0,134.34285714285716,230.0,31.0 5 | 4,560.0,98.2842712474619,35.956732571737504,21.363970841383622,0.8043485463431711,560.0,122.56785714285714,255.0,39.0 6 | 5,246.0,62.62741699796952,20.978962555644124,15.551721120759561,0.6711729782022215,246.0,100.57317073170732,170.0,35.0 7 | 6,232.0,71.79898987322333,32.42175506045694,10.848026543739202,0.9423634550273913,232.0,78.56896551724138,144.0,45.0 8 | 7,287.0,62.04163056034261,22.92700821676731,16.012649989080767,0.7156894562258453,287.0,99.36933797909407,202.0,39.0 9 | 8,199.0,49.45584412271571,16.549055843166773,15.33134177318362,0.3764968138336619,199.0,94.75879396984925,164.0,46.0 10 | 9,245.0,55.45584412271571,19.211014921213053,16.24556852500638,0.5337564944436297,245.0,94.60816326530612,158.0,44.0 11 | 10,68.0,36.03553390593274,17.243048997203047,5.229914125918703,0.9528933228458172,68.0,78.23529411764706,118.0,43.0 12 | 11,158.0,45.31370849898476,15.280565104622022,13.539840291682417,0.4635276944621839,158.0,97.86708860759494,177.0,42.0 13 | 12,258.0,58.2842712474619,18.870613365410627,17.63882429747281,0.355373245050833,258.0,91.30232558139535,161.0,40.0 14 | 13,154.0,43.21320343559643,14.225458584946928,13.777071138467196,0.24909159892734115,154.0,80.5909090909091,117.0,39.0 15 | 14,281.0,60.2842712474619,19.616350836255222,18.24033593321819,0.3679295331704436,281.0,104.93594306049822,209.0,37.0 16 | 15,146.0,43.79898987322333,15.624185753191757,11.982396259209478,0.641750691997861,146.0,82.02054794520548,149.0,47.0 17 | 16,265.0,58.04163056034262,20.602069040680437,16.441147144185656,0.6026127092214929,265.0,100.26792452830189,158.0,41.0 18 | 17,299.0,64.5269119345812,20.384452903171166,19.04399843155989,0.3566414637353316,299.0,90.94983277591973,221.0,29.0 19 | 18,302.0,68.18376618407356,25.718743613501072,15.25568600436167,0.8050744010027099,302.0,89.77152317880795,224.0,38.0 20 | 19,266.0,58.04163056034261,19.697971992251645,17.239067394919672,0.4838161543519443,266.0,114.00375939849624,214.0,40.0 21 | 20,141.0,43.21320343559643,14.766481987311382,12.175617557432885,0.5657974978712474,141.0,82.77304964539007,124.0,50.0 22 | 21,269.0,59.45584412271571,22.213334587589593,15.432694140026705,0.7192521759416195,269.0,102.7360594795539,180.0,44.0 23 | 22,253.0,57.698484809834994,19.496542701078223,16.565469490173502,0.5273278466356502,253.0,103.3596837944664,184.0,43.0 24 | 23,304.0,63.35533905932738,21.660898231928094,17.94404727650372,0.5601261148057505,304.0,103.9967105263158,166.0,34.0 25 | 24,152.0,45.21320343559643,16.857070311112924,11.53060412535806,0.72946153607791,152.0,82.28947368421052,138.0,49.0 26 | 25,258.0,58.2842712474619,18.616249678231043,17.710726953000627,0.30808610330196246,258.0,124.40310077519379,220.0,25.0 27 | 26,261.0,57.698484809834994,19.431265419905912,17.1211595755656,0.4729039621562609,261.0,117.29501915708812,217.0,31.0 28 | 27,146.0,43.798989873223334,16.063907457998315,11.612368637201746,0.6909676521109455,146.0,84.45205479452055,131.0,42.0 29 | 28,252.0,58.87005768508881,21.775652729515794,14.783337772355852,0.7342372380545804,252.0,116.39682539682539,217.0,32.0 30 | 29,271.0,59.698484809834994,19.431414178599255,17.776101483621023,0.40387870093315204,271.0,116.83025830258302,229.0,31.0 31 | 30,307.0,63.11269837220809,20.79075219998726,18.90360534726135,0.4162910126965829,307.0,99.10749185667753,175.0,43.0 32 | 31,448.0,78.76955262170047,28.107337631604633,20.394914546896914,0.6881080919628039,448.0,100.77455357142857,194.0,37.0 33 | 32,386.0,78.07716446627535,27.44528242195857,18.269382921876936,0.746250082872476,386.0,96.0958549222798,178.0,35.0 34 | 33,240.0,54.87005768508881,17.858376516111107,17.119589149662904,0.2846525171106431,240.0,105.94166666666666,173.0,43.0 35 | 34,299.0,63.4558441227157,21.953541919937294,17.437066300901623,0.6075633672531575,299.0,105.98996655518394,207.0,33.0 36 | 35,271.0,60.2842712474619,21.650780466189893,16.014326925436553,0.6729751290672787,271.0,105.22878228782288,180.0,38.0 37 | 36,282.0,61.11269837220809,20.804069404355534,17.367348070772753,0.5505452363663462,282.0,112.73049645390071,212.0,33.0 38 | 37,362.0,87.08326112068524,30.938366116495647,17.045483967410856,0.8345384427960199,362.0,90.27348066298343,179.0,36.0 39 | 38,241.0,56.04163056034261,19.69435885670769,15.605418019524114,0.6100276869101098,241.0,98.80497925311204,191.0,42.0 40 | 39,122.0,45.9350288425444,19.80686018159024,8.341671248145222,0.9069907186272937,122.0,114.32786885245902,228.0,37.0 41 | 40,432.0,81.15432893255071,29.404522778210445,19.02172519020729,0.762576590368836,432.0,106.05092592592592,226.0,38.0 42 | 41,270.0,58.2842712474619,18.874853466937164,18.207413129937734,0.2635759449276921,270.0,117.4037037037037,232.0,31.0 43 | 42,285.0,60.2842712474619,20.122095750401325,18.07685655934698,0.43926294366096225,285.0,103.33333333333333,182.0,38.0 44 | 43,291.0,61.698484809834994,21.774958289107037,17.015615385429882,0.6239923531394556,291.0,98.96219931271477,162.0,40.0 45 | 44,251.0,55.698484809834994,18.35890304663013,17.439660866235922,0.31246476131835604,251.0,116.45418326693228,187.0,30.0 46 | 45,267.0,60.384776310850235,19.785729051630977,17.639915639625347,0.4529273698100322,267.0,113.5880149812734,205.0,35.0 47 | 46,252.0,56.2842712474619,18.388251124565915,17.465063160844895,0.31287387042611775,252.0,102.30952380952381,196.0,45.0 48 | 47,274.0,61.79898987322333,23.569138477404273,15.003549774235248,0.7712139098415567,274.0,85.61313868613139,208.0,42.0 49 | 48,47.0,31.863961030678926,16.373965815136156,3.8425422856174216,0.9720741558157201,47.0,91.74468085106383,145.0,33.0 50 | 49,299.0,67.01219330881976,26.257205717142288,14.889506795066287,0.8236739779381012,299.0,102.94983277591973,236.0,36.0 51 | 50,272.0,59.698484809834994,20.00853349213255,17.327719136400745,0.5000155087954151,272.0,99.55147058823529,207.0,42.0 52 | 51,276.0,59.698484809834994,21.67665413520328,16.3536838773971,0.6563717248543259,276.0,111.82608695652173,201.0,32.0 53 | 52,284.0,60.526911934581186,20.179863313380125,17.980743524139065,0.4539561030979067,284.0,103.88380281690141,194.0,33.0 54 | 53,238.0,57.935028842544405,20.55200510054954,15.253689381264708,0.6701789282784195,238.0,96.95798319327731,197.0,32.0 55 | -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f9620/20P1_POS0005_D_1UL_labels.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f9620/20P1_POS0005_D_1UL_labels.tif -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f9620/20P1_POS0007_D_1UL.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f9620/20P1_POS0007_D_1UL.tif -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f9620/20P1_POS0007_D_1UL_features.csv: -------------------------------------------------------------------------------- 1 | label,area_filled,perimeter,axis_major_length,axis_minor_length,eccentricity,area,intensity_mean,intensity_max,intensity_min 2 | 1,221.0,53.21320343559643,17.60492603184554,16.115153100055434,0.4025966227798165,221.0,97.6289592760181,171.0,42.0 3 | 2,146.0,42.14213562373095,14.99816508952656,12.478785369281228,0.5547444298876055,146.0,89.41780821917808,164.0,49.0 4 | 3,359.0,84.08326112068522,26.607198251069487,19.286103137244307,0.6889116501497691,359.0,95.98607242339833,180.0,45.0 5 | 4,326.0,67.698484809835,24.936987149900837,16.802648291992497,0.7389098813688547,326.0,83.04601226993866,142.0,45.0 6 | 5,281.0,62.04163056034261,21.28197998555295,17.10637803420745,0.5949045406954346,281.0,95.64768683274022,209.0,35.0 7 | 6,245.0,60.04163056034262,20.97233613323084,15.810548018700672,0.657016333914018,245.0,96.9673469387755,157.0,39.0 8 | 7,148.0,43.21320343559643,15.780190451713436,11.942621274000597,0.6536338062482389,148.0,86.22297297297297,160.0,41.0 9 | 8,429.0,75.35533905932738,23.920989565848554,22.911516980220313,0.2874364392765659,429.0,100.24708624708624,197.0,42.0 10 | 9,472.0,89.97665940288701,31.840141386148034,20.47692267711445,0.7657682879998173,472.0,96.63135593220339,201.0,39.0 11 | 10,70.0,35.31370849898476,15.965660116217656,5.92584645743461,0.9285681258251638,70.0,81.47142857142858,114.0,50.0 12 | 11,301.0,62.52691193458118,20.780471022271634,18.64800405572035,0.44125613765714394,301.0,95.94019933554817,161.0,38.0 13 | 12,150.0,46.62741699796952,17.826828944267557,10.948562199497655,0.7891799221100277,150.0,77.29333333333334,117.0,47.0 14 | 13,242.0,56.2842712474619,18.622222567031745,16.552291326118777,0.45820571206709515,242.0,97.33471074380165,161.0,45.0 15 | 14,257.0,56.8700576850888,18.916017680589604,17.307899134338832,0.4034846553088624,257.0,100.24124513618678,182.0,38.0 16 | 15,302.0,63.11269837220809,21.16827263918225,18.233952269565126,0.5079590667555055,302.0,106.43708609271523,206.0,42.0 17 | 16,300.0,63.11269837220809,20.56383862670388,18.599393264936634,0.4265353715460502,300.0,105.89666666666666,184.0,44.0 18 | 17,286.0,62.2842712474619,20.1418123653836,18.38123549242749,0.4088737887029303,286.0,98.8986013986014,202.0,46.0 19 | 18,240.0,56.2842712474619,20.546146169185395,14.96711357294985,0.6850848204232567,240.0,97.92916666666666,199.0,46.0 20 | 19,288.0,60.8700576850888,19.328036349683167,18.987424893207685,0.18690844354398445,288.0,111.67013888888889,203.0,39.0 21 | 20,287.0,61.698484809834994,21.14203007229465,17.642370083683264,0.5510547869421156,287.0,95.34146341463415,152.0,43.0 22 | 21,351.0,69.11269837220809,23.696316952085418,18.998631120937258,0.5976533788696464,351.0,95.17378917378917,186.0,40.0 23 | 22,208.0,54.14213562373095,20.191250913001582,13.417887983179751,0.7472529536034437,208.0,104.72596153846153,169.0,45.0 24 | 23,306.0,64.52691193458118,21.407821156105037,18.250155434916973,0.5227281451598931,306.0,102.18954248366013,196.0,42.0 25 | 24,139.0,42.04163056034261,14.423319112109617,12.290775024928005,0.5233039620739448,139.0,79.94964028776978,133.0,46.0 26 | 25,302.0,66.2842712474619,22.02963754131695,17.954469613453423,0.579440843640815,302.0,85.85099337748345,148.0,44.0 27 | 26,257.0,58.2842712474619,18.805151105551047,17.491933549715085,0.36713634896031583,257.0,123.80933852140078,245.0,41.0 28 | 27,161.0,45.798989873223334,14.832230741185985,13.908966548130298,0.3473033330142837,161.0,80.98136645962732,127.0,46.0 29 | 28,303.0,66.5269119345812,23.57737467512804,16.83239000695965,0.700225946171772,303.0,98.88118811881188,193.0,41.0 30 | 29,144.0,41.21320343559643,14.097133297478113,12.998901879662162,0.38696260611725286,144.0,101.71527777777777,159.0,41.0 31 | 30,216.0,52.87005768508881,17.743962596065025,15.507394843067635,0.48600988875493567,216.0,121.82407407407408,247.0,42.0 32 | 31,355.0,71.698484809835,24.69691401279467,18.660293473246064,0.6550657609270254,355.0,77.59154929577464,110.0,47.0 33 | 32,282.0,60.04163056034261,19.482128546405196,18.457285945869774,0.3200644893074351,282.0,96.19503546099291,183.0,45.0 34 | 33,172.0,46.62741699796952,15.48418710581927,14.250400484793756,0.3911673315311404,172.0,72.04651162790698,96.0,49.0 35 | 34,252.0,58.2842712474619,18.581777237312412,17.65149289622005,0.3124455704055053,252.0,86.37301587301587,171.0,42.0 36 | 35,729.0,107.74011537017762,42.43870548906161,22.298817111516136,0.8508332221961393,729.0,108.440329218107,240.0,43.0 37 | 36,207.0,53.21320343559643,20.6597448284109,12.753708423980875,0.7867108370443373,207.0,140.07729468599032,255.0,28.0 38 | 37,247.0,57.21320343559643,18.934664234912887,16.845227645494607,0.4566426812830697,247.0,101.00404858299595,187.0,41.0 39 | 38,277.0,65.97665940288702,21.18610891567245,16.96331134503185,0.599091147389233,277.0,68.65342960288808,91.0,45.0 40 | 39,306.0,64.76955262170047,21.95039576184951,18.096487855519438,0.5659690391812813,306.0,93.48366013071896,193.0,40.0 41 | 40,305.0,63.11269837220809,21.004710397628198,18.553822626904996,0.46877571329492457,305.0,106.59344262295082,255.0,48.0 42 | 41,291.0,63.941125496954285,23.63072819591016,15.8273010712981,0.7425629558818223,291.0,124.23024054982818,255.0,28.0 43 | 42,272.0,60.526911934581186,19.40262738256357,18.070220262685666,0.36418015606422555,272.0,118.82720588235294,222.0,39.0 44 | 43,338.0,81.59797974644667,22.62990312194095,21.220283349072687,0.3474193624733752,338.0,94.0828402366864,184.0,28.0 45 | 44,275.0,58.8700576850888,19.73825410374637,17.766649115793,0.43565754820348784,275.0,101.33818181818182,188.0,41.0 46 | 45,401.0,87.59797974644667,34.012353048989425,16.772568542076808,0.8699546848277031,401.0,98.11970074812967,250.0,39.0 47 | 46,303.0,63.698484809834994,20.99047023707132,18.5974909927215,0.46369121303365995,303.0,82.73597359735973,158.0,44.0 48 | 47,254.0,56.04163056034261,18.59639867038837,17.442698662751067,0.34674048481121583,254.0,124.34645669291339,255.0,40.0 49 | 48,161.0,45.21320343559643,15.529126931200722,13.19696266126384,0.527073017922518,161.0,85.95031055900621,121.0,47.0 50 | 49,289.0,61.45584412271571,21.3762077617482,17.241168955569186,0.591153843191389,289.0,106.49134948096886,195.0,39.0 51 | 50,162.0,44.62741699796952,15.348819961919554,13.490807919144586,0.4769184200215409,162.0,82.73456790123457,132.0,48.0 52 | 51,56.0,25.31370849898476,8.862073966446282,8.019706093714507,0.42552457423717577,56.0,75.32142857142857,95.0,51.0 53 | 52,265.0,58.2842712474619,19.485092450331678,17.39277850982237,0.45081034529665026,265.0,112.5320754716981,198.0,31.0 54 | 53,155.0,43.798989873223334,15.094996121649636,13.055963329289373,0.5019098282358995,155.0,98.12903225806451,166.0,45.0 55 | 54,270.0,58.87005768508881,19.12079885536317,18.074374324910806,0.32628057247845876,270.0,104.54074074074074,177.0,42.0 56 | 55,284.0,61.11269837220809,20.268254073108952,17.99491594917147,0.4601571256565737,284.0,111.59154929577464,219.0,39.0 57 | 56,331.0,65.698484809835,22.47263182338868,18.864987344039317,0.543413795684318,331.0,113.02719033232628,234.0,37.0 58 | 57,320.0,65.698484809835,23.243053929984153,17.585833439386604,0.6538710891928299,320.0,89.596875,182.0,44.0 59 | 58,314.0,64.8700576850888,23.005454901222148,17.50993436109004,0.6486099405956343,314.0,125.14012738853503,255.0,37.0 60 | 59,259.0,58.2842712474619,18.903670696024843,17.493011398240135,0.3790494076439208,259.0,114.06949806949807,228.0,33.0 61 | 60,152.0,47.9350288425444,16.994045038348304,11.87271813885399,0.7154734604736604,152.0,76.89473684210526,134.0,44.0 62 | 61,306.0,64.52691193458118,22.584799457026023,17.51987727069326,0.6310556511034258,306.0,100.140522875817,196.0,44.0 63 | 62,294.0,60.8700576850888,20.33979335631212,18.421137221341326,0.4239836746240258,294.0,110.08503401360544,210.0,41.0 64 | 63,304.0,62.04163056034262,20.922721448871467,18.55261601413525,0.46230499472049497,304.0,101.49013157894737,185.0,39.0 65 | 64,272.0,60.04163056034261,19.71372910442772,17.76723615661677,0.4332743868456616,272.0,104.85661764705883,226.0,39.0 66 | 65,287.0,61.698484809834994,22.30625096315206,16.4389671087518,0.6759289077687055,287.0,99.05226480836237,179.0,41.0 67 | 66,225.0,54.526911934581186,19.648153155574555,14.593681485611533,0.6695679564345073,225.0,111.99111111111111,209.0,34.0 68 | 67,335.0,68.2842712474619,24.13504270937914,17.79117533212653,0.6757278524090774,335.0,97.24179104477612,184.0,39.0 69 | 68,315.0,64.04163056034261,20.68089786811274,19.51533523088134,0.3309718800057719,315.0,98.99365079365079,199.0,38.0 70 | 69,308.0,63.94112549695428,20.611654386211324,19.099008273306787,0.37601864781424876,308.0,103.34740259740259,184.0,37.0 71 | 70,253.0,56.62741699796952,18.667563299353755,17.320750188076538,0.3729467119646554,253.0,104.54150197628458,229.0,37.0 72 | 71,33.0,23.071067811865476,10.944869714630578,4.021578792457079,0.9300473773266072,33.0,95.06060606060606,167.0,35.0 73 | 72,341.0,66.5269119345812,22.61907304774512,19.211167663186345,0.5278543964325493,341.0,98.87096774193549,207.0,42.0 74 | 73,301.0,61.698484809834994,20.973223242185476,18.295399052915442,0.4889322484609349,301.0,122.4983388704319,251.0,36.0 75 | 74,294.0,61.21320343559642,19.772112962176543,19.00373739102458,0.2760669116183426,294.0,89.77210884353741,205.0,39.0 76 | 75,256.0,58.04163056034261,19.388059985645846,17.18989628502375,0.46249322945395055,256.0,115.83984375,233.0,38.0 77 | 76,539.0,92.66904755831214,36.26738191404396,19.84296324148951,0.8370478167198342,539.0,94.291280148423,231.0,38.0 78 | 77,266.0,59.11269837220809,19.791323732010202,17.2052168431061,0.49422982629333956,266.0,104.46616541353383,175.0,43.0 79 | 78,61.0,32.520815280171306,13.825342140819581,6.165323844076583,0.8950610265229897,61.0,97.73770491803279,175.0,38.0 80 | 79,195.0,50.87005768508881,18.761661094493444,13.248807793622786,0.7080484054643967,195.0,77.85128205128206,122.0,50.0 81 | 80,240.0,59.62741699796952,19.075866297128783,16.46717079230537,0.5047829675815158,240.0,91.88333333333334,200.0,39.0 82 | 81,273.0,60.52691193458119,23.377586547945363,14.953779182062414,0.7686554071234493,273.0,115.02930402930403,242.0,37.0 83 | 82,210.0,51.698484809834994,18.281720001142858,14.677999084019278,0.5961427586692825,210.0,78.88095238095238,132.0,48.0 84 | 83,293.0,63.11269837220809,23.690376296241354,15.793294158914543,0.745366942689209,293.0,93.04778156996586,177.0,39.0 85 | 84,224.0,53.798989873223334,19.708827907260954,14.471622406385272,0.6788563744251758,224.0,80.40625,139.0,49.0 86 | 85,6.0,5.414213562373095,3.6514837167011076,2.10818510677892,0.8164965809277259,6.0,84.33333333333333,137.0,47.0 87 | -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f9620/20P1_POS0007_D_1UL_labels.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f9620/20P1_POS0007_D_1UL_labels.tif -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f9620/20P1_POS0008_D_1UL.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f9620/20P1_POS0008_D_1UL.tif -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f9620/20P1_POS0008_D_1UL_features.csv: -------------------------------------------------------------------------------- 1 | label,area_filled,perimeter,axis_major_length,axis_minor_length,eccentricity,area,intensity_mean,intensity_max,intensity_min 2 | 1,109.0,37.65685424949238,13.629365239371191,10.512457410218103,0.6364603856338512,109.0,117.77981651376147,212.0,52.0 3 | 2,143.0,48.72792206135785,19.6767737487966,9.77867885096043,0.867770265621355,143.0,103.72727272727273,158.0,46.0 4 | 3,84.0,36.72792206135786,15.43101836645857,7.421959729948362,0.8767333968009052,84.0,98.75,220.0,49.0 5 | 4,173.0,48.970562748477136,18.13862032188627,12.703831131471226,0.7137753507959774,173.0,121.3757225433526,246.0,47.0 6 | 5,295.0,65.01219330881975,22.083029608596384,17.768505777368564,0.5937864877425361,295.0,98.07118644067796,194.0,53.0 7 | 6,281.0,62.2842712474619,20.72226502393676,17.61609184857258,0.5266139465508964,281.0,99.20284697508897,210.0,45.0 8 | 7,192.0,50.2842712474619,16.232099102112343,15.212708858797534,0.34879481807053386,192.0,93.95833333333333,153.0,48.0 9 | 8,267.0,60.8700576850888,22.952715208487387,14.882662509102678,0.7612953099391043,267.0,114.43820224719101,239.0,48.0 10 | 9,166.0,46.04163056034261,15.950426193095431,13.316820742242786,0.5504197392927053,166.0,82.2710843373494,177.0,51.0 11 | 10,70.0,33.69238815542512,14.634959535729871,6.398915740409109,0.8993473200662688,70.0,99.38571428571429,175.0,54.0 12 | 11,224.0,52.62741699796952,17.67548888718684,16.132194273834244,0.4086586445311588,224.0,112.78571428571429,175.0,53.0 13 | 12,335.0,66.2842712474619,21.423777112965976,20.01617893414562,0.3564945950824057,335.0,108.4089552238806,217.0,45.0 14 | 13,246.0,57.45584412271571,18.994251268256235,16.804701949972397,0.46611207197682836,246.0,97.26829268292683,178.0,49.0 15 | 14,78.0,37.31370849898476,16.90169111035597,6.257053666210887,0.928950953528843,78.0,80.8076923076923,127.0,54.0 16 | 15,279.0,61.11269837220809,20.365187827634994,17.81969691077528,0.48410893456136606,279.0,100.01075268817205,172.0,50.0 17 | 16,274.0,61.11269837220809,20.606157580940327,17.197391494785492,0.550893782221845,274.0,102.2919708029197,180.0,46.0 18 | 17,294.0,62.2842712474619,20.909980629312955,17.93970224048438,0.5137344459676589,294.0,105.63945578231292,179.0,45.0 19 | 18,263.0,63.49137802864845,19.42304121298573,17.701795807925375,0.4115631126705414,263.0,92.83269961977186,160.0,45.0 20 | 19,293.0,62.87005768508881,23.856366682694187,15.71981276840273,0.7521992309976239,293.0,113.25597269624573,206.0,46.0 21 | 20,185.0,47.798989873223334,17.276561032971994,13.655103660051875,0.6126127578950092,185.0,116.65945945945946,184.0,44.0 22 | 21,289.0,60.2842712474619,19.936135891786456,18.463256402410387,0.37722876134372335,289.0,120.17647058823529,220.0,50.0 23 | 22,268.0,58.87005768508881,20.033089276673593,17.11504697065154,0.5197163508718582,268.0,108.18283582089552,223.0,48.0 24 | 23,278.0,60.8700576850888,20.463169117463668,17.453064714038284,0.5220720973116023,278.0,108.36690647482014,210.0,43.0 25 | 24,57.0,25.31370849898476,9.223863721922156,7.873268633098017,0.5209683528414869,57.0,104.6140350877193,169.0,48.0 26 | 25,303.0,62.87005768508881,21.157128957424504,18.408439336425744,0.49290681419836424,303.0,114.31353135313532,205.0,44.0 27 | 26,201.0,51.45584412271572,17.11146147237937,15.07134407843613,0.47353537289166625,201.0,97.91044776119404,218.0,53.0 28 | 27,94.0,34.72792206135785,12.607604576709928,9.543963457631236,0.6534142516400798,94.0,86.2872340425532,111.0,50.0 29 | 28,291.0,61.698484809834994,20.15489008189771,18.509525927729268,0.3957366829877648,291.0,108.3573883161512,208.0,46.0 30 | 29,315.0,66.5269119345812,23.17970661066203,17.527995449340512,0.6543654158070359,315.0,97.68571428571428,171.0,48.0 31 | 30,367.0,70.2842712474619,24.4739287809634,19.17970083626873,0.6211661852456396,367.0,94.19346049046321,153.0,53.0 32 | 31,263.0,61.73401871576773,20.45589395487585,16.670534870158633,0.5795309926861588,263.0,99.34600760456274,188.0,50.0 33 | 32,295.0,63.59797974644666,21.917148797616207,17.293171805980528,0.6143614726784883,295.0,108.51525423728813,213.0,49.0 34 | 33,277.0,60.2842712474619,21.184332757914227,16.75021075496172,0.6122185166268554,277.0,110.68231046931407,248.0,49.0 35 | 34,165.0,45.798989873223334,15.663462046446218,13.463557480981372,0.511048578822789,165.0,80.16363636363636,119.0,56.0 36 | 35,261.0,58.04163056034261,20.330059281637375,16.425882222778114,0.5892368286471019,261.0,115.04214559386973,221.0,47.0 37 | 36,257.0,56.8700576850888,18.42603320650069,17.78170158587186,0.2621341183860916,257.0,128.46303501945525,221.0,44.0 38 | 37,291.0,61.698484809834994,20.371852968395846,18.24721931448694,0.44464397666638455,291.0,116.5807560137457,224.0,45.0 39 | 38,314.0,63.698484809834994,20.421440286153686,19.688130712384968,0.26557140862372147,314.0,105.94904458598727,204.0,49.0 40 | 39,328.0,64.76955262170047,21.23255282622715,19.744010085868695,0.36782920191338253,328.0,109.14634146341463,168.0,47.0 41 | 40,116.0,38.384776310850235,12.98375609640506,11.451649237419407,0.4712528108383559,116.0,90.34482758620689,127.0,51.0 42 | 41,309.0,64.04163056034261,21.3079730757928,18.63509122815966,0.4849181405765812,309.0,105.84466019417475,181.0,53.0 43 | 42,341.0,69.11269837220809,21.551317647631254,20.38037024833176,0.32513673286450756,341.0,112.20821114369501,193.0,46.0 44 | 43,249.0,60.62741699796952,20.11076659701443,16.982087960241127,0.5356695762821838,249.0,109.50602409638554,224.0,44.0 45 | 44,157.0,51.21320343559643,18.554026769209443,11.749572067323685,0.7739369628360988,157.0,75.53503184713375,121.0,49.0 46 | 45,311.0,71.35533905932738,22.40629198842821,18.60224727479215,0.5574295215411984,311.0,106.85530546623794,225.0,38.0 47 | 46,57.0,25.31370849898476,8.695424947709531,8.319374488095828,0.29090130400988434,57.0,93.3157894736842,133.0,60.0 48 | 47,266.0,58.62741699796952,20.801546451933742,16.325940194797674,0.61969513757666,266.0,118.62781954887218,251.0,46.0 49 | 48,150.0,43.21320343559643,14.150862969457561,13.509338724570878,0.2976811144377792,150.0,84.89333333333333,149.0,55.0 50 | 49,457.0,99.59797974644665,39.32491480595294,17.032758743063887,0.901331969712448,457.0,103.91684901531728,236.0,46.0 51 | 50,156.0,48.520815280171306,19.07923917249491,10.856047623713467,0.8223389532002635,156.0,106.62179487179488,183.0,48.0 52 | 51,185.0,48.04163056034262,16.384090606466128,14.436694283533736,0.47285357732184236,185.0,108.85405405405406,163.0,50.0 53 | 52,327.0,67.4558441227157,22.268109039558407,19.139211075300693,0.5111530105754707,327.0,99.27217125382263,162.0,47.0 54 | 53,232.0,54.87005768508881,19.341954082085213,15.358672217561885,0.6078393729706075,232.0,145.04741379310346,254.0,37.0 55 | 54,364.0,71.35533905932738,25.474359669295772,18.53777760275321,0.68589196857869,364.0,107.15934065934066,178.0,43.0 56 | 55,52.0,23.899494936611664,8.215298184506453,8.038369524685004,0.20641984661685955,52.0,103.61538461538461,153.0,53.0 57 | 56,452.0,84.18376618407356,32.96565416454177,17.84851771805288,0.840747325434632,452.0,111.19690265486726,255.0,45.0 58 | 57,84.0,32.14213562373095,10.804541925010126,9.921401584030631,0.39597307637667867,84.0,88.19047619047619,156.0,53.0 59 | 58,593.0,95.84062043356595,37.486889545932,20.370421476707364,0.8394731175936277,593.0,101.44350758853288,206.0,44.0 60 | 59,10.0,9.207106781186548,7.182900436301448,1.7680331790383554,0.969233081198103,10.0,77.0,92.0,67.0 61 | 60,331.0,66.5269119345812,22.34178836973517,18.94329670925566,0.5301780732948306,331.0,108.01510574018127,167.0,50.0 62 | 61,174.0,47.798989873223334,15.68366929385986,14.26795843743301,0.4151928057569167,174.0,89.27011494252874,116.0,48.0 63 | 62,549.0,100.08326112068522,39.434568882339484,19.203148758283138,0.8734229837843683,549.0,101.52094717668488,255.0,46.0 64 | 63,360.0,70.18376618407356,25.08786224245971,18.444873695263638,0.6778382572175127,360.0,96.78611111111111,245.0,50.0 65 | 64,137.0,41.798989873223334,14.077236629473955,12.419569600176107,0.4707908393560076,137.0,93.77372262773723,175.0,51.0 66 | 65,562.0,88.18376618407356,30.31561094975782,23.94951094477536,0.613099264026446,562.0,115.50533807829181,255.0,43.0 67 | 66,136.0,40.384776310850235,13.599004748923157,12.711856327541328,0.3552700092942855,136.0,106.23529411764706,172.0,48.0 68 | 67,419.0,74.76955262170047,23.37299935436705,22.87287271786293,0.2057605122341006,419.0,125.472553699284,255.0,44.0 69 | 68,295.0,63.11269837220809,22.36086668149349,17.056944214455203,0.646630524736855,295.0,102.9457627118644,197.0,46.0 70 | 69,75.0,34.48528137423857,15.390718007346656,6.423050443217243,0.9087537554818249,75.0,104.33333333333333,161.0,48.0 71 | 70,85.0,38.72792206135786,16.214728518147286,7.161040633749652,0.8971933221557351,85.0,111.15294117647059,237.0,45.0 72 | -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f9620/20P1_POS0008_D_1UL_labels.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f9620/20P1_POS0008_D_1UL_labels.tif -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f9620/20P1_POS0010_D_1UL.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f9620/20P1_POS0010_D_1UL.tif -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f9620/20P1_POS0010_D_1UL_features.csv: -------------------------------------------------------------------------------- 1 | label,area_filled,perimeter,axis_major_length,axis_minor_length,eccentricity,area,intensity_mean,intensity_max,intensity_min 2 | 1,19.0,14.82842712474619,8.70571500132014,2.9171382022212673,0.9421885683055246,19.0,84.05263157894737,138.0,50.0 3 | 2,142.0,43.31370849898476,15.862859958723652,11.769689688945913,0.6704384213877176,142.0,112.19718309859155,206.0,37.0 4 | 3,211.0,63.66295090390226,23.956579811919244,13.043426690715712,0.8387860692377206,211.0,89.7867298578199,197.0,39.0 5 | 4,415.0,82.56244584051393,29.877496924052796,18.472112653390052,0.7859722927225076,415.0,101.27469879518073,217.0,36.0 6 | 5,265.0,59.21320343559643,20.958000402615113,16.1748222516775,0.6358979364260025,265.0,97.96981132075472,191.0,42.0 7 | 6,158.0,44.384776310850235,15.57976283271431,12.963880955649284,0.5546294532372438,158.0,94.25316455696202,149.0,34.0 8 | 7,529.0,86.66904755831214,31.55716081991891,21.601676495903064,0.7289890587536461,529.0,114.71266540642722,242.0,33.0 9 | 8,84.0,32.14213562373095,10.903445129781131,9.837530981965264,0.431232978989642,84.0,69.25,87.0,53.0 10 | 9,8.0,6.0,6.0,1.7320508075688772,0.9574271077563381,8.0,80.875,109.0,56.0 11 | 10,243.0,56.87005768508881,20.256693889704525,15.3475149501766,0.6526593074976904,243.0,111.01646090534979,220.0,42.0 12 | 11,359.0,75.18376618407356,25.095353318610794,19.319668720292356,0.6382243371822602,359.0,118.73259052924791,226.0,33.0 13 | 12,259.0,60.04163056034261,20.8211033937806,16.04165087000117,0.6374985859021041,259.0,103.6911196911197,244.0,37.0 14 | 13,144.0,43.798989873223334,17.073226408274525,10.84608943634433,0.7722910389005063,144.0,98.67361111111111,180.0,36.0 15 | 14,197.0,50.62741699796952,16.626745764756063,15.14492792421293,0.4126769386803772,197.0,99.84771573604061,192.0,40.0 16 | 15,136.0,40.97056274847714,13.519890590284138,12.851181651717146,0.31060559990160513,136.0,91.78676470588235,166.0,49.0 17 | 16,177.0,48.04163056034262,17.5119131108183,12.871929347680275,0.678025432597417,177.0,89.80790960451978,199.0,43.0 18 | 17,261.0,57.4558441227157,18.52076952112377,17.95340373053131,0.2456208750597913,261.0,120.727969348659,255.0,35.0 19 | 18,231.0,54.62741699796952,19.285179575640566,15.312605324719494,0.6079060584079433,231.0,105.2034632034632,193.0,42.0 20 | 19,273.0,60.04163056034261,20.474680543437486,17.100462730617338,0.5499456169760231,273.0,115.26739926739927,227.0,30.0 21 | 20,250.0,58.87005768508881,20.99105472376032,15.256249787680442,0.6868516130306885,250.0,122.276,240.0,29.0 22 | 21,149.0,43.798989873223334,14.871672499490733,12.769481319954963,0.5125714065520613,149.0,102.36912751677852,187.0,44.0 23 | 22,258.0,59.11269837220809,19.901747536256014,16.743999649581678,0.5405169337807809,258.0,117.96511627906976,255.0,30.0 24 | 23,57.0,25.31370849898476,9.382285928428816,7.713222035406911,0.5693362307226644,57.0,64.80701754385964,90.0,53.0 25 | 24,216.0,54.2842712474619,19.991179696389946,13.873022707326784,0.7200162712840915,216.0,101.12962962962963,218.0,48.0 26 | 25,497.0,94.91168824543142,30.789773748487363,22.86566251480186,0.6696928299925291,497.0,98.1327967806841,192.0,41.0 27 | 26,199.0,51.45584412271571,18.82086050643218,13.490769461554958,0.69728010049418,199.0,98.321608040201,156.0,37.0 28 | 27,378.0,78.18376618407356,23.974224924593276,21.90796849154909,0.4061342534184665,378.0,105.77777777777777,185.0,34.0 29 | 28,154.0,44.384776310850235,16.133700262841188,12.237731532272903,0.6516499612865873,154.0,81.91558441558442,139.0,50.0 30 | 29,247.0,59.45584412271571,20.92281799695628,15.46365644531807,0.6736166061994963,247.0,127.5506072874494,255.0,30.0 31 | 30,243.0,55.45584412271571,19.211647227373863,16.114931435999495,0.5444234963676874,243.0,118.18930041152264,230.0,30.0 32 | 31,304.0,62.87005768508881,22.00635035142551,17.689461466658543,0.5948531371408806,304.0,99.42763157894737,186.0,31.0 33 | 32,292.0,62.52691193458118,21.70324110655748,17.25797188079634,0.6063741433041002,292.0,128.4931506849315,255.0,33.0 34 | 33,282.0,59.698484809834994,20.116247354478666,17.871545058537755,0.45904412790075355,282.0,109.80496453900709,177.0,39.0 35 | 34,554.0,86.42640687119285,28.016647653990866,25.327207374274753,0.4275205381223548,554.0,110.10830324909747,216.0,45.0 36 | 35,298.0,61.698484809834994,20.279652497951712,18.70739506467335,0.3860659444137337,298.0,87.61744966442953,135.0,48.0 37 | 36,205.0,54.62741699796952,19.562139267049325,13.998856734264615,0.6985003567208035,205.0,83.26829268292683,209.0,31.0 38 | 37,265.0,59.11269837220809,18.765179104747965,18.240863851322587,0.2347360847871957,265.0,123.39622641509433,242.0,33.0 39 | 38,291.0,60.2842712474619,20.752787534969283,17.871671861508336,0.5083175621560311,291.0,124.08934707903781,231.0,33.0 40 | 39,213.0,52.04163056034261,18.02103339352882,15.080097536073026,0.547500475740198,213.0,90.63849765258216,191.0,39.0 41 | 40,198.0,49.798989873223334,16.84610150790051,15.00153063619277,0.4549742670390384,198.0,98.47979797979798,206.0,44.0 42 | 41,305.0,62.8700576850888,21.273429768477772,18.37972204338137,0.5035338535780313,305.0,96.75081967213114,178.0,38.0 43 | 42,292.0,60.87005768508881,20.085498401623664,18.541642187194956,0.38447410310182795,292.0,111.84931506849315,194.0,42.0 44 | 43,90.0,32.72792206135786,11.810909300650222,9.67821541352431,0.5731790268749206,90.0,85.4888888888889,143.0,48.0 45 | 44,256.0,57.698484809834994,18.47598166275451,17.818650693446436,0.2643660762634256,256.0,120.2265625,229.0,30.0 46 | 45,241.0,54.62741699796952,18.790140829685186,16.349904434327048,0.49281858031357645,241.0,108.7759336099585,221.0,31.0 47 | 46,252.0,56.87005768508881,19.05459973052174,16.853251331940303,0.46659412735935835,252.0,107.28174603174604,163.0,38.0 48 | 47,95.0,39.31370849898477,16.900949833164937,7.518354272680232,0.895606067644247,95.0,97.9578947368421,196.0,46.0 49 | 48,233.0,55.45584412271571,18.6206857130224,15.96606815768475,0.5145886615731912,233.0,104.57081545064378,186.0,41.0 50 | 49,237.0,56.38477631085023,20.907165962427396,14.515685084741008,0.7196930963027758,237.0,132.83966244725738,255.0,26.0 51 | 50,242.0,58.52691193458119,20.606575944497067,15.137116481683202,0.6785253490587674,242.0,92.30578512396694,160.0,36.0 52 | 51,215.0,51.79898987322333,17.718544852931306,15.468735162821027,0.48767519807636917,215.0,96.07906976744187,163.0,47.0 53 | 52,243.0,55.45584412271571,18.145214334865663,17.09880624578812,0.334681082235427,243.0,114.10699588477367,221.0,40.0 54 | 53,277.0,61.11269837220809,20.764608985243626,17.0763247224743,0.5689437845407236,277.0,109.51985559566786,203.0,35.0 55 | 54,51.0,31.313708498984763,14.103260643706253,4.966632219290216,0.9359390677371746,51.0,79.90196078431373,116.0,48.0 56 | 55,272.0,63.4558441227157,24.758735370076632,14.086072425247785,0.8223835744691679,272.0,96.72426470588235,183.0,46.0 57 | 56,5.0,5.207106781186548,3.098386676965933,1.7888543819998317,0.816496580927726,5.0,74.2,77.0,70.0 58 | 57,260.0,58.62741699796952,20.44613951717555,16.282938219776078,0.6047938925968442,260.0,110.41153846153846,226.0,38.0 59 | 58,277.0,60.8700576850888,19.248964009852166,18.445807391699333,0.285846788745925,277.0,107.4043321299639,226.0,41.0 60 | 59,299.0,66.2842712474619,26.57593889316687,14.38051429584095,0.8409516288527966,299.0,94.11036789297658,181.0,38.0 61 | 60,294.0,62.526911934581186,20.45569509804618,18.403094594125758,0.43659887146729265,294.0,94.34693877551021,153.0,48.0 62 | 61,344.0,69.11269837220809,22.027630197638995,20.216880534644897,0.39705125393996615,344.0,87.49709302325581,140.0,41.0 63 | 62,126.0,42.04163056034261,16.86426347980293,9.636201557061273,0.820673293941958,126.0,71.72222222222223,102.0,35.0 64 | 63,61.0,33.384776310850235,14.641432533666379,5.992458643272826,0.9124084322327877,61.0,71.27868852459017,101.0,46.0 65 | 64,134.0,43.79898987322333,17.225134039461057,10.14695063444193,0.8080760460447325,134.0,68.21641791044776,96.0,44.0 66 | 65,235.0,55.45584412271571,18.160405661931886,16.685049713430843,0.3948170805377721,235.0,88.66382978723404,148.0,0.0 67 | 66,327.0,68.2842712474619,24.47078952094854,17.373904850437576,0.7042163311277622,327.0,89.60244648318043,163.0,35.0 68 | 67,147.0,44.04163056034261,14.850251793517293,12.670823057900195,0.5215190954031477,147.0,74.68707482993197,107.0,52.0 69 | 68,283.0,62.14213562373095,19.318617744660695,19.04851037583855,0.1666371438109183,283.0,117.79858657243817,255.0,32.0 70 | 69,50.0,27.44974746830583,11.721452294726985,5.745220283195369,0.8716404776365555,50.0,77.14,128.0,50.0 71 | 70,35.0,23.86396103067893,11.616297621241845,4.045102478865893,0.9374104308005388,35.0,83.6,128.0,48.0 72 | -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f9620/20P1_POS0010_D_1UL_labels.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f9620/20P1_POS0010_D_1UL_labels.tif -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f9620/20P1_POS0011_D_1UL.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f9620/20P1_POS0011_D_1UL.tif -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f9620/20P1_POS0011_D_1UL_features.csv: -------------------------------------------------------------------------------- 1 | label,area_filled,perimeter,axis_major_length,axis_minor_length,eccentricity,area,intensity_mean,intensity_max,intensity_min 2 | 1,25.0,16.82842712474619,7.554136610795001,4.235920214716824,0.8279907159480056,25.0,85.76,111.0,66.0 3 | 2,138.0,43.89949493661166,17.30245594741157,10.393231600152776,0.7994898798308376,138.0,96.96376811594203,156.0,46.0 4 | 3,222.0,54.04163056034261,18.287589593760483,15.678520161464927,0.5147652906524057,222.0,122.7927927927928,224.0,51.0 5 | 4,213.0,51.79898987322333,18.06427914339276,15.161692854983652,0.5436392208325289,213.0,82.87793427230046,116.0,56.0 6 | 5,388.0,75.94112549695427,28.371063573035652,18.109442828337272,0.7697820651874167,388.0,117.79123711340206,255.0,41.0 7 | 6,376.0,78.08326112068524,24.297268833685848,20.481920551059286,0.5379572305097163,376.0,121.04521276595744,217.0,38.0 8 | 7,254.0,59.45584412271571,21.858381003655367,14.966505519634612,0.728821923635024,254.0,109.35826771653544,187.0,48.0 9 | 8,495.0,84.32590180780451,27.802578084744535,23.416077443904346,0.5391233183818116,495.0,129.87676767676768,210.0,53.0 10 | 9,228.0,71.35533905932738,29.21204346495392,11.394679745933386,0.920786105546715,228.0,79.34649122807018,125.0,50.0 11 | 10,405.0,72.76955262170047,24.772076126954754,20.81817799831883,0.5419838408837543,405.0,144.89876543209877,255.0,52.0 12 | 11,363.0,78.9116882454314,25.573798022230676,19.016277954180552,0.6686420564076543,363.0,106.28374655647383,177.0,50.0 13 | 12,216.0,52.87005768508881,18.34033174469662,15.038389227629693,0.5724168543471468,216.0,125.56944444444444,255.0,41.0 14 | 13,392.0,82.18376618407356,27.99314254677864,18.613284441342973,0.7469119080480507,392.0,112.44897959183673,211.0,46.0 15 | 14,249.0,56.62741699796952,18.763364410940166,16.97959748199039,0.42555295417037775,249.0,122.0,226.0,39.0 16 | 15,429.0,83.01219330881975,28.204921260011,20.713494531743905,0.6787245659985865,429.0,121.25407925407926,212.0,42.0 17 | 16,215.0,54.04163056034261,19.43586061632386,14.132591979786868,0.6864891831694103,215.0,123.53023255813953,215.0,49.0 18 | 17,8.0,8.414213562373096,4.898979485566356,1.9364916731037085,0.9185586535436918,8.0,86.875,111.0,62.0 19 | 18,1000.0,125.53910524340094,42.62483338921564,31.64296564074877,0.6700013642081165,1000.0,136.614,242.0,50.0 20 | 19,9.0,8.0,3.265986323710904,3.265986323710904,0.0,9.0,78.33333333333333,88.0,67.0 21 | 20,229.0,54.04163056034261,17.643730093264224,16.65728017372368,0.3296860499085623,229.0,118.62445414847161,255.0,50.0 22 | 21,792.0,104.08326112068522,36.20508625052358,27.939372287093754,0.6359898307550669,792.0,146.15656565656565,255.0,33.0 23 | 22,243.0,55.798989873223334,18.579481259296248,16.707262976480173,0.43747219126848025,243.0,111.43621399176955,168.0,54.0 24 | 23,222.0,53.698484809834994,17.783754147927528,16.047442514914156,0.4309720161937022,222.0,127.97747747747748,237.0,38.0 25 | 24,166.0,45.21320343559643,15.082057688231655,14.013978830509522,0.3696221408794132,166.0,92.59638554216868,146.0,57.0 26 | 25,257.0,58.04163056034261,19.96269244360621,16.467114158387574,0.565286785721396,257.0,111.45525291828794,201.0,46.0 27 | 26,91.0,35.89949493661166,14.248507925464903,8.50347507997887,0.8023918281435402,91.0,96.96703296703296,173.0,57.0 28 | 27,248.0,57.45584412271571,18.16868787504944,17.67791170858874,0.23085652293033376,248.0,118.26612903225806,201.0,41.0 29 | 28,243.0,56.87005768508881,19.82782152522655,15.91192382065352,0.5966455349310713,243.0,103.08641975308642,221.0,56.0 30 | 29,502.0,81.84062043356595,27.23353306228812,23.64165279536375,0.49637504922625114,502.0,129.9641434262948,246.0,31.0 31 | 30,308.0,63.11269837220809,20.227603163594825,19.546837300825235,0.2572506610869287,308.0,143.85714285714286,255.0,37.0 32 | 31,478.0,80.42640687119285,26.77596504900229,22.940135363670414,0.5157426574437067,478.0,127.78033472803347,255.0,48.0 33 | 32,199.0,49.45584412271571,16.966355548702175,14.929916499336567,0.4750257011139753,199.0,104.58793969849246,186.0,46.0 34 | 33,250.0,58.87005768508881,21.085181280109868,15.265059527722265,0.689830419919089,250.0,89.448,140.0,50.0 35 | 34,298.0,63.45584412271571,22.88162133440441,16.656595402115407,0.6856339706134564,298.0,108.27181208053692,188.0,50.0 36 | 35,243.0,56.62741699796952,19.927723480661903,15.60856134569032,0.6216960046588849,243.0,109.65020576131687,216.0,34.0 37 | 36,94.0,33.55634918610404,11.091960041885681,10.813352181395041,0.22272199601773743,94.0,82.34042553191489,125.0,59.0 38 | 37,223.0,54.62741699796952,20.599562827631654,13.813692445745847,0.7418355715993693,223.0,144.7085201793722,253.0,39.0 39 | 38,112.0,36.970562748477136,12.265500372593877,11.612365884100706,0.32196880538542694,112.0,91.6875,131.0,58.0 40 | 39,124.0,40.14213562373095,13.107090859788025,12.327655035024462,0.3397015849329621,124.0,86.66129032258064,117.0,53.0 41 | 40,290.0,61.698484809834994,20.990814531768788,17.697648867786427,0.5377349180367812,290.0,116.61379310344827,201.0,50.0 42 | 41,240.0,55.45584412271571,18.799657375866467,16.281732923570328,0.4999307053622813,240.0,122.55833333333334,216.0,47.0 43 | 42,211.0,55.698484809834994,22.025010164766808,12.385545855406338,0.8269060652145062,211.0,143.61611374407582,255.0,39.0 44 | 43,313.0,64.2842712474619,21.56299086174289,18.6130010677581,0.504875808846551,313.0,120.22683706070288,243.0,48.0 45 | 44,201.0,50.87005768508881,16.383701614246817,15.62996761715104,0.29982286454067936,201.0,140.08457711442787,255.0,51.0 46 | 45,278.0,61.45584412271571,20.315827626778674,17.653258114106023,0.494915468758476,278.0,110.74460431654676,194.0,47.0 47 | 46,294.0,62.04163056034261,21.601338352427064,17.48086431561332,0.5874656092632387,294.0,92.50680272108843,162.0,56.0 48 | 47,283.0,63.4558441227157,23.03937270924534,15.853024453992989,0.7256310121369081,283.0,123.68904593639576,204.0,41.0 49 | 48,517.0,87.35533905932738,33.55179616691229,20.028853747075857,0.8022760235470748,517.0,110.55512572533848,207.0,43.0 50 | 49,262.0,59.45584412271571,22.225977701679078,15.130917741075281,0.7324914321175106,262.0,101.17175572519083,161.0,54.0 51 | 50,80.0,35.10660171779821,14.333130976010843,7.557040189420621,0.8497146720512502,80.0,125.0125,190.0,41.0 52 | 51,291.0,64.2842712474619,20.526392086519614,18.38529964728583,0.44467748930834744,291.0,90.64948453608247,134.0,52.0 53 | 52,510.0,99.63961030678928,38.572261102433025,17.873298486349448,0.886163960366052,510.0,108.99019607843137,254.0,41.0 54 | 53,261.0,59.45584412271571,21.17543780193903,15.929739048727853,0.6588499663448403,261.0,121.57088122605364,227.0,42.0 55 | 54,75.0,30.14213562373095,11.132830701511027,8.572804060538324,0.6379870335055441,75.0,91.33333333333333,131.0,53.0 56 | 55,258.0,57.698484809834994,18.703705053137444,17.629063516777016,0.3340822579764546,258.0,126.40697674418605,235.0,47.0 57 | 56,253.0,57.11269837220809,19.452959756921864,16.581299054969904,0.5229241159820005,253.0,119.87351778656127,214.0,48.0 58 | 57,471.0,82.32590180780451,28.3873197320249,21.636594436130203,0.647350762402546,471.0,117.1995753715499,247.0,51.0 59 | 58,191.0,49.21320343559643,16.26803257377907,14.961441875631614,0.39266038271178144,191.0,118.16753926701571,187.0,53.0 60 | 59,234.0,54.8700576850888,18.477738417533686,16.20498463124787,0.4804895804184689,234.0,123.03418803418803,240.0,33.0 61 | 60,360.0,75.25483399593904,26.424342519561193,17.713311558247025,0.7420534897225219,360.0,110.6361111111111,188.0,43.0 62 | 61,169.0,46.62741699796952,15.457071816757306,13.932506914593795,0.4330543589982288,169.0,117.49704142011835,235.0,47.0 63 | 62,244.0,56.384776310850235,19.14383422958491,16.466657380682328,0.5100333680838635,244.0,134.1639344262295,252.0,49.0 64 | 63,250.0,56.2842712474619,19.370944113321,16.441845035110703,0.5287316593204087,250.0,123.86,223.0,52.0 65 | 64,295.0,61.698484809834994,21.623345839314833,17.535262737560945,0.5851276070587653,295.0,103.22033898305085,155.0,53.0 66 | 65,288.0,63.11269837220809,19.780986452610907,18.789413249760244,0.31263782087418795,288.0,94.86458333333333,159.0,44.0 67 | 66,256.0,57.11269837220809,20.27759082481288,16.100346760558125,0.6079216450529564,256.0,122.06640625,196.0,48.0 68 | 67,211.0,51.21320343559643,16.650822141035853,16.148486509833088,0.24377752030952704,211.0,115.30331753554502,209.0,59.0 69 | 68,295.0,62.2842712474619,21.135020686830106,18.111082794437507,0.5154446409115655,295.0,114.23728813559322,204.0,43.0 70 | 69,632.0,97.25483399593904,32.224709310052134,26.080257490306792,0.5873613148766074,632.0,122.45094936708861,255.0,46.0 71 | 70,257.0,59.45584412271571,19.543125384153193,16.835486292440997,0.5078371057206688,257.0,114.06614785992218,224.0,56.0 72 | 71,22.0,14.242640687119284,5.502816709244202,4.972652484064489,0.4282593998234223,22.0,77.81818181818181,86.0,65.0 73 | 72,434.0,113.39696961966999,35.04697175822254,21.557141368017007,0.7884546905360833,434.0,101.43778801843318,239.0,44.0 74 | 73,79.0,35.31370849898476,15.310551822033366,6.922887518640302,0.8919345793963376,79.0,103.9367088607595,145.0,55.0 75 | 74,1088.0,142.46803743153546,55.12264712611771,25.888969314727163,0.8828467279060028,1088.0,122.90716911764706,232.0,51.0 76 | 75,214.0,72.31980515339464,24.69889035834665,13.04079333585369,0.8492499273331574,214.0,101.7196261682243,200.0,49.0 77 | 76,243.0,57.45584412271571,20.75153424991913,15.020728939793788,0.6899709795189888,243.0,112.16460905349794,201.0,0.0 78 | 77,123.0,39.798989873223334,14.291581640989326,11.006653635587808,0.6378634932061119,123.0,110.86178861788618,170.0,52.0 79 | 78,122.0,38.970562748477136,14.047688271352188,11.171610853420427,0.6062642102049708,122.0,109.89344262295081,156.0,46.0 80 | -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f9620/20P1_POS0011_D_1UL_labels.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/src/napari_clusters_plotter/sample_data/BBBC007_v1_images/f9620/20P1_POS0011_D_1UL_labels.tif -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/cells3d/nucleus.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/src/napari_clusters_plotter/sample_data/cells3d/nucleus.tif -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/shapes_skeleton/blobs.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/src/napari_clusters_plotter/sample_data/shapes_skeleton/blobs.tif -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/tracking_data/LICENSE: -------------------------------------------------------------------------------- 1 | Janelia Open-Source Software 2 | Copyright © 2018 Howard Hughes Medical Institute 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | Neither the name of HHMI nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 9 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 10 | -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/tracking_data/README.md: -------------------------------------------------------------------------------- 1 | The data in this folder may be used as an example dataset for the layer type "tracking data". 2 | 3 | It has been derived from [tgmm-mini](https://github.com/mastodon-sc/mastodon-example-data/tree/master/tgmm-mini) using [Fiji](https://fiji.sc/) with the [Mastodon](https://mastodon.readthedocs.io/en/latest/) and the [Mastodon-Deep-Lineage](https://mastodon.readthedocs.io/en/latest/docs/partC/mastodon_deep_lineage.html) plugin. 4 | 5 | The data is licensed under the conditions in [LICENSE](LICENSE). 6 | -------------------------------------------------------------------------------- /src/napari_clusters_plotter/sample_data/tracking_data/tgmm-mini.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BiAPoL/napari-clusters-plotter/07d38b17f58d1383d9d86448433ad17eee67aa7f/src/napari_clusters_plotter/sample_data/tracking_data/tgmm-mini.tif -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | # For more information about tox, see https://tox.readthedocs.io/en/latest/ 2 | [tox] 3 | envlist = py{39, 310,311,312,313}-{linux,macos,windows} 4 | isolated_build=true 5 | 6 | [gh-actions] 7 | python = 8 | 3.9: py39 9 | 3.10: py310 10 | 3.11: py311 11 | 3.12: py312 12 | 3.13: py313 13 | 14 | [gh-actions:env] 15 | PLATFORM = 16 | ubuntu-latest: linux 17 | macos-latest: macos 18 | windows-latest: windows 19 | 20 | [testenv] 21 | platform = 22 | macos: darwin 23 | linux: linux 24 | windows: win32 25 | passenv = 26 | CI 27 | GITHUB_ACTIONS 28 | DISPLAY 29 | XAUTHORITY 30 | NUMPY_EXPERIMENTAL_ARRAY_FUNCTION 31 | PYVISTA_OFF_SCREEN 32 | extras = 33 | testing 34 | commands = pytest -v --color=yes --cov=napari_clusters_plotter --cov-report=xml 35 | --------------------------------------------------------------------------------