0
# Tree Visualization and Display
1
2
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.
3
4
## Capabilities
5
6
### Tree Display
7
8
Display tree structure with customizable formatting, filtering, and sorting options.
9
10
```python { .api }
11
def show(nid=None, level=ROOT, idhidden=True, filter=None, key=None,
12
reverse=False, line_type="ascii-ex", data_property=None,
13
stdout=True, sorting=True) -> str | None:
14
"""
15
Display tree structure with customizable formatting.
16
17
Parameters:
18
- nid: str, root node for subtree display (default: entire tree)
19
- level: int, starting level for display (ROOT, or specific level)
20
- idhidden: bool, hide node identifiers in output
21
- filter: callable, function to filter nodes (node) -> bool
22
- key: callable, function for sorting nodes (node) -> comparable
23
- reverse: bool, reverse sort order
24
- line_type: str, line drawing style ("ascii-ex", "ascii-em", etc.)
25
- data_property: str, node data property to display
26
- stdout: bool, print to console if True, return string if False
27
- sorting: bool, enable/disable sorting
28
29
Returns:
30
str if stdout=False, None if stdout=True
31
"""
32
```
33
34
**Usage Examples:**
35
36
```python
37
# Basic tree display
38
tree.show()
39
40
# Display specific subtree
41
tree.show(nid="engineering")
42
43
# Show with node identifiers
44
tree.show(idhidden=False)
45
46
# Custom line style
47
tree.show(line_type="ascii-em")
48
49
# Display with filtering
50
tree.show(filter=lambda node: node.is_leaf(tree.identifier))
51
52
# Sorted display
53
tree.show(key=lambda node: node.tag.lower(), reverse=True)
54
55
# Show specific data property
56
tree.show(data_property="role", idhidden=False)
57
58
# Get display as string
59
tree_display = tree.show(stdout=False)
60
print("Tree structure:")
61
print(tree_display)
62
63
# Combined options
64
tree.show(
65
nid="company",
66
idhidden=False,
67
line_type="ascii-em",
68
key=lambda node: node.tag,
69
filter=lambda node: not node.is_leaf(tree.identifier) # Non-leaf nodes only
70
)
71
```
72
73
### Line Drawing Styles
74
75
Multiple line drawing styles for different visual preferences and contexts.
76
77
**Available Line Types:**
78
79
```python
80
# ASCII Extended (default)
81
tree.show(line_type="ascii-ex")
82
# Output:
83
# Root
84
# ├── Child A
85
# │ └── Grandchild
86
# └── Child B
87
88
# ASCII Emphasized
89
tree.show(line_type="ascii-em")
90
# Output:
91
# Root
92
# +-- Child A
93
# | `-- Grandchild
94
# `-- Child B
95
96
# ASCII Expanded Plus
97
tree.show(line_type="ascii-exr")
98
# Root
99
# +-- Child A
100
# | +-- Grandchild
101
# +-- Child B
102
103
# ASCII Plus
104
tree.show(line_type="ascii-emh")
105
# Root
106
# +-- Child A
107
# | +-- Grandchild
108
# +-- Child B
109
110
# ASCII Dotted
111
tree.show(line_type="ascii-emv")
112
# Root
113
# :-- Child A
114
# : :-- Grandchild
115
# :-- Child B
116
```
117
118
**Usage Examples:**
119
120
```python
121
# Compare different styles
122
styles = ["ascii-ex", "ascii-em", "ascii-exr", "ascii-emh", "ascii-emv"]
123
124
for style in styles:
125
print(f"\n=== {style.upper()} ===")
126
tree.show(line_type=style)
127
128
# Choose style based on context
129
def display_for_context(tree, context="console"):
130
"""Display tree with appropriate style for context."""
131
style_map = {
132
"console": "ascii-ex", # Best for terminal
133
"documentation": "ascii-em", # Clean for docs
134
"email": "ascii-emh", # Plain ASCII for email
135
"presentation": "ascii-ex" # Professional look
136
}
137
138
style = style_map.get(context, "ascii-ex")
139
tree.show(line_type=style)
140
141
display_for_context(tree, "documentation")
142
```
143
144
### File Output
145
146
Save tree visualizations to files for documentation and reporting.
147
148
```python { .api }
149
def save2file(filename, nid=None, level=ROOT, idhidden=True, filter=None,
150
key=None, reverse=False, line_type="ascii-ex",
151
data_property=None, sorting=True) -> None:
152
"""
153
Save tree display to file.
154
155
Parameters:
156
- filename: str, output filename
157
- (other parameters same as show() method)
158
"""
159
```
160
161
**Usage Examples:**
162
163
```python
164
# Save basic tree structure
165
tree.save2file("organization.txt")
166
167
# Save with custom formatting
168
tree.save2file(
169
"org_detailed.txt",
170
idhidden=False,
171
line_type="ascii-em",
172
data_property="role"
173
)
174
175
# Save filtered view
176
tree.save2file(
177
"managers_only.txt",
178
filter=lambda node: node.data and node.data.get("is_manager", False)
179
)
180
181
# Save subtree
182
tree.save2file("engineering_dept.txt", nid="engineering")
183
184
# Generate multiple report formats
185
def generate_tree_reports(tree, base_filename):
186
"""Generate multiple tree visualization reports."""
187
reports = {
188
"full": {"filter": None, "description": "Complete organization"},
189
"managers": {
190
"filter": lambda n: n.data and n.data.get("is_manager", False),
191
"description": "Management hierarchy"
192
},
193
"leaves": {
194
"filter": lambda n: n.is_leaf(tree.identifier),
195
"description": "Individual contributors"
196
}
197
}
198
199
for report_type, config in reports.items():
200
filename = f"{base_filename}_{report_type}.txt"
201
tree.save2file(
202
filename,
203
filter=config["filter"],
204
idhidden=False
205
)
206
print(f"Generated {filename}: {config['description']}")
207
208
generate_tree_reports(tree, "org_report")
209
```
210
211
### Advanced Display Filtering
212
213
Sophisticated filtering and conditional display logic.
214
215
**Usage Examples:**
216
217
```python
218
# Multi-condition filtering
219
def complex_filter(node):
220
"""Complex filtering logic."""
221
if not node.data:
222
return True # Show nodes without data
223
224
# Show if high salary or manager
225
salary = node.data.get("salary", 0)
226
is_manager = node.data.get("is_manager", False)
227
228
return salary > 100000 or is_manager
229
230
tree.show(filter=complex_filter)
231
232
# Level-based filtering
233
def show_levels(tree, max_level=2):
234
"""Show only nodes up to specified level."""
235
tree.show(filter=lambda node: tree.level(node.identifier) <= max_level)
236
237
show_levels(tree, max_level=3)
238
239
# Department-specific views
240
departments = ["engineering", "sales", "hr"]
241
for dept in departments:
242
if dept in tree:
243
print(f"\n=== {dept.upper()} DEPARTMENT ===")
244
tree.show(
245
nid=dept,
246
filter=lambda node: node.identifier != dept # Exclude dept header
247
)
248
249
# Dynamic filtering based on node properties
250
def show_by_role(tree, target_role):
251
"""Show only nodes with specific role."""
252
tree.show(
253
filter=lambda node: (
254
node.data and
255
node.data.get("role", "").lower() == target_role.lower()
256
),
257
key=lambda node: node.tag
258
)
259
260
show_by_role(tree, "engineer")
261
```
262
263
### Custom Display Formatting
264
265
Advanced formatting and customization options.
266
267
**Usage Examples:**
268
269
```python
270
# Display with custom data formatting
271
def show_with_salary(tree):
272
"""Display tree with salary information."""
273
def format_node_with_salary(node):
274
if node.data and "salary" in node.data:
275
return f"{node.tag} (${node.data['salary']:,})"
276
return node.tag
277
278
# Temporarily modify tags for display
279
original_tags = {}
280
for node_id in tree.expand_tree():
281
node = tree[node_id]
282
original_tags[node_id] = node.tag
283
node.tag = format_node_with_salary(node)
284
285
tree.show()
286
287
# Restore original tags
288
for node_id, original_tag in original_tags.items():
289
tree[node_id].tag = original_tag
290
291
show_with_salary(tree)
292
293
# Create hierarchical summary
294
def show_summary(tree):
295
"""Display tree with summary statistics."""
296
print("ORGANIZATION SUMMARY")
297
print("=" * 50)
298
299
for node_id in tree.expand_tree():
300
node = tree[node_id]
301
level = tree.level(node_id)
302
children_count = len(tree.children(node_id))
303
304
indent = " " * level
305
summary = f"{indent}{node.tag}"
306
307
if children_count > 0:
308
summary += f" ({children_count} direct reports)"
309
310
if node.data and "salary" in node.data:
311
summary += f" - ${node.data['salary']:,}"
312
313
print(summary)
314
315
show_summary(tree)
316
317
# Interactive display with user filtering
318
def interactive_tree_display(tree):
319
"""Interactive tree display with user-controlled filtering."""
320
while True:
321
print("\nTree Display Options:")
322
print("1. Show full tree")
323
print("2. Show by level")
324
print("3. Show by role")
325
print("4. Show leaves only")
326
print("5. Exit")
327
328
choice = input("Choose option (1-5): ").strip()
329
330
if choice == "1":
331
tree.show()
332
elif choice == "2":
333
max_level = int(input("Enter max level: "))
334
tree.show(filter=lambda n: tree.level(n.identifier) <= max_level)
335
elif choice == "3":
336
role = input("Enter role to filter: ")
337
tree.show(filter=lambda n: n.data and role.lower() in n.data.get("role", "").lower())
338
elif choice == "4":
339
tree.show(filter=lambda n: n.is_leaf(tree.identifier))
340
elif choice == "5":
341
break
342
else:
343
print("Invalid choice")
344
345
# interactive_tree_display(tree) # Uncomment for interactive use
346
```
347
348
### Display Constants and Options
349
350
Available constants and configuration options for tree display.
351
352
```python { .api }
353
ROOT = 0 # Display starting from root level
354
355
# Line type options:
356
# "ascii-ex" - ASCII Extended (├── └──)
357
# "ascii-em" - ASCII Emphasized (+-- `--)
358
# "ascii-exr" - ASCII Extended Right (+-- +--)
359
# "ascii-emh" - ASCII Emphasized Horizontal (+-- +--)
360
# "ascii-emv" - ASCII Emphasized Vertical (:-- :--)
361
```
362
363
### Performance Optimization for Large Trees
364
365
Efficient display strategies for large tree structures.
366
367
**Usage Examples:**
368
369
```python
370
# Lazy display for large trees
371
def display_large_tree_paginated(tree, page_size=50):
372
"""Display large tree in pages."""
373
all_nodes = list(tree.expand_tree())
374
total_pages = (len(all_nodes) + page_size - 1) // page_size
375
376
for page in range(total_pages):
377
start_idx = page * page_size
378
end_idx = min(start_idx + page_size, len(all_nodes))
379
page_nodes = set(all_nodes[start_idx:end_idx])
380
381
print(f"\n=== Page {page + 1}/{total_pages} ===")
382
tree.show(filter=lambda node: node.identifier in page_nodes)
383
384
if page < total_pages - 1:
385
input("Press Enter for next page...")
386
387
# Abbreviated display for overview
388
def show_tree_summary_levels(tree, max_children_shown=5):
389
"""Show tree with limited children per node."""
390
def limited_children_filter(node):
391
parent = tree.parent(node.identifier)
392
if parent:
393
siblings = tree.children(parent.identifier)
394
node_index = next(i for i, sibling in enumerate(siblings)
395
if sibling.identifier == node.identifier)
396
return node_index < max_children_shown
397
return True
398
399
tree.show(filter=limited_children_filter)
400
401
# Show counts of hidden nodes
402
for node_id in tree.expand_tree():
403
children = tree.children(node_id)
404
if len(children) > max_children_shown:
405
hidden_count = len(children) - max_children_shown
406
level = tree.level(node_id)
407
indent = " " * (level + 1)
408
print(f"{indent}... and {hidden_count} more")
409
410
show_tree_summary_levels(tree, max_children_shown=3)
411
412
# Memory-efficient display streaming
413
def stream_tree_display(tree, chunk_size=100):
414
"""Stream tree display for very large trees."""
415
nodes_processed = 0
416
current_chunk = []
417
418
for node_id in tree.expand_tree():
419
current_chunk.append(node_id)
420
nodes_processed += 1
421
422
if len(current_chunk) >= chunk_size:
423
# Display current chunk
424
chunk_set = set(current_chunk)
425
tree.show(filter=lambda node: node.identifier in chunk_set)
426
current_chunk = []
427
print(f"\n--- Processed {nodes_processed} nodes ---\n")
428
429
# Display remaining nodes
430
if current_chunk:
431
chunk_set = set(current_chunk)
432
tree.show(filter=lambda node: node.identifier in chunk_set)
433
434
# Usage for large trees
435
if len(tree) > 1000:
436
display_large_tree_paginated(tree)
437
else:
438
tree.show()
439
```