TreeSwift: Fast tree module for Python 2 and 3 - A Python library for parsing, manipulating, and iterating over rooted tree structures with emphasis on performance and speed.
TreeSwift Node objects represent individual tree nodes with parent-child relationships, labels, and edge lengths. Node operations provide fine-grained control over tree structure and enable custom tree construction and manipulation algorithms.
Create and inspect individual nodes with their basic properties.
class Node:
"""Individual tree node with parent-child relationships."""
def __init__(self, label: object = None, edge_length: float = None) -> None:
"""
Create a new Node.
Parameters:
- label (object): Node label (any object, typically string)
- edge_length (float): Length of edge leading to this node
"""
def __str__(self) -> str:
"""String representation of node (returns label as string)."""
def __copy__(self) -> Node:
"""Create a copy of this node."""
def __lt__(self, other: Node) -> bool:
"""Less than comparison based on labels."""Usage examples:
import treeswift
# Create nodes
root = treeswift.Node()
leaf_a = treeswift.Node(label="A", edge_length=0.1)
leaf_b = treeswift.Node(label="B", edge_length=0.2)
print(f"Root: {root}") # Empty string (no label)
print(f"Leaf A: {leaf_a}") # "A"
print(f"Leaf B: {leaf_b}") # "B"
# Copy nodes
leaf_a_copy = leaf_a.__copy__()
print(f"Original: {leaf_a.get_label()}, Copy: {leaf_a_copy.get_label()}")
# Compare nodes
nodes = [treeswift.Node(label="C"), treeswift.Node(label="A"), treeswift.Node(label="B")]
sorted_nodes = sorted(nodes)
print(f"Sorted labels: {[str(n) for n in sorted_nodes]}")Manage the hierarchical structure of nodes through parent-child relationships.
def add_child(self, child: Node) -> None:
"""
Add child to this node.
Parameters:
- child (Node): Child node to add
"""
def remove_child(self, child: Node) -> None:
"""
Remove child from this node.
Parameters:
- child (Node): Child node to remove
Raises:
- RuntimeError: If child is not found
"""
def child_nodes(self) -> list[Node]:
"""
Get list of child nodes.
Returns:
- list[Node]: Copy of children list
"""
def get_parent(self) -> Node | None:
"""
Get parent node.
Returns:
- Node | None: Parent node (None if root)
"""
def set_parent(self, parent: Node) -> None:
"""
Set parent node (use carefully to avoid breaking tree structure).
Parameters:
- parent (Node): New parent node
"""Usage examples:
import treeswift
# Build tree structure manually
root = treeswift.Node()
internal = treeswift.Node(edge_length=0.1)
leaf_a = treeswift.Node(label="A", edge_length=0.2)
leaf_b = treeswift.Node(label="B", edge_length=0.3)
# Construct tree
root.add_child(internal)
internal.add_child(leaf_a)
internal.add_child(leaf_b)
# Inspect relationships
print(f"Root children: {len(root.child_nodes())}")
print(f"Internal node parent is root: {internal.get_parent() == root}")
print(f"Leaf A parent: {leaf_a.get_parent() == internal}")
# Modify structure
leaf_c = treeswift.Node(label="C", edge_length=0.4)
internal.add_child(leaf_c)
print(f"Internal node now has {len(internal.child_nodes())} children")
# Remove child
internal.remove_child(leaf_c)
print(f"After removal: {len(internal.child_nodes())} children")Query node properties and structural status within the tree.
def is_leaf(self) -> bool:
"""
Check if node is a leaf (no children).
Returns:
- bool: True if leaf, False otherwise
"""
def is_root(self) -> bool:
"""
Check if node is root (no parent).
Returns:
- bool: True if root, False otherwise
"""
def num_children(self) -> int:
"""
Get number of children.
Returns:
- int: Number of child nodes
"""
def num_nodes(self, leaves: bool = True, internal: bool = True) -> int:
"""
Count nodes in subtree rooted at this node.
Parameters:
- leaves (bool): Include leaf nodes in count
- internal (bool): Include internal nodes in count
Returns:
- int: Number of selected nodes in subtree
"""Usage examples:
import treeswift
# Create tree structure
tree = treeswift.read_tree_newick("((A,B),(C,D));")
# Check node properties
for node in tree.traverse_preorder():
label = node.get_label() or "internal"
status = []
if node.is_root():
status.append("root")
if node.is_leaf():
status.append("leaf")
print(f"{label}: {', '.join(status) if status else 'internal'}")
print(f" Children: {node.num_children()}")
if not node.is_leaf():
subtree_size = node.num_nodes()
leaf_count = node.num_nodes(internal=False)
internal_count = node.num_nodes(leaves=False)
print(f" Subtree: {subtree_size} total, {leaf_count} leaves, {internal_count} internal")Get and set node labels with flexible typing support.
def get_label(self) -> object:
"""
Get node label.
Returns:
- object: Node label (any type, None if not set)
"""
def set_label(self, label: object) -> None:
"""
Set node label.
Parameters:
- label (object): New label (any type)
"""Usage examples:
import treeswift
# Work with different label types
node1 = treeswift.Node()
node2 = treeswift.Node()
node3 = treeswift.Node()
# String labels
node1.set_label("Species_A")
print(f"String label: {node1.get_label()}")
# Numeric labels
node2.set_label(42)
print(f"Numeric label: {node2.get_label()}")
# Complex object labels
node3.set_label({"species": "Homo sapiens", "confidence": 0.95})
print(f"Dict label: {node3.get_label()}")
# None labels
node4 = treeswift.Node()
print(f"No label: {node4.get_label()}")
print(f"String representation: '{node4}'")Manage branch lengths associated with nodes.
def get_edge_length(self) -> float | None:
"""
Get edge length leading to this node.
Returns:
- float | None: Edge length (None if not set)
"""
def set_edge_length(self, length: float) -> None:
"""
Set edge length leading to this node.
Parameters:
- length (float): Edge length (must be convertible to float)
Raises:
- TypeError: If length cannot be converted to float
"""Usage examples:
import treeswift
# Edge length operations
node = treeswift.Node(label="A")
# Initially no edge length
print(f"Initial edge length: {node.get_edge_length()}")
# Set edge length
node.set_edge_length(0.123)
print(f"Set edge length: {node.get_edge_length()}")
# Update edge length
node.set_edge_length(0.456)
print(f"Updated edge length: {node.get_edge_length()}")
# Edge length type conversion
node.set_edge_length("0.789") # String converted to float
print(f"From string: {node.get_edge_length()}")
node.set_edge_length(1) # Integer converted to float
print(f"From integer: {node.get_edge_length()}")
# Error handling
try:
node.set_edge_length("invalid")
except TypeError as e:
print(f"Error: {e}")Modify node structure and resolve local tree issues.
def contract(self) -> None:
"""Contract this node by connecting children directly to parent."""
def resolve_polytomies(self) -> None:
"""Resolve polytomies below this node using zero-length edges."""Usage examples:
import treeswift
# Contract node example
tree = treeswift.read_tree_newick("(((A,B),C),D);")
print(f"Before contraction: {tree.newick()}")
# Find internal node to contract
for node in tree.traverse_internal():
if node.num_children() == 1: # Unifurcation
node.contract() # Remove this node
break
print(f"After contraction: {tree.newick()}")
# Resolve polytomies at node level
tree = treeswift.Tree()
root = tree.root
for label in ["A", "B", "C", "D"]:
child = treeswift.Node(label=label, edge_length=0.1)
root.add_child(child)
print(f"Polytomy: {tree.newick()}")
root.resolve_polytomies() # Resolve only below this node
print(f"Resolved: {tree.newick()}")Generate string representations of subtrees rooted at nodes.
def newick(self) -> str:
"""
Generate Newick string for subtree rooted at this node.
Returns:
- str: Newick representation of subtree
"""Usage examples:
import treeswift
# Generate subtree Newick strings
tree = treeswift.read_tree_newick("((A:0.1,B:0.2):0.3,(C:0.4,D:0.5):0.6);")
print(f"Full tree: {tree.newick()}")
# Get Newick for each subtree
for node in tree.traverse_internal():
if node != tree.root:
subtree_newick = node.newick()
print(f"Subtree with {node.num_children()} children: {subtree_newick}")
# Single node Newick
for leaf in tree.traverse_leaves():
leaf_newick = leaf.newick()
print(f"Leaf {leaf.get_label()}: {leaf_newick}")Direct access to node attributes (use with caution).
# Node attributes (direct access)
children: list[Node] # List of child nodes
parent: Node | None # Parent node (None for root)
label: object # Node label
edge_length: float | None # Edge lengthUsage examples:
import treeswift
# Direct attribute access (advanced usage)
node = treeswift.Node(label="test", edge_length=0.5)
# Access attributes directly
print(f"Label: {node.label}")
print(f"Edge length: {node.edge_length}")
print(f"Children list: {node.children}")
print(f"Parent: {node.parent}")
# Modify attributes directly (be careful!)
node.label = "modified_label"
node.edge_length = 1.0
# Add to tree
tree = treeswift.Tree()
tree.root.children.append(node) # Direct list manipulation
node.parent = tree.root # Set parent reference
print(f"Tree: {tree.newick()}")Install with Tessl CLI
npx tessl i tessl/pypi-treeswift