This document is the long-form companion to Table S2 in the paper
(functionality_table.tex). For every operation listed in the table,
it records the cell assignment (✓ full, ◐ partial, blank none) for each
of the three comparison libraries — ARGneedle-lib, matUtils (BTE), and
DendroPy — together with justification/references. The
comparisons are illustrative, not exhaustive: the goal is to defend
the markers in Table S2 with concrete pointers a reader can verify.
-
tskit — Python API reference: https://tskit.dev/tskit/docs/stable/python-api.html
-
ARGneedle-lib — manual: https://palamaralab.github.io/software/argneedle/manual/; Python source under https://github.com/PalamaraLab/arg-needle-lib/tree/main/src (the public package re-exports
arg_needle_lib_pybind,grm,metrics,serialize_arg, andconvert). -
matUtils (BTE) — matUtils CLI: https://usher-wiki.readthedocs.io/en/latest/matUtils.html; BTE Python interface: https://jmcbroome.github.io/BTE/build/html/index.html; source: https://github.com/jmcbroome/BTE/blob/main/src/bte.pyx.
-
DendroPy — library reference: https://jeetsukumaran.github.io/DendroPy/library/index.html.
The cell assignments below are defended against a frozen snapshot of
each library's user-facing documentation and source, captured on
2026-04-11 and kept in the working directory lib_docs/ (not
tracked in git). The pinned versions are:
| Library | Version | Release date |
|---|---|---|
| tskit | 1.0.2 | (as per tskit_python-api.html) |
| arg-needle-lib | 1.2.1 | 2025-11-07 |
| UShER/matUtils | 0.6.6 | 2024-07-11 |
| BTE | 0.9.3 | (latest tagged release on GitHub at snapshot time) |
| DendroPy | 5.0.8 | (as per dendropy_index.html) |
Each file in lib_docs/ was saved directly from the upstream source
listed below. To re-create the snapshot, fetch each URL at the
corresponding version tag.
Rendered documentation pages (HTML):
tskit_python-api.html— https://tskit.dev/tskit/docs/v1.0.2/python-api.htmlargneedle_manual.html— https://palamaralab.github.io/software/argneedle/manual/argneedlelib_readthedocs.html— https://arg-needle-lib.readthedocs.io/en/latest/argneedlelib_modules.html— https://arg-needle-lib.readthedocs.io/en/latest/modules.htmlmatutils.html— https://usher-wiki.readthedocs.io/en/latest/matUtils.htmldendropy_index.html— https://jeetsukumaran.github.io/DendroPy/library/index.htmldendropy_popgenstat.html— https://jeetsukumaran.github.io/DendroPy/library/popgenstat.htmldendropy_treecompare.html— https://jeetsukumaran.github.io/DendroPy/library/treecompare.htmldendropy_treemodel.html— https://jeetsukumaran.github.io/DendroPy/library/treemodel.html
Raw source (at the version tags listed above):
argneedle___init__.py,argneedle_convert.py,argneedle_grm.py,argneedle_metrics.py,argneedle_pybind.cpp— from https://github.com/PalamaraLab/arg-needle-lib/tree/v1.2.1 undersrc/arg_needle_lib/(Python) andsrc/(C++).bte.pyx,bte_index.rst— from https://github.com/jmcbroome/BTE/tree/v0.9.3 undersrc/anddocs/source/respectively.matutils.rst— from https://github.com/yatisht/usher/tree/v0.6.6 underdocs/.
An operation counts for a library only if it is directly accessible through that library's Python API. (For matUtils the Python API is BTE, since matUtils itself is CLI-only.)
- ✓ (full): documented and accessible, with no substantive restriction relative to the tskit equivalent.
- ◐ (partial): accessible (importable and callable from Python) but not clearly documented in the user-facing docs, or documented but restricted to a subset of what tskit offers.
- blank: not available through the Python API at all.
The cell assignments above score each library's Python API. A separate question is whether a library also exposes a documented C or C++ library that external code can link against directly.
-
arg-needle-lib. The ReadTheDocs site is titled "arg-needle-lib Python API Reference" (
argneedlelib_readthedocs.html) and its toctree contains only Python module pages; there is no C++ API reference or header-file documentation. The manual notes that C++ code exists but does not document it:"For more advanced users,
arg-needle-libcontains lower-level C++ functions that can be used by includingarg-needle-libas a C++ module. However, we have designedarg-needle-libso that users can in most cases simply use the Python API. Please reach out if you have a particular use case not included in the Python API and would like to discuss options for having it implemented." -
matUtils / UShER. The matUtils documentation (
matutils.rst,matutils.html) documents CLI subcommands only. The C++ code is compiled into thematUtilsandusherbinaries; no library-level API is documented for external C/C++ consumers. -
BTE. BTE is itself a Python extension, not a standalone C++ library. From
bte_index.rst:"BTE (Big Tree Explorer) is a Python extension for analysis and traversal of extremely large phylogenetic trees. […] BTE streamlines this process by exposing the heavily optimized MAT library underlying UShER and matUtils to Python."
This section is about properties of the in-memory data structure each library exposes — what biological entities can be represented and how they are accessed in code. File-format concerns are in section 2 (file formats).
Here by "ARG" we mean which segments of genome are inherited by whom: in other words, the topology and times only. The mutations/genotypes are covered by the next topics.
-
tskit (✓): the tree-sequence data model encodes a full ancestral recombination graph as a shared-edge structure. See
tskit.TreeSequenceand the data-model overview at https://tskit.dev/tskit/docs/stable/data-model.html. -
ARGneedle-lib (✓): the main data structure of the library,
arg_needle_lib.ARG, stores a full recombination graph and supports round-tripping viaserialize_arg/deserialize_arg. -
matUtils/BTE (blank): the MAT data model is a single phylogeny - there is no notion of recombination or alternative topologies along a genome.
-
DendroPy (blank): stores a
TreeorTreeList; no ARG data structure.
-
tskit (✓): the Site and Mutation tables are members of
TableCollection; mutations are anchored to specific edges and inherited by descendants during tree traversal. -
ARGneedle-lib (✓): mutations are an intrinsic part of the ARG;
generate_mutations,get_mutations_matrix, andget_genotypeoperate on mutations attached to ARG edges. -
matUtils/BTE (✓): mutation annotation is the entire point of the data model -
MATNode.mutationsis a first-class node property and the protobuf format encodes per-edge mutations natively. -
DendroPy (◐): sequence/character data lives in a separate
CharacterMatrixindexed by taxon; mutations are not anchored to tree edges (but, they are associated with nodes).
-
tskit (✓):
TreeSequence.reference_sequence/has_reference_sequenceandTableCollection.reference_sequencestore the reference inside the data structure itself, alongside schema metadata. -
ARGneedle-lib (blank): no reference-sequence concept.
-
matUtils/BTE (◐): the reference is supplied as an external
--input-fasta(-f) argument tomatUtils summary,matUtils extract, and as an argument toMATree.translate(so, "partial"). It is not stored inside the protobuf. -
DendroPy (blank): no reference concept.
-
tskit (✓): the
IndividualTablegroups one or more sample nodes under a single biological individual, capturing ploidy directly. This makes diploids and family-structured simulations first-class. -
ARGneedle-lib (◐): there is no representation of individuals, but the Python API has some diploid-aware methods:
exact_arg_grmandmonte_carlo_arg_grmaccept adiploid=Trueflag, andhaploid_grm_to_diploidoperates on GRMs; all these work by pairing neighbouring sample IDs as a haploid couple. Counted as partial because there is no representation in data besides this adjacent-IDs convention. -
matUtils/BTE (blank):
MATNodeis a single-leaf abstraction; no individual or ploidy concept. -
DendroPy (blank):
TaxonandTaxonNamespacecarry labels but there is no individual-vs-genome distinction.
-
tskit (✓): the
IndividualTablerecordsparentsfor each individual, so pedigrees are stored natively inside the tree sequence. -
ARGneedle-lib (blank): no pedigree encoding.
-
matUtils/BTE (blank): no pedigree encoding.
-
DendroPy (blank): no pedigree encoding.
-
tskit (✓): the
PopulationTablestores population assignments inside the data structure, and it is easy to pull sets of samples associated with each population. -
ARGneedle-lib (blank): samples are a flat haploid list; no built-in population concept.
-
matUtils/BTE (◐): matUtils accepts geographic region annotations as an external TSV (used by
introduce), so this is a "partial", but the MAT data structure itself has no population concept. -
DendroPy (◐): population labels can be encoded as taxon labels and passed to
PopulationPairSummaryStatistics(thus, "partial"), but they are not a typed part of the tree data structure.
-
tskit (✓): every column of every Table is a NumPy array (
nodes.time,edges.left,edges.right,mutations.node, ...). -
ARGneedle-lib (blank): the ARG is a C++ node-pointer object exposed through per-node Python wrappers; no NumPy column views.
-
matUtils/BTE (blank):
MATNodeis a per-node wrapper around the underlying C++ object; tree-wide attributes are accessed by traversal, not bulk array. -
DendroPy (blank): the
Tree/Node/Edgegraph is a pure Python object hierarchy.
-
tskit (✓): ancestral and derived states can be arbitrary strings.
-
ARGneedle-lib (blank): There is no notion of allelic state; only "lack of mutation" or "mutation".
-
matUtils/BTE (✓): Allows arbitrary data associated with mutations.
-
DendroPy (✓): Sophisticated models of character states.
This section is about which named on-disk file formats each library can read or write, including each library's native binary serialisation format.
-
tskit (✓): the
.treesfile format (kastore-backed) loaded viatskit.loadand written viaTreeSequence.dump. -
ARGneedle-lib (✓):
.argnHDF5 format viaarg_needle_lib.serialize_arg/deserialize_arg. -
matUtils/BTE (✓): UShER mutation-annotated tree protobuf (
.pb) viamatUtils extract --write-pbandMATree.save_pb/MATree.from_pb. -
DendroPy (blank): all on-disk formats are text (Newick, NEXUS, NeXML, PHYLIP, FASTA).
-
tskit (✓):
TreeSequence.write_vcfandTreeSequence.as_vcf. -
ARGneedle-lib (blank): no VCF writer. Note that
threadswill output to VCF (viathreads vcf), but AFAICT this needs a.threadsfile, and there is no current way to convert an.argnfile file to.threads. -
matUtils/BTE (✓):
matUtils extract --write-vcfandMATree.write_vcf(lib_docs/bte.pyx). -
DendroPy (blank): no VCF reader or writer.
-
tskit (✓):
Tree.as_newickandTreeSequence.as_newick. -
ARGneedle-lib (✓):
arg_needle_lib.arg_to_newick. -
matUtils/BTE (✓):
matUtils extract --write-newick;MATree.get_newick/MATree.write_newick. -
DendroPy (✓):
Tree.write(schema="newick")andTree.as_string(schema="newick").
-
tskit (✓):
TreeSequence.as_fasta/write_fastaandTreeSequence.alignments. -
ARGneedle-lib (blank): no FASTA writer.
-
matUtils/BTE (blank): BTE uses FASTA for various operations, but does not write out to FASTA.
-
DendroPy (✓):
CharacterMatrix.write(schema="fasta").
-
tskit (✓): writer, no reader (note this is "export")
-
ARGneedle-lib (blank): not supported.
-
matUtils/BTE (blank): not supported.
-
DendroPy (✓): first-class NEXUS reader/writer via the unified
read/writeschemas (NeXML is also supported).
-
tskit (✓):
TreeSequence.treesiterator andTreeSequence.breakpoints. -
ARGneedle-lib (blank): the C++ side iterates local trees, (see well-commented
arg-needle-lib/src/arg_traversal.hpp), but the Python API does not expose a per-tree iterator. -
matUtils/BTE (blank): the data model is a single phylogeny, not a sequence of trees along a genome; no notion of recombination.
-
DendroPy (blank): same - single tree or list of trees, no genomic positioning.
-
tskit (✓):
Tree.preorder,Tree.postorder,Tree.timeasc/timedesc. -
ARGneedle-lib (blank): the C++
arg_traversal.hppmachinery traverses ARG nodes (time_efficient_visit), but no Python-level pre/post-order iterator over local trees is exposed. -
matUtils/BTE (✓):
MATree.depth_first_expansion(pre-order) andMATree.breadth_first_expansion. -
DendroPy (✓):
Tree.preorder_node_iter,postorder_node_iter,levelorder_node_iter,leaf_node_iter.
-
tskit (✓):
Tree.mrcaandTree.tmrca. -
ARGneedle-lib (✓):
arg_needle_lib.most_recent_common_ancestor; also seearg_needle_lib.kc2_tmrca_sv_stabfor ARG-vs-ARG TMRCA comparisons. -
matUtils/BTE (✓):
MATree.LCA(node_ids)(last common ancestor) andMATNode.parentfor traversal upward. -
DendroPy (✓):
Tree.mrca(taxa=...).
-
tskit (✓):
Tree.branch_length,Tree.total_branch_length. -
ARGneedle-lib (✓): per-edge length is
e.parent.height - e.child.heighton anyARGEdge(for examplearg.node(1).parent_edges()[0]), andlocal_volume/total_volumegive total branch areas across all branches. -
matUtils/BTE (✓):
MATNode.branch_length/MATNode.set_branch_length. -
DendroPy (✓):
Edge.length,Tree.length(),Node.distance_from_root.
-
tskit (✓):
Tree.kc_distance,TreeSequence.kc_distance, andTree.rf_distance. -
ARGneedle-lib (✓):
arg_needle_lib.kc_topologyandarg_needle_lib.metrics.kc2_tmrca_mse_stab/rf_total_variation_stabcompute KC² and scaled RF between ARGs. -
matUtils/BTE (blank): no Robinson-Foulds, KC, or quartet distance is exposed in either matUtils or BTE; topology comparison is not part of the matUtils workflow.
-
DendroPy (✓):
treecompare.symmetric_difference(unweighted RF),weighted_robinson_foulds_distance,euclidean_distance. No KC, but good support generally.
-
tskit (✓):
Tree.colless_index,Tree.sackin_index,Tree.b1_index, andTree.b2_indexcover the standard balance/imbalance indices. -
ARGneedle-lib (blank): no balance metrics.
-
matUtils/BTE (◐):
MATree.tree_entropyreports per-split entropy andcount_clades_inclusivegives clade sizes - usable as shape descriptors but not the standard balance indices. -
DendroPy (✓):
treemeasure.colless_tree_imbalance,sackin_index,pybus_harvey_gamma.
-
tskit (✓):
Tree.rankandTree.unrankmap each leaf-labelled tree to a canonical(shape, label)integer pair and back;tskit.all_trees,all_tree_shapes, andall_tree_labellingsenumerate all topologies of a given size; andTopologyCountertabulates topology frequencies across a tree sequence. -
ARGneedle-lib (blank): no such enumeration API.
-
matUtils/BTE (blank): operates on a single mutation-annotated tree; no enumeration of alternative topologies.
-
DendroPy (blank): no such enumeration API.
-
tskit (✓):
TreeSequence.simplify. -
ARGneedle-lib (blank): no equivalent.
-
matUtils/BTE (blank):
MATreehas various functions for subtree selection, butsimplifyis an ARG operation, and matUtils is not an ARG library. -
DendroPy (blank): same.
-
tskit (✓):
TreeSequence.subsetandsimplifywith a sample list. -
ARGneedle-lib (blank): no Python-level subset operation.
-
matUtils/BTE (✓):
matUtils extract --samples/--clade/--regex;MATree.subtree,MATree.get_clade,MATree.get_regex,MATree.get_random. -
DendroPy (✓):
Tree.extract_tree_with_taxa,extract_tree_without_taxa,prune_taxa,prune_leaves_without_taxa.
-
tskit (✓):
TreeSequence.union. -
ARGneedle-lib (blank): no ARG union operation.
-
matUtils/BTE (blank): no union of two MATs.
-
DendroPy (blank):
TreeListconcatenates lists of trees but there is no shared-history union.
-
tskit (✓):
TreeSequence.keep_intervalsanddelete_intervals. -
ARGneedle-lib (✓):
arg_needle_lib.trim_arg -
matUtils/BTE (blank): the data model has no notion of genomic intervals over which the tree changes.
-
DendroPy (blank): same.
-
tskit (✓):
TreeSequence.trim. -
ARGneedle-lib (✓):
arg_needle_lib.trim_argprovides exactly this operation. -
matUtils/BTE (blank): not applicable.
-
DendroPy (blank): not applicable.
-
tskit (✓):
TreeSequence.extend_haplotypesreturns a new tree sequence in which the span of each ancestral node is extended across adjacent marginal trees wherever the relevant parent–child relationship continues to hold, producing a more parsimonious edge table without changing the genotypes. Introduced in Fritze et al. (2026). -
ARGneedle-lib (blank): no similar operation. library's ARG editing primitives are restricted to trimming.
-
matUtils/BTE (blank): not applicable.
-
DendroPy (blank): not applicable.
-
tskit (✓):
TreeSequence.diversityandsegregating_sites; branch and site mode, windowed. -
ARGneedle-lib (blank): no diversity statistics in the Python API.
-
matUtils/BTE (◐):
MATree.compute_nucleotide_diversityreturns mean pairwise nucleotide differences over the MAT; no segregating sites (thus, "partial"). -
DendroPy (✓):
popgenstat.nucleotide_diversity,popgenstat.num_segregating_sites, andpopgenstat.average_number_of_pairwise_differences.
-
tskit (✓):
TreeSequence.Tajimas_D. -
ARGneedle-lib (blank): no.
-
matUtils/BTE (blank): no.
-
DendroPy (✓):
popgenstat.tajimas_d.
-
tskit (✓):
TreeSequence.Fstanddivergence. -
ARGneedle-lib (blank): no.
-
matUtils/BTE (blank): no.
-
DendroPy (blank): the popgenstat module computes within-sample diversity statistics but does not implement Fst or between-population divergence directly.
-
tskit (✓):
TreeSequence.allele_frequency_spectrumin branch and site mode, single- and multi-population. -
ARGneedle-lib (blank): This could be done using
bitset_volume_maporstab_return_all_bitsets(branch mode), or withget_mutations_matrix(site mode), but this isn't a first-class method, and with large numbers of samples the former would be$O(2^n)$ . -
matUtils/BTE (blank): no.
-
DendroPy (◐):
popgenstat.unfolded_site_frequency_spectrumcomputes the 1D unfolded SFS for a character matrix. Counted as partial because there is no joint/multi-population SFS.
-
tskit (✓):
TreeSequence.ld_matrixand theLdCalculatorinterface. -
ARGneedle-lib (blank): no.
-
matUtils/BTE (blank): no.
-
DendroPy (blank): no.
-
tskit (✓):
TreeSequence.pair_coalescence_countscalculates the average number of labelled pairs that coalesce in a given node or time window, using an efficient tree-traversal algorithm.TreeSequence.pair_coalescence_ratesestimates the hazard (coalescence) rate from the pair coalescence counts with a Kaplan-Meier-like estimator.TreeSequence.pair_coalescence_quantilesestimates quantiles of the pair coalescence time distribution by inverting the empirical CDF. -
ARGneedle-lib (blank): no.
-
matUtils/BTE (blank): no.
-
DendroPy (blank): no.
-
tskit (✓): every statistic in
tskit.TreeSequenceacceptsmode="branch", computing the corresponding branch-length statistic on the trees themselves rather than on observed sites. This is the duality property and has no analogue in the comparison libraries. -
ARGneedle-lib (blank): no, although for instance the GRM is computed by putting down mutations under the infinite-sites model, which approximates branch mode.
-
matUtils/BTE (blank): no.
-
DendroPy (blank): no.
-
tskit (✓):
TreeSequence.link_ancestors(and the underlyingTableCollection.link_ancestors) returns an edge table describing, for each sample in a specified set, which segments of the genome are inherited from which members of a specified set of ancestors. Introduced in Tsambos et al. (2023). -
ARGneedle-lib (blank): no.
-
matUtils/BTE (blank): not applicable — a mutation-annotated tree has no notion of multiple local ancestors along a genome.
-
DendroPy (blank): not applicable.
-
tskit (✓):
TreeSequence.ibd_segments. -
ARGneedle-lib (blank): the library has no IBD-segment extractor in its Python API.
-
matUtils/BTE (blank): not applicable to a single phylogeny.
-
DendroPy (blank): not applicable.
-
tskit (✓):
TreeSequence.genetic_relatedness_matrix,genetic_relatedness,genetic_relatedness_weighted.genetic_relatedness_vector. -
ARGneedle-lib (✓):
arg_needle_lib.exact_arg_grmandmonte_carlo_arg_grm(inarg_needle_lib.grm); accompanied bygower_center,row_column_center, andwrite_grmfor downstream use. -
matUtils/BTE (blank): no.
-
DendroPy (blank): no.
-
tskit (✓):
TreeSequence.genetic_relatedness_vectorcomputes the product of the branch GRM with one or more vectors directly from the tree sequence without materialising the full matrix, giving$O(n + n_T \log n)$ scaling rather than$O(n^2)$ . -
ARGneedle-lib (✓): available as
arg_matmul(documented but not shown by readthedocs). -
matUtils/BTE (blank): no.
-
DendroPy (blank): no.
-
tskit (✓):
TreeSequence.pcacomputes a randomised PCA directly from the tree sequence by repeatedly applying the branch-mode GRM-vector product, without materialising the full relatedness matrix. -
ARGneedle-lib (blank): no direct PCA API; downstream PCA would require materialising a GRM via
exact_arg_grm/monte_carlo_arg_grmand then calling an external linear-algebra library. -
matUtils/BTE (blank): no.
-
DendroPy (blank): no.
-
tskit (✓):
TreeSequence.divergence,divergence_matrix, andTree.tmrca. -
ARGneedle-lib (✓):
arg_needle_lib.distance_matrixanddistance_matrix_v2give pairwise distances. ARG nodes carry times directly so coalescence-time queries are first-class. -
matUtils/BTE (✓): in the tree context, basically the same as MRCA, above.
-
DendroPy (✓):
treemeasure.patristic_distancegives branch-length sums between taxa, andnode_agesreturns coalescence times for an ultrametric tree.
-
tskit (✓):
TreeSequence.genealogical_nearest_neighbours. -
ARGneedle-lib (blank): no.
-
matUtils/BTE (blank): no.
-
DendroPy (blank): no.
-
tskit (✓):
TreeSequence.variantsandgenotype_matrix. -
ARGneedle-lib (✓):
arg_needle_lib.get_mutations_matrixandget_genotypereturn mutation/genotype matrices, andarg.mutations()allows iteration over mutations. -
matUtils/BTE (✓):
MATree.get_mutation_samples,get_mutation,count_mutation_types, andcount_haplotypesenumerate variants and the samples carrying each mutation. -
DendroPy (✓):
dendropy.datamodel.charmatrixmodellets you iterate over characters.
-
tskit (✓):
TreeSequence.haplotypesandalignments. -
ARGneedle-lib (blank): no haplotype iteration is exposed (
write_mutations_to_hapswrites a HAPS file but there is no Python iterator). -
matUtils/BTE (✓):
MATree.get_haplotypereconstructs the full mutation set carried by a sample relative to the reference;count_haplotypesenumerates unique haplotypes. -
DendroPy (✓):
dendropy.datamodel.charmatrixmodelalso provides this, effectively.
-
tskit (✓):
Tree.map_mutationsperforms Hartigan parsimony to place mutations on a tree. -
ARGneedle-lib (✓):
map_genotype_to_ARG,map_genotype_to_ARG_diploid,mutation_match, andmutation_bestplace genotypes optimally onto an ARG. -
matUtils/BTE (✓): parsimony placement is the central operation of UShER and matUtils;
MATree.simple_parsimonyandMATree.get_parsimony_scoreexpose it from BTE. -
DendroPy (✓): provides
dendropy.model.parsimony.fitch_up_pass(note: requires bifurcating trees).
-
tskit (✓):
Tree.draw_svgandTreeSequence.draw_svgproduce styled, configurable SVG. -
ARGneedle-lib (blank): no built-in plotting.
-
matUtils/BTE (◐): matUtils emits Auspice JSON for visualisation in an external viewer; it does not draw SVG itself.
-
DendroPy (✓): produces TikZ output, which is convertable to SVG.
-
tskit (✓):
TreeSequence.draw_svgdraws all trees along the genome with shared coordinate axes. -
ARGneedle-lib (blank): no.
-
matUtils/BTE (blank): not applicable.
-
DendroPy (blank): not applicable.
-
tskit (✓):
Tree.draw_textandTreeSequence.draw_text. -
ARGneedle-lib (blank): no.
-
matUtils/BTE (blank): no.
-
DendroPy (✓):
Tree.as_ascii_plotandTree.print_plot;Tree.as_tikz_plotfor vector output.
-
tskit (✓):
tskit.MetadataSchemawith JSON, struct, and permissive codecs; every table column has its own schema and validation. -
ARGneedle-lib (blank): no.
-
matUtils/BTE (◐):
MATNode.annotationscarries clade-level annotations andmatUtils annotateadds named clade labels - an unstructured kind of metadata. No user-defined schema. -
DendroPy (◐): similar to matUtils, taxa and trees carry free-form
annotationscollections, but there is no schema or validation layer.
-
tskit (✓):
TreeSequence.provenancesand the provenance schema; most operations that produce a new tree sequence appends a provenance record. -
ARGneedle-lib (blank): no.
-
matUtils/BTE (blank): no.
-
DendroPy (blank): no.