A Python implementation of tree data structure with hierarchical organization and efficient operations for traversal, modification, search, and visualization.
Comprehensive functionality for visualizing and displaying tree structures with customizable formats, line styles, filtering options, and export capabilities. Provides rich text-based tree representations optimized for console output and documentation.
Display tree structure with customizable formatting, filtering, and sorting options.
def show(nid=None, level=ROOT, idhidden=True, filter=None, key=None,
reverse=False, line_type="ascii-ex", data_property=None,
stdout=True, sorting=True) -> str | None:
"""
Display tree structure with customizable formatting.
Parameters:
- nid: str, root node for subtree display (default: entire tree)
- level: int, starting level for display (ROOT, or specific level)
- idhidden: bool, hide node identifiers in output
- filter: callable, function to filter nodes (node) -> bool
- key: callable, function for sorting nodes (node) -> comparable
- reverse: bool, reverse sort order
- line_type: str, line drawing style ("ascii-ex", "ascii-em", etc.)
- data_property: str, node data property to display
- stdout: bool, print to console if True, return string if False
- sorting: bool, enable/disable sorting
Returns:
str if stdout=False, None if stdout=True
"""Usage Examples:
# Basic tree display
tree.show()
# Display specific subtree
tree.show(nid="engineering")
# Show with node identifiers
tree.show(idhidden=False)
# Custom line style
tree.show(line_type="ascii-em")
# Display with filtering
tree.show(filter=lambda node: node.is_leaf(tree.identifier))
# Sorted display
tree.show(key=lambda node: node.tag.lower(), reverse=True)
# Show specific data property
tree.show(data_property="role", idhidden=False)
# Get display as string
tree_display = tree.show(stdout=False)
print("Tree structure:")
print(tree_display)
# Combined options
tree.show(
nid="company",
idhidden=False,
line_type="ascii-em",
key=lambda node: node.tag,
filter=lambda node: not node.is_leaf(tree.identifier) # Non-leaf nodes only
)Multiple line drawing styles for different visual preferences and contexts.
Available Line Types:
# ASCII Extended (default)
tree.show(line_type="ascii-ex")
# Output:
# Root
# ├── Child A
# │ └── Grandchild
# └── Child B
# ASCII Emphasized
tree.show(line_type="ascii-em")
# Output:
# Root
# +-- Child A
# | `-- Grandchild
# `-- Child B
# ASCII Expanded Plus
tree.show(line_type="ascii-exr")
# Root
# +-- Child A
# | +-- Grandchild
# +-- Child B
# ASCII Plus
tree.show(line_type="ascii-emh")
# Root
# +-- Child A
# | +-- Grandchild
# +-- Child B
# ASCII Dotted
tree.show(line_type="ascii-emv")
# Root
# :-- Child A
# : :-- Grandchild
# :-- Child BUsage Examples:
# Compare different styles
styles = ["ascii-ex", "ascii-em", "ascii-exr", "ascii-emh", "ascii-emv"]
for style in styles:
print(f"\n=== {style.upper()} ===")
tree.show(line_type=style)
# Choose style based on context
def display_for_context(tree, context="console"):
"""Display tree with appropriate style for context."""
style_map = {
"console": "ascii-ex", # Best for terminal
"documentation": "ascii-em", # Clean for docs
"email": "ascii-emh", # Plain ASCII for email
"presentation": "ascii-ex" # Professional look
}
style = style_map.get(context, "ascii-ex")
tree.show(line_type=style)
display_for_context(tree, "documentation")Save tree visualizations to files for documentation and reporting.
def save2file(filename, nid=None, level=ROOT, idhidden=True, filter=None,
key=None, reverse=False, line_type="ascii-ex",
data_property=None, sorting=True) -> None:
"""
Save tree display to file.
Parameters:
- filename: str, output filename
- (other parameters same as show() method)
"""Usage Examples:
# Save basic tree structure
tree.save2file("organization.txt")
# Save with custom formatting
tree.save2file(
"org_detailed.txt",
idhidden=False,
line_type="ascii-em",
data_property="role"
)
# Save filtered view
tree.save2file(
"managers_only.txt",
filter=lambda node: node.data and node.data.get("is_manager", False)
)
# Save subtree
tree.save2file("engineering_dept.txt", nid="engineering")
# Generate multiple report formats
def generate_tree_reports(tree, base_filename):
"""Generate multiple tree visualization reports."""
reports = {
"full": {"filter": None, "description": "Complete organization"},
"managers": {
"filter": lambda n: n.data and n.data.get("is_manager", False),
"description": "Management hierarchy"
},
"leaves": {
"filter": lambda n: n.is_leaf(tree.identifier),
"description": "Individual contributors"
}
}
for report_type, config in reports.items():
filename = f"{base_filename}_{report_type}.txt"
tree.save2file(
filename,
filter=config["filter"],
idhidden=False
)
print(f"Generated {filename}: {config['description']}")
generate_tree_reports(tree, "org_report")Sophisticated filtering and conditional display logic.
Usage Examples:
# Multi-condition filtering
def complex_filter(node):
"""Complex filtering logic."""
if not node.data:
return True # Show nodes without data
# Show if high salary or manager
salary = node.data.get("salary", 0)
is_manager = node.data.get("is_manager", False)
return salary > 100000 or is_manager
tree.show(filter=complex_filter)
# Level-based filtering
def show_levels(tree, max_level=2):
"""Show only nodes up to specified level."""
tree.show(filter=lambda node: tree.level(node.identifier) <= max_level)
show_levels(tree, max_level=3)
# Department-specific views
departments = ["engineering", "sales", "hr"]
for dept in departments:
if dept in tree:
print(f"\n=== {dept.upper()} DEPARTMENT ===")
tree.show(
nid=dept,
filter=lambda node: node.identifier != dept # Exclude dept header
)
# Dynamic filtering based on node properties
def show_by_role(tree, target_role):
"""Show only nodes with specific role."""
tree.show(
filter=lambda node: (
node.data and
node.data.get("role", "").lower() == target_role.lower()
),
key=lambda node: node.tag
)
show_by_role(tree, "engineer")Advanced formatting and customization options.
Usage Examples:
# Display with custom data formatting
def show_with_salary(tree):
"""Display tree with salary information."""
def format_node_with_salary(node):
if node.data and "salary" in node.data:
return f"{node.tag} (${node.data['salary']:,})"
return node.tag
# Temporarily modify tags for display
original_tags = {}
for node_id in tree.expand_tree():
node = tree[node_id]
original_tags[node_id] = node.tag
node.tag = format_node_with_salary(node)
tree.show()
# Restore original tags
for node_id, original_tag in original_tags.items():
tree[node_id].tag = original_tag
show_with_salary(tree)
# Create hierarchical summary
def show_summary(tree):
"""Display tree with summary statistics."""
print("ORGANIZATION SUMMARY")
print("=" * 50)
for node_id in tree.expand_tree():
node = tree[node_id]
level = tree.level(node_id)
children_count = len(tree.children(node_id))
indent = " " * level
summary = f"{indent}{node.tag}"
if children_count > 0:
summary += f" ({children_count} direct reports)"
if node.data and "salary" in node.data:
summary += f" - ${node.data['salary']:,}"
print(summary)
show_summary(tree)
# Interactive display with user filtering
def interactive_tree_display(tree):
"""Interactive tree display with user-controlled filtering."""
while True:
print("\nTree Display Options:")
print("1. Show full tree")
print("2. Show by level")
print("3. Show by role")
print("4. Show leaves only")
print("5. Exit")
choice = input("Choose option (1-5): ").strip()
if choice == "1":
tree.show()
elif choice == "2":
max_level = int(input("Enter max level: "))
tree.show(filter=lambda n: tree.level(n.identifier) <= max_level)
elif choice == "3":
role = input("Enter role to filter: ")
tree.show(filter=lambda n: n.data and role.lower() in n.data.get("role", "").lower())
elif choice == "4":
tree.show(filter=lambda n: n.is_leaf(tree.identifier))
elif choice == "5":
break
else:
print("Invalid choice")
# interactive_tree_display(tree) # Uncomment for interactive useAvailable constants and configuration options for tree display.
ROOT = 0 # Display starting from root level
# Line type options:
# "ascii-ex" - ASCII Extended (├── └──)
# "ascii-em" - ASCII Emphasized (+-- `--)
# "ascii-exr" - ASCII Extended Right (+-- +--)
# "ascii-emh" - ASCII Emphasized Horizontal (+-- +--)
# "ascii-emv" - ASCII Emphasized Vertical (:-- :--)Efficient display strategies for large tree structures.
Usage Examples:
# Lazy display for large trees
def display_large_tree_paginated(tree, page_size=50):
"""Display large tree in pages."""
all_nodes = list(tree.expand_tree())
total_pages = (len(all_nodes) + page_size - 1) // page_size
for page in range(total_pages):
start_idx = page * page_size
end_idx = min(start_idx + page_size, len(all_nodes))
page_nodes = set(all_nodes[start_idx:end_idx])
print(f"\n=== Page {page + 1}/{total_pages} ===")
tree.show(filter=lambda node: node.identifier in page_nodes)
if page < total_pages - 1:
input("Press Enter for next page...")
# Abbreviated display for overview
def show_tree_summary_levels(tree, max_children_shown=5):
"""Show tree with limited children per node."""
def limited_children_filter(node):
parent = tree.parent(node.identifier)
if parent:
siblings = tree.children(parent.identifier)
node_index = next(i for i, sibling in enumerate(siblings)
if sibling.identifier == node.identifier)
return node_index < max_children_shown
return True
tree.show(filter=limited_children_filter)
# Show counts of hidden nodes
for node_id in tree.expand_tree():
children = tree.children(node_id)
if len(children) > max_children_shown:
hidden_count = len(children) - max_children_shown
level = tree.level(node_id)
indent = " " * (level + 1)
print(f"{indent}... and {hidden_count} more")
show_tree_summary_levels(tree, max_children_shown=3)
# Memory-efficient display streaming
def stream_tree_display(tree, chunk_size=100):
"""Stream tree display for very large trees."""
nodes_processed = 0
current_chunk = []
for node_id in tree.expand_tree():
current_chunk.append(node_id)
nodes_processed += 1
if len(current_chunk) >= chunk_size:
# Display current chunk
chunk_set = set(current_chunk)
tree.show(filter=lambda node: node.identifier in chunk_set)
current_chunk = []
print(f"\n--- Processed {nodes_processed} nodes ---\n")
# Display remaining nodes
if current_chunk:
chunk_set = set(current_chunk)
tree.show(filter=lambda node: node.identifier in chunk_set)
# Usage for large trees
if len(tree) > 1000:
display_large_tree_paginated(tree)
else:
tree.show()Install with Tessl CLI
npx tessl i tessl/pypi-treelib