CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-treeswift

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.

Overview
Eval results
Files

node-operations.mddocs/

Node Operations

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.

Capabilities

Node Creation and Properties

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]}")

Parent-Child Relationships

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")

Node Properties and Status

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")

Label Management

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}'")

Edge Length Management

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}")

Node Structural Operations

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()}")

Node Output Formatting

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}")

Node Attributes Access

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 length

Usage 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

docs

index.md

node-operations.md

tree-analysis.md

tree-io.md

tree-manipulation.md

tree-traversal.md

visualization.md

tile.json