Skip to main content

seqhesion

Sequence cohesion: which sequences group together, at every scale the data supports, and how strongly. Built for fungal ITS barcodes, from many small overlapping trees rather than one large one.

seqhesion takes a set of sequences and produces a hierarchy of groups, from near-identical sequences up to relationships across the whole corpus, with the evidence behind every group. It does not name anything. Labels may travel alongside the input for display, but nothing in the processing path reads them, and agreement with labels is never a target. Deciding which groups become named units is curation, and happens downstream.

The result is a map for navigating a large barcode collection: which sequences belong together, how confidently, and what else is nearby. It is not a phylogeny. Groups at the coarse and corpus levels are leads for further research, not taxonomic conclusions; ITS alone cannot settle deep relationships.

Principles

  • Label-blind. Names never enter a decision. They may be shown next to the output, and used afterwards as a sanity check, never as a target.
  • Many small trees. No single alignment of a diverse corpus is trustworthy. Each tree covers one neighbourhood of 150–180 sequences that align well, and a sequence's place in the hierarchy is decided by every tree that holds it.
  • Tree distance and identity distance are not comparable. Every grouping decision is made from the shard trees (model-corrected distance on trimmed columns, sub-resolution branches collapsed). Alignment identity (vsearch) is used only to decide what is sampled together: which sequences form a component or a shard. The identity_* columns of a release are reporting for readers, not evidence.
  • Annotate, don't threshold. Every group carries its confidence measures. Choosing a partition is left to the reader.
  • Nothing is corrected, nothing silently dropped. Sequences are used as given; every input is accounted for in a release, with the reason when it was not built.

How it works

  1. Input. Every input sequence is identified by a content hash: the smaller of sha256 of the cleaned sequence and of its reverse complement. seqhesion input prepares any FASTA this way; exact copies in either orientation become one input.

  2. Intake. pyitsx finds the ITS regions and orients each sequence. Sequences with a complete ITS1–5.8S–ITS2 become tips, exactly dereplicated (a tip's id is a hash of its extracted sequence). ITS2-only, chimeric and other sequences are counted by class and not built.

  3. Regions. Connected components of the graph of 90% centroids, linked at 86% identity. A component of 150 or more tips is built on its own. A smaller one draws its rooting context from its nearest sequences anywhere in the corpus; that context is pruned before grouping. A lone tip gets no tree.

  4. Covers. Two independent covers of each component by shards: a seed and its 149 nearest neighbours, topped up so every shard holds at least 30 sequences below 97% identity to its seed (150–180 sequences), plus a shared scaffold of up to 30 sequences for rooting. Every sequence is in at least three shards of each cover.

  5. Shard trees. MAFFT L-INS-i, trimAl -gappyout, FastTree -gtr -gamma; cached under a key of exactly what made them. Each tree is rooted on the scaffold, the scaffold pruned, and branches shorter than half an expected change collapsed.

  6. Co-association. For each pair of sequences, every shard holding both records the level at which it joins them: the diameter of the smallest clade holding both. The median over shards is the pair's join level. Average linkage over observed pairs only gives the hierarchy. Pairs no shard holds are not evidence, and parts nothing connects stay a forest. Both covers are pooled; a shard drawn by both (same members, so the same tree) counts once.

  7. Evidence. The hierarchy is cut at levels 0.005 … 0.1 (substitutions per site). Each group gets:

    • cohesion: the share of shard votes on its pairs that join them at or below the level;
    • pull: the share of its members' votes that join them to their strongest outside target;
    • margin = cohesion − pull: the confidence measure. It predicts which groups recur when the shards are resampled.

    Each group also carries its stem length, spread, nearest outside group, and every shard's verdict on it (clade, unresolved or conflict).

  8. Coarse layer (levels 0.125 … 0.3). Local shards rarely hold two distant sequences, so the groups at 0.1 (and lone tips) become units. Stratified sparse shards then sample them: one random member from each of 150 random units, plus an outgroup from outside the component, giving about 24 votes per unit pair. Average linkage over unit-pair medians builds levels above the fine ones.

  9. Corpus levels (0.4, 0.5, 0.75). Each component's groups at 0.3 become super-units, and a cover over them, chosen by representative identity, relates components across the corpus. The result is one tree over every tip; corpus groups may span many components.

  10. Releases and antenomina. A release is a set of TSV tables and a JSON manifest. Each group has an antenomen: a stable id carried from release to release when a group and its predecessor are each other's best match and share more than half of the inputs both releases hold. lineage.tsv logs every match, and an id is never reused.

The fine levels are where the shard trees resolve structure directly (to about 0.075). The coarse and corpus levels are relative: their groups are stable under resampling, but each is a starting point for investigation.

Install

pip install seqhesion          # or, from a clone: pip install -e '.[test]'

External tools, found on PATH: vsearch, MAFFT, trimAl and FastTree. To use a particular build, name it in SEQHESION_MAFFT, SEQHESION_TRIMAL or SEQHESION_FASTTREE. The shard-tree cache is keyed by each tool's version, so a different version builds new trees rather than reusing old ones.

Alignment is nearly all of the compute. An optimised MAFFT 7.526 whose output is byte-identical to stock, about 5x faster on Apple silicon and on AVX-512 x86, is at joshuaowalker/mafft (branch exact-speedups, with a technical report in paper/). Check any build against stock on a sample of your own shards before relying on it.

Use

From a FASTA to a release (every command takes --procs N):

seqhesion input   sequences.fasta INPUT           # content-hash ids, names.tsv, manifest
seqhesion intake  INPUT/sequences.fasta INTAKE    # pyitsx: extract, orient, dereplicate
seqhesion regions INTAKE REGIONS                  # writes REGIONS/large.txt and small.txt

# the fine hierarchy of every component (independent: run them in parallel)
for r in $(cat REGIONS/large.txt REGIONS/small.txt); do
    seqhesion build $r --out $r/hierarchy.json
done

# the coarse layer of every component
seqhesion sparse-plan INTAKE $(cat REGIONS/large.txt REGIONS/small.txt)
for r in $(cat REGIONS/large.txt REGIONS/small.txt); do seqhesion sparse-build $r; done

# corpus levels (corpus-trees --chunk I --of N splits the trees over machines)
seqhesion corpus-plan   INTAKE CORPUS $(cat REGIONS/large.txt REGIONS/small.txt)
seqhesion corpus-trees  CORPUS
seqhesion corpus-layer  CORPUS

seqhesion release OUT --input INPUT --intake INTAKE --layer --corpus CORPUS \
    $(for r in $(cat REGIONS/large.txt REGIONS/small.txt); do echo $r=$r/hierarchy.json; done) \
    [--previous PREVIOUS_RELEASE]

build is cover, prepare and hierarchy in one; they can also be run one at a time. Without --corpus, the coarse layer runs to 0.5 within each component; without --layer, a release stops at 0.1. --previous carries group ids forward from an earlier release.

Almost all of the compute is shard trees, one MAFFT L-INS-i alignment and one FastTree per shard. Trees are cached, so a rebuild after the corpus grows rebuilds only the shards that changed.

Releases

A release directory holds:

file contents
manifest.json schema (seqhesion-release/0.5), seqhesion commit, input fingerprint, method, levels, counts, and the columns of every table
inputs.tsv every input: its tip, and whether it was built, not built, or dropped (with its intake class)
tips.tsv, tips.fasta every tip of a built component, with its extracted, oriented full-ITS sequence
groups.tsv one row per distinct group: size, level range, parent, cohesion, pull, margin, stem, spread, nearest group, shard verdicts
group_levels.tsv, group_members.tsv a group's evidence at each level; its tips
membership.tsv per tip and level: its group, how firmly it belongs, its strongest outside pull
lineage.tsv, minted.tsv how each group id relates to the previous release; every id ever minted
dendrogram/ the linkage the levels are cut from, as Newick (corpus.nwk: one tree of every tip)
shards/ the prepared shard trees, for drawing and on-demand distances

The columns are documented in seqhesion/export.py and listed in every manifest.

Status

Version 0.1. seqhesion is in production on a corpus of fungal ITS sequences drawn mainly from MycoMap, with other sources: about 226,000 input sequences, 147,000 distinct full-ITS tips in 4,172 components. The method was developed and validated in a separate research prototype (simulation, reproducibility between independent covers, resampling of shards). The draft white paper in docs/whitepaper describes the method, its validation and its limits, and is revised alongside the code.

Not yet in the release: placement of ITS2-only sequences on the hierarchy. The code is in seqhesion/place.py, but running it at corpus scale awaits a batch interface.

License

BSD 3-Clause; see LICENSE.

Metadata

Release files for seqhesion 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for seqhesion 0.1.0
File Size Uploaded
seqhesion-0.1.0.tar.gz 80.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for seqhesion 0.1.0
File Interpreter ABI Platform
seqhesion-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 157.5 kB

Release files / seqhesion-0.1.0.tar.gz

Download URL seqhesion-0.1.0.tar.gz
Size 80.3 kB
Tags Source
SHA-256 checksum
How to use checksums
9bc5039dbe0b3273742d8fa6f01cd84f613a2b0a9a9697d9f3051476d7fbd518
BLAKE2b-256 checksum
How to use checksums
02c42970fd8c5ddf9caed2909abcb55c05a1dfc28e913ce3c7676d71ddc294cf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.

Transparency log

Release files / seqhesion-0.1.0-py3-none-any.whl

Download URL seqhesion-0.1.0-py3-none-any.whl
Size 77.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
910556b73ce92b3b48eb29daca329533f63d50f42150102fbde801d061d7c055
BLAKE2b-256 checksum
How to use checksums
3d636d2b0c07e77cec1cd19e14ed9348034746e6419321abfcb228d2d66843e9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page