Programmatic styling of phylogenetic trees for FigTree visualization
FigTreeKit is a Python library for programmatic publication-ready styling of phylogenetic trees. It addresses the problem of reproducible, scriptable tree visualization in evolutionary biology and comparative genomics — turning raw Newick/Nexus trees into annotated, publication-quality figures compatible with FigTree.
Typical use cases include:
- Styling phylogenomic trees with taxonomic group highlights
- Batch-processing hundreds of gene trees with consistent formatting
- Validating and collapsing clades by taxonomic group name
- Generating publication-ready figures from BEAST/RAxML/IQ-TREE output
- FigTree-Compatible Output: Generates Nexus files with
[&!hilight],[&!color],[&!font]annotations - Pythonic API: Method chaining for intuitive tree styling
- Taxonomy-Aware Analysis: Automatic taxonomy extraction from labels (embedded
_d_/_p_/_g_/_s_/_ss_format and tabled__/p__format) - Monophyly Detection: Check if taxa form monophyletic groups, with special identifiers (LUCA/LACA/LBCA)
- Clade Collapse: Collapse clades by taxonomic group name with monophyly validation
- Multi-Tree Handling: Detect and process multiple trees with
split/first/last/randommodes - Deep Input Validation: Structural checks, negative branch detection, duplicate tip names, malicious character scanning
- Real-Time Logging: ISO 8601 timestamps, stdout flush, optional log file output
- Self-Test Mode:
--self-testverifies dependencies, parsing, taxonomy, and monophyly logic - Batch Processing: Process multiple tree files via CLI
- Image Rendering: Export to PNG/PDF/SVG/JPEG without opening FigTree GUI (requires FigTree JAR); for command-line rendering of very large trees, TreeViewer is also worth considering.
| Capability | FigTreeKit | FigTree GUI | DendroPy | ETE3 | TreeViewer |
|---|---|---|---|---|---|
| Programmatic / scriptable styling | ✅ | ❌ | ✅ (CLI) | ||
| Python API | ✅ | ❌ | ✅ | ✅ | ❌ |
Inject FigTree annotations (!hilight/!color/!font) |
✅ | N/A | ❌ | ❌ | ❌ |
| Taxonomy-aware collapse / monophyly check | ✅ | manual | ❌ | ||
| Deep input validation (brackets, negative branches, malicious chars) | ✅ | ❌ | ❌ | ❌ | ❌ |
| Batch CLI processing | ✅ | ❌ | ❌ | ✅ | ✅ |
| Image rendering (PNG/PDF/SVG/JPEG) | ✅ | ✅ | ❌ | ✅ | ✅ |
See docs/comparison_EN.md for the full comparison matrix and reproduction instructions.
pip install figtreekit
# Also apply the requested --background-color/--foreground-color to raster
# output (the post-render appearance pass needs Pillow):
pip install "figtreekit[render]"git clone https://github.com/ZengZichao/FigTreeKit.git
cd FigTreeKit
pip install -r requirements.txt
pip install -e .- Required: Python 3.11, Biopython (>=1.80, <2.0)
- Optional: psutil (for memory logging), Java 8+ (for rendering)
- Tested on: macOS (Apple Silicon) and Ubuntu Linux, Python 3.11, in continuous integration
After installation, verify everything works:
figtreekit --self-testThis runs 11 built-in checks (dependencies, parsing, taxonomy, monophyly) and requires no external files. See the Quick Start section for expected output.
figtreekit --self-test [PASS] Dependency: biopython
[PASS] Dependency: python
[PASS] Parse: Newick example
[PASS] Taxonomy: embedded format extraction
[PASS] Taxonomy: table format extraction
[PASS] Monophyly: Cyanobacteriales (monophyletic)
[PASS] Special ID: LUCA resolves all taxa
[PASS] Special ID: LACA resolves Archaea only
[PASS] Export: Newick → Nexus round-trip
[PASS] Validation: FASTA example
[PASS] Security: control char detection
All 11 checks passed.
from figtreekit import FigTreeStyler, LayoutType, FontStyle
styler = FigTreeStyler().load_content("((A:0.1,B:0.2):0.3,(C:0.4,D:0.5):0.6);")
styler.set_layout(LayoutType.RECTILINEAR)
styler.set_appearance(background_color="#FAFAFA", branch_line_width=2.0)
styler.highlight_clade(["A", "B"], color="#FF0000")
styler.set_tip_labels(is_shown=True, font_size=12)
styler.export("output.nex")figtreekit input.tre -o output.nex --layout polar --tip-labels-show
figtreekit input.tre --validate
figtreekit input.tre -o output.nex --clade Cyanobacteriotafigtreekit --setup-figtree # one-time setup
figtreekit input.tre -o output.nex --render tree.png
figtreekit input.tre -o output.nex --render tree.pdf --render-width 1600FigTreeKit can extract taxonomy from two formats:
Format A (Embedded) — taxonomy encoded in the label:
GB_GCA_000252485.1_d_Bacteria_p_Cyanobacteriota_c_Cyanobacteriia_o_Cyanobacteriales_f_Prochloraceae_g_Prochloron
Format B (Table) — semicolon-delimited taxonomy strings:
d__Archaea;p__Thermoproteota;c__Korarchaeia;o__Korarchaeales;f__Korarchaeaceae;g__WALU01;s__
from figtreekit import FigTreeStyler
styler = FigTreeStyler("tree.nwk")
# Check monophyly by group name (auto-detects format)
result = styler.check_monophyly_by_group("Cyanobacteriales")
print(result["is_monophyletic"]) # True/False
print(result["resolved_taxa"]) # list of taxon names
# Collapse a monophyletic clade
styler.collapse_by_group("Cyanobacteriales")
styler.export("collapsed.nex")# Collapse by taxon group name
figtreekit tree.nwk -o collapsed.nex --clade Cyanobacteriota
# Strict mode (abort if not monophyletic)
figtreekit tree.nwk -o collapsed.nex --clade Cyanobacteriota --strict
# Multiple clades
figtreekit tree.nwk -o out.nex --clade Cyanobacteriota --clade Proteobacteria
# Custom taxonomy parsing
figtreekit tree.nwk -o out.nex --taxonomy-delimiter-mode greedy
figtreekit tree.nwk -o out.nex --taxonomy-table-sep "|"
figtreekit tree.nwk -o out.nex --taxonomy-levels "k:kingdom,ss:subspecies"| Identifier | Description |
|---|---|
LUCA |
Last Universal Common Ancestor (all Bacteria + Archaea) |
LACA |
Last Archaeal Common Ancestor |
LBCA |
Last Bacterial Common Ancestor |
root |
Root of the tree (all terminal taxa) |
result = styler.check_monophyly_by_group("LUCA")When labels don't contain taxonomy, provide a mapping file (TSV/CSV, two-column format). See Input Format Details for the full specification.
figtreekit tree.nwk -o out.nex --clade CyanobacterialesWhen a file contains multiple trees (e.g., Nexus with multiple tree statements):
# Default: print summary and abort (exit code 2)
figtreekit multi.nex -o out.nex
# Process all trees with numeric suffixes
figtreekit multi.nex -o out.nex --multi-tree split
# Process only the first/last tree
figtreekit multi.nex -o out.nex --multi-tree first
figtreekit multi.nex -o out.nex --multi-tree last
# Random selection
figtreekit multi.nex -o out.nex --multi-tree random
# Same as split (process all trees)
figtreekit multi.nex -o out.nex --multi-tree allFigTreeKit can validate FASTA/FASTQ files:
# Validate FASTA
figtreekit sequences.fasta --validate
# Validate with expected molecule type
figtreekit sequences.fasta --validate --mol-type DNA
# Skip alignment length check
figtreekit aligned.fasta --validate --skip-length-check
# Cross-validate tree tips against sequence IDs
figtreekit tree.nwk -o out.nex --sequences sequences.fasta
# Cross-validate during validation mode
figtreekit tree.nwk --validate --sequences sequences.fastaNote: When using
--validatewith a sequence file (FASTA/FASTQ), the CLI returns exit code 0 (success) if deep validation passes, even though the file is not a tree format. This allows independent sequence validation in scripts.
Checks include:
- Duplicate sequence IDs (ERROR)
- Alphabet validation (DNA/RNA/protein) with invalid character reporting
- Alignment length consistency (WARNING)
See Input Format Details for FASTA/FASTQ format specifications.
FigTreeKit performs comprehensive validation on all input files:
| Check | Level |
|---|---|
| Bracket balance (parentheses, brackets) | ERROR with position |
| Negative branch lengths | CRITICAL (abort) |
| Empty node names | ERROR |
| Duplicate tip names | ERROR |
| Self-loop detection | ERROR |
| Control characters / Unicode bidi overrides | CRITICAL (abort) |
| Check | Level |
|---|---|
| Duplicate sequence IDs | ERROR (abort) |
| Invalid characters for alphabet | ERROR with line number |
| Alignment length inconsistency | WARNING |
- Control characters (
\x00-\x1f) in node names → CRITICAL - Unicode bidi overrides (
\u202E) → CRITICAL - Circular dependencies in taxonomy tables → ERROR
- Empty files (0 bytes) → CRITICAL
FigTreeKit exports FigTree-compatible Nexus files with three blocks:
#NEXUS
begin taxa;
dimensions ntax=3;
taxlabels A B C ;
end;
begin trees;
tree TREE1 = ((A:0.1,B:0.2):0.3,C:0.4);
end;
begin figtree;
set appearance.backgroundColour=#ffffff;
set layout.layoutType=POLAR;
set tipLabels.isShown=true;
end;
FigTreeKit injects annotations into the Newick tree string:
| Annotation | Format | Description |
|---|---|---|
!hilight |
[&!hilight={tipCount,height,color}] |
Background highlight for a clade. tipCount = number of tips, height = node height from root, color = hex RGB. |
!color |
[&!color=#RRGGBB] |
Branch color applied to the MRCA node. |
!font |
[&!font=Name-STYLE-size] |
Font annotation (Java Font.decode() format). STYLE: PLAIN, BOLD, ITALIC, BOLDITALIC. |
!stroke |
[&!stroke=N] |
Branch stroke width (forward compatibility; FigTree 1.4.4 ignores this). |
Example — highlighting clade (A,B):
((A:0.1,B:0.2)[&!hilight={2,0.3,#ff0000}]:0.3,C:0.4);
| Mode | Output Pattern |
|---|---|
| Single tree | <output>.nex (user-specified) |
| Batch | <input_stem>.nex in output directory |
| Multi-tree split | <output>_tree1.nex, <output>_tree2.nex, ... |
| Collapsed clade | Same as input (clade replaced in-place) |
FigTreeKit follows these standards:
- Newick: Newick tree format — branch lengths are in substitution units (evolutionary distances from parent node)
- Nexus: Nexus file format — compliant with the Maddison et al. (1997) specification
- FASTA: FASTA format — standard bioinformatics sequence format
- FASTQ: FASTQ format — Illumina/Sanger quality encoding
Newick (.nwk, .newick, .tree, .tre, .treefile, .nh, .nhy, .nhx):
((A:0.1,B:0.2):0.3,C:0.4);
- Branch lengths are optional (default: no branch length displayed)
- Quoted names supported:
('Species A':0.1,'Species B':0.2); - Bracket comments preserved:
(A:0.1[&posterior=0.95],B:0.2);
Nexus (.nex, .nexus, .nx):
#NEXUS
begin taxa;
dimensions ntax=3;
taxlabels A B C ;
end;
begin trees;
tree TREE1 = ((A:0.1,B:0.2):0.3,C:0.4);
end;
- Translate blocks supported (BEAST format)
- Multiple trees preserved (all written to output)
- Existing
figtreeblock parsed and merged - BEAST output: Translate blocks and bracket annotations (e.g.
[&posterior=0.95]) are preserved
Two-column format (auto-detected TSV/CSV):
With header:
name taxonomy
GB_GCA_000252485.1 d__Bacteria;p__Cyanobacteriota;c__Cyanobacteriia;o__Cyanobacteriales;f__Prochloraceae;g__Prochloron;s__
RS_GCF_000013425.1 d__Archaea;p__Euryarchaeota;c__Methanomicrobia;o__Methanosarcinales;f__Methanosarcinaceae;g__Methanosarcina;s__
Without header:
GB_GCA_000252485.1 d__Bacteria;p__Cyanobacteriota;c__Cyanobacteriia;o__Cyanobacteriales;f__Prochloraceae;g__Prochloron;s__
RS_GCF_000013425.1 d__Archaea;p__Euryarchaeota;c__Methanomicrobia;o__Methanosarcinales;f__Methanosarcinaceae;g__Methanosarcina;s__
- Delimiter: tab (
.tsv) or comma (.csv), auto-detected from extension - Force delimiter:
--table-sep "," - Missing ranks (e.g.
s__with no value) → stored as empty string - Malformed rows:
--ignore-malformedto skip instead of aborting
| Type | Format | Extensions |
|---|---|---|
| Tree | Newick | .nwk, .newick, .tree, .tre, .treefile, .nh, .nhy, .nhx |
| Tree | Nexus | .nex, .nexus, .nx |
| Tree | PhyloXML † | .xml, .phyloxml |
| Sequence | FASTA | .fasta, .fa, .fas, .fna, .faa, .ffn, .frn |
| Sequence | FASTQ | .fastq, .fq |
| Sequence | GenBank | .gb, .gbk, .genbank |
| Sequence | EMBL | .embl |
| Sequence | Stockholm | .stockholm, .sto |
| Sequence | Phylip | .phylip, .phy |
| Sequence | Clustal | .clustal, .aln |
| Taxonomy | TSV/CSV | .tsv, .csv |
† Format support scope: Tree styling and rendering (
FigTreeStylerand Nexus export) support Newick and Nexus only. PhyloXML is recognized by the input validator (--validate) but is not loaded, styled, or rendered by the tree styler. Sequence formats (FASTA, FASTQ, GenBank, EMBL, Stockholm, Phylip, Clustal) are supported for input validation and tree↔sequence cross-validation (--validate/--sequences), not for tree styling.
Input File
│
▼
┌─────────────────┐
│ Format Detect │ (Newick / Nexus / FASTA / FASTQ)
└────────┬────────┘
▼
┌─────────────────┐
│ Deep Validation │ (brackets, branch lengths, duplicates, malicious chars)
└────────┬────────┘
▼
┌─────────────────┐
│ Multi-Tree Check │ (ask / split / first / last / random / all)
└────────┬────────┘
▼
┌─────────────────┐
│ Taxonomy Parse │ (embedded _d_/_p_ or table d__/p__)
└────────┬────────┘
▼
┌─────────────────┐
│ Style & Collapse │ (clade highlights, colors, monophyly check)
└────────┬────────┘
▼
┌─────────────────┐
│ Export / Render │ (Nexus output, optional PNG/PDF/SVG/JPEG)
└─────────────────┘
- Quoted taxon names: Names with spaces or special characters must be single-quoted in Newick:
('Species A':0.1,'Species B':0.2); - Missing branch lengths: Trees without branch lengths are valid; FigTree will display equal-length branches
- Polytomies: Unresolved nodes (more than 2 children) are fully supported
- Translate blocks: BEAST-style numeric taxon IDs are automatically resolved
- Encoding: Files with BOM (UTF-8-sig) or legacy encodings (latin-1) are handled transparently
- Large trees: Trees with >10,000 tips trigger a resource warning; use
--low-memorymode - Empty taxa names: Detected and rejected as ERROR (cannot map taxonomy)
- Duplicate tip names: Detected and rejected as ERROR (would cause taxonomy mapping conflicts)
All operations produce real-time log output with ISO 8601 timestamps:
2026-06-13T15:30:56.135 | [ INFO] | >>> Input file validation ...
2026-06-13T15:30:56.135 | [ INFO] | <<< Input file validation (0 ms)
2026-06-13T15:30:56.135 | [ INFO] | >>> Parsing tree file ...
2026-06-13T15:30:56.192 | [ INFO] | tree.nwk: parsed successfully, 3 taxa detected
2026-06-13T15:30:56.192 | [ INFO] | <<< Parsing tree file (57 ms)
2026-06-13T15:30:56.192 | [ INFO] | tree.nwk: DONE (total 0.06 s)
| Flag | Level | Description |
|---|---|---|
-q |
ERROR | Suppress all non-error output |
| (default) | WARNING | Warnings and errors only |
-v |
INFO | Normal operation flow |
-vv |
DEBUG | Detailed debugging info |
# Write logs to file (all levels, UTF-8)
figtreekit tree.nwk -o out.nex --log-file figtreekit.logfigtreekit input.tre -o output.nex [OPTIONS]
figtreekit input.tre --validate
figtreekit --version
figtreekit --self-test
figtreekit --helpFor the complete and up-to-date list, run
figtreekit --help.
positional arguments:
input Input tree file or directory for batch processing
options:
-o, --output OUTPUT Output Nexus file (or directory for batch)
--validate Check compatibility without exporting
-v, --verbose Increase verbosity (-v INFO, -vv DEBUG) (default: WARNING)
-q, --quiet Suppress non-error output
--version Show version, git commit hash, date and dependencies
--self-test Run self-diagnostic checks
--config FILE JSON config file
--log-file FILE Write logs to file (UTF-8, all levels)
--force Overwrite existing output files
--no-clobber Skip if output exists
--strip-annotations Strip bracket comments (NHX/bootstrap/posterior) to reduce file size
Tree:
--clade NAME Collapse clade by taxonomic group name
--strict Abort on non-monophyletic clades (default: warn and skip)
--multi-tree MODE Multi-tree handling (default: ask)
Choices: ask/split/first/last/random/all
--rooted Set tree as rooted
--unrooted Set tree as unrooted (takes precedence over --rooted)
Taxonomy:
--taxonomy-levels SPEC Extend rank prefixes (e.g. "k:kingdom,ss:subspecies")
--taxonomy-delimiter-mode MODE reverse/greedy/segment (default: reverse)
--taxonomy-table-sep CHAR Separator for taxonomy strings (default: ";")
--taxonomy-source-priority P embedded/table (default: table)
--taxonomy-mapping-file FILE Path to taxonomy mapping file (TSV/CSV)
--table-sep CHAR Force column delimiter for mapping file
--ignore-malformed Skip malformed taxonomy rows
Sequence:
--mol-type TYPE DNA/RNA/protein (default: auto-detect)
--sequences FILE Sequence file for cross-validation against tree tips
--no-cross-check Skip tree-sequence label cross-validation
--skip-length-check Skip alignment length check
--low-memory Reduce memory usage for large files (streaming)
Rendering:
--render FILE Render tree to image (PNG/PDF/SVG/JPEG)
--render-format FORMAT Force render format (PNG/PDF/SVG/JPEG)
--render-width PX Image width (default: 1200)
--render-height PX Image height (default: 800)
--figtree-jar PATH Path to figtree.jar
--setup-figtree Download/compile FigTree JAR
--check-figtree Check if FigTree JAR is available
{
"layout.layoutType": "POLAR",
"appearance.backgroundColour": "#FAFAFA",
"tipLabels.isShown": true,
"tipLabels.fontName": "Arial",
"tipLabels.fontSize": 10
}figtreekit input.tre -o output.nex --config style.jsonfrom figtreekit import FigTreeStyler, LayoutType, FontStyle, TransformType
styler = FigTreeStyler("tree.nwk")
# Layout
styler.set_layout(LayoutType.POLAR)
styler.set_polar_layout(angular_range=270, root_angle=45)
# Appearance
styler.set_appearance(background_color="#FFFFFF", branch_line_width=2.0)
# Clade annotations
styler.highlight_clade(["A", "B"], color="#FF0000")
styler.set_clade_color(["A", "B"], color="#2196F3")
styler.set_clade_color_all(["A", "B"], color="#2196F3") # color all branches in subtree
# Note: set_clade_color + highlight_clade on the same taxa will drop the
# MRCA-level color to avoid FigTree ClassCastException.
# Use set_clade_color_all() as the recommended alternative.
styler.set_clade_font(["A"], font_name="Arial", font_style=FontStyle.BOLD, font_size=14)
# Labels
styler.set_tip_labels(is_shown=True, font_size=12)
styler.set_node_labels(is_shown=True, display_attribute="height")
styler.set_branch_labels(is_shown=True, display_attribute="length")
# Scale
styler.set_scale_bar(is_shown=True)
styler.set_scale_axis(is_shown=True)
styler.set_scale(root_age=1.0)
# Layout-specific settings
styler.set_radial_layout(spread=1.0)
styler.set_rectilinear_layout(curvature=0, root_length=0)
# Trees
styler.set_trees(rooting=True, transform=TransformType.PHYLOGRAM)
# Legend / node decorations
styler.set_legend(is_shown=True, position="bottom")
styler.set_node_bars(is_shown=True)
styler.set_node_shapes(is_shown=True)
# Apply from dict and reset
styler.apply_dict({"layout.layoutType": "POLAR"})
# Full reset: clears settings, annotations, taxonomy config, AND tree content
# Must reload tree via load_file / load_content before further operations
styler.reset()
# Or reset only styling, keeping the loaded tree
styler.reset(keep_tree=True)
# Export
styler.export("output.nex")
styler.render("tree.png")
styler.render("tree.pdf", format="PDF", width=1600, height=1000)# Check monophyly
result = styler.check_monophyly(["A", "B", "C"])
result = styler.check_monophyly_by_group("Cyanobacteriales")
result = styler.check_monophyly_by_group("LUCA")
# Collapse clades
styler.collapse_clade(["A", "B"], label="Clade1")
styler.collapse_by_group("Cyanobacteriales")
styler.collapse_by_group("Cyanobacteriales", label="Cyano")
# Nested collapse: collapse inner and outer clades simultaneously
# (automatically sorted by size, processed inner-first)
styler.collapse_clade(["A", "B"], label="Inner")
styler.collapse_clade(["A", "B", "C"], label="Outer") # Both labels appear in output
# Convenience: check + style in one call
styler.style_monophyletic_clade(
["A", "B", "C"],
color="#E91E63",
highlight_color="#FFCDD2",
font_name="Arial",
font_style=FontStyle.BOLD,
font_size=12,
)
# Clear pending operations
styler.clear_annotations()
styler.clear_clade_hilights()
styler.clear_collapses()
# Strip all bracket comments (NHX, bootstrap, posterior, etc.) to reduce output size
styler.strip_annotations()
# Get detailed clade information (MRCA, descendant tips, monophyly, etc.)
info = styler.get_clade_info(["A", "B", "C"])
print(info["is_monophyletic"], info["mrca_terminal_count"])# Load from string or file (auto-detect)
styler = FigTreeStyler().load_tree("((A:0.1,B:0.2):0.3,C:0.4);")
styler = FigTreeStyler().load_tree("tree.nwk") # auto-loads from file if exists
# Access annotations and collapses
annotations = styler.get_annotations() # get current annotations list
collapses = styler.get_collapses() # get current collapses list
# Set font with defaults
styler.set_clade_font(["A", "B"]) # uses defaults: Arial, PLAIN, 12
styler.set_clade_font(["A", "B"], font_name="Helvetica", font_style=FontStyle.BOLD, font_size=14)from figtreekit import (
validate_input_file,
deep_validate_newick,
deep_validate_fasta,
deep_validate_fastq,
TreeValidator,
)
# File validation
result = validate_input_file("tree.nwk")
if not result["valid"]:
for err in result["errors"]:
print(err)
# Deep Newick validation
dv = deep_validate_newick(content, label="tree.nwk")
for err in dv["errors"]:
print(err)
# FASTA / FASTQ validation
dv = deep_validate_fasta("seqs.fasta", expected_alphabet="DNA")
dv = deep_validate_fastq("reads.fastq", expected_alphabet="DNA")
# Styler-level validation
issues = styler.validate()
# Biological plausibility check (degenerate trees, all-zero branches, large tree warnings)
warnings = TreeValidator.validate_biological_plausibility(newick)from figtreekit import (
parse_taxonomy_auto,
detect_taxonomy_format,
TaxonomyMapper,
MonophylyAnalyzer,
get_rank_prefixes,
extend_rank_prefixes,
)
# Apply settings from CLI arguments
from figtreekit import apply_cli_args
# apply_cli_args(styler, args) # args from argparse.Namespace
# Auto-detect and parse
tax = parse_taxonomy_auto("GB_GCA_000252485.1_d_Bacteria_p_Cyanobacteriota_c_Cyanobacteriia_o_Cyanobacteriales_f_Prochloraceae_g_Prochloron")
# {"domain": "Bacteria", "phylum": "Cyanobacteriota", ...}
tax = parse_taxonomy_auto("d__Archaea;p__Euryarchaeota;s__")
# {"domain": "Archaea", "phylum": "Euryarchaeota", "species": ""}
# Styler taxonomy configuration
styler.configure_taxonomy(
delimiter_mode="reverse", # reverse / greedy / segment
table_sep=";",
source_priority="table", # table / embedded
mapping_file="taxonomy.tsv",
ignore_malformed=False,
)
# Direct mapper usage
mapper = TaxonomyMapper()
mapper.load_mapping("taxonomy.tsv")
groups = mapper.identify_groups(rank="genus")
# Taxonomy analysis with automatic monophyly detection (requires pattern or mapping_file)
result = styler.analyze_taxonomy(mapping_file="taxonomy.tsv", rank="phylum")
# Convenience method: equivalent to analyze_taxonomy(mapping_file=...)
result = styler.analyze_taxonomy_from_mapping("taxonomy.tsv", rank="phylum")
# Parse taxonomy from labels (built-in patterns or custom regex)
taxonomy = styler.parse_label_taxonomy("genus_species")
# Check taxonomy data completeness
completeness = styler.check_taxonomy_completeness(mapping_file="taxonomy.tsv")from figtreekit import (
parse_taxonomy, # Standardized taxonomy parsing
is_monophyletic, # Monophyly check
load_tree, # Tree loading
cross_validate, # Cross-validation
# Standardized exception hierarchy
PhyloFormatError, # File format error (inherits from ParseError)
TaxonomyConflictError, # Taxonomy conflict (inherits from ValidationError)
MonophylyError, # Monophyly analysis error (inherits from ValidationError)
)
# Parse taxonomy label (standardized signature)
tax = parse_taxonomy("d__Bacteria;p__Cyanobacteriota", mode="reverse")
# -> {"domain": "Bacteria", "phylum": "Cyanobacteriota", ...}
# Check monophyly (standardized signature)
mono = is_monophyletic("tree.nwk", "Cyanobacteriota", rooted=True)
# -> True / False
# Load tree file (standardized signature)
styler = load_tree("tree.nwk", validate=True)
# Cross-validate tree and sequences (standardized signature)
report = cross_validate("tree.nwk", "sequences.fasta", strict=True)
# -> {"valid": True, "matched": 50, "tree_only": [], "seq_only": [], "errors": []}| Code | Meaning | Description |
|---|---|---|
| 0 | Success | All operations completed successfully |
| 1 | Runtime error | Dependency issues, self-test failures |
| 2 | Usage error | Invalid command-line arguments, missing input |
| 3 | Data error | Invalid input data (malformed tree, bad sequences) |
| 130 | Interrupted | User pressed Ctrl+C (SIGINT) or SIGTERM received |
| Exception | Base Class | Purpose |
|---|---|---|
FigTreeKitError |
Exception |
Base class for all FigTreeKit exceptions |
ParseError |
FigTreeKitError |
Tree/sequence file parsing errors |
ValidationError |
FigTreeKitError |
Input validation failure |
ExportError |
FigTreeKitError |
Export/render errors |
PhyloFormatError |
ParseError |
File format error (library mode API alias) |
TaxonomyConflictError |
ValidationError |
Taxonomy conflict (library mode API alias) |
MonophylyError |
ValidationError |
Monophyly analysis error (library mode API alias) |
CompatibilityWarning |
UserWarning |
Compatibility warning |
figtreekit tree.nwk -o existing.nex --force # overwrite
figtreekit tree.nwk -o existing.nex --no-clobber # skip if exists
figtreekit tree.nwk -o new/dir/output.nex # auto-create dirsPress Ctrl+C to gracefully terminate — progress is displayed, temporary files are cleaned up, exit code 130.
- Encoding: UTF-8 with BOM and latin-1 fallback handled transparently
- Newlines: Unix
\non all platforms - Paths:
pathlib.Paththroughout (platform-independent path handling) - Temporary files: Auto-cleaned on exit, permissions set to 0o600 (HPC-safe), including Ctrl+C
Note: The full test suite runs on macOS and Ubuntu (Python 3.11) in continuous integration, and both are supported deployment environments. Windows is not verified: it has never been run in CI or locally, so compatibility with Windows is not claimed.
For trees with more than 10,000 tips:
- An INFO log entry warns about memory requirements
- Use
--low-memoryto stream sequence IDs during cross-validation - Install
psutilfor DEBUG-level memory logging
| Tree Size | Approx. Memory | Parse Time | Export Time |
|---|---|---|---|
| 100 tips | < 10 MB | < 0.01 s | < 0.01 s |
| 1,000 tips | ~ 20 MB | < 0.01 s | ~ 0.01 s |
| 10,000 tips | ~ 100 MB | ~ 0.01 s | ~ 0.1 s |
| 100,000 tips | ~ 1 GB | ~ 0.1 s | ~ 1 s |
Alternative note: FigTreeKit rendering relies on the FigTree JAR to preserve FigTree annotations and styles in automated workflows. If you only need a cross-platform GUI/CLI tool to render very large trees (>100,000 taxa) without FigTree-compatible Nexus annotations, consider TreeViewer.
# Check status
figtreekit --check-figtree
# Download and compile
figtreekit --setup-figtree
# Use existing JAR
figtreekit --setup-figtree --figtree-jar /path/to/figtree.jar| Format | Extension | Best For |
|---|---|---|
| PNG | .png |
Web, presentations, quick preview |
.pdf |
Publication, vector editing (Adobe Illustrator) | |
| SVG | .svg |
Web, scalable vector graphics |
| JPEG | .jpg |
Email, small file size (lossy compression) |
# PNG (default, good for most uses)
figtreekit tree.nwk -o tree.nex --render tree.png
# PDF for publication
figtreekit tree.nwk -o tree.nex --render tree.pdf
# SVG for web
figtreekit tree.nwk -o tree.nex --render tree.svg
# Custom dimensions
figtreekit tree.nwk -o tree.nex --render tree.png --render-width 2000 --render-height 1500
# Explicit render format when extension is ambiguous
figtreekit tree.nwk -o tree.nex --render tree.out --render-format PNGSee docs/user_manual_EN.md for detailed compilation instructions.
- Author: Zeng Zichao (Shanghai Jiao Tong University)
- Email: zengzichao@sjtu.edu.cn
- GitHub Issues: https://github.com/ZengZichao/FigTreeKit/issues
- GitHub Discussions: https://github.com/ZengZichao/FigTreeKit/discussions
If you use FigTreeKit in your research, please cite:
Zeng, Zichao & Wang, Yinzhao (2026). FigTreeKit: A Python toolkit for programmatic FigTree styling, taxonomy-aware clade auditing, and phylogenetic tree rendering. August 2026. DOI: 10.64898/2026.08.27.747475. License: CC BY-NC-ND 4.0.
@software{figtreekit2026,
author = {Zeng, Zichao and Wang, Yinzhao},
title = {FigTreeKit: A Python toolkit for programmatic FigTree styling,
taxonomy-aware clade auditing, and phylogenetic tree rendering},
year = {2026},
month = aug,
doi = {10.64898/2026.08.27.747475},
url = {https://doi.org/10.64898/2026.08.27.747475},
note = {License: CC BY-NC-ND 4.0}
}The software itself is licensed under GPL-2.0-or-later (see License below).
FigTreeKit is free software licensed under the GNU General Public License v2.0 or later (GPL-2.0-or-later).
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the LICENSE file for details.
- FigTree (
figtreekit/figtree_patched.jar,_figtree_patch/, modified Java sources in_figtree_patch/src/figtree/): derived from FigTree v1.4.4 by Andrew Rambaut, licensed under GPL-2.0-or-later. The original unmodified JAR (_figtree_patch/figtree_original.jar) is also provided to satisfy GPL source-provision requirements; see_figtree_patch/README.mdfor rebuild instructions. - iText (bundled inside the FigTree JARs for PDF export): licensed under the GNU Affero General Public License v3 (AGPL-3.0).
- Biopython (runtime dependency): BSD-3-Clause.
When you redistribute FigTreeKit or the patched FigTree JAR, the copyleft terms of GPL-2.0-or-later and AGPL-3.0 apply.
License compatibility: FigTreeKit uses GPL-2.0-or-later, which allows upgrading to GPL-3.0, thereby achieving compatibility with iText's AGPL-3.0 license. GPL-3.0 and AGPL-3.0 have a defined compatibility path (AGPL-3.0 §13). Downstream users in strict compliance environments may treat FigTreeKit as a combined GPL-3.0 / AGPL-3.0 project.
- Repository: https://github.com/ZengZichao/FigTreeKit
- PyPI: https://pypi.org/project/figtreekit/
- Zenodo Archive:
(auto-generated on each GitHub Release; see .zenodo.json)
- Documentation: docs/user_manual_EN.md
- FigTree: http://tree.bio.ed.ac.uk/software/figtree/
- TreeViewer: https://doi.org/10.1002/ece3.10873
- Biopython: https://biopython.org/
This software is developed and tested on the following environment:
| OS | Python | Biopython | Status |
|---|---|---|---|
| macOS (Apple Silicon) | 3.11 | 1.87 / 1.88 | ✅ Pass (CI) |
| Ubuntu Linux (CI runner) | 3.11 | 1.87 / 1.88 | ✅ Pass (CI) |
| Windows | – | – |
Note: Deployment environments verified in CI are macOS and Ubuntu with Python 3.11. The published benchmark and coverage figures were produced in a separate frozen environment (see
benchmarks/benchmark_meta.json: macOS, Apple M5, Python 3.14.6, Biopython 1.87, Java 1.8.0_501) because the benchmark ladder needs a newer interpreter than the deployment pin; both environment files ship in the release (environment.ymlfor deployment,environment-benchmark.ymlfor the benchmark). Compatibility with Windows, and with Python versions other than 3.11 (deployment) and 3.14.6 (benchmark), has not been verified.
To reproduce the exact environment:
pip install figtreekit==1.1.4 biopython==1.87
figtreekit --self-testContributions are welcome! Please see CONTRIBUTING.md for guidelines.