Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,19 @@ jobs:
- uses: actions/setup-python@v6
with:
python-version: "3.11"
- name: Set up QEMU for Linux aarch64 wheel tests
uses: docker/setup-qemu-action@v4
with:
platforms: arm64
- name: Build and test repaired Linux wheels
uses: pypa/cibuildwheel@v4.1.0
env:
CIBW_PLATFORM: linux
CIBW_ARCHS_LINUX: "x86_64 aarch64"
with:
output-dir: dist-linux
- name: Verify repaired Linux wheels
run: python scripts/check_python_wheel.py --wheel-only --out-dir dist-linux
run: python scripts/check_python_wheel.py --wheel-only --out-dir dist-linux --require-repaired-linux-architectures x86_64 aarch64
- uses: actions/upload-artifact@v7
with:
name: dotmatch-linux-repaired-wheels
Expand Down Expand Up @@ -108,6 +113,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: Set up QEMU for Linux arm64 container tests
uses: docker/setup-qemu-action@v4
with:
platforms: arm64
- uses: docker/setup-buildx-action@v4
- name: Build local smoke-test image
run: docker build -t dotmatch:ci .
Expand All @@ -118,6 +127,14 @@ jobs:
docker run --rm dotmatch:ci dist ACGT AGGT | grep '^1$'
docker run --rm dotmatch:ci leq 1 ACGT AGGT | grep '^true$'
docker image inspect dotmatch:ci --format '{{ index .Config.Labels "org.opencontainers.image.version" }}' | grep "^${VERSION}$"
- name: Build Linux arm64 smoke-test image
run: docker buildx build --platform linux/arm64 --load -t dotmatch:ci-arm64 .
- name: Smoke test Linux arm64 container
run: |
VERSION=$(python -c "import tomllib; print(tomllib.load(open('pyproject.toml', 'rb'))['project']['version'])")
docker run --rm --platform linux/arm64 dotmatch:ci-arm64 --version | grep "^dotmatch ${VERSION}$"
docker run --rm --platform linux/arm64 dotmatch:ci-arm64 dist ACGT AGGT | grep '^1$'
docker run --rm --platform linux/arm64 dotmatch:ci-arm64 leq 1 ACGT AGGT | grep '^true$'
- uses: docker/metadata-action@v6
id: meta
with:
Expand All @@ -143,8 +160,18 @@ jobs:
with:
context: .
push: ${{ startsWith(github.ref, 'refs/tags/') }}
platforms: linux/amd64,linux/arm64
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
- name: Verify published multi-architecture manifest
if: startsWith(github.ref, 'refs/tags/')
env:
VERSION: ${{ github.ref_name }}
run: |
docker buildx imagetools inspect "ghcr.io/dnncha/dotmatch:${VERSION}" --raw > ghcr-manifest.json
python scripts/check_oci_manifest.py ghcr-manifest.json \
--require-platform linux/amd64 \
--require-platform linux/arm64

pypi-sdist:
name: Publish PyPI sdist, macOS wheel, and repaired Linux wheels
Expand Down
4 changes: 2 additions & 2 deletions .zenodo.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"title": "DotMatch: deterministic known-target short-DNA assignment for sequencing workflows",
"upload_type": "software",
"version": "0.2.2",
"version": "0.3.0",
"conceptdoi": "10.5281/zenodo.20541628",
"creators": [
{
Expand All @@ -25,7 +25,7 @@
],
"related_identifiers": [
{
"identifier": "10.5281/zenodo.20541629",
"identifier": "10.5281/zenodo.21511337",
"relation": "isNewVersionOf",
"scheme": "doi",
"resource_type": "software"
Expand Down
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,25 @@

All notable user-facing changes are tracked here. Public statements in release notes must stay aligned with `docs/scientific-claims.md`.

## 0.3.0 - 2026-07-23

### Added

- Added `dotmatch feature matrix` for deterministic cell-by-feature matrices
from pre-extracted observation tables. The command retains unique,
ambiguous, unmatched, and invalid observations in explicit output artifacts.
- Added strict paired R1/R2 support to `dotmatch pair-count`, including
canonical read-name and record-count checks before counting.
- Added a Galaxy XML wrapper and Planemo fixtures for CRISPR guide counting.
The wrapper is a local integration asset and does not indicate IUC
acceptance.

### Changed

- Configured tagged releases to build repaired Linux `x86_64` and `aarch64`
wheels and publish multi-architecture `linux/amd64` and `linux/arm64`
container manifests after their checks pass.

## 0.2.2 - 2026-07-23

### Changed
Expand Down
3 changes: 1 addition & 2 deletions CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ authors:
orcid: "https://orcid.org/0009-0003-5012-7229"
repository-code: "https://github.com/dnncha/dotmatch"
license: Apache-2.0
version: "0.2.2"
doi: 10.5281/zenodo.21511337
version: "0.3.0"
abstract: "DotMatch is a deterministic known-target short-DNA assignment engine for CRISPR guide counting, barcode demultiplexing, and fixed-target FASTQ workflows."
keywords:
- bioinformatics
Expand Down
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: dotmatch
Title: R Interface to DotMatch (Deterministic Short-DNA Assignment)
Version: 0.2.2
Version: 0.3.0
Authors@R:
person("DotMatch Contributors", email = "donncha@example.com", role = c("aut", "cre"))
Description: Provides R wrappers around the Python dotmatch package via
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ LABEL org.opencontainers.image.title="DotMatch" \
org.opencontainers.image.source="https://github.com/dnncha/dotmatch" \
org.opencontainers.image.url="https://dotmatch.readthedocs.io/" \
org.opencontainers.image.documentation="https://dotmatch.readthedocs.io/" \
org.opencontainers.image.version="0.2.2" \
org.opencontainers.image.version="0.3.0" \
org.opencontainers.image.licenses="Apache-2.0" \
org.opencontainers.image.authors="Donncha O'Toole"

Expand Down
49 changes: 48 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ match, an ambiguous match, unmatched, or invalid.
[![Documentation](https://readthedocs.org/projects/dotmatch/badge/?version=latest)](https://dotmatch.readthedocs.io/en/latest/)
[![Bioconda](https://img.shields.io/conda/vn/bioconda/dotmatch?label=Bioconda)](https://anaconda.org/bioconda/dotmatch)
[![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](https://github.com/dnncha/dotmatch/blob/main/LICENSE)
[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.21511337.svg)](https://doi.org/10.5281/zenodo.21511337)
[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.20541628.svg)](https://doi.org/10.5281/zenodo.20541628)

[Documentation](https://dotmatch.readthedocs.io/en/latest/) ·
[Getting started](https://dotmatch.readthedocs.io/en/latest/getting-started.html) ·
Expand Down Expand Up @@ -148,6 +148,53 @@ dotmatch barcode autopsy \
Open `autopsy/report.html` first. The tables beside it record offset scans,
near-neighbour barcodes, correction safety, and frequent unmatched windows.

### Build a cell-by-feature matrix from extracted observations

When an upstream workflow has already extracted feature windows and attached an
explicit cell identifier, DotMatch can write a sparse cells × features matrix:

```bash
dotmatch feature matrix \
--observations feature_observations.tsv \
--targets feature_library.tsv \
--id-column observation_id \
--cell-column cell_barcode \
--sequence-column feature_seq \
--metric hamming --k 1 \
--out-dir feature_matrix/
```

The output directory contains `matrix.mtx`, cell and feature axes, long-form
counts, per-observation assignments, per-cell QC, and a JSON summary. Only
unique assignments add a matrix count. This command does not perform FASTQ
pairing, cell-barcode correction, UMI deduplication, or cell calling; those
upstream steps should remain documented with the observation table.

See the [scverse and feature-barcode tutorial](https://dotmatch.readthedocs.io/en/latest/tutorials/scverse-perturb-seq.html)
for the file contract and AnnData handoff.

### Count target pairs across R1 and R2

Use `pair-count` when a left target and a right target are sequenced in
synchronized FASTQ mates:

```bash
dotmatch pair-count \
--left-targets r1_targets.tsv \
--right-targets r2_targets.tsv \
--left-reads sample_R1.fastq.gz \
--right-reads sample_R2.fastq.gz \
--left-start 0 --left-length 20 \
--right-start 0 --right-length 20 \
--k 1 --metric hamming \
--out pair_counts.tsv \
--summary pair_summary.json
```

R1 and R2 must contain the same records in the same order. DotMatch checks the
canonical read identifier before assignment and records input synchronization,
side-specific unmatched totals, and side-specific invalid totals in the summary.

### Check a target library

Before allowing mismatch correction, check whether neighbouring targets can
Expand Down
4 changes: 2 additions & 2 deletions app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const biocondaUrl = "https://anaconda.org/bioconda/dotmatch";
const releaseUrl = `${repoUrl}/releases`;
const containerUrl = `${repoUrl}/pkgs/container/dotmatch`;
const workflowExamplesUrl = `${repoUrl}/tree/main/examples/workflows`;
const doiUrl = "https://doi.org/10.5281/zenodo.21511337";
const doiUrl = "https://doi.org/10.5281/zenodo.20541628";

const basePath = process.env.NEXT_PUBLIC_BASE_PATH ?? "";
const assignmentWorkflowImage = `${basePath}/dotmatch-read-assignment-v2.webp`;
Expand All @@ -37,7 +37,7 @@ const structuredData = {
name: "DotMatch",
applicationCategory: "Bioinformatics software",
operatingSystem: "Linux, macOS",
softwareVersion: "0.2.2",
softwareVersion: "0.3.0",
softwareHelp: docsUrl,
codeRepository: repoUrl,
downloadUrl: pypiUrl,
Expand Down
4 changes: 2 additions & 2 deletions codemeta.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
"issueTracker": "https://github.com/dnncha/dotmatch/issues",
"license": "https://spdx.org/licenses/Apache-2.0",
"identifier": "https://doi.org/10.5281/zenodo.20541628",
"version": "0.2.2",
"softwareVersion": "0.2.2",
"version": "0.3.0",
"softwareVersion": "0.3.0",
"programmingLanguage": [
"C",
"Python",
Expand Down
22 changes: 19 additions & 3 deletions docs/assayspec.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,25 @@ Demux mode uses `mode = "demux"`, `barcodes`, `reads`, `[extract]`, and writes
`demuxed/`, `summary.json`, optional `assignments.tsv`, `ambiguous.fastq`, and
`unmatched.fastq`.

Pair mode uses `mode = "pair-count"`, `left_targets`, `right_targets`, `reads`,
`[left]`, and `[right]`. It writes `pair_counts.tsv`, `pair_summary.json`, and
optional `pair_assignments.tsv`.
Pair mode uses `mode = "pair-count"`, `left_targets`, `right_targets`, `[left]`, and `[right]`.
It accepts one of two input layouts:

```toml
# Both target windows occur in one read.
reads = "reads.fastq.gz"

# Or, remove reads and use synchronized mates.
left_reads = "sample_R1.fastq.gz"
right_reads = "sample_R2.fastq.gz"
```

For paired inputs, left extraction coordinates apply to `left_reads` and right
coordinates apply to `right_reads`. The two files must have the same number of
complete records in matching order. DotMatch compares canonical read IDs and
stops on the first mismatch. It writes `pair_counts.tsv`, `pair_summary.json`, and
optional `pair_assignments.tsv`. The summary records the input layout and
side-specific unmatched and invalid outcomes; methods and assay reports list
both FASTQ inputs.

## Safety Policy

Expand Down
48 changes: 48 additions & 0 deletions docs/command-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,54 @@ dotmatch audit --targets guides.tsv --k 3 --audit-mode exact --out-dir audit/
Proceed only when `safe_at_hamming_k2` or `safe_at_hamming_k3` is true for the
radius you plan to use.

## Pre-extracted Feature Matrices

```bash
dotmatch feature matrix \
--observations feature_observations.tsv \
--targets feature_library.tsv \
--id-column observation_id \
--cell-column cell_barcode \
--sequence-column feature_seq \
--metric hamming --k 1 --ambiguity-policy radius \
--out-dir feature_matrix/
```

Use `feature matrix` when an upstream workflow has already made a headered
observation table with an explicit cell identifier and a feature sequence
window. It writes a deterministic sparse Matrix Market matrix with cells on
rows and features on columns, plus feature/cell axes, long-form counts,
per-observation assignments, per-cell QC, and a JSON summary.

Only unique assignments add matrix counts. The command does not pair FASTQ
reads, correct cell barcodes, deduplicate UMIs, or call cells; retain those
upstream decisions and provenance with the input table.

## Pair Counting Across Paired FASTQs

`pair-count` assigns a left target and a right target for each record pair.
Use `--reads` when both windows are present in one read, or give synchronized
R1 and R2 files:

```bash
dotmatch pair-count \
--left-targets r1_targets.tsv \
--right-targets r2_targets.tsv \
--left-reads sample_R1.fastq.gz \
--right-reads sample_R2.fastq.gz \
--left-start 0 --left-length 20 \
--right-start 0 --right-length 20 \
--k 1 --metric hamming \
--out pair_counts.tsv \
--summary pair_summary.json \
--assignments pair_assignments.tsv
```

Paired inputs must contain the same number of complete FASTQ records in the
same order. DotMatch compares the first header token after removing a terminal
`/1` or `/2`; a mismatch stops the command before counts are written. The
summary records the input mode and side-specific unmatched and invalid totals.

## AssaySpec Workflows

```bash
Expand Down
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
project = "DotMatch"
author = "Donncha O'Toole"
copyright = "2026, Donncha O'Toole"
release = "0.2.2"
release = "0.3.0"
version = release

extensions = [
Expand Down
Loading
Loading