diff --git a/.github/actions/nf-test/action.yml b/.github/actions/nf-test/action.yml index 3b9724c7..7964ef2b 100644 --- a/.github/actions/nf-test/action.yml +++ b/.github/actions/nf-test/action.yml @@ -37,7 +37,7 @@ runs: - name: Setup apptainer if: contains(inputs.profile, 'singularity') - uses: eWaterCycle/setup-apptainer@main + uses: eWaterCycle/setup-apptainer@3f706d898c9db585b1d741b4692e66755f3a1b40 # v2.0.0 - name: Set up Singularity if: contains(inputs.profile, 'singularity') diff --git a/.github/workflows/branch.yml b/.github/workflows/branch.yml index 9a789de4..b1fcf88e 100644 --- a/.github/workflows/branch.yml +++ b/.github/workflows/branch.yml @@ -2,11 +2,13 @@ name: nf-core branch protection # This workflow is triggered on PRs to `main`/`master` branch on the repository # It fails when someone tries to make a PR against the nf-core `main`/`master` branch instead of `dev` on: - pull_request_target: + pull_request: branches: - main - master +permissions: {} + jobs: test: runs-on: ubuntu-latest @@ -14,33 +16,47 @@ jobs: # PRs to the nf-core repo main/master branch are only ok if coming from the nf-core repo `dev` or any `patch` branches - name: Check PRs if: github.repository == 'nf-core/spatialaxe' + env: + HEAD_REPO: ${{ github.event.pull_request.head.repo.full_name }} run: | - { [[ ${{github.event.pull_request.head.repo.full_name }} == nf-core/spatialaxe ]] && [[ $GITHUB_HEAD_REF == "dev" ]]; } || [[ $GITHUB_HEAD_REF == "patch" ]] + { [[ "$HEAD_REPO" == nf-core/spatialaxe ]] && [[ $GITHUB_HEAD_REF == "dev" ]]; } || [[ $GITHUB_HEAD_REF == "patch" ]] - # If the above check failed, post a comment on the PR explaining the failure - # NOTE - this doesn't currently work if the PR is coming from a fork, due to limitations in GitHub actions secrets - - name: Post PR comment + # If the above check failed, build a comment to be posted by the shared poster workflow + - name: Build PR comment if: failure() - uses: mshick/add-pr-comment@8e4927817251f1ff60c001f04568532b38e0b4a0 # v3 - with: - message: | - ## This PR is against the `${{github.event.pull_request.base.ref}}` branch :x: + env: + PR_NUMBER: ${{ github.event.pull_request.number }} + BASE_REF: ${{ github.event.pull_request.base.ref }} + HEAD_REPO: ${{ github.event.pull_request.head.repo.full_name }} + PR_USER: ${{ github.event.pull_request.user.login }} + run: | + mkdir -p pr-comment + echo "$PR_NUMBER" > pr-comment/pr_number.txt + echo "branch" > pr-comment/header.txt + cat > pr-comment/comment.md < pr-comment/pr_number.txt + echo "lint" > pr-comment/header.txt + [ -f lint_results.md ] && cp lint_results.md pr-comment/comment.md || true + + - name: Upload PR comment artifact + if: ${{ always() }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: pr-comment + path: pr-comment/ diff --git a/.github/workflows/linting_comment.yml b/.github/workflows/linting_comment.yml deleted file mode 100644 index 5b0c24f7..00000000 --- a/.github/workflows/linting_comment.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: nf-core linting comment -# This workflow is triggered after the linting action is complete -# It posts an automated comment to the PR, even if the PR is coming from a fork - -on: - workflow_run: - workflows: ["nf-core linting"] - -jobs: - test: - runs-on: ubuntu-latest - steps: - - name: Download lint results - uses: dawidd6/action-download-artifact@b6e2e70617bc3265edd6dab6c906732b2f1ae151 # v21 - with: - workflow: linting.yml - workflow_conclusion: completed - - - name: Get PR number - id: pr_number - run: echo "pr_number=$(cat linting-logs/PR_number.txt)" >> $GITHUB_OUTPUT - - - name: Post PR comment - uses: marocchino/sticky-pull-request-comment@70d2764d1a7d5d9560b100cbea0077fc8f633987 # v3 - with: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - number: ${{ steps.pr_number.outputs.pr_number }} - path: linting-logs/lint_results.md diff --git a/.github/workflows/nf-test.yml b/.github/workflows/nf-test.yml index 410a24c3..5dc5a547 100644 --- a/.github/workflows/nf-test.yml +++ b/.github/workflows/nf-test.yml @@ -119,6 +119,22 @@ jobs: fi fi + # continue-on-error keeps latest-everything from failing the job, so it never shows up in + # `needs.nf-test.result` downstream and CI stays green. Surface it via a PR comment instead; + # other NXF_VER failures already fail the job/CI directly, so no comment is needed for those. + - name: Prepare PR comment fragment + if: ${{ always() && steps.run_nf_test.outcome == 'failure' && matrix.NXF_VER == 'latest-everything' }} + run: | + mkdir -p pr-comment-fragment + echo "* ❌ \`${{ matrix.profile }}\` | \`${{ matrix.NXF_VER }}\` | Shard ${{ matrix.shard }}/${{ env.TOTAL_SHARDS }}" > pr-comment-fragment/fragment.md + + - name: Upload PR comment fragment + if: ${{ always() && steps.run_nf_test.outcome == 'failure' && matrix.NXF_VER == 'latest-everything' }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: pr-comment-fragment-${{ strategy.job-index }} + path: pr-comment-fragment/ + confirm-pass: needs: [nf-test] if: always() @@ -145,3 +161,44 @@ jobs: echo "DEBUG: toJSON(needs) = ${{ toJSON(needs) }}" echo "DEBUG: toJSON(needs.*.result) = ${{ toJSON(needs.*.result) }}" echo "::endgroup::" + + - name: Download PR comment fragments + if: ${{ always() }} + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + continue-on-error: true + with: + pattern: pr-comment-fragment-* + path: pr-comment-fragments + merge-multiple: true + + # Build a comment for the shared pr-comment.yml poster to publish on the PR. + # Based on the fragments above (not needs.*.result) so non-blocking failures are still reported. + - name: Prepare PR comment + if: ${{ always() }} + env: + PR_NUMBER: ${{ github.event.pull_request.number }} + RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + run: | + mkdir -p pr-comment + echo "$PR_NUMBER" > pr-comment/pr_number.txt + echo "nf-test" > pr-comment/header.txt + if [ -d pr-comment-fragments ] && [ -n "$(ls -A pr-comment-fragments)" ]; then + { + echo "## ❌ nf-test failed with latest Nextflow version" + echo "" + echo "> [!NOTE]" + echo "> Tests with Nextflow's latest version failed but it will not cause a CI workflow failure." + echo "> Please check if the failure is expected with newer (edge-)releases of Nextflow or if it needs fixing." + echo "" + cat pr-comment-fragments/*.md + echo "" + echo "See the [full run](${RUN_URL}) for details." + } > pr-comment/comment.md + fi + + - name: Upload PR comment artifact + if: ${{ always() }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: pr-comment + path: pr-comment/ diff --git a/.github/workflows/pr-comment.yml b/.github/workflows/pr-comment.yml new file mode 100644 index 00000000..ab7b59dd --- /dev/null +++ b/.github/workflows/pr-comment.yml @@ -0,0 +1,82 @@ +name: Post PR comment +# Shared, privileged comment poster. +# +# This is the single workflow that runs with a write token. It is triggered +# after any of the listed "producer" workflows complete on a pull request. +# Each producer runs untrusted PR code (if any) with a read-only token and +# uploads a `pr-comment` artifact describing the comment to post; this workflow +# only ever reads that plain-text artifact, so no PR code is executed here. +# +# Artifact contract (uploaded by producers under the name `pr-comment`): +# pr_number.txt - the pull request number +# header.txt - sticky-comment identifier (keeps comment types separate) +# comment.md - the Markdown body (omit the file to post nothing) + +on: + workflow_run: + workflows: + - "nf-core linting" + - "nf-core template version comment" + - "nf-core branch protection" + - "Run nf-test" + +permissions: + actions: read + contents: read + pull-requests: write + +jobs: + post-comment: + runs-on: ubuntu-latest + if: github.event.workflow_run.event == 'pull_request' + steps: + - name: Download PR comment artifact + uses: dawidd6/action-download-artifact@b6e2e70617bc3265edd6dab6c906732b2f1ae151 # v21 + with: + run_id: ${{ github.event.workflow_run.id }} + name: pr-comment + path: pr-comment + if_no_artifact_found: ignore + + - name: Read comment metadata + id: meta + run: | + echo "::group::Downloaded pr-comment contents" + ls -la pr-comment 2>/dev/null || echo "No pr-comment/ directory was downloaded." + echo "::endgroup::" + + if [ ! -d pr-comment ]; then + echo "No pr-comment artifact found; nothing to post." + exit 0 + fi + + if [ ! -f pr-comment/comment.md ]; then + echo "Artifact present but no comment.md; nothing to post." + exit 0 + fi + + pr_number=$(cat pr-comment/pr_number.txt) + header=$(cat pr-comment/header.txt) + echo "Found comment.md (header='$header', pr_number='$pr_number')." + + # Guard against anything unexpected ending up in the PR number. + case "$pr_number" in + ''|*[!0-9]*) + echo "Invalid PR number: '$pr_number'" + exit 1 + ;; + esac + + echo "pr_number=$pr_number" >> "$GITHUB_OUTPUT" + echo "header=$header" >> "$GITHUB_OUTPUT" + echo "post=true" >> "$GITHUB_OUTPUT" + echo "Will post comment to PR #${pr_number}." + + - name: Post PR comment + if: steps.meta.outputs.post == 'true' + uses: marocchino/sticky-pull-request-comment@5770ad5eb8f42dd2c4f34da00c94c5381e49af88 # v3.0.5 + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + number: ${{ steps.meta.outputs.pr_number }} + header: ${{ steps.meta.outputs.header }} + path: pr-comment/comment.md diff --git a/.github/workflows/release-announcements.yml b/.github/workflows/release-announcements.yml index 431d3d44..abc44c92 100644 --- a/.github/workflows/release-announcements.yml +++ b/.github/workflows/release-announcements.yml @@ -18,7 +18,7 @@ jobs: id: get_description run: | echo "description=$(curl -s https://nf-co.re/pipelines.json | jq -r '.remote_workflows[] | select(.full_name == "${{ github.repository }}") | .description')" >> $GITHUB_OUTPUT - - uses: rzr/fediverse-action@master + - uses: rzr/fediverse-action@66c2cbb5b1997666b0e28d597631b6a4f09a2719 # v0.0.6 with: access-token: ${{ secrets.MASTODON_ACCESS_TOKEN }} host: "mstdn.science" # custom host if not "mastodon.social" (default) diff --git a/.github/workflows/template-version-comment.yml b/.github/workflows/template-version-comment.yml index e8560fc7..ee102f71 100644 --- a/.github/workflows/template-version-comment.yml +++ b/.github/workflows/template-version-comment.yml @@ -2,14 +2,17 @@ name: nf-core template version comment # This workflow is triggered on PRs to check if the pipeline template version matches the latest nf-core version. # It posts a comment to the PR, even if it comes from a fork. -on: pull_request_target +on: + pull_request: + +permissions: {} jobs: - template_version: + check_template_version: runs-on: ubuntu-latest steps: - name: Check out pipeline code - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: ref: ${{ github.event.pull_request.head.sha }} @@ -22,25 +25,36 @@ jobs: - name: Install nf-core run: | python -m pip install --upgrade pip - pip install nf-core==${{ steps.read_yml.outputs['nf_core_version'] }} + pip install nf-core + + - name: Build PR comment if template is outdated + # The fork-controlled version is passed via the environment and only ever + # used as quoted shell data (never interpolated into a command), so it + # cannot be used for script injection. + env: + PR_VERSION: ${{ steps.read_yml.outputs['nf_core_version'] }} + PR_NUMBER: ${{ github.event.pull_request.number }} + run: | + mkdir -p pr-comment + echo "$PR_NUMBER" > pr-comment/pr_number.txt + echo "template-version" > pr-comment/header.txt + + latest_version=$(nf-core --version | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -n1) - - name: Check nf-core outdated - id: nf_core_outdated - run: echo "OUTPUT=$(pip list --outdated | grep nf-core)" >> ${GITHUB_ENV} + if [ -n "$PR_VERSION" ] && [ -n "$latest_version" ] && [ "$PR_VERSION" != "$latest_version" ]; then + cat > pr-comment/comment.md < [!WARNING] + > Newer version of the nf-core template is available. + > + > Your pipeline is using an old version of the nf-core template: ${PR_VERSION}. + > Please update your pipeline to the latest version. + > + > For more documentation on how to update your pipeline, please see the [Synchronisation documentation](https://nf-co.re/docs/developing/template-syncs/overview). + EOF + fi - - name: Post nf-core template version comment - uses: mshick/add-pr-comment@b8f338c590a895d50bcbfa6c5859251edc8952fc # v2 - if: | - contains(env.OUTPUT, 'nf-core') + - name: Upload PR comment artifact + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: - repo-token: ${{ secrets.NF_CORE_BOT_AUTH_TOKEN }} - allow-repeats: false - message: | - > [!WARNING] - > Newer version of the nf-core template is available. - > - > Your pipeline is using an old version of the nf-core template: ${{ steps.read_yml.outputs['nf_core_version'] }}. - > Please update your pipeline to the latest version. - > - > For more documentation on how to update your pipeline, please see the [nf-core documentation](https://github.com/nf-core/tools?tab=readme-ov-file#sync-a-pipeline-with-the-template) and [Synchronisation documentation](https://nf-co.re/docs/contributing/sync). - # + name: pr-comment + path: pr-comment/ diff --git a/.nf-core.yml b/.nf-core.yml index 1e590ce5..352e6ed3 100644 --- a/.nf-core.yml +++ b/.nf-core.yml @@ -3,13 +3,14 @@ lint: files_exist: - .github/workflows/awsfulltest.yml - .github/workflows/awstest.yml + - .github/workflows/linting_comment.yml files_unchanged: - .gitignore - assets/nf-core-spatialaxe_logo_light.png - docs/images/nf-core-spatialaxe_logo_dark.png - docs/images/nf-core-spatialaxe_logo_light.png - .github/PULL_REQUEST_TEMPLATE.md -nf_core_version: 4.0.2 +nf_core_version: 4.0.3 repository_type: pipeline template: author: Sameesh Kher, Dongze He, Florian Heyl @@ -21,4 +22,4 @@ template: outdir: . skip_features: - igenomes - version: 1.0.0dev + version: 1.0.1dev diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c96b9d5..c3dbe4cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## 1.0.0dev - [date] +## 1.0.1dev - [date] Initial release of nf-core/spatialaxe, created with the [nf-core](https://nf-co.re/) template. @@ -11,6 +11,23 @@ Initial release of nf-core/spatialaxe, created with the [nf-core](https://nf-co. ### `Fixed` +### `Dependencies` + +### `Deprecated` + +## 1.0.1 - [06.08.2026] + +Hotfix to tackle some bugs + +### `Added` + +- Template update for nf-core/tools version 4.0.3 +- Adding new conf/tests folder +- Adding new test for coordinate mode to check the bugfixes +- Remove default outdir='results' for test profiles (tests) + +### `Fixed` + - Only pass `--expansion-distance` to `xeniumranger import-segmentation` for nuclei-based imports. It was applied to every import, but xeniumranger rejects it for transcript-assignment imports (proseg/baysor/segger) and cells-only imports with `ERROR: --expansion-distance requires --nuclei`. - Preserve the URI scheme (e.g. `s3://`) when building Xenium bundle child paths, so bundle validation works when the work directory is on object storage (S3/GCS/Azure). Previously `Path.toString()` dropped the scheme and the resulting path was resolved on the local filesystem, causing `Xenium bundle does not exist` / `NoSuchFileException` failures on AWS Batch. diff --git a/README.md b/README.md index 9bf464aa..d0d3e0e9 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ [![Open in GitHub Codespaces](https://img.shields.io/badge/Open_In_GitHub_Codespaces-black?labelColor=grey&logo=github)](https://github.com/codespaces/new/nf-core/spatialaxe) [![GitHub Actions CI Status](https://github.com/nf-core/spatialaxe/actions/workflows/nf-test.yml/badge.svg)](https://github.com/nf-core/spatialaxe/actions/workflows/nf-test.yml) -[![GitHub Actions Linting Status](https://github.com/nf-core/spatialaxe/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-core/spatialaxe/actions/workflows/linting.yml)[![AWS CI](https://img.shields.io/badge/CI%20tests-full%20size-FF9900?labelColor=000000&logo=Amazon%20AWS)](https://nf-co.re/spatialaxe/results)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX) +[![GitHub Actions Linting Status](https://github.com/nf-core/spatialaxe/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-core/spatialaxe/actions/workflows/linting.yml)[![AWS CI](https://img.shields.io/badge/CI%20tests-full%20size-FF9900?labelColor=000000&logo=Amazon%20AWS)](https://nf-co.re/spatialaxe/results)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.20733817-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.20733817) [![nf-test](https://img.shields.io/badge/unit_tests-nf--test-337ab7.svg)](https://www.nf-test.com) [![Nextflow](https://img.shields.io/badge/version-%E2%89%A525.04.0-green?style=flat&logo=nextflow&logoColor=white&color=%230DC09D&link=https%3A%2F%2Fnextflow.io)](https://www.nextflow.io/) @@ -182,7 +182,7 @@ For further information or help, don't hesitate to get in touch on the [Slack `# ## Citations - +If you use nf-core/spatialaxe for your analysis, please cite it using the following doi: [10.5281/zenodo.20733817](https://doi.org/10.5281/zenodo.20733817) An extensive list of references for the tools used by the pipeline can be found in the [`CITATIONS.md`](CITATIONS.md) file. diff --git a/assets/nf-core-spatialaxe_logo_light.png b/assets/nf-core-spatialaxe_logo_light.png index c7a25c98..933ee0ee 100644 Binary files a/assets/nf-core-spatialaxe_logo_light.png and b/assets/nf-core-spatialaxe_logo_light.png differ diff --git a/conf/modules.config b/conf/modules.config index d7c5d75e..4e8e2b9b 100644 --- a/conf/modules.config +++ b/conf/modules.config @@ -82,13 +82,6 @@ process { path: "${params.outdir}/${params.mode}/xeniumranger/import_segementation", mode: params.publish_dir_mode, ] - // --expansion-distance is only valid for nuclei-based imports (it expands nuclei - // into cell boundaries). xeniumranger rejects it for transcript-assignment imports - // (proseg/baysor/segger) and cells-only imports with "--expansion-distance requires - // --nuclei", so only emit it when a nuclei segmentation is being imported. - ext.args = {[ - (nuclei && params.expansion_distance != null) ? "--expansion-distance=${params.expansion_distance}" : "", - ].join(' ').trim()} } // ---------------------------- proseg --------------------------------------------------- diff --git a/conf/test.config b/conf/test.config index e317612d..1784c30f 100644 --- a/conf/test.config +++ b/conf/test.config @@ -30,6 +30,5 @@ params { // Input data input = "${projectDir}/assets/samplesheet.csv" - outdir = 'results' mode = 'coordinate' } diff --git a/conf/test_coordinate_mode.config b/conf/tests/test_coordinate_mode.config similarity index 95% rename from conf/test_coordinate_mode.config rename to conf/tests/test_coordinate_mode.config index cccdae57..52b1f869 100644 --- a/conf/test_coordinate_mode.config +++ b/conf/tests/test_coordinate_mode.config @@ -26,6 +26,5 @@ params { // Input data input = "${projectDir}/assets/samplesheet.csv" - outdir = 'results' mode = 'coordinate' } diff --git a/conf/test_image_mode.config b/conf/tests/test_image_mode.config similarity index 95% rename from conf/test_image_mode.config rename to conf/tests/test_image_mode.config index ff9199d1..987c68c4 100644 --- a/conf/test_image_mode.config +++ b/conf/tests/test_image_mode.config @@ -26,6 +26,5 @@ params { // Input data input = "${projectDir}/assets/samplesheet.csv" - outdir = 'results' mode = 'image' } diff --git a/conf/test_preview_mode.config b/conf/tests/test_preview_mode.config similarity index 95% rename from conf/test_preview_mode.config rename to conf/tests/test_preview_mode.config index 5f312892..80bbf059 100644 --- a/conf/test_preview_mode.config +++ b/conf/tests/test_preview_mode.config @@ -26,6 +26,5 @@ params { // Input data input = "${projectDir}/assets/samplesheet.csv" - outdir = 'results' mode = 'preview' } diff --git a/conf/test_segfree_mode.config b/conf/tests/test_segfree_mode.config similarity index 95% rename from conf/test_segfree_mode.config rename to conf/tests/test_segfree_mode.config index 4576929d..0ffa05e9 100644 --- a/conf/test_segfree_mode.config +++ b/conf/tests/test_segfree_mode.config @@ -26,6 +26,5 @@ params { // Input data input = "${projectDir}/assets/samplesheet.csv" - outdir = 'results' mode = 'segfree' } diff --git a/docs/images/nf-core-spatialaxe_logo_dark.png b/docs/images/nf-core-spatialaxe_logo_dark.png index 52ecaa70..9eea0195 100644 Binary files a/docs/images/nf-core-spatialaxe_logo_dark.png and b/docs/images/nf-core-spatialaxe_logo_dark.png differ diff --git a/docs/images/nf-core-spatialaxe_logo_light.png b/docs/images/nf-core-spatialaxe_logo_light.png index 67bdab99..3b655587 100644 Binary files a/docs/images/nf-core-spatialaxe_logo_light.png and b/docs/images/nf-core-spatialaxe_logo_light.png differ diff --git a/docs/usage.md b/docs/usage.md index 02523048..406f538a 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -42,7 +42,7 @@ This runs the default image mode:
nextflow run nf-core/spatialaxe \ -profile --input ./samplesheet.csv \ - --outdir ./results \ + --outdir \ --mode image ``` @@ -55,7 +55,7 @@ This runs the default coordinate mode:
nextflow run nf-core/spatialaxe \ -profile --input ./samplesheet.csv \ - --outdir ./results \ + --outdir \ --mode coordinate ``` @@ -91,7 +91,7 @@ It is possible to run the quality control with `--run_qc` to couple it with anot nextflow run nf-core/spatialaxe \ -profile --input ./samplesheet.csv \ - --outdir ./results \ + --outdir \ --mode image \ --run_qc ``` @@ -136,7 +136,7 @@ eg: To run proseg segmentation use the `coordinate` mode and the `proseg` segmen nextflow run nf-core/spatialaxe \ -profile --input ./samplesheet.csv \ - --outdir ./results \ + --outdir \ --mode coordinate \ --method proseg ``` @@ -147,7 +147,7 @@ eg: To run cellpose segmentation use the `image` mode and the `cellpose` segment nextflow run nf-core/spatialaxe \ -profile --input ./samplesheet.csv \ - --outdir ./results \ + --outdir \ --mode image \ --method cellpose ``` diff --git a/main.nf b/main.nf index 71dc509c..15827672 100644 --- a/main.nf +++ b/main.nf @@ -136,7 +136,6 @@ workflow { params.plaintext_email, params.outdir, params.monochrome_logs, - params.hook_url, NFCORE_SPATIALAXE.out.multiqc_report ) } diff --git a/modules.json b/modules.json index 3e2f7a45..80c37636 100644 --- a/modules.json +++ b/modules.json @@ -69,7 +69,7 @@ ], "patch": "modules/nf-core/unzip/unzip.diff" }, - "xeniumranger/import-segmentation": { + "xeniumranger/importsegmentation": { "branch": "master", "git_sha": "39365e944e936511e33b993cdd978e0f12adac9a", "installed_by": [ diff --git a/modules/nf-core/xeniumranger/import-segmentation/tests/main.nf.test b/modules/nf-core/xeniumranger/import-segmentation/tests/main.nf.test deleted file mode 100644 index 71198099..00000000 --- a/modules/nf-core/xeniumranger/import-segmentation/tests/main.nf.test +++ /dev/null @@ -1,314 +0,0 @@ -nextflow_process { - - name "Test Process XENIUMRANGER_IMPORT_SEGMENTATION" - script "../main.nf" - process "XENIUMRANGER_IMPORT_SEGMENTATION" - config "./nextflow.config" - - tag "modules" - tag "modules_nfcore" - tag "xeniumranger" - tag "xeniumranger/import-segmentation" - tag "unzip" - - setup { - run("UNZIP") { - script "modules/nf-core/unzip/main.nf" - process { - """ - input[0] = [[], file('https://raw.githubusercontent.com/nf-core/test-datasets/spatialaxe/Xenium_Prime_Mouse_Ileum_tiny_outs.zip', checkIfExists: true)] - """ - } - } - } - - test("xeniumranger import-segmentation nuclei npy") { - when { - process { - """ - input[0] = channel.of([ - [id: "test_xeniumranger_import-segmentation"], - ]).combine(UNZIP.out.unzipped_archive.map { it[1] }) - input[1] = 0 - input[2] = [] - input[3] = UNZIP.out.unzipped_archive.map { it[1] } + "/segmentations/nuclei.npy" - input[4] = [] - input[5] = [] - input[6] = [] - """ - } - } - then { - assertAll( - { assert process.success }, - { assert snapshot( - process.out.versions, - process.out.outs.get(0).get(1).findAll { file(it).name !in [ - 'analysis_summary.html', - 'metrics_summary.csv', - 'cell_boundaries.csv.gz', - 'cell_boundaries.parquet', - 'nucleus_boundaries.csv.gz', - 'nucleus_boundaries.parquet', - 'cells.csv.gz', - 'cells.parquet', - 'cells.zarr.zip', - 'transcripts.parquet', - 'transcripts.zarr.zip', - 'clusters.csv', - 'differential_expression.csv', - 'components.csv', - 'projection.csv', - 'variance.csv', - 'analysis.zarr.zip', - 'experiment.xenium', - 'cell_feature_matrix.zarr.zip' - ]} - ).match() - }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'analysis_summary.html' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'metrics_summary.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cell_boundaries.csv.gz' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cell_boundaries.parquet' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'nucleus_boundaries.csv.gz' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'nucleus_boundaries.parquet' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cells.csv.gz' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cells.parquet' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cells.zarr.zip' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'transcripts.parquet' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'clusters.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'differential_expression.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'components.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'projection.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'variance.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'analysis.zarr.zip' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'experiment.xenium' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cell_feature_matrix.zarr.zip' }).exists() }, - ) - } - } - - - test("xeniumranger import-segmentation nuclei tif") { - when { - process { - """ - input[0] = channel.of([ - [id: "test_xeniumranger_import-segmentation"], - ]).combine(UNZIP.out.unzipped_archive.map { it[1] }) - input[1] = 0 - input[2] = [] - input[3] = UNZIP.out.unzipped_archive.map { it[1] } + "/segmentations/nuclei.npy" - input[4] = [] - input[5] = [] - input[6] = [] - """ - } - } - then { - assertAll( - { assert process.success }, - { assert snapshot( - process.out.versions, - process.out.outs.get(0).get(1).findAll { file(it).name !in [ - 'analysis_summary.html', - 'metrics_summary.csv', - 'cell_boundaries.csv.gz', - 'cell_boundaries.parquet', - 'nucleus_boundaries.csv.gz', - 'nucleus_boundaries.parquet', - 'cells.csv.gz', - 'cells.parquet', - 'cells.zarr.zip', - 'transcripts.parquet', - 'transcripts.zarr.zip', - 'clusters.csv', - 'differential_expression.csv', - 'components.csv', - 'projection.csv', - 'variance.csv', - 'analysis.zarr.zip', - 'experiment.xenium', - 'cell_feature_matrix.zarr.zip' - ]} - ).match() - }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'analysis_summary.html' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'metrics_summary.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cell_boundaries.csv.gz' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cell_boundaries.parquet' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'nucleus_boundaries.csv.gz' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'nucleus_boundaries.parquet' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cells.csv.gz' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cells.parquet' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cells.zarr.zip' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'transcripts.parquet' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'clusters.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'differential_expression.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'components.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'projection.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'variance.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'analysis.zarr.zip' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'experiment.xenium' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cell_feature_matrix.zarr.zip' }).exists() }, - ) - } - } - - test("xeniumranger import-segmentation segmentation csv") { - when { - process { - """ - input[0] = channel.of([ - [id: "test_xeniumranger_import-segmentation"], - ]).combine(UNZIP.out.unzipped_archive.map { it[1] }) - input[1] = 0 - input[2] = UNZIP.out.unzipped_archive.map { it[1] } + "/segmentations/imagealignment.csv" - input[3] = [] - input[4] = [] - input[5] = UNZIP.out.unzipped_archive.map { it[1] } + "/segmentations/segmentation.csv" - input[6] = UNZIP.out.unzipped_archive.map { it[1] } + "/segmentations/segmentation_polygons.json" - """ - } - } - then { - assertAll( - { assert process.success }, - { assert snapshot( - process.out.versions, - process.out.outs.get(0).get(1).findAll { file(it).name !in [ - 'analysis_summary.html', - 'metrics_summary.csv', - 'cell_boundaries.csv.gz', - 'cell_boundaries.parquet', - 'nucleus_boundaries.csv.gz', - 'nucleus_boundaries.parquet', - 'cells.csv.gz', - 'cells.parquet', - 'cells.zarr.zip', - 'transcripts.parquet', - 'transcripts.zarr.zip', - 'clusters.csv', - 'differential_expression.csv', - 'components.csv', - 'projection.csv', - 'variance.csv', - 'analysis.zarr.zip', - 'experiment.xenium', - 'cell_feature_matrix.zarr.zip' - ]} - ).match() - }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'analysis_summary.html' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'metrics_summary.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cell_boundaries.csv.gz' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cell_boundaries.parquet' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'nucleus_boundaries.csv.gz' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'nucleus_boundaries.parquet' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cells.csv.gz' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cells.parquet' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cells.zarr.zip' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'transcripts.parquet' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'clusters.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'differential_expression.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'components.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'projection.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'variance.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'analysis.zarr.zip' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'experiment.xenium' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cell_feature_matrix.zarr.zip' }).exists() }, - ) - } - } - - test("xeniumranger import-segmentation") { - when { - process { - """ - input[0] = channel.of([ - [id: "test_xeniumranger_import-segmentation"], - ]).combine(UNZIP.out.unzipped_archive.map { it[1] }) - input[1] = 0 - input[2] = [] - input[3] = UNZIP.out.unzipped_archive.map { it[1] } + "/cells.zarr.zip" - input[4] = [] - input[5] = [] - input[6] = [] - """ - } - } - then { - assertAll( - { assert process.success }, - { assert snapshot( - process.out.versions, - process.out.outs.get(0).get(1).findAll { file(it).name !in [ - 'analysis_summary.html', - 'metrics_summary.csv', - 'cell_boundaries.csv.gz', - 'cell_boundaries.parquet', - 'nucleus_boundaries.csv.gz', - 'nucleus_boundaries.parquet', - 'cells.csv.gz', - 'cells.parquet', - 'cells.zarr.zip', - 'transcripts.parquet', - 'transcripts.zarr.zip', - 'clusters.csv', - 'differential_expression.csv', - 'components.csv', - 'projection.csv', - 'variance.csv', - 'analysis.zarr.zip', - 'experiment.xenium', - 'cell_feature_matrix.zarr.zip' - ]} - ).match() - }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'analysis_summary.html' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'metrics_summary.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cell_boundaries.csv.gz' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cell_boundaries.parquet' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'nucleus_boundaries.csv.gz' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'nucleus_boundaries.parquet' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cells.csv.gz' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cells.parquet' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cells.zarr.zip' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'transcripts.parquet' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'clusters.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'differential_expression.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'components.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'projection.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'variance.csv' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'analysis.zarr.zip' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'experiment.xenium' }).exists() }, - { assert file(process.out.outs.get(0).get(1).find { file(it).name == 'cell_feature_matrix.zarr.zip' }).exists() }, - ) - } - } - - test("xeniumranger import-segmentation stub") { - options "-stub" - when { - process { - """ - input[0] = channel.of([ - [id: "test_xeniumranger_import-segmentation"], - ]).combine(UNZIP.out.unzipped_archive.map { it[1] }) - input[1] = 0 - input[2] = [] - input[3] = UNZIP.out.unzipped_archive.map { it[1] } + "/cells.zarr.zip" - input[4] = [] - input[5] = [] - input[6] = [] - """ - } - } - then { - assertAll( - { assert process.success }, - { assert snapshot(process.out).match() } - ) - } - } -} \ No newline at end of file diff --git a/modules/nf-core/xeniumranger/import-segmentation/tests/main.nf.test.snap b/modules/nf-core/xeniumranger/import-segmentation/tests/main.nf.test.snap deleted file mode 100644 index 1c312ae0..00000000 --- a/modules/nf-core/xeniumranger/import-segmentation/tests/main.nf.test.snap +++ /dev/null @@ -1,127 +0,0 @@ -{ - "xeniumranger import-segmentation": { - "content": [ - [ - "versions.yml:md5,d76e870d71abf94ed9ae972a08b83f63" - ], - [ - "dispersion.csv:md5,e8b1abb880ece8fb730ce34a15f958b4", - "features_selected.csv:md5,c5e32d69f001f938ed316d2108a21e00", - "cell_feature_matrix.h5:md5,96cb400f1b1dd6f8796daea0ad5c74e6", - "barcodes.tsv.gz:md5,04ea06796d6b28517c288904ca043582", - "features.tsv.gz:md5,7862242129681900a9cc4086dc83b62e", - "matrix.mtx.gz:md5,489f86fbd8d65d6b973bb9cc7c5a76f1", - "gene_panel.json:md5,8890dd5fd90706e751554ac3fdfdedde", - "morphology.ome.tif:md5,6b65fff28a38a001b8f25061737fbf9b", - "morphology_focus_0000.ome.tif:md5,90e796ad634d14e62cf2ebcadf2eaf98" - ] - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" - }, - "timestamp": "2024-10-30T00:13:13.575888" - }, - "xeniumranger import-segmentation nuclei npy": { - "content": [ - [ - "versions.yml:md5,d76e870d71abf94ed9ae972a08b83f63" - ], - [ - "dispersion.csv:md5,e8b1abb880ece8fb730ce34a15f958b4", - "features_selected.csv:md5,c5e32d69f001f938ed316d2108a21e00", - "cell_feature_matrix.h5:md5,96cb400f1b1dd6f8796daea0ad5c74e6", - "barcodes.tsv.gz:md5,04ea06796d6b28517c288904ca043582", - "features.tsv.gz:md5,7862242129681900a9cc4086dc83b62e", - "matrix.mtx.gz:md5,489f86fbd8d65d6b973bb9cc7c5a76f1", - "gene_panel.json:md5,8890dd5fd90706e751554ac3fdfdedde", - "morphology.ome.tif:md5,6b65fff28a38a001b8f25061737fbf9b", - "morphology_focus_0000.ome.tif:md5,90e796ad634d14e62cf2ebcadf2eaf98" - ] - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" - }, - "timestamp": "2024-10-29T23:03:26.726334" - }, - "xeniumranger import-segmentation segmentation csv": { - "content": [ - [ - "versions.yml:md5,d76e870d71abf94ed9ae972a08b83f63" - ], - [ - "dispersion.csv:md5,e8b1abb880ece8fb730ce34a15f958b4", - "features_selected.csv:md5,c5e32d69f001f938ed316d2108a21e00", - "cell_feature_matrix.h5:md5,5d74ea595561e0300b6c3e5ec8d06fff", - "barcodes.tsv.gz:md5,97496a9b448d9380cff0575b8e7a6f57", - "features.tsv.gz:md5,7862242129681900a9cc4086dc83b62e", - "matrix.mtx.gz:md5,f93ed82a2a74c154392fc6237642f1d2", - "gene_panel.json:md5,8890dd5fd90706e751554ac3fdfdedde", - "morphology.ome.tif:md5,6b65fff28a38a001b8f25061737fbf9b", - "morphology_focus_0000.ome.tif:md5,90e796ad634d14e62cf2ebcadf2eaf98" - ] - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" - }, - "timestamp": "2024-10-29T23:22:58.158857" - }, - "xeniumranger import-segmentation stub": { - "content": [ - { - "0": [ - [ - { - "id": "test_xeniumranger_import-segmentation" - }, - "fake_file.txt:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "1": [ - "versions.yml:md5,d76e870d71abf94ed9ae972a08b83f63" - ], - "outs": [ - [ - { - "id": "test_xeniumranger_import-segmentation" - }, - "fake_file.txt:md5,d41d8cd98f00b204e9800998ecf8427e" - ] - ], - "versions": [ - "versions.yml:md5,d76e870d71abf94ed9ae972a08b83f63" - ] - } - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" - }, - "timestamp": "2024-10-30T22:49:39.204133" - }, - "xeniumranger import-segmentation nuclei tif": { - "content": [ - [ - "versions.yml:md5,d76e870d71abf94ed9ae972a08b83f63" - ], - [ - "dispersion.csv:md5,e8b1abb880ece8fb730ce34a15f958b4", - "features_selected.csv:md5,c5e32d69f001f938ed316d2108a21e00", - "cell_feature_matrix.h5:md5,96cb400f1b1dd6f8796daea0ad5c74e6", - "barcodes.tsv.gz:md5,04ea06796d6b28517c288904ca043582", - "features.tsv.gz:md5,7862242129681900a9cc4086dc83b62e", - "matrix.mtx.gz:md5,489f86fbd8d65d6b973bb9cc7c5a76f1", - "gene_panel.json:md5,8890dd5fd90706e751554ac3fdfdedde", - "morphology.ome.tif:md5,6b65fff28a38a001b8f25061737fbf9b", - "morphology_focus_0000.ome.tif:md5,90e796ad634d14e62cf2ebcadf2eaf98" - ] - ], - "meta": { - "nf-test": "0.9.0", - "nextflow": "24.04.4" - }, - "timestamp": "2024-10-29T23:11:37.18721" - } -} \ No newline at end of file diff --git a/modules/nf-core/xeniumranger/import-segmentation/tests/nextflow.config b/modules/nf-core/xeniumranger/import-segmentation/tests/nextflow.config deleted file mode 100644 index e69de29b..00000000 diff --git a/modules/nf-core/xeniumranger/import-segmentation/tests/tags.yml b/modules/nf-core/xeniumranger/import-segmentation/tests/tags.yml deleted file mode 100644 index 90c2b805..00000000 --- a/modules/nf-core/xeniumranger/import-segmentation/tests/tags.yml +++ /dev/null @@ -1,2 +0,0 @@ -xeniumranger/import-segmentation: - - "modules/nf-core/xeniumranger/import-segmentation/**" diff --git a/modules/nf-core/xeniumranger/import-segmentation/main.nf b/modules/nf-core/xeniumranger/importsegmentation/main.nf similarity index 77% rename from modules/nf-core/xeniumranger/import-segmentation/main.nf rename to modules/nf-core/xeniumranger/importsegmentation/main.nf index 264b8a72..57ff2cb6 100644 --- a/modules/nf-core/xeniumranger/import-segmentation/main.nf +++ b/modules/nf-core/xeniumranger/importsegmentation/main.nf @@ -1,11 +1,11 @@ -process XENIUMRANGER_IMPORT_SEGMENTATION { +process XENIUMRANGER_IMPORTSEGMENTATION { tag "$meta.id" label 'process_high' - container "nf-core/xeniumranger:4.0" + container "quay.io/nf-core/xeniumranger:4.0" input: - tuple val(meta), path(xenium_bundle, stageAs: "bundle/"), path(transcript_assignment), path(viz_polygons), path(nuclei), path(cells), path(coordinate_transform), val(units) + tuple val(meta), path(xenium_bundle, stageAs: "bundle/"), path(transcript_assignment), path(viz_polygons), path(nuclei), path(cells), path(coordinate_transform), val(units), val(expansion_distance) output: tuple val(meta), path("${prefix}"), emit: outs @@ -18,7 +18,7 @@ process XENIUMRANGER_IMPORT_SEGMENTATION { // Exit if running this module with -profile conda / -profile mamba if (workflow.profile.tokenize(',').intersect(['conda', 'mamba']).size() >= 1) { - error "XENIUMRANGER_IMPORT_SEGMENTATION module does not support Conda. Please use Docker / Singularity / Podman instead." + error "XENIUMRANGER_IMPORTSEGMENTATION module does not support Conda. Please use Docker / Singularity / Podman instead." } prefix = task.ext.prefix ?: "${meta.id}" @@ -32,6 +32,9 @@ process XENIUMRANGER_IMPORT_SEGMENTATION { def assembled_args = [] if (task.ext.args) { assembled_args << task.ext.args.trim() } + // --expansion-distance is only valid for nuclei-based imports. + // xeniumranger rejects it for transcript-assignment imports and cells-only imports. + if (nuclei && expansion_distance != null) { assembled_args << "--expansion-distance=${expansion_distance}" } if (nuclei) { assembled_args << "--nuclei=\"${nuclei}\"" } if (cells) { assembled_args << "--cells=\"${cells}\"" } if (transcript_assignment) { assembled_args << "--transcript-assignment=\"${transcript_assignment}\"" } @@ -48,14 +51,14 @@ process XENIUMRANGER_IMPORT_SEGMENTATION { """ xeniumranger import-segmentation \\ - --id="XENIUMRANGER_IMPORT_SEGMENTATION" \\ + --id="XENIUMRANGER_IMPORTSEGMENTATION" \\ --xenium-bundle="${xenium_bundle}" \\ --localcores=${task.cpus} \\ --localmem=${task.memory.toGiga()} \\ ${args} rm -rf "${prefix}" - mv XENIUMRANGER_IMPORT_SEGMENTATION/outs "${prefix}" + mv XENIUMRANGER_IMPORTSEGMENTATION/outs "${prefix}" """ stub: diff --git a/modules/nf-core/xeniumranger/import-segmentation/meta.yml b/modules/nf-core/xeniumranger/importsegmentation/meta.yml similarity index 92% rename from modules/nf-core/xeniumranger/import-segmentation/meta.yml rename to modules/nf-core/xeniumranger/importsegmentation/meta.yml index e222df58..801aa47a 100644 --- a/modules/nf-core/xeniumranger/import-segmentation/meta.yml +++ b/modules/nf-core/xeniumranger/importsegmentation/meta.yml @@ -1,6 +1,6 @@ -name: xeniumranger_import_segmentation +name: XENIUMRANGER_IMPORTSEGMENTATION description: | - The xeniumranger import-segmentation module runs `xeniumranger import-segmentation` + The xeniumranger importsegmentation module runs `xeniumranger import-segmentation` to recompute Xenium Onboard Analysis outputs using external segmentation results. It supports two execution modes mirroring the Xenium Ranger CLI: an image-based mode that accepts nuclei and/or cell masks (TIFF/NPY) or GeoJSON polygons together @@ -102,6 +102,13 @@ input: enum: - "microns" - "pixels" + - expansion_distance: + type: integer + optional: true + description: | + Distance (in microns) to expand nuclei outward into cell boundaries. Only valid for + nuclei-based imports (`nuclei` must be set); xeniumranger rejects it for + transcript-assignment imports and cells-only imports. Default: 5. Range: 0-100. output: outs: - - meta: diff --git a/modules/nf-core/xeniumranger/importsegmentation/tests/main.nf.test b/modules/nf-core/xeniumranger/importsegmentation/tests/main.nf.test new file mode 100644 index 00000000..1510df32 --- /dev/null +++ b/modules/nf-core/xeniumranger/importsegmentation/tests/main.nf.test @@ -0,0 +1,91 @@ +nextflow_process { + + name "Test Process XENIUMRANGER_IMPORTSEGMENTATION" + script "../main.nf" + process "XENIUMRANGER_IMPORTSEGMENTATION" + config "./nextflow.config" + + tag "modules" + tag "modules_nfcore" + tag "xeniumranger" + tag "xeniumranger/importsegmentation" + tag "untar" + + + setup { + + run("UNTAR") { + script "modules/nf-core/untar/main.nf" + process { + """ + input[0] = [[], file('https://raw.githubusercontent.com/nf-core/test-datasets/spatialaxe/xenium_bundle.tar.gz', checkIfExists: true)] + """ + } + } + + } + + test("xeniumranger importsegmentation nuclei") { + when { + process { + """ + input[0] = UNTAR.out.untar + .map { meta, bundle -> + [ + [id: "test_xeniumranger_importsegmentation"], + bundle, + [], + [], + bundle + "/cells.zarr.zip", + [], + [], + [], + 5 + ] + } + """ + } + } + + then { + assertAll( + { assert process.success }, + { assert process.out.outs != null }, + { assert file(process.out.outs.get(0).get(1)).isDirectory() }, + { assert file(process.out.outs.get(0).get(1)).list().size() > 0 }, + { assert snapshot(sanitizeOutput(process.out, unstableKeys: ["outs"])).match()}, + ) + } + } + + test("xeniumranger importsegmentation stub") { + options "-stub" + + when { + process { + """ + input[0] = UNTAR.out.untar + .map { meta, bundle -> + [ + [id: "test_xeniumranger_importsegmentation"], + bundle, + [], + [], + bundle + "/cells.zarr.zip", + [], + [], + [], + 5 + ] + } + """ + } + } + then { + assertAll( + { assert process.success }, + { assert snapshot(sanitizeOutput(process.out)).match() } + ) + } + } +} diff --git a/modules/nf-core/xeniumranger/importsegmentation/tests/main.nf.test.snap b/modules/nf-core/xeniumranger/importsegmentation/tests/main.nf.test.snap new file mode 100644 index 00000000..7fb43655 --- /dev/null +++ b/modules/nf-core/xeniumranger/importsegmentation/tests/main.nf.test.snap @@ -0,0 +1,56 @@ +{ + "xeniumranger importsegmentation stub": { + "content": [ + { + "outs": [ + [ + { + "id": "test_xeniumranger_importsegmentation" + }, + [ + "experiment.xenium:md5,d41d8cd98f00b204e9800998ecf8427e" + ] + ] + ], + "versions_xeniumranger": [ + [ + "XENIUMRANGER_IMPORTSEGMENTATION", + "xeniumranger", + "4.0.1.1" + ] + ] + } + ], + "timestamp": "2026-07-27T15:02:26.958198169", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.6" + } + }, + "xeniumranger importsegmentation nuclei": { + "content": [ + { + "outs": [ + [ + { + "id": "test_xeniumranger_importsegmentation" + }, + "test_xeniumranger_importsegmentation" + ] + ], + "versions_xeniumranger": [ + [ + "XENIUMRANGER_IMPORTSEGMENTATION", + "xeniumranger", + "4.0.1.1" + ] + ] + } + ], + "timestamp": "2026-07-27T15:02:12.93562615", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.6" + } + } +} \ No newline at end of file diff --git a/modules/nf-core/xeniumranger/importsegmentation/tests/nextflow.config b/modules/nf-core/xeniumranger/importsegmentation/tests/nextflow.config new file mode 100644 index 00000000..39b095f8 --- /dev/null +++ b/modules/nf-core/xeniumranger/importsegmentation/tests/nextflow.config @@ -0,0 +1,7 @@ +process { + withName: XENIUMRANGER_IMPORTSEGMENTATION { + cpus = 2 + memory = '4.GB' + time = '30.m' + } +} diff --git a/nextflow.config b/nextflow.config index b36056e9..24fce141 100644 --- a/nextflow.config +++ b/nextflow.config @@ -386,7 +386,7 @@ manifest { mainScript = 'main.nf' defaultBranch = 'master' nextflowVersion = '!>=25.04.0' - version = '1.1.0dev' + version = '1.0.1dev' doi = '' } diff --git a/ro-crate-metadata.json b/ro-crate-metadata.json index d5575c0b..42e4dcd5 100644 --- a/ro-crate-metadata.json +++ b/ro-crate-metadata.json @@ -22,8 +22,8 @@ "@id": "./", "@type": "Dataset", "creativeWorkStatus": "InProgress", - "datePublished": "2026-06-17T15:15:09+00:00", - "description": "

\n \n \n \"nf-core/spatialaxe\"\n \n

\n\n[![Open in GitHub Codespaces](https://img.shields.io/badge/Open_In_GitHub_Codespaces-black?labelColor=grey&logo=github)](https://github.com/codespaces/new/nf-core/spatialaxe)\n[![GitHub Actions CI Status](https://github.com/nf-core/spatialaxe/actions/workflows/nf-test.yml/badge.svg)](https://github.com/nf-core/spatialaxe/actions/workflows/nf-test.yml)\n[![GitHub Actions Linting Status](https://github.com/nf-core/spatialaxe/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-core/spatialaxe/actions/workflows/linting.yml)[![AWS CI](https://img.shields.io/badge/CI%20tests-full%20size-FF9900?labelColor=000000&logo=Amazon%20AWS)](https://nf-co.re/spatialaxe/results)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.XXXXXXX-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.XXXXXXX)\n[![nf-test](https://img.shields.io/badge/unit_tests-nf--test-337ab7.svg)](https://www.nf-test.com)\n\n[![Nextflow](https://img.shields.io/badge/version-%E2%89%A525.04.0-green?style=flat&logo=nextflow&logoColor=white&color=%230DC09D&link=https%3A%2F%2Fnextflow.io)](https://www.nextflow.io/)\n[![nf-core template version](https://img.shields.io/badge/nf--core_template-3.4.1-green?style=flat&logo=nfcore&logoColor=white&color=%2324B064&link=https%3A%2F%2Fnf-co.re)](https://github.com/nf-core/tools/releases/tag/3.4.1)\n[![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/)\n[![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/)\n[![Launch on Seqera Platform](https://img.shields.io/badge/Launch%20%F0%9F%9A%80-Seqera%20Platform-%234256e7)](https://cloud.seqera.io/launch?pipeline=https://github.com/nf-core/spatialaxe)\n\n[![Get help on Slack](http://img.shields.io/badge/slack-nf--core%20%23spatialaxe-4A154B?labelColor=000000&logo=slack)](https://nfcore.slack.com/channels/spatialaxe)[![Follow on Bluesky](https://img.shields.io/badge/bluesky-%40nf__core-1185fe?labelColor=000000&logo=bluesky)](https://bsky.app/profile/nf-co.re)[![Follow on Mastodon](https://img.shields.io/badge/mastodon-nf__core-6364ff?labelColor=FFFFFF&logo=mastodon)](https://mstdn.science/@nf_core)[![Watch on YouTube](http://img.shields.io/badge/youtube-nf--core-FF0000?labelColor=000000&logo=youtube)](https://www.youtube.com/c/nf-core)\n\n## Introduction\n\n**nf-core/spatialaxe** is a bioinformatics best-practice processing and quality control pipeline for Xenium (and soon Atera) data. The current plan for the pipeline implementation is shown in the metromap below. **The pipeline is under active developement and changes might occure frequently**.\n\n![nf-core/spatialaxe-metromap](docs/images/spatialaxe-metromap.png)\n\n> [!NOTE]\n> We are currently extending the pipeline for the [10x Atera system](https://www.10xgenomics.com/platforms/atera).\n\n## Tools supported\n\nThe pipeline supports the following tools:\n\n- Segmenation methods:\n - [Baysor](https://doi.org/10.1038/s41587-021-01044-w)\n - [Cellpose](https://doi.org/10.1038/s41592-020-01018-x)\n - [Xenium ranger (XR)](https://www.10xgenomics.com/support/software/xenium-ranger/latest)\n - [StarDist](https://doi.org/10.48550/arXiv.2203.02284)\n- Segmentation free methods:\n - [Ficture](https://doi.org/10.1038/s41592-024-02415-2)\n - [Baysor](https://doi.org/10.1038/s41587-021-01044-w)\n- Transcript assignment methods:\n - [Segger](https://doi.org/10.1101/2025.03.14.643160)\n - [Proseg](https://doi.org/10.1038/s41592-025-02697-0)\n- Utility methods:\n - [SpatialData](https://doi.org/10.1038/s41592-024-02212-x)\n - [Baysor](https://doi.org/10.1038/s41587-021-01044-w)\n- QC methods:\n - [MultiQC Xenium Extra Plugin](https://github.com/MultiQC/xenium-extra)\n - [OPT](https://github.com/JEFworks-Lab/off-target-probe-tracker)\n\n## Usage\n\nOn release, automated continuous integration tests run the pipeline on a full-sized dataset on the AWS cloud infrastructure. This ensures that the pipeline runs on AWS, has sensible resource allocation defaults set to run on real-world datasets, and permits the persistent storage of results to benchmark between pipeline releases and other analysis sources. The results obtained from the full-sized test can be viewed on the [nf-core website](https://nf-co.re/spatialaxe/results).\n\n> [!NOTE]\n> The pipeline does not support conda currently. We are working on it.\n\n## Quick Start\n\n`samplesheet.csv`:\n\n```csv\nsample,bundle,image\ntest_sample,/path/to/xenium-bundle,/path/to/morphology.ome.tif\n```\n\nNow, you can run the pipeline using:\n\n### Run image-based segmentation mode
\n\n`CELLPOSE -> BAYSOR -> XR-IMPORT_SEGMENTATION -> SPATIALDATA -> QC`\n\n```bash\nnextflow run nf-core/spatialaxe \\\n -profile \\\n --input samplesheet.csv \\\n --outdir \\\n --mode \n```\n\n### Run coordinate-based segmentation mode
\n\n`PROSEG -> PROSEG2BAYSOR -> XR-IMPORT_SEGMENTATION -> SPATIALDATA -> QC`\n\n```bash\nnextflow run nf-core/spatialaxe \\\n -profile \\\n --input samplesheet.csv \\\n --outdir \\\n --mode coordinate\n```\n\n### Run segfree mode
\n\n`BAYSOR_SEGFREE`\n\n```bash\nnextflow run nf-core/spatialaxe \\\n -profile \\\n --input samplesheet.csv \\\n --outdir \\\n --mode segfree\n```\n\n### Run preview mode
\n\n`BAYSOR_PREVIEW`\n\n```bash\nnextflow run nf-core/spatialaxe \\\n -profile \\\n --input samplesheet.csv \\\n --outdir \\\n --mode preview\n```\n\n### Run just the quality control
\n\n```bash\nnextflow run nf-core/spatialaxe \\\n -profile \\\n --input samplesheet.csv \\\n --outdir \\\n --mode qc\n```\n\n### Additional information\n\n> [!WARNING]\n> Please provide pipeline parameters via the CLI or Nextflow `-params-file` option. Custom config files including those provided by the `-c` Nextflow option can be used to provide any configuration _**except for parameters**_; see [docs](https://nf-co.re/docs/usage/getting_started/configuration#custom-configuration-files).\n\nFor more details and further functionality, please refer to the [usage documentation](https://nf-co.re/spatialaxe/usage) and the [parameter documentation](https://nf-co.re/spatialaxe/parameters).\n\n## Pipeline output\n\nTo see the results of an example test run with a full size dataset refer to the [results](https://nf-co.re/spatialaxe/results) tab on the nf-core website pipeline page.\nFor more details about the output files and reports, please refer to the\n[output documentation](https://nf-co.re/spatialaxe/output).\n\n## Runtime and resource estimations\n\n| Tool | Compute | Runtime (min / med / max) | Peak RSS (min / med / max) |\n| ------------------------- | ------- | ------------------------- | -------------------------- |\n| Cellpose | GPU | 1m / 4m / 1.4h | 10 GB / 26 GB / 554 GB |\n| Cellpose | CPU | 1.3h / 2.3h / 6.5h | 161 GB / 426 GB / 1115 GB |\n| StarDist | GPU | 1m / 4m / 7m | 5 GB / 12 GB / 18 GB |\n| StarDist | CPU | 5m / 6m / 7m | 18 GB / 18 GB / 18 GB |\n| Segger (create_dataset) | GPU | 2m / 9m / 31m | 1.7 GB / 14 GB / 50 GB |\n| Segger (create_dataset) | CPU | 13m / 21m / 46m | 13 GB / 19 GB / 49 GB |\n| Segger (train) | GPU | 10m / 43m / 2.9h | 30 GB / 33 GB / 60 GB |\n| Segger (predict) | GPU | 2m / 16m / 59m | 10 GB / 25 GB / 87 GB |\n| Baysor (whole-image) | CPU | 2m / 30m / 17h | 6 GB / 10 GB / 650 GB |\n| Baysor (tiled) | CPU | 1m / 18m / 13h | 0.2 GB / 34 GB / 530 GB |\n| Proseg | CPU | 1m / 18m / 6.8h | 279 MB / 3.8 GB / 136 GB |\n| XeniumRanger (resegment) | CPU | 18m / 39m / 3.7h | 28 GB / 54 GB / 60 GB |\n| XeniumRanger (import_seg) | CPU | 2m / 7m / 2.7h | 2.6 GB / 11 GB / 51 GB |\n| Ficture (preprocess) | CPU | 3m / 4m / 13m | 331 MB / 357 MB / 21 GB |\n\n- Cellpose GPU vs CPU: 35x faster on GPU (4m median vs 2.3h), 16x less memory (26 GB vs 426 GB)\n- Segger: Only tool that truly requires GPU for all 3 steps (create_dataset, train, predict)\n- StarDist: Very fast on CPU, GPU is not necessary to run its default model\n\n## Credits\n\nnf-core/spatialaxe is mainly developed by [Sameesh Kher](https://github.com/khersameesh24), [Dongze He](https://github.com/dongzehe), and [Florian Heyl](https://github.com/heylf).\n\nWe thank the following people for their extensive assistance in the development of this pipeline:\n\n- Tobias Krause\n- Kre\u0161imir Be\u0161tak (kbestak)\n- Matthias H\u00f6rtenhuber (mashehu)\n- Maxime Garcia (maxulysse)\n- K\u00fcbra Narc\u0131 (kubranarci)\n\n## Contributions and Support\n\nIf you would like to contribute to this pipeline, please see the [contributing guidelines](.github/CONTRIBUTING.md).\n\nFor further information or help, don't hesitate to get in touch on the [Slack `#spatialaxe` channel](https://nfcore.slack.com/channels/spatialaxe) (you can join with [this invite](https://nf-co.re/join/slack)).\n\n## Citations\n\n\n\nAn extensive list of references for the tools used by the pipeline can be found in the [`CITATIONS.md`](CITATIONS.md) file.\n\nYou can cite the `nf-core` publication as follows:\n\n> **The nf-core framework for community-curated bioinformatics pipelines.**\n>\n> Philip Ewels, Alexander Peltzer, Sven Fillinger, Harshil Patel, Johannes Alneberg, Andreas Wilm, Maxime Ulysse Garcia, Paolo Di Tommaso & Sven Nahnsen.\n>\n> _Nat Biotechnol._ 2020 Feb 13. doi: [10.1038/s41587-020-0439-x](https://dx.doi.org/10.1038/s41587-020-0439-x).\n", + "datePublished": "2026-08-06T14:03:08+00:00", + "description": "

\n \n \n \"nf-core/spatialaxe\"\n \n

\n\n[![Open in GitHub Codespaces](https://img.shields.io/badge/Open_In_GitHub_Codespaces-black?labelColor=grey&logo=github)](https://github.com/codespaces/new/nf-core/spatialaxe)\n[![GitHub Actions CI Status](https://github.com/nf-core/spatialaxe/actions/workflows/nf-test.yml/badge.svg)](https://github.com/nf-core/spatialaxe/actions/workflows/nf-test.yml)\n[![GitHub Actions Linting Status](https://github.com/nf-core/spatialaxe/actions/workflows/linting.yml/badge.svg)](https://github.com/nf-core/spatialaxe/actions/workflows/linting.yml)[![AWS CI](https://img.shields.io/badge/CI%20tests-full%20size-FF9900?labelColor=000000&logo=Amazon%20AWS)](https://nf-co.re/spatialaxe/results)[![Cite with Zenodo](http://img.shields.io/badge/DOI-10.5281/zenodo.20733817-1073c8?labelColor=000000)](https://doi.org/10.5281/zenodo.20733817)\n[![nf-test](https://img.shields.io/badge/unit_tests-nf--test-337ab7.svg)](https://www.nf-test.com)\n\n[![Nextflow](https://img.shields.io/badge/version-%E2%89%A525.04.0-green?style=flat&logo=nextflow&logoColor=white&color=%230DC09D&link=https%3A%2F%2Fnextflow.io)](https://www.nextflow.io/)\n[![nf-core template version](https://img.shields.io/badge/nf--core_template-3.4.1-green?style=flat&logo=nfcore&logoColor=white&color=%2324B064&link=https%3A%2F%2Fnf-co.re)](https://github.com/nf-core/tools/releases/tag/3.4.1)\n[![run with docker](https://img.shields.io/badge/run%20with-docker-0db7ed?labelColor=000000&logo=docker)](https://www.docker.com/)\n[![run with singularity](https://img.shields.io/badge/run%20with-singularity-1d355c.svg?labelColor=000000)](https://sylabs.io/docs/)\n[![Launch on Seqera Platform](https://img.shields.io/badge/Launch%20%F0%9F%9A%80-Seqera%20Platform-%234256e7)](https://cloud.seqera.io/launch?pipeline=https://github.com/nf-core/spatialaxe)\n\n[![Get help on Slack](http://img.shields.io/badge/slack-nf--core%20%23spatialaxe-4A154B?labelColor=000000&logo=slack)](https://nfcore.slack.com/channels/spatialaxe)[![Follow on Bluesky](https://img.shields.io/badge/bluesky-%40nf__core-1185fe?labelColor=000000&logo=bluesky)](https://bsky.app/profile/nf-co.re)[![Follow on Mastodon](https://img.shields.io/badge/mastodon-nf__core-6364ff?labelColor=FFFFFF&logo=mastodon)](https://mstdn.science/@nf_core)[![Watch on YouTube](http://img.shields.io/badge/youtube-nf--core-FF0000?labelColor=000000&logo=youtube)](https://www.youtube.com/c/nf-core)\n\n## Introduction\n\n**nf-core/spatialaxe** is a bioinformatics best-practice processing and quality control pipeline for Xenium (and soon Atera) data. The current plan for the pipeline implementation is shown in the metromap below. **The pipeline is under active developement and changes might occure frequently**.\n\n![nf-core/spatialaxe-metromap](docs/images/spatialaxe-metromap.png)\n\n> [!NOTE]\n> We are currently extending the pipeline for the [10x Atera system](https://www.10xgenomics.com/platforms/atera).\n\n## Tools supported\n\nThe pipeline supports the following tools:\n\n- Segmenation methods:\n - [Baysor](https://doi.org/10.1038/s41587-021-01044-w)\n - [Cellpose](https://doi.org/10.1038/s41592-020-01018-x)\n - [Xenium ranger (XR)](https://www.10xgenomics.com/support/software/xenium-ranger/latest)\n - [StarDist](https://doi.org/10.48550/arXiv.2203.02284)\n- Segmentation free methods:\n - [Ficture](https://doi.org/10.1038/s41592-024-02415-2)\n - [Baysor](https://doi.org/10.1038/s41587-021-01044-w)\n- Transcript assignment methods:\n - [Segger](https://doi.org/10.1101/2025.03.14.643160)\n - [Proseg](https://doi.org/10.1038/s41592-025-02697-0)\n- Utility methods:\n - [SpatialData](https://doi.org/10.1038/s41592-024-02212-x)\n - [Baysor](https://doi.org/10.1038/s41587-021-01044-w)\n- QC methods:\n - [MultiQC Xenium Extra Plugin](https://github.com/MultiQC/xenium-extra)\n - [OPT](https://github.com/JEFworks-Lab/off-target-probe-tracker)\n\n## Usage\n\nOn release, automated continuous integration tests run the pipeline on a full-sized dataset on the AWS cloud infrastructure. This ensures that the pipeline runs on AWS, has sensible resource allocation defaults set to run on real-world datasets, and permits the persistent storage of results to benchmark between pipeline releases and other analysis sources. The results obtained from the full-sized test can be viewed on the [nf-core website](https://nf-co.re/spatialaxe/results).\n\n> [!NOTE]\n> The pipeline does not support conda currently. We are working on it.\n\n## Quick Start\n\n`samplesheet.csv`:\n\n```csv\nsample,bundle,image\ntest_sample,/path/to/xenium-bundle,/path/to/morphology.ome.tif\n```\n\nNow, you can run the pipeline using:\n\n### Run image-based segmentation mode
\n\n`CELLPOSE -> BAYSOR -> XR-IMPORT_SEGMENTATION -> SPATIALDATA -> QC`\n\n```bash\nnextflow run nf-core/spatialaxe \\\n -profile \\\n --input samplesheet.csv \\\n --outdir \\\n --mode \n```\n\n### Run coordinate-based segmentation mode
\n\n`PROSEG -> PROSEG2BAYSOR -> XR-IMPORT_SEGMENTATION -> SPATIALDATA -> QC`\n\n```bash\nnextflow run nf-core/spatialaxe \\\n -profile \\\n --input samplesheet.csv \\\n --outdir \\\n --mode coordinate\n```\n\n### Run segfree mode
\n\n`BAYSOR_SEGFREE`\n\n```bash\nnextflow run nf-core/spatialaxe \\\n -profile \\\n --input samplesheet.csv \\\n --outdir \\\n --mode segfree\n```\n\n### Run preview mode
\n\n`BAYSOR_PREVIEW`\n\n```bash\nnextflow run nf-core/spatialaxe \\\n -profile \\\n --input samplesheet.csv \\\n --outdir \\\n --mode preview\n```\n\n### Run just the quality control
\n\n```bash\nnextflow run nf-core/spatialaxe \\\n -profile \\\n --input samplesheet.csv \\\n --outdir \\\n --mode qc\n```\n\n### Additional information\n\n> [!WARNING]\n> Please provide pipeline parameters via the CLI or Nextflow `-params-file` option. Custom config files including those provided by the `-c` Nextflow option can be used to provide any configuration _**except for parameters**_; see [docs](https://nf-co.re/docs/usage/getting_started/configuration#custom-configuration-files).\n\nFor more details and further functionality, please refer to the [usage documentation](https://nf-co.re/spatialaxe/usage) and the [parameter documentation](https://nf-co.re/spatialaxe/parameters).\n\n## Pipeline output\n\nTo see the results of an example test run with a full size dataset refer to the [results](https://nf-co.re/spatialaxe/results) tab on the nf-core website pipeline page.\nFor more details about the output files and reports, please refer to the\n[output documentation](https://nf-co.re/spatialaxe/output).\n\n## Runtime and resource estimations\n\n| Tool | Compute | Runtime (min / med / max) | Peak RSS (min / med / max) |\n| ------------------------- | ------- | ------------------------- | -------------------------- |\n| Cellpose | GPU | 1m / 4m / 1.4h | 10 GB / 26 GB / 554 GB |\n| Cellpose | CPU | 1.3h / 2.3h / 6.5h | 161 GB / 426 GB / 1115 GB |\n| StarDist | GPU | 1m / 4m / 7m | 5 GB / 12 GB / 18 GB |\n| StarDist | CPU | 5m / 6m / 7m | 18 GB / 18 GB / 18 GB |\n| Segger (create_dataset) | GPU | 2m / 9m / 31m | 1.7 GB / 14 GB / 50 GB |\n| Segger (create_dataset) | CPU | 13m / 21m / 46m | 13 GB / 19 GB / 49 GB |\n| Segger (train) | GPU | 10m / 43m / 2.9h | 30 GB / 33 GB / 60 GB |\n| Segger (predict) | GPU | 2m / 16m / 59m | 10 GB / 25 GB / 87 GB |\n| Baysor (whole-image) | CPU | 2m / 30m / 17h | 6 GB / 10 GB / 650 GB |\n| Baysor (tiled) | CPU | 1m / 18m / 13h | 0.2 GB / 34 GB / 530 GB |\n| Proseg | CPU | 1m / 18m / 6.8h | 279 MB / 3.8 GB / 136 GB |\n| XeniumRanger (resegment) | CPU | 18m / 39m / 3.7h | 28 GB / 54 GB / 60 GB |\n| XeniumRanger (import_seg) | CPU | 2m / 7m / 2.7h | 2.6 GB / 11 GB / 51 GB |\n| Ficture (preprocess) | CPU | 3m / 4m / 13m | 331 MB / 357 MB / 21 GB |\n\n- Cellpose GPU vs CPU: 35x faster on GPU (4m median vs 2.3h), 16x less memory (26 GB vs 426 GB)\n- Segger: Only tool that truly requires GPU for all 3 steps (create_dataset, train, predict)\n- StarDist: Very fast on CPU, GPU is not necessary to run its default model\n\n## Credits\n\nnf-core/spatialaxe is mainly developed by [Sameesh Kher](https://github.com/khersameesh24), [Dongze He](https://github.com/dongzehe), and [Florian Heyl](https://github.com/heylf).\n\nWe thank the following people for their extensive assistance in the development of this pipeline:\n\n- Tobias Krause\n- Krešimir Beštak (kbestak)\n- Matthias Hörtenhuber (mashehu)\n- Maxime Garcia (maxulysse)\n- Kübra Narcı (kubranarci)\n\n## Contributions and Support\n\nIf you would like to contribute to this pipeline, please see the [contributing guidelines](.github/CONTRIBUTING.md).\n\nFor further information or help, don't hesitate to get in touch on the [Slack `#spatialaxe` channel](https://nfcore.slack.com/channels/spatialaxe) (you can join with [this invite](https://nf-co.re/join/slack)).\n\n## Citations\n\nIf you use nf-core/spatialaxe for your analysis, please cite it using the following doi: [10.5281/zenodo.20733817](https://doi.org/10.5281/zenodo.20733817)\n\nAn extensive list of references for the tools used by the pipeline can be found in the [`CITATIONS.md`](CITATIONS.md) file.\n\nYou can cite the `nf-core` publication as follows:\n\n> **The nf-core framework for community-curated bioinformatics pipelines.**\n>\n> Philip Ewels, Alexander Peltzer, Sven Fillinger, Harshil Patel, Johannes Alneberg, Andreas Wilm, Maxime Ulysse Garcia, Paolo Di Tommaso & Sven Nahnsen.\n>\n> _Nat Biotechnol._ 2020 Feb 13. doi: [10.1038/s41587-020-0439-x](https://dx.doi.org/10.1038/s41587-020-0439-x).\n", "hasPart": [ { "@id": "main.nf" @@ -105,7 +105,7 @@ }, "mentions": [ { - "@id": "#f9351d64-871a-4ac7-b2f8-a41f21061c8e" + "@id": "#ae53c394-e66c-4071-90b6-f65fa2ca9cde" } ], "name": "nf-core/spatialaxe" @@ -132,19 +132,21 @@ "SoftwareSourceCode", "ComputationalWorkflow" ], - "contributor": [ + "author": [ { "@id": "https://orcid.org/0009-0008-2420-6464" }, - { - "@id": "#79ea84f2-1720-4192-abf8-4298bf91da8f" - }, { "@id": "https://orcid.org/0000-0002-3651-5685" } ], + "contributor": [ + { + "@id": "https://orcid.org/0000-0001-8259-7434" + } + ], "dateCreated": "", - "dateModified": "2026-06-26T11:19:26Z", + "dateModified": "2026-08-06T16:03:08Z", "dct:conformsTo": "https://bioschemas.org/profiles/ComputationalWorkflow/1.0-RELEASE/", "keywords": [ "nf-core", @@ -161,6 +163,14 @@ "license": [ "MIT" ], + "maintainer": [ + { + "@id": "https://orcid.org/0009-0008-2420-6464" + }, + { + "@id": "https://orcid.org/0000-0002-3651-5685" + } + ], "name": [ "nf-core/spatialaxe" ], @@ -175,7 +185,7 @@ "https://nf-co.re/spatialaxe/dev/" ], "version": [ - "1.1.0dev" + "1.0.1dev" ] }, { @@ -191,11 +201,11 @@ "version": "!>=25.04.0" }, { - "@id": "#f9351d64-871a-4ac7-b2f8-a41f21061c8e", + "@id": "#ae53c394-e66c-4071-90b6-f65fa2ca9cde", "@type": "TestSuite", "instance": [ { - "@id": "#6665fb11-77f3-4e28-a01c-3b13037a23a0" + "@id": "#c5acff29-7d94-4ad2-bdb8-b21c374cca24" } ], "mainEntity": { @@ -204,7 +214,7 @@ "name": "Test suite for nf-core/spatialaxe" }, { - "@id": "#6665fb11-77f3-4e28-a01c-3b13037a23a0", + "@id": "#c5acff29-7d94-4ad2-bdb8-b21c374cca24", "@type": "TestInstance", "name": "GitHub Actions workflow for testing nf-core/spatialaxe", "resource": "repos/nf-core/spatialaxe/actions/workflows/nf-test.yml", @@ -345,18 +355,26 @@ { "@id": "https://orcid.org/0009-0008-2420-6464", "@type": "Person", - "email": "khersameesh24@gmail.com", - "name": "Sameesh Kher" + "affiliation": "German Cancer Research Center (DKFZ), Heidelberg, DE", + "email": "sameesh.kher@dkfz-heidelberg.de", + "name": "Sameesh Kher", + "url": "https://github.com/khersameesh24" }, { - "@id": "#79ea84f2-1720-4192-abf8-4298bf91da8f", + "@id": "https://orcid.org/0000-0002-3651-5685", "@type": "Person", - "name": "Dongze He" + "affiliation": "German Cancer Research Center (DKFZ), Heidelberg, DE", + "email": "florian.heyl@dkfz-heidelberg.de", + "name": "Florian Heyl", + "url": "https://github.com/heylf" }, { - "@id": "https://orcid.org/0000-0002-3651-5685", + "@id": "https://orcid.org/0000-0001-8259-7434", "@type": "Person", - "name": "Florian Heyl" + "affiliation": "Altos Labs, San Diego, USA", + "email": "dongzehe.zaza@gmail.com", + "name": "Dongze He", + "url": "https://github.com/dongzehe" } ] } \ No newline at end of file diff --git a/subworkflows/local/baysor_run_prior_segmentation_mask/main.nf b/subworkflows/local/baysor_run_prior_segmentation_mask/main.nf index d5acc0a1..df9a6680 100644 --- a/subworkflows/local/baysor_run_prior_segmentation_mask/main.nf +++ b/subworkflows/local/baysor_run_prior_segmentation_mask/main.nf @@ -4,7 +4,7 @@ include { BAYSOR_PREPROCESS_TRANSCRIPTS } from '../../../modules/local/baysor/preprocess/main' include { BAYSOR_RUN } from '../../../modules/local/baysor/run/main' -include { XENIUMRANGER_IMPORT_SEGMENTATION } from '../../../modules/nf-core/xeniumranger/import-segmentation/main' +include { XENIUMRANGER_IMPORTSEGMENTATION } from '../../../modules/nf-core/xeniumranger/importsegmentation/main' workflow BAYSOR_RUN_PRIOR_SEGMENTATION_MASK { @@ -18,6 +18,7 @@ workflow BAYSOR_RUN_PRIOR_SEGMENTATION_MASK { min_qv // value: minimum transcript QV min_x // value: spatial filter lower x bound min_y // value: spatial filter lower y bound + expansion_distance // value: nuclear expansion distance main: @@ -69,13 +70,14 @@ workflow BAYSOR_RUN_PRIOR_SEGMENTATION_MASK { polygons2d, [], ch_coordinate_space.val, + expansion_distance, ) } - XENIUMRANGER_IMPORT_SEGMENTATION( + XENIUMRANGER_IMPORTSEGMENTATION( ch_imp_seg_inputs ) - ch_redefined_bundle = XENIUMRANGER_IMPORT_SEGMENTATION.out.outs + ch_redefined_bundle = XENIUMRANGER_IMPORTSEGMENTATION.out.outs emit: coordinate_space = ch_coordinate_space // channel: [ "pixels" ] diff --git a/subworkflows/local/baysor_run_transcripts_parquet/main.nf b/subworkflows/local/baysor_run_transcripts_parquet/main.nf index aff27051..eeaa6835 100644 --- a/subworkflows/local/baysor_run_transcripts_parquet/main.nf +++ b/subworkflows/local/baysor_run_transcripts_parquet/main.nf @@ -15,7 +15,7 @@ include { BAYSOR_RUN } from '../../../modules/local/baysor include { BAYSOR_PREPROCESS_TRANSCRIPTS } from '../../../modules/local/baysor/preprocess/main' include { XENIUM_PATCH_STITCH } from '../../../modules/local/xenium_patch/stitch/main' include { RECONSTRUCT_PATCHES } from '../../../modules/local/utility/reconstruct_patches/main' -include { XENIUMRANGER_IMPORT_SEGMENTATION } from '../../../modules/nf-core/xeniumranger/import-segmentation/main' +include { XENIUMRANGER_IMPORTSEGMENTATION } from '../../../modules/nf-core/xeniumranger/importsegmentation/main' workflow BAYSOR_RUN_TRANSCRIPTS_PARQUET { @@ -35,6 +35,7 @@ workflow BAYSOR_RUN_TRANSCRIPTS_PARQUET { min_qv // value: minimum transcript QV min_x // value: spatial filter lower x bound min_y // value: spatial filter lower y bound + expansion_distance // value: nuclear expansion distance main: @@ -112,11 +113,12 @@ workflow BAYSOR_RUN_TRANSCRIPTS_PARQUET { xr_transcript_metadata, xr_cell_polygons, [], [], [], - "microns" + "microns", + expansion_distance, ) } - XENIUMRANGER_IMPORT_SEGMENTATION (ch_xr) + XENIUMRANGER_IMPORTSEGMENTATION (ch_xr) } else { @@ -154,13 +156,14 @@ workflow BAYSOR_RUN_TRANSCRIPTS_PARQUET { segmentation_csv, polygons2d, [], [], [], - ch_coordinate_space.val) + ch_coordinate_space.val, + expansion_distance) } - XENIUMRANGER_IMPORT_SEGMENTATION(ch_xr) + XENIUMRANGER_IMPORTSEGMENTATION(ch_xr) } emit: - redefined_bundle = XENIUMRANGER_IMPORT_SEGMENTATION.out.outs + redefined_bundle = XENIUMRANGER_IMPORTSEGMENTATION.out.outs coordinate_space = ch_coordinate_space } diff --git a/subworkflows/local/baysor_run_transcripts_parquet_tiled/main.nf b/subworkflows/local/baysor_run_transcripts_parquet_tiled/main.nf index 70045331..5e69d2d9 100644 --- a/subworkflows/local/baysor_run_transcripts_parquet_tiled/main.nf +++ b/subworkflows/local/baysor_run_transcripts_parquet_tiled/main.nf @@ -6,7 +6,7 @@ include { XENIUM_PATCH_DIVIDE } from '../../../modules/local/xenium include { BAYSOR_PREPROCESS_TRANSCRIPTS } from '../../../modules/local/baysor/preprocess/main' include { BAYSOR_RUN } from '../../../modules/local/baysor/run/main' include { XENIUM_PATCH_STITCH } from '../../../modules/local/xenium_patch/stitch/main' -include { XENIUMRANGER_IMPORT_SEGMENTATION } from '../../../modules/nf-core/xeniumranger/import-segmentation/main' +include { XENIUMRANGER_IMPORTSEGMENTATION } from '../../../modules/nf-core/xeniumranger/importsegmentation/main' workflow BAYSOR_RUN_TRANSCRIPTS_PARQUET_TILED { @@ -19,6 +19,7 @@ workflow BAYSOR_RUN_TRANSCRIPTS_PARQUET_TILED { min_qv // value: minimum transcript QV min_x // value: spatial filter lower x bound min_y // value: spatial filter lower y bound + expansion_distance // value: nuclear expansion distance main: @@ -93,12 +94,12 @@ workflow BAYSOR_RUN_TRANSCRIPTS_PARQUET_TILED { .combine(XENIUM_PATCH_STITCH.out.xr_polygons_transcript, by: 0) .combine(ch_coordinate_space) .map { meta, bundle, geojson, csv, coord_space -> - tuple(meta, bundle, csv, geojson, [], [], [], coord_space) + tuple(meta, bundle, csv, geojson, [], [], [], coord_space, expansion_distance) } - XENIUMRANGER_IMPORT_SEGMENTATION ( ch_xr ) + XENIUMRANGER_IMPORTSEGMENTATION ( ch_xr ) emit: coordinate_space = ch_coordinate_space // channel: [ "microns" ] - redefined_bundle = XENIUMRANGER_IMPORT_SEGMENTATION.out.outs // channel: [ val(meta), ["redefined-xenium-bundle"] ] + redefined_bundle = XENIUMRANGER_IMPORTSEGMENTATION.out.outs // channel: [ val(meta), ["redefined-xenium-bundle"] ] } diff --git a/subworkflows/local/cellpose_baysor_import_segmentation/main.nf b/subworkflows/local/cellpose_baysor_import_segmentation/main.nf index 38bbcc74..4f90ba49 100644 --- a/subworkflows/local/cellpose_baysor_import_segmentation/main.nf +++ b/subworkflows/local/cellpose_baysor_import_segmentation/main.nf @@ -11,7 +11,7 @@ include { CONVERT_MASK_UINT32 } from '../../../modules/local/utilit include { BAYSOR_PREPROCESS_TRANSCRIPTS } from '../../../modules/local/baysor/preprocess/main' include { RESIZE_TIF } from '../../../modules/local/utility/resize_tif/main' include { GET_TRANSCRIPTS_COORDINATES } from '../../../modules/local/utility/get_coordinates/main' -include { XENIUMRANGER_IMPORT_SEGMENTATION } from '../../../modules/nf-core/xeniumranger/import-segmentation/main' +include { XENIUMRANGER_IMPORTSEGMENTATION } from '../../../modules/nf-core/xeniumranger/importsegmentation/main' workflow CELLPOSE_BAYSOR_IMPORT_SEGMENTATION { take: @@ -30,6 +30,7 @@ workflow CELLPOSE_BAYSOR_IMPORT_SEGMENTATION { nucleus_segmentation_only // value: bool sharpen_tiff // value: bool stardist_nuclei_model // value: stardist pretrained model name + expansion_distance // value: nuclear expansion distance main: @@ -180,12 +181,13 @@ workflow CELLPOSE_BAYSOR_IMPORT_SEGMENTATION { [], [], ch_coordinate_space.val, + expansion_distance, ) } - XENIUMRANGER_IMPORT_SEGMENTATION(ch_imp_seg_inputs) + XENIUMRANGER_IMPORTSEGMENTATION(ch_imp_seg_inputs) emit: coordinate_space = ch_coordinate_space // channel: [ val("microns") ] - redefined_bundle = XENIUMRANGER_IMPORT_SEGMENTATION.out.outs // channel: [ val(meta), ["redefined-xenium-bundle"] ] + redefined_bundle = XENIUMRANGER_IMPORTSEGMENTATION.out.outs // channel: [ val(meta), ["redefined-xenium-bundle"] ] } diff --git a/subworkflows/local/cellpose_resolift_morphology_ome_tif/main.nf b/subworkflows/local/cellpose_resolift_morphology_ome_tif/main.nf index 6bb38ded..59a0d703 100644 --- a/subworkflows/local/cellpose_resolift_morphology_ome_tif/main.nf +++ b/subworkflows/local/cellpose_resolift_morphology_ome_tif/main.nf @@ -9,7 +9,7 @@ include { CELLPOSE as CELLPOSE_CELLS } from '../../../modules/nf-core/cell include { EXTRACT_DAPI } from '../../../modules/local/utility/extract_dapi/main' include { STARDIST as STARDIST_NUCLEI } from '../../../modules/nf-core/stardist/main' include { CONVERT_MASK_UINT32 } from '../../../modules/local/utility/convert_mask_uint32/main' -include { XENIUMRANGER_IMPORT_SEGMENTATION } from '../../../modules/nf-core/xeniumranger/import-segmentation/main' +include { XENIUMRANGER_IMPORTSEGMENTATION } from '../../../modules/nf-core/xeniumranger/importsegmentation/main' workflow CELLPOSE_RESOLIFT_MORPHOLOGY_OME_TIF { take: @@ -20,6 +20,7 @@ workflow CELLPOSE_RESOLIFT_MORPHOLOGY_OME_TIF { nucleus_segmentation_only // value: bool sharpen_tiff // value: bool stardist_nuclei_model // value: stardist pretrained model name + expansion_distance // value: nuclear expansion distance main: @@ -106,9 +107,10 @@ workflow CELLPOSE_RESOLIFT_MORPHOLOGY_OME_TIF { [], [], coord_space, + expansion_distance, ) } - XENIUMRANGER_IMPORT_SEGMENTATION( + XENIUMRANGER_IMPORTSEGMENTATION( ch_imp_seg_inputs ) } @@ -128,14 +130,15 @@ workflow CELLPOSE_RESOLIFT_MORPHOLOGY_OME_TIF { cells_seg, [], coord_space, + expansion_distance, ) } - XENIUMRANGER_IMPORT_SEGMENTATION( + XENIUMRANGER_IMPORTSEGMENTATION( ch_imp_seg_inputs ) } emit: coordinate_space = ch_coordinate_space // channel: [ ["pixels"] ] - redefined_bundle = XENIUMRANGER_IMPORT_SEGMENTATION.out.outs // channel: [ val(meta), ["redefined-xenium-bundle"] ] + redefined_bundle = XENIUMRANGER_IMPORTSEGMENTATION.out.outs // channel: [ val(meta), ["redefined-xenium-bundle"] ] } diff --git a/subworkflows/local/proseg_preset_proseg2baysor/main.nf b/subworkflows/local/proseg_preset_proseg2baysor/main.nf index 3f9d8c99..47b38013 100644 --- a/subworkflows/local/proseg_preset_proseg2baysor/main.nf +++ b/subworkflows/local/proseg_preset_proseg2baysor/main.nf @@ -4,12 +4,13 @@ include { PROSEG } from '../../../modules/local/proseg/preset/main' include { PROSEG2BAYSOR } from '../../../modules/local/proseg/proseg2baysor/main' -include { XENIUMRANGER_IMPORT_SEGMENTATION } from '../../../modules/nf-core/xeniumranger/import-segmentation/main' +include { XENIUMRANGER_IMPORTSEGMENTATION } from '../../../modules/nf-core/xeniumranger/importsegmentation/main' workflow PROSEG_PRESET_PROSEG2BAYSOR { take: ch_bundle_path // channel: [ val(meta), ["path-to-xenium-bundle"] ] ch_transcripts_file // channel: [ val(meta), [ "transcripts.parquet" ] ] + expansion_distance // value: nuclear expansion distance main: @@ -37,14 +38,15 @@ workflow PROSEG_PRESET_PROSEG2BAYSOR { [], [], ch_coordinate_space.val, + expansion_distance, ) } - XENIUMRANGER_IMPORT_SEGMENTATION( + XENIUMRANGER_IMPORTSEGMENTATION( ch_imp_seg_inputs ) emit: coordinate_space = ch_coordinate_space // channel: [ "microns" ] - redefined_bundle = XENIUMRANGER_IMPORT_SEGMENTATION.out.outs // channel: [ val(meta), ["redefined-xenium-bundle"] ] + redefined_bundle = XENIUMRANGER_IMPORTSEGMENTATION.out.outs // channel: [ val(meta), ["redefined-xenium-bundle"] ] } diff --git a/subworkflows/local/proseg_preset_proseg2baysor_tiled/main.nf b/subworkflows/local/proseg_preset_proseg2baysor_tiled/main.nf index 7ff6b783..a39242c5 100644 --- a/subworkflows/local/proseg_preset_proseg2baysor_tiled/main.nf +++ b/subworkflows/local/proseg_preset_proseg2baysor_tiled/main.nf @@ -6,13 +6,14 @@ include { XENIUM_PATCH_DIVIDE } from '../../../modules/local/xenium include { PROSEG } from '../../../modules/local/proseg/preset/main' include { PROSEG2BAYSOR } from '../../../modules/local/proseg/proseg2baysor/main' include { XENIUM_PATCH_STITCH } from '../../../modules/local/xenium_patch/stitch/main' -include { XENIUMRANGER_IMPORT_SEGMENTATION } from '../../../modules/nf-core/xeniumranger/import-segmentation/main' +include { XENIUMRANGER_IMPORTSEGMENTATION } from '../../../modules/nf-core/xeniumranger/importsegmentation/main' workflow PROSEG_PRESET_PROSEG2BAYSOR_TILED { take: ch_bundle_path // channel: [ val(meta), ["path-to-xenium-bundle"] ] ch_transcripts_file // channel: [ val(meta), [ "transcripts.parquet" ] ] + expansion_distance // value: nuclear expansion distance main: @@ -75,12 +76,12 @@ workflow PROSEG_PRESET_PROSEG2BAYSOR_TILED { .combine(XENIUM_PATCH_STITCH.out.xr_polygons_transcript, by: 0) .combine(ch_coordinate_space) .map { meta, bundle, geojson, csv, coord_space -> - tuple(meta, bundle, csv, geojson, [], [], [], coord_space) + tuple(meta, bundle, csv, geojson, [], [], [], coord_space, expansion_distance) } - XENIUMRANGER_IMPORT_SEGMENTATION ( ch_xr ) + XENIUMRANGER_IMPORTSEGMENTATION ( ch_xr ) emit: coordinate_space = ch_coordinate_space // channel: [ "microns" ] - redefined_bundle = XENIUMRANGER_IMPORT_SEGMENTATION.out.outs // channel: [ val(meta), ["redefined-xenium-bundle"] ] + redefined_bundle = XENIUMRANGER_IMPORTSEGMENTATION.out.outs // channel: [ val(meta), ["redefined-xenium-bundle"] ] } diff --git a/subworkflows/local/segger_create_train_predict/main.nf b/subworkflows/local/segger_create_train_predict/main.nf index 3f832d61..ab9ae090 100644 --- a/subworkflows/local/segger_create_train_predict/main.nf +++ b/subworkflows/local/segger_create_train_predict/main.nf @@ -6,13 +6,14 @@ include { SEGGER2XR } from '../../../modules/local/utilit include { SEGGER_TRAIN } from '../../../modules/local/segger/train/main' include { SEGGER_PREDICT } from '../../../modules/local/segger/predict/main' include { SEGGER_CREATE_DATASET } from '../../../modules/local/segger/create_dataset/main' -include { XENIUMRANGER_IMPORT_SEGMENTATION } from '../../../modules/nf-core/xeniumranger/import-segmentation/main' +include { XENIUMRANGER_IMPORTSEGMENTATION } from '../../../modules/nf-core/xeniumranger/importsegmentation/main' workflow SEGGER_CREATE_TRAIN_PREDICT { take: ch_bundle // channel: [ val(meta), ["path-to-xenium-bundle"] ] ch_transcripts_file // channel: [ val(meta), [bundle + "/transcripts.parquet"]] segger_model // value: path to a pre-trained segger model checkpoint (or null) + expansion_distance // value: nuclear expansion distance main: @@ -64,14 +65,15 @@ workflow SEGGER_CREATE_TRAIN_PREDICT { [], // cells [], // coordinate_transform ch_coordinate_space.val, + expansion_distance, ) } - XENIUMRANGER_IMPORT_SEGMENTATION( + XENIUMRANGER_IMPORTSEGMENTATION( ch_imp_seg_inputs ) emit: coordinate_space = ch_coordinate_space // channel: [ "microns" ] - redefined_bundle = XENIUMRANGER_IMPORT_SEGMENTATION.out.outs // channel: [ val(meta), ["redefined-xenium-bundle"] ] + redefined_bundle = XENIUMRANGER_IMPORTSEGMENTATION.out.outs // channel: [ val(meta), ["redefined-xenium-bundle"] ] } diff --git a/subworkflows/local/stardist_resolift_morphology_ome_tif/main.nf b/subworkflows/local/stardist_resolift_morphology_ome_tif/main.nf index bc255409..54e11f24 100644 --- a/subworkflows/local/stardist_resolift_morphology_ome_tif/main.nf +++ b/subworkflows/local/stardist_resolift_morphology_ome_tif/main.nf @@ -6,7 +6,7 @@ include { RESOLIFT } from '../../../modules/local/resoli include { EXTRACT_DAPI } from '../../../modules/local/utility/extract_dapi/main' include { STARDIST as STARDIST_NUCLEI } from '../../../modules/nf-core/stardist/main' include { CONVERT_MASK_UINT32 } from '../../../modules/local/utility/convert_mask_uint32/main' -include { XENIUMRANGER_IMPORT_SEGMENTATION } from '../../../modules/nf-core/xeniumranger/import-segmentation/main' +include { XENIUMRANGER_IMPORTSEGMENTATION } from '../../../modules/nf-core/xeniumranger/importsegmentation/main' workflow STARDIST_RESOLIFT_MORPHOLOGY_OME_TIF { take: @@ -14,6 +14,7 @@ workflow STARDIST_RESOLIFT_MORPHOLOGY_OME_TIF { ch_bundle_path // channel: [ val(meta), ["path-to-xenium-bundle"] ] sharpen_tiff // value: bool stardist_nuclei_model // value: stardist pretrained model name + expansion_distance // value: nuclear expansion distance main: @@ -58,13 +59,14 @@ workflow STARDIST_RESOLIFT_MORPHOLOGY_OME_TIF { [], [], ch_coordinate_space.val, + expansion_distance, ) } - XENIUMRANGER_IMPORT_SEGMENTATION( + XENIUMRANGER_IMPORTSEGMENTATION( ch_imp_seg_inputs ) emit: coordinate_space = ch_coordinate_space // channel: [ ["pixels"] ] - redefined_bundle = XENIUMRANGER_IMPORT_SEGMENTATION.out.outs // channel: [ val(meta), ["redefined-xenium-bundle"] ] + redefined_bundle = XENIUMRANGER_IMPORTSEGMENTATION.out.outs // channel: [ val(meta), ["redefined-xenium-bundle"] ] } diff --git a/subworkflows/local/utils_nfcore_spatialaxe_pipeline/main.nf b/subworkflows/local/utils_nfcore_spatialaxe_pipeline/main.nf index 70297723..f5484986 100644 --- a/subworkflows/local/utils_nfcore_spatialaxe_pipeline/main.nf +++ b/subworkflows/local/utils_nfcore_spatialaxe_pipeline/main.nf @@ -8,14 +8,14 @@ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -include { UTILS_NFSCHEMA_PLUGIN } from '../../nf-core/utils_nfschema_plugin' -include { paramsSummaryMap } from 'plugin/nf-schema' -include { samplesheetToList } from 'plugin/nf-schema' -include { completionEmail } from '../../nf-core/utils_nfcore_pipeline' -include { completionSummary } from '../../nf-core/utils_nfcore_pipeline' -include { imNotification } from '../../nf-core/utils_nfcore_pipeline' -include { UTILS_NFCORE_PIPELINE } from '../../nf-core/utils_nfcore_pipeline' -include { UTILS_NEXTFLOW_PIPELINE } from '../../nf-core/utils_nextflow_pipeline' +include { UTILS_NFSCHEMA_PLUGIN } from '../../nf-core/utils_nfschema_plugin' +include { paramsSummaryMap } from 'plugin/nf-schema' +include { samplesheetToList } from 'plugin/nf-schema' +include { paramsHelp } from 'plugin/nf-schema' +include { completionEmail } from '../../nf-core/utils_nfcore_pipeline' +include { completionSummary } from '../../nf-core/utils_nfcore_pipeline' +include { UTILS_NFCORE_PIPELINE } from '../../nf-core/utils_nfcore_pipeline' +include { UTILS_NEXTFLOW_PIPELINE } from '../../nf-core/utils_nextflow_pipeline' /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -63,6 +63,9 @@ workflow PIPELINE_INITIALISATION { // // Validate parameters and generate parameter summary to stdout // + + def before_text = "" + def after_text = "" before_text = """ -\033[2m----------------------------------------------------\033[0m- \033[0;32m,--.\033[0;30m/\033[0;32m,-.\033[0m @@ -166,7 +169,6 @@ workflow PIPELINE_COMPLETION { plaintext_email // boolean: Send plain-text email instead of HTML outdir // path: Path to output directory where results will be published monochrome_logs // boolean: Disable ANSI colour codes in log output - hook_url // string: hook URL for notifications multiqc_report // string: Path to MultiQC report main: @@ -190,13 +192,11 @@ workflow PIPELINE_COMPLETION { } completionSummary(monochrome_logs) - if (hook_url) { - imNotification(summary_params, hook_url) - } + } workflow.onError { - error("❌ Pipeline failed. Please refer to troubleshooting docs: https://nf-co.re/docs/usage/troubleshooting") + log.error "Pipeline failed. Please refer to troubleshooting docs for common issues: https://nf-co.re/docs/running/troubleshooting" } } @@ -294,23 +294,27 @@ def validateInputParameters( // Generate methods description for MultiQC // def toolCitationText() { + // TODO nf-core: Optionally add in-text citation tools to this list. // Can use ternary operators to dynamically construct based conditions, e.g. params["run_xyz"] ? "Tool (Foo et al. 2023)" : "", // Uncomment function in methodsDescriptionText to render in MultiQC report def citation_text = [ - "Tools used in the workflow included:", - "MultiQC (Ewels et al. 2016)", - ".", - ].join(' ').trim() + "Tools used in the workflow included:", + "FastQC (Andrews 2010),", + "MultiQC (Ewels et al. 2016)", + "." + ].join(' ').trim() return citation_text } def toolBibliographyText() { + // TODO nf-core: Optionally add bibliographic entries to this list. // Can use ternary operators to dynamically construct based conditions, e.g. params["run_xyz"] ? "
  • Author (2023) Pub name, Journal, DOI
  • " : "", // Uncomment function in methodsDescriptionText to render in MultiQC report def reference_text = [ - "
  • Ewels, P., Magnusson, M., Lundin, S., & Käller, M. (2016). MultiQC: summarize analysis results for multiple tools and samples in a single report. Bioinformatics , 32(19), 3047–3048. doi: /10.1093/bioinformatics/btw354
  • " - ].join(' ').trim() + "
  • Andrews S, (2010) FastQC, URL: https://www.bioinformatics.babraham.ac.uk/projects/fastqc/).
  • ", + "
  • Ewels, P., Magnusson, M., Lundin, S., & Käller, M. (2016). MultiQC: summarize analysis results for multiple tools and samples in a single report. Bioinformatics , 32(19), 3047–3048. doi: /10.1093/bioinformatics/btw354
  • " + ].join(' ').trim() return reference_text } diff --git a/subworkflows/local/xeniumranger_import_segmentation_redefine_bundle/main.nf b/subworkflows/local/xeniumranger_import_segmentation_redefine_bundle/main.nf index 4c7b41d5..a2d298f8 100644 --- a/subworkflows/local/xeniumranger_import_segmentation_redefine_bundle/main.nf +++ b/subworkflows/local/xeniumranger_import_segmentation_redefine_bundle/main.nf @@ -2,9 +2,9 @@ // Run xeniumranger import-segmentation // -include { XENIUMRANGER_IMPORT_SEGMENTATION as IMP_SEG_COUNT_MATRIX_EXP_DISTANCE } from '../../../modules/nf-core/xeniumranger/import-segmentation/main' -include { XENIUMRANGER_IMPORT_SEGMENTATION as IMP_SEG_POLYGON_GEOJSON_INPUT } from '../../../modules/nf-core/xeniumranger/import-segmentation/main' -include { XENIUMRANGER_IMPORT_SEGMENTATION as IMP_SEG_TRANS_MATRIX_INPUT } from '../../../modules/nf-core/xeniumranger/import-segmentation/main' +include { XENIUMRANGER_IMPORTSEGMENTATION as IMP_SEG_COUNT_MATRIX_EXP_DISTANCE } from '../../../modules/nf-core/xeniumranger/importsegmentation/main' +include { XENIUMRANGER_IMPORTSEGMENTATION as IMP_SEG_POLYGON_GEOJSON_INPUT } from '../../../modules/nf-core/xeniumranger/importsegmentation/main' +include { XENIUMRANGER_IMPORTSEGMENTATION as IMP_SEG_TRANS_MATRIX_INPUT } from '../../../modules/nf-core/xeniumranger/importsegmentation/main' workflow XENIUMRANGER_IMPORT_SEGMENTATION_REDEFINE_BUNDLE { @@ -40,6 +40,7 @@ workflow XENIUMRANGER_IMPORT_SEGMENTATION_REDEFINE_BUNDLE { [], [], ch_coordinate_space.val, + expansion_distance, ) } @@ -65,6 +66,7 @@ workflow XENIUMRANGER_IMPORT_SEGMENTATION_REDEFINE_BUNDLE { [], [], ch_coordinate_space.val, + expansion_distance, ) } @@ -88,6 +90,7 @@ workflow XENIUMRANGER_IMPORT_SEGMENTATION_REDEFINE_BUNDLE { polygons_geojson, [], ch_coordinate_space.val, + expansion_distance, ) } @@ -117,6 +120,7 @@ workflow XENIUMRANGER_IMPORT_SEGMENTATION_REDEFINE_BUNDLE { polygons_geojson, alignment_csv_file, ch_coordinate_space.val, + expansion_distance, ) } diff --git a/subworkflows/local/xeniumranger_resegment_morphology_ome_tif/main.nf b/subworkflows/local/xeniumranger_resegment_morphology_ome_tif/main.nf index bcd97584..7999b647 100644 --- a/subworkflows/local/xeniumranger_resegment_morphology_ome_tif/main.nf +++ b/subworkflows/local/xeniumranger_resegment_morphology_ome_tif/main.nf @@ -3,12 +3,13 @@ // include { XENIUMRANGER_RESEGMENT } from '../../../modules/nf-core/xeniumranger/resegment/main' -include { XENIUMRANGER_IMPORT_SEGMENTATION } from '../../../modules/nf-core/xeniumranger/import-segmentation/main' +include { XENIUMRANGER_IMPORTSEGMENTATION } from '../../../modules/nf-core/xeniumranger/importsegmentation/main' workflow XENIUMRANGER_RESEGMENT_MORPHOLOGY_OME_TIF { take: ch_bundle_path // channel: [ val(meta), ["path-to-xenium-bundle"] ] nucleus_segmentation_only // value: bool + expansion_distance // value: nuclear expansion distance main: @@ -41,14 +42,15 @@ workflow XENIUMRANGER_RESEGMENT_MORPHOLOGY_OME_TIF { cells_zarr, [], "pixels", + expansion_distance, ) } - XENIUMRANGER_IMPORT_SEGMENTATION( + XENIUMRANGER_IMPORTSEGMENTATION( ch_imp_seg_inputs ) - ch_redefined_bundle = XENIUMRANGER_IMPORT_SEGMENTATION.out.outs + ch_redefined_bundle = XENIUMRANGER_IMPORTSEGMENTATION.out.outs } else { diff --git a/tests/coordinate_mode.nf.test b/tests/coordinate_mode.nf.test index e0ff2ac4..0e866407 100644 --- a/tests/coordinate_mode.nf.test +++ b/tests/coordinate_mode.nf.test @@ -3,7 +3,55 @@ nextflow_pipeline { name "Test pipeline for the `coordinate` mode, test run the proseg subworkflow" script "../main.nf" tag "pipeline" - config "../conf/test_coordinate_mode.config" + config "../conf/tests/test_coordinate_mode.config" + + + test("-profile test") { + + when { + params { + outdir = "$outputDir" + } + } + + then { + // Stable_name: All files + folders in ${params.outdir}/ with a stable name. + // Zarr tables store one chunk file per obs/var column, leading to incoherent output files. + // Only the tables' existence is checked below instead. + // Xeniumranger's secondary analysis is skipped entirely on some runs (writing + // a single note.txt instead of the clustering/diffexp/pca/umap tree). + def stable_name = getAllFilesFromDir(params.outdir, relative: true, includeDir: true, ignore: [ + 'pipeline_info/*.{html,json,txt}', + '**/proseg/preset/**', + 'coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/tables/**', + 'coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/tables/**', + 'coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/tables/**', + 'coordinate/spatialdata/meta/spatialdata/test_run/metadata/tables/**', + 'xeniumranger/test_run/**', + 'coordinate/untar/test_run/**', + ]) + // stable_path: All files in ${params.outdir}/ with stable content + def stable_path = getAllFilesFromDir(params.outdir, ignoreFile: 'tests/.nftignore') + assertAll( + { assert workflow.success}, + { assert snapshot( + // pipeline versions.yml file for multiqc from which Nextflow version is removed because we test pipelines on multiple Nextflow versions + removeNextflowVersion("$outputDir/pipeline_info/nf_core_spatialaxe_software_mqc_versions.yml"), + // All stable path name, with a relative path + stable_name, + // All files with stable contents + stable_path + ).match() }, + { assert file("$outputDir/coordinate/proseg/preset/test_run/proseg-output.zarr").exists() }, + { assert file("$outputDir/coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/tables/table").exists() }, + { assert file("$outputDir/coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/tables/table").exists() }, + { assert file("$outputDir/coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/tables/raw_table").exists() }, + { assert file("$outputDir/coordinate/spatialdata/meta/spatialdata/test_run/metadata/tables/raw_table").exists() }, + { assert file("$outputDir/xeniumranger/test_run").exists() }, + { assert file("$outputDir/coordinate/untar/test_run").exists() }, + ) + } + } test("-profile test stub") { diff --git a/tests/coordinate_mode.nf.test.snap b/tests/coordinate_mode.nf.test.snap index 72a452ec..22434439 100644 --- a/tests/coordinate_mode.nf.test.snap +++ b/tests/coordinate_mode.nf.test.snap @@ -1,4 +1,354 @@ { + "-profile test": { + "content": [ + { + "PROSEG2BAYSOR": { + "proseg": "3.1.0" + }, + "PROSEG": { + "proseg": "3.1.0" + }, + "SPATIALDATA_MERGE_RAW_REDEFINED": { + "spatialdata": "0.7.2" + }, + "SPATIALDATA_META": { + "spatialdata": "0.7.2" + }, + "SPATIALDATA_WRITE_RAW_BUNDLE": { + "spatialdata": "0.7.2" + }, + "SPATIALDATA_WRITE_REDEFINED_BUNDLE": { + "spatialdata": "0.7.2" + }, + "UNTAR": { + "untar": 1.34 + }, + "Workflow": { + "nf-core/spatialaxe": "v1.0.1" + }, + "XENIUMRANGER_IMPORTSEGMENTATION": { + "xeniumranger": "4.0.1.1" + } + }, + [ + "coordinate", + "coordinate/multiqc", + "coordinate/multiqc/raw_bundle", + "coordinate/multiqc/raw_bundle/MultiQC-Pre-Xeniumranger-import-segmentation-Run_multiqc_report.html", + "coordinate/multiqc/raw_bundle/MultiQC-Pre-Xeniumranger-import-segmentation-Run_multiqc_report_data", + "coordinate/multiqc/raw_bundle/MultiQC-Pre-Xeniumranger-import-segmentation-Run_multiqc_report_data/llms-full.txt", + "coordinate/multiqc/raw_bundle/MultiQC-Pre-Xeniumranger-import-segmentation-Run_multiqc_report_data/multiqc.log", + "coordinate/multiqc/raw_bundle/MultiQC-Pre-Xeniumranger-import-segmentation-Run_multiqc_report_data/multiqc.parquet", + "coordinate/multiqc/raw_bundle/MultiQC-Pre-Xeniumranger-import-segmentation-Run_multiqc_report_data/multiqc_citations.txt", + "coordinate/multiqc/raw_bundle/MultiQC-Pre-Xeniumranger-import-segmentation-Run_multiqc_report_data/multiqc_data.json", + "coordinate/multiqc/raw_bundle/MultiQC-Pre-Xeniumranger-import-segmentation-Run_multiqc_report_data/multiqc_general_stats.txt", + "coordinate/multiqc/raw_bundle/MultiQC-Pre-Xeniumranger-import-segmentation-Run_multiqc_report_data/multiqc_software_versions.txt", + "coordinate/multiqc/raw_bundle/MultiQC-Pre-Xeniumranger-import-segmentation-Run_multiqc_report_data/multiqc_sources.txt", + "coordinate/multiqc/raw_bundle/MultiQC-Pre-Xeniumranger-import-segmentation-Run_multiqc_report_data/multiqc_xenium.txt", + "coordinate/multiqc/raw_bundle/MultiQC-Pre-Xeniumranger-import-segmentation-Run_multiqc_report_data/xenium_fov_quality_ranges.txt", + "coordinate/multiqc/raw_bundle/MultiQC-Pre-Xeniumranger-import-segmentation-Run_multiqc_report_data/xenium_segmentation.txt", + "coordinate/multiqc/raw_bundle/MultiQC-Pre-Xeniumranger-import-segmentation-Run_multiqc_report_data/xenium_transcript_quality_per_sample_table.txt", + "coordinate/multiqc/raw_bundle/MultiQC-Pre-Xeniumranger-import-segmentation-Run_multiqc_report_data/xenium_transcripts_per_gene.txt", + "coordinate/multiqc/raw_bundle/MultiQC-Pre-Xeniumranger-import-segmentation-Run_multiqc_report_plots", + "coordinate/multiqc/raw_bundle/MultiQC-Pre-Xeniumranger-import-segmentation-Run_multiqc_report_plots/pdf", + "coordinate/multiqc/raw_bundle/MultiQC-Pre-Xeniumranger-import-segmentation-Run_multiqc_report_plots/png", + "coordinate/multiqc/raw_bundle/MultiQC-Pre-Xeniumranger-import-segmentation-Run_multiqc_report_plots/svg", + "coordinate/multiqc/redefined_bundle", + "coordinate/multiqc/redefined_bundle/MultiQC-Post-Xeniumranger-import-segmentation-Run_multiqc_report.html", + "coordinate/multiqc/redefined_bundle/MultiQC-Post-Xeniumranger-import-segmentation-Run_multiqc_report_data", + "coordinate/multiqc/redefined_bundle/MultiQC-Post-Xeniumranger-import-segmentation-Run_multiqc_report_data/llms-full.txt", + "coordinate/multiqc/redefined_bundle/MultiQC-Post-Xeniumranger-import-segmentation-Run_multiqc_report_data/multiqc.log", + "coordinate/multiqc/redefined_bundle/MultiQC-Post-Xeniumranger-import-segmentation-Run_multiqc_report_data/multiqc.parquet", + "coordinate/multiqc/redefined_bundle/MultiQC-Post-Xeniumranger-import-segmentation-Run_multiqc_report_data/multiqc_citations.txt", + "coordinate/multiqc/redefined_bundle/MultiQC-Post-Xeniumranger-import-segmentation-Run_multiqc_report_data/multiqc_data.json", + "coordinate/multiqc/redefined_bundle/MultiQC-Post-Xeniumranger-import-segmentation-Run_multiqc_report_data/multiqc_software_versions.txt", + "coordinate/multiqc/redefined_bundle/MultiQC-Post-Xeniumranger-import-segmentation-Run_multiqc_report_data/multiqc_sources.txt", + "coordinate/proseg", + "coordinate/proseg/preset", + "coordinate/proseg/proseg2baysor", + "coordinate/proseg/proseg2baysor/test_run", + "coordinate/proseg/proseg2baysor/test_run/cell-polygons.geojson", + "coordinate/proseg/proseg2baysor/test_run/transcript-metadata.csv", + "coordinate/spatialdata", + "coordinate/spatialdata/merge", + "coordinate/spatialdata/merge/spatialdata", + "coordinate/spatialdata/merge/spatialdata/test_run", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/images", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/images/morphology_focus", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/images/morphology_focus/0", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/images/morphology_focus/0/c", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/images/morphology_focus/0/c/0", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/images/morphology_focus/0/c/0/0", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/images/morphology_focus/0/c/0/0/0", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/images/morphology_focus/0/c/0/0/1", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/images/morphology_focus/0/zarr.json", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/images/morphology_focus/1", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/images/morphology_focus/1/c", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/images/morphology_focus/1/c/0", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/images/morphology_focus/1/c/0/0", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/images/morphology_focus/1/c/0/0/0", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/images/morphology_focus/1/zarr.json", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/images/morphology_focus/2", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/images/morphology_focus/2/c", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/images/morphology_focus/2/c/0", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/images/morphology_focus/2/c/0/0", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/images/morphology_focus/2/c/0/0/0", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/images/morphology_focus/2/zarr.json", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/images/morphology_focus/3", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/images/morphology_focus/3/c", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/images/morphology_focus/3/c/0", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/images/morphology_focus/3/c/0/0", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/images/morphology_focus/3/c/0/0/0", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/images/morphology_focus/3/zarr.json", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/images/morphology_focus/4", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/images/morphology_focus/4/c", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/images/morphology_focus/4/c/0", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/images/morphology_focus/4/c/0/0", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/images/morphology_focus/4/c/0/0/0", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/images/morphology_focus/4/zarr.json", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/images/morphology_focus/zarr.json", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/images/zarr.json", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/points", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/points/raw_transcripts", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/points/raw_transcripts/points.parquet", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/points/raw_transcripts/points.parquet/part.0.parquet", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/points/raw_transcripts/zarr.json", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/points/zarr.json", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/shapes", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/shapes/raw_cell_boundaries", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/shapes/raw_cell_boundaries/shapes.parquet", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/shapes/raw_cell_boundaries/zarr.json", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/shapes/zarr.json", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/tables", + "coordinate/spatialdata/merge/spatialdata/test_run/merged_bundle/zarr.json", + "coordinate/spatialdata/meta", + "coordinate/spatialdata/meta/spatialdata", + "coordinate/spatialdata/meta/spatialdata/test_run", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/images", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/images/morphology_focus", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/images/morphology_focus/0", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/images/morphology_focus/0/c", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/images/morphology_focus/0/c/0", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/images/morphology_focus/0/c/0/0", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/images/morphology_focus/0/c/0/0/0", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/images/morphology_focus/0/c/0/0/1", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/images/morphology_focus/0/zarr.json", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/images/morphology_focus/1", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/images/morphology_focus/1/c", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/images/morphology_focus/1/c/0", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/images/morphology_focus/1/c/0/0", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/images/morphology_focus/1/c/0/0/0", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/images/morphology_focus/1/zarr.json", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/images/morphology_focus/2", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/images/morphology_focus/2/c", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/images/morphology_focus/2/c/0", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/images/morphology_focus/2/c/0/0", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/images/morphology_focus/2/c/0/0/0", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/images/morphology_focus/2/zarr.json", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/images/morphology_focus/3", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/images/morphology_focus/3/c", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/images/morphology_focus/3/c/0", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/images/morphology_focus/3/c/0/0", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/images/morphology_focus/3/c/0/0/0", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/images/morphology_focus/3/zarr.json", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/images/morphology_focus/4", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/images/morphology_focus/4/c", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/images/morphology_focus/4/c/0", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/images/morphology_focus/4/c/0/0", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/images/morphology_focus/4/c/0/0/0", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/images/morphology_focus/4/zarr.json", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/images/morphology_focus/zarr.json", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/images/zarr.json", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/points", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/points/raw_transcripts", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/points/raw_transcripts/points.parquet", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/points/raw_transcripts/points.parquet/part.0.parquet", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/points/raw_transcripts/zarr.json", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/points/zarr.json", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/shapes", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/shapes/raw_cell_boundaries", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/shapes/raw_cell_boundaries/shapes.parquet", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/shapes/raw_cell_boundaries/zarr.json", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/shapes/zarr.json", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/tables", + "coordinate/spatialdata/meta/spatialdata/test_run/metadata/zarr.json", + "coordinate/spatialdata/write", + "coordinate/spatialdata/write/spatialdata", + "coordinate/spatialdata/write/spatialdata/test_run", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/images", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/images/morphology_focus", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/images/morphology_focus/0", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/images/morphology_focus/0/c", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/images/morphology_focus/0/c/0", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/images/morphology_focus/0/c/0/0", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/images/morphology_focus/0/c/0/0/0", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/images/morphology_focus/0/c/0/0/1", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/images/morphology_focus/0/zarr.json", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/images/morphology_focus/1", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/images/morphology_focus/1/c", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/images/morphology_focus/1/c/0", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/images/morphology_focus/1/c/0/0", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/images/morphology_focus/1/c/0/0/0", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/images/morphology_focus/1/zarr.json", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/images/morphology_focus/2", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/images/morphology_focus/2/c", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/images/morphology_focus/2/c/0", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/images/morphology_focus/2/c/0/0", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/images/morphology_focus/2/c/0/0/0", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/images/morphology_focus/2/zarr.json", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/images/morphology_focus/3", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/images/morphology_focus/3/c", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/images/morphology_focus/3/c/0", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/images/morphology_focus/3/c/0/0", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/images/morphology_focus/3/c/0/0/0", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/images/morphology_focus/3/zarr.json", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/images/morphology_focus/4", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/images/morphology_focus/4/c", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/images/morphology_focus/4/c/0", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/images/morphology_focus/4/c/0/0", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/images/morphology_focus/4/c/0/0/0", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/images/morphology_focus/4/zarr.json", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/images/morphology_focus/zarr.json", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/images/zarr.json", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/points", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/points/transcripts", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/points/transcripts/points.parquet", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/points/transcripts/points.parquet/part.0.parquet", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/points/transcripts/zarr.json", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/points/zarr.json", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/shapes", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/shapes/cell_boundaries", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/shapes/cell_boundaries/shapes.parquet", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/shapes/cell_boundaries/zarr.json", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/shapes/zarr.json", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/tables", + "coordinate/spatialdata/write/spatialdata/test_run/raw_bundle/zarr.json", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/images", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/images/morphology_focus", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/images/morphology_focus/0", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/images/morphology_focus/0/c", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/images/morphology_focus/0/c/0", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/images/morphology_focus/0/c/0/0", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/images/morphology_focus/0/c/0/0/0", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/images/morphology_focus/0/c/0/0/1", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/images/morphology_focus/0/zarr.json", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/images/morphology_focus/1", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/images/morphology_focus/1/c", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/images/morphology_focus/1/c/0", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/images/morphology_focus/1/c/0/0", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/images/morphology_focus/1/c/0/0/0", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/images/morphology_focus/1/zarr.json", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/images/morphology_focus/2", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/images/morphology_focus/2/c", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/images/morphology_focus/2/c/0", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/images/morphology_focus/2/c/0/0", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/images/morphology_focus/2/c/0/0/0", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/images/morphology_focus/2/zarr.json", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/images/morphology_focus/3", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/images/morphology_focus/3/c", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/images/morphology_focus/3/c/0", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/images/morphology_focus/3/c/0/0", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/images/morphology_focus/3/c/0/0/0", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/images/morphology_focus/3/zarr.json", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/images/morphology_focus/4", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/images/morphology_focus/4/c", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/images/morphology_focus/4/c/0", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/images/morphology_focus/4/c/0/0", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/images/morphology_focus/4/c/0/0/0", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/images/morphology_focus/4/zarr.json", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/images/morphology_focus/zarr.json", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/images/zarr.json", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/points", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/points/transcripts", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/points/transcripts/points.parquet", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/points/transcripts/points.parquet/part.0.parquet", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/points/transcripts/zarr.json", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/points/zarr.json", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/shapes", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/shapes/cell_boundaries", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/shapes/cell_boundaries/shapes.parquet", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/shapes/cell_boundaries/zarr.json", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/shapes/zarr.json", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/tables", + "coordinate/spatialdata/write/spatialdata/test_run/redefined_bundle/zarr.json", + "coordinate/untar", + "coordinate/untar/test_run", + "pipeline_info", + "pipeline_info/nf_core_spatialaxe_software_mqc_versions.yml", + "xeniumranger", + "xeniumranger/test_run" + ], + [ + "multiqc_citations.txt:md5,4c806e63a283ec1b7e78cdae3a923d4f", + "multiqc_general_stats.txt:md5,e38eaaa52226a0d985578208b3261585", + "multiqc_software_versions.txt:md5,4c66c24e7c7ec9133e99bf68a3ab05f9", + "multiqc_xenium.txt:md5,f52e6ac3376565f7975e4e9fc23ed52a", + "xenium_fov_quality_ranges.txt:md5,153e0a905781d0b1b2f01b5ea6e384a8", + "xenium_segmentation.txt:md5,abd99ee57c53568a7f915bd10d2ee5af", + "xenium_transcript_quality_per_sample_table.txt:md5,d0135a0006f4ad3631b9f3906cc7ee0b", + "xenium_transcripts_per_gene.txt:md5,b46b3c414bc660e03e3df0345dd5e3e2", + "multiqc_citations.txt:md5,4c806e63a283ec1b7e78cdae3a923d4f", + "multiqc_software_versions.txt:md5,4c66c24e7c7ec9133e99bf68a3ab05f9", + "0:md5,397dc21e479c58fd2ffcbe6c3e627683", + "1:md5,f1a6b9238c3095bad7867b22f293e5e6", + "zarr.json:md5,893b4d8873fc997d364288c63ef0871f", + "0:md5,519d79fe18256d530a2070e31925fac6", + "zarr.json:md5,9e0748b559911795c141000a77ab7e59", + "0:md5,f349fb7934242be4cf4ac28e1a7e18f4", + "zarr.json:md5,32b707be767bd056085d0f349d3ab68c", + "0:md5,000e609e16f4975474a7d57eed232daa", + "zarr.json:md5,4690fb68f05cbca9148144c85bd9687f", + "0:md5,4890e52e8f0efc8f560bc51199d5071c", + "zarr.json:md5,1f4482a1e3b6e9ab30623b0ad12f5213", + "zarr.json:md5,b98263d3964a5236145ccf6c808f8919", + "0:md5,397dc21e479c58fd2ffcbe6c3e627683", + "1:md5,f1a6b9238c3095bad7867b22f293e5e6", + "zarr.json:md5,893b4d8873fc997d364288c63ef0871f", + "0:md5,519d79fe18256d530a2070e31925fac6", + "zarr.json:md5,9e0748b559911795c141000a77ab7e59", + "0:md5,f349fb7934242be4cf4ac28e1a7e18f4", + "zarr.json:md5,32b707be767bd056085d0f349d3ab68c", + "0:md5,000e609e16f4975474a7d57eed232daa", + "zarr.json:md5,4690fb68f05cbca9148144c85bd9687f", + "0:md5,4890e52e8f0efc8f560bc51199d5071c", + "zarr.json:md5,1f4482a1e3b6e9ab30623b0ad12f5213", + "zarr.json:md5,b98263d3964a5236145ccf6c808f8919", + "0:md5,397dc21e479c58fd2ffcbe6c3e627683", + "1:md5,f1a6b9238c3095bad7867b22f293e5e6", + "zarr.json:md5,893b4d8873fc997d364288c63ef0871f", + "0:md5,519d79fe18256d530a2070e31925fac6", + "zarr.json:md5,9e0748b559911795c141000a77ab7e59", + "0:md5,f349fb7934242be4cf4ac28e1a7e18f4", + "zarr.json:md5,32b707be767bd056085d0f349d3ab68c", + "0:md5,000e609e16f4975474a7d57eed232daa", + "zarr.json:md5,4690fb68f05cbca9148144c85bd9687f", + "0:md5,4890e52e8f0efc8f560bc51199d5071c", + "zarr.json:md5,1f4482a1e3b6e9ab30623b0ad12f5213", + "zarr.json:md5,b98263d3964a5236145ccf6c808f8919", + "0:md5,397dc21e479c58fd2ffcbe6c3e627683", + "1:md5,f1a6b9238c3095bad7867b22f293e5e6", + "zarr.json:md5,893b4d8873fc997d364288c63ef0871f", + "0:md5,519d79fe18256d530a2070e31925fac6", + "zarr.json:md5,9e0748b559911795c141000a77ab7e59", + "0:md5,f349fb7934242be4cf4ac28e1a7e18f4", + "zarr.json:md5,32b707be767bd056085d0f349d3ab68c", + "0:md5,000e609e16f4975474a7d57eed232daa", + "zarr.json:md5,4690fb68f05cbca9148144c85bd9687f", + "0:md5,4890e52e8f0efc8f560bc51199d5071c", + "zarr.json:md5,1f4482a1e3b6e9ab30623b0ad12f5213", + "zarr.json:md5,b98263d3964a5236145ccf6c808f8919" + ] + ], + "timestamp": "2026-08-04T14:29:47.103357166", + "meta": { + "nf-test": "0.9.5", + "nextflow": "26.04.6" + } + }, "-profile test stub": { "content": [ { @@ -24,9 +374,9 @@ "untar": 1.34 }, "Workflow": { - "nf-core/spatialaxe": "v1.1.0dev" + "nf-core/spatialaxe": "v1.0.1" }, - "XENIUMRANGER_IMPORT_SEGMENTATION": { + "XENIUMRANGER_IMPORTSEGMENTATION": { "xeniumranger": "4.0.1.1" } }, @@ -98,12 +448,11 @@ "coordinate/untar/test_run/nucleus_boundaries.parquet", "coordinate/untar/test_run/transcripts.parquet", "coordinate/untar/test_run/transcripts.zarr.zip", - "coordinate/xeniumranger", - "coordinate/xeniumranger/import_segementation", - "coordinate/xeniumranger/import_segementation/test_run", - "coordinate/xeniumranger/import_segementation/test_run/experiment.xenium", "pipeline_info", - "pipeline_info/nf_core_spatialaxe_software_mqc_versions.yml" + "pipeline_info/nf_core_spatialaxe_software_mqc_versions.yml", + "xeniumranger", + "xeniumranger/test_run", + "xeniumranger/test_run/experiment.xenium" ], [ ".stub:md5,d41d8cd98f00b204e9800998ecf8427e", @@ -112,41 +461,16 @@ ".stub:md5,d41d8cd98f00b204e9800998ecf8427e", ".stub:md5,d41d8cd98f00b204e9800998ecf8427e", "multiqc_report.html:md5,d41d8cd98f00b204e9800998ecf8427e", - "cell-polygons.geojson:md5,d41d8cd98f00b204e9800998ecf8427e", - "transcript-metadata.csv:md5,d41d8cd98f00b204e9800998ecf8427e", - "fake_file.txt:md5,d41d8cd98f00b204e9800998ecf8427e", "fake_file.txt:md5,d41d8cd98f00b204e9800998ecf8427e", "fake_file.txt:md5,d41d8cd98f00b204e9800998ecf8427e", "fake_file.txt:md5,d41d8cd98f00b204e9800998ecf8427e", - ".end-of-run:md5,d41d8cd98f00b204e9800998ecf8427e", - "analysis.tar.gz:md5,d41d8cd98f00b204e9800998ecf8427e", - "analysis.zarr.zip:md5,d41d8cd98f00b204e9800998ecf8427e", - "analysis_summary.html:md5,d41d8cd98f00b204e9800998ecf8427e", - "aux_outputs.tar.gz:md5,d41d8cd98f00b204e9800998ecf8427e", - "cell_boundaries.csv.gz:md5,d41d8cd98f00b204e9800998ecf8427e", - "cell_boundaries.parquet:md5,d41d8cd98f00b204e9800998ecf8427e", - "cell_feature_matrix.h5:md5,d41d8cd98f00b204e9800998ecf8427e", - "cell_feature_matrix.tar.gz:md5,d41d8cd98f00b204e9800998ecf8427e", - "cell_feature_matrix.zarr.zip:md5,d41d8cd98f00b204e9800998ecf8427e", - "cells.csv.gz:md5,d41d8cd98f00b204e9800998ecf8427e", - "cells.parquet:md5,d41d8cd98f00b204e9800998ecf8427e", - "cells.zarr.zip:md5,d41d8cd98f00b204e9800998ecf8427e", - "experiment.xenium:md5,d41d8cd98f00b204e9800998ecf8427e", - "gene_panel.json:md5,d41d8cd98f00b204e9800998ecf8427e", - "metrics_summary.csv:md5,d41d8cd98f00b204e9800998ecf8427e", - "morphology.ome.tif:md5,d41d8cd98f00b204e9800998ecf8427e", - "morphology_focus_0000.ome.tif:md5,d41d8cd98f00b204e9800998ecf8427e", - "nucleus_boundaries.csv.gz:md5,d41d8cd98f00b204e9800998ecf8427e", - "nucleus_boundaries.parquet:md5,d41d8cd98f00b204e9800998ecf8427e", - "transcripts.parquet:md5,d41d8cd98f00b204e9800998ecf8427e", - "transcripts.zarr.zip:md5,d41d8cd98f00b204e9800998ecf8427e", - "experiment.xenium:md5,d41d8cd98f00b204e9800998ecf8427e" + "fake_file.txt:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "timestamp": "2026-05-18T21:58:08.945192717", + "timestamp": "2026-08-04T14:30:03.467198601", "meta": { "nf-test": "0.9.5", - "nextflow": "25.10.4" + "nextflow": "26.04.6" } } } \ No newline at end of file diff --git a/tests/default.nf.test.snap b/tests/default.nf.test.snap index 3289c2a0..840d3c89 100644 --- a/tests/default.nf.test.snap +++ b/tests/default.nf.test.snap @@ -24,9 +24,9 @@ "untar": 1.34 }, "Workflow": { - "nf-core/spatialaxe": "v1.1.0dev" + "nf-core/spatialaxe": "v1.0.1" }, - "XENIUMRANGER_IMPORT_SEGMENTATION": { + "XENIUMRANGER_IMPORTSEGMENTATION": { "xeniumranger": "4.0.1.1" } }, @@ -98,12 +98,11 @@ "coordinate/untar/test_run/nucleus_boundaries.parquet", "coordinate/untar/test_run/transcripts.parquet", "coordinate/untar/test_run/transcripts.zarr.zip", - "coordinate/xeniumranger", - "coordinate/xeniumranger/import_segementation", - "coordinate/xeniumranger/import_segementation/test_run", - "coordinate/xeniumranger/import_segementation/test_run/experiment.xenium", "pipeline_info", - "pipeline_info/nf_core_spatialaxe_software_mqc_versions.yml" + "pipeline_info/nf_core_spatialaxe_software_mqc_versions.yml", + "xeniumranger", + "xeniumranger/test_run", + "xeniumranger/test_run/experiment.xenium" ], [ ".stub:md5,d41d8cd98f00b204e9800998ecf8427e", @@ -143,10 +142,10 @@ "experiment.xenium:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "timestamp": "2026-05-18T21:55:37.544217665", + "timestamp": "2026-07-28T12:20:41.663589777", "meta": { "nf-test": "0.9.5", - "nextflow": "25.10.4" + "nextflow": "26.04.6" } } } \ No newline at end of file diff --git a/tests/image_mode.nf.test b/tests/image_mode.nf.test index 4a594afa..667ac1e2 100644 --- a/tests/image_mode.nf.test +++ b/tests/image_mode.nf.test @@ -3,7 +3,7 @@ nextflow_pipeline { name "Test pipeline for the `image` mode, test run the cellpose->baysor subworkflow" script "../main.nf" tag "pipeline" - config "../conf/test_image_mode.config" + config "../conf/tests/test_image_mode.config" test("-profile test stub") { diff --git a/tests/image_mode.nf.test.snap b/tests/image_mode.nf.test.snap index a9b73c2c..129ba64b 100644 --- a/tests/image_mode.nf.test.snap +++ b/tests/image_mode.nf.test.snap @@ -30,18 +30,13 @@ "untar": 1.34 }, "Workflow": { - "nf-core/spatialaxe": "v1.1.0dev" + "nf-core/spatialaxe": "v1.0.1" }, - "XENIUMRANGER_IMPORT_SEGMENTATION": { + "XENIUMRANGER_IMPORTSEGMENTATION": { "xeniumranger": "4.0.1.1" } }, [ - "coordinate", - "coordinate/xeniumranger", - "coordinate/xeniumranger/import_segementation", - "coordinate/xeniumranger/import_segementation/test_run", - "coordinate/xeniumranger/import_segementation/test_run/experiment.xenium", "image", "image/baysor", "image/baysor/preprocess", @@ -115,10 +110,12 @@ "image/utility/resize_tif/test_run", "image/utility/resize_tif/test_run/resized_morphology_focus_0000.ome_cp_masks.tif.tif", "pipeline_info", - "pipeline_info/nf_core_spatialaxe_software_mqc_versions.yml" + "pipeline_info/nf_core_spatialaxe_software_mqc_versions.yml", + "xeniumranger", + "xeniumranger/test_run", + "xeniumranger/test_run/experiment.xenium" ], [ - "experiment.xenium:md5,d41d8cd98f00b204e9800998ecf8427e", "filtered_transcripts.csv:md5,d41d8cd98f00b204e9800998ecf8427e", "segmentation.csv:md5,d41d8cd98f00b204e9800998ecf8427e", "segmentation_polygons_2d.json:md5,d41d8cd98f00b204e9800998ecf8427e", @@ -158,10 +155,10 @@ "resized_morphology_focus_0000.ome_cp_masks.tif.tif:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "timestamp": "2026-05-18T22:00:39.030306506", + "timestamp": "2026-08-04T14:37:29.360791601", "meta": { "nf-test": "0.9.5", - "nextflow": "25.10.4" + "nextflow": "26.04.6" } } } \ No newline at end of file diff --git a/tests/nextflow.config b/tests/nextflow.config index 2c1bfd32..5a98fc21 100644 --- a/tests/nextflow.config +++ b/tests/nextflow.config @@ -7,7 +7,7 @@ // Or any resources requirements params { modules_testdata_base_path = 'https://raw.githubusercontent.com/nf-core/test-datasets/modules/data/' - pipelines_testdata_base_path = 'https://raw.githubusercontent.com/nf-core/test-datasets/refs/heads/spatialaxe' + pipelines_testdata_base_path = 'https://raw.githubusercontent.com/nf-core/test-datasets/refs/heads/spatialaxe/' } aws.client.anonymous = true // fixes S3 access issues on self-hosted runners diff --git a/tests/preview_mode.nf.test b/tests/preview_mode.nf.test index 5a423490..2b615814 100644 --- a/tests/preview_mode.nf.test +++ b/tests/preview_mode.nf.test @@ -3,7 +3,7 @@ nextflow_pipeline { name "Test pipeline for the `preview` mode, test run the basyor-preview subworkflow" script "../main.nf" tag "pipeline" - config "../conf/test_preview_mode.config" + config "../conf/tests/test_preview_mode.config" test("-profile test stub") { diff --git a/tests/preview_mode.nf.test.snap b/tests/preview_mode.nf.test.snap index 3d364f04..cc286151 100644 --- a/tests/preview_mode.nf.test.snap +++ b/tests/preview_mode.nf.test.snap @@ -18,7 +18,7 @@ "untar": 1.34 }, "Workflow": { - "nf-core/spatialaxe": "v1.1.0dev" + "nf-core/spatialaxe": "v1.0.1" } }, [ @@ -111,10 +111,10 @@ "umap_mqc.tsv:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "timestamp": "2026-06-17T11:15:30.764424637", + "timestamp": "2026-07-23T15:57:29.316600844", "meta": { "nf-test": "0.9.5", - "nextflow": "26.04.2" + "nextflow": "26.04.6" } } } \ No newline at end of file diff --git a/tests/segfree_mode.nf.test b/tests/segfree_mode.nf.test index 854b17d5..6d048bc1 100644 --- a/tests/segfree_mode.nf.test +++ b/tests/segfree_mode.nf.test @@ -3,7 +3,7 @@ nextflow_pipeline { name "Test pipeline" script "../main.nf" tag "pipeline" - config "../conf/test_segfree_mode.config" + config "../conf/tests/test_segfree_mode.config" test("-profile test stub") { diff --git a/tests/segfree_mode.nf.test.snap b/tests/segfree_mode.nf.test.snap index ac663a43..90a83476 100644 --- a/tests/segfree_mode.nf.test.snap +++ b/tests/segfree_mode.nf.test.snap @@ -12,7 +12,7 @@ "untar": 1.34 }, "Workflow": { - "nf-core/spatialaxe": "v1.1.0dev" + "nf-core/spatialaxe": "v1.0.1" } }, [ @@ -88,10 +88,10 @@ "transcripts.zarr.zip:md5,d41d8cd98f00b204e9800998ecf8427e" ] ], - "timestamp": "2026-05-18T22:02:39.947804998", + "timestamp": "2026-07-23T15:57:58.134363385", "meta": { "nf-test": "0.9.5", - "nextflow": "25.10.4" + "nextflow": "26.04.6" } } } \ No newline at end of file diff --git a/workflows/spatialaxe.nf b/workflows/spatialaxe.nf index d7f449b9..1a09f2dc 100644 --- a/workflows/spatialaxe.nf +++ b/workflows/spatialaxe.nf @@ -470,6 +470,7 @@ workflow SPATIALAXE { nucleus_segmentation_only, sharpen_tiff, stardist_nuclei_model, + expansion_distance, ) ch_redefined_bundle = CELLPOSE_BAYSOR_IMPORT_SEGMENTATION.out.redefined_bundle ch_coordinate_space = CELLPOSE_BAYSOR_IMPORT_SEGMENTATION.out.coordinate_space @@ -481,6 +482,7 @@ workflow SPATIALAXE { XENIUMRANGER_RESEGMENT_MORPHOLOGY_OME_TIF( ch_bundle_path, nucleus_segmentation_only, + expansion_distance, ) ch_redefined_bundle = XENIUMRANGER_RESEGMENT_MORPHOLOGY_OME_TIF.out.redefined_bundle ch_coordinate_space = XENIUMRANGER_RESEGMENT_MORPHOLOGY_OME_TIF.out.coordinate_space @@ -500,6 +502,7 @@ workflow SPATIALAXE { min_qv, min_x, min_y, + expansion_distance, ) } ch_redefined_bundle = BAYSOR_RUN_PRIOR_SEGMENTATION_MASK.out.redefined_bundle @@ -517,6 +520,7 @@ workflow SPATIALAXE { nucleus_segmentation_only, sharpen_tiff, stardist_nuclei_model, + expansion_distance, ) ch_redefined_bundle = CELLPOSE_RESOLIFT_MORPHOLOGY_OME_TIF.out.redefined_bundle ch_coordinate_space = CELLPOSE_RESOLIFT_MORPHOLOGY_OME_TIF.out.coordinate_space @@ -530,6 +534,7 @@ workflow SPATIALAXE { ch_bundle_path, sharpen_tiff, stardist_nuclei_model, + expansion_distance, ) ch_redefined_bundle = STARDIST_RESOLIFT_MORPHOLOGY_OME_TIF.out.redefined_bundle ch_coordinate_space = STARDIST_RESOLIFT_MORPHOLOGY_OME_TIF.out.coordinate_space @@ -550,6 +555,7 @@ workflow SPATIALAXE { PROSEG_PRESET_PROSEG2BAYSOR_TILED( ch_bundle_path, ch_transcripts_file, + expansion_distance, ) ch_redefined_bundle = PROSEG_PRESET_PROSEG2BAYSOR_TILED.out.redefined_bundle ch_coordinate_space = PROSEG_PRESET_PROSEG2BAYSOR_TILED.out.coordinate_space @@ -557,6 +563,7 @@ workflow SPATIALAXE { PROSEG_PRESET_PROSEG2BAYSOR( ch_bundle_path, ch_transcripts_file, + expansion_distance, ) ch_redefined_bundle = PROSEG_PRESET_PROSEG2BAYSOR.out.redefined_bundle ch_coordinate_space = PROSEG_PRESET_PROSEG2BAYSOR.out.coordinate_space @@ -570,6 +577,7 @@ workflow SPATIALAXE { ch_bundle_path, ch_transcripts_file, segger_model, + expansion_distance, ) ch_redefined_bundle = SEGGER_CREATE_TRAIN_PREDICT.out.redefined_bundle ch_coordinate_space = SEGGER_CREATE_TRAIN_PREDICT.out.coordinate_space @@ -601,6 +609,7 @@ workflow SPATIALAXE { min_qv, min_x, min_y, + expansion_distance, ) ch_redefined_bundle = BAYSOR_RUN_TRANSCRIPTS_PARQUET.out.redefined_bundle ch_coordinate_space = BAYSOR_RUN_TRANSCRIPTS_PARQUET.out.coordinate_space