Implementation:Online ml River Tree Viz
| Knowledge Sources | |
|---|---|
| Domains | Online_Learning, Decision_Trees, Visualization |
| Last Updated | 2026-02-08 16:00 GMT |
Overview
Visualization utilities for rendering decision trees as interactive HTML representations in Jupyter notebooks. Provides clean, hierarchical tree displays without requiring external dependencies beyond Python's standard library.
Description
The viz module enables tree visualization directly in Jupyter notebooks by generating HTML/CSS representations. When a Branch object is displayed in a notebook, it automatically renders as a styled tree diagram showing:
- Branch nodes with split conditions
- Leaf nodes with their content
- Hierarchical structure with connecting lines
- Clean, readable formatting
This visualization is lightweight, requiring only ElementTree (standard library) and CSS for styling, making it dependency-free compared to graphviz-based solutions.
Code Reference
Source Location:
/tmp/kapso_repo_178qi9vb/river/tree/viz.py
Signature:
def tree_to_html(tree: Branch) -> ET.Element:
"""Convert tree Branch to HTML element tree."""
# Returns <ul class="tree"> element
CSS = """
.tree, .tree ul, .tree li { ... }
...
"""
Import:
from river.tree.viz import tree_to_html, CSS
Usage
In Jupyter Notebook:
from river import tree
from river import datasets
# Train a tree
model = tree.HoeffdingTreeClassifier()
for x, y in datasets.Phishing():
model.learn_one(x, y)
# Display in notebook (automatic HTML rendering)
model._root # Shows interactive tree visualization
Manual HTML Generation:
from river.tree.viz import tree_to_html, CSS
from xml.etree import ElementTree as ET
# Generate HTML element
html_element = tree_to_html(model._root)
# Convert to string
html_string = ET.tostring(html_element, encoding='unicode')
# Add CSS styling
full_html = f"""
<div>
{html_string}
<style scoped>{CSS}</style>
</div>
"""
Implementation Details
tree_to_html Function
Algorithm:
1. Create root `
- ` element
2. Recursively add nodes:
* For Branch nodes:
* Create `
- ` with `
` containing split condition * Create nested `- ` for children
* Recursively add each child
* For Leaf nodes:
* Create `
- ` with `
` containing repr(node) 3. Return root element Structure:<ul class="tree"> <li> <code>age ≤ 35.0</code> <ul> <li> <code>income ≤ 50000</code> <ul> <li><code>Leaf: class=0, n=150</code></li> <li><code>Leaf: class=1, n=80</code></li> </ul> </li> <li><code>Leaf: class=1, n=200</code></li> </ul> </li> </ul>
CSS Styling
The included CSS provides:
Layout:
- Centered tree display
- Table-based layout for proper child alignment
- Hierarchical indentation
Connectors:
- Vertical and horizontal lines connecting nodes
- Lines drawn using CSS borders
- Proper line termination at first/last children
Node Appearance:
- Bordered code boxes for nodes
- Padding and margins for readability
- Monospace font for code content
Key CSS Classes:
- .tree: Root container with centering
- .tree ul: Child container with full width
- .tree li: Individual node with table-cell display
- .tree code: Node content box with border
- .tree li:before: Horizontal connector line
- .tree ul:before, code:before: Vertical connector lines
Integration with Branch Class
The Branch base class includes automatic HTML rendering:
class Branch: def _repr_html_(self): from river.tree import viz div = viz.tree_to_html(self) return f"<div>{ET.tostring(div, encoding='unicode')}<style scoped>{viz.CSS}</style></div>"
When a Branch object is the last expression in a Jupyter cell, the notebook: 1. Checks for `_repr_html_` method 2. Calls it to get HTML string 3. Renders HTML directly in the output cell
Customization
Custom Node Representation:
Override `repr_split` in Branch subclasses or `__repr__` in Leaf subclasses:
class CustomLeaf(Leaf): @property def __repr__(self): return f"Samples: {self.n_samples}, Mean: {self.mean:.2f}" class CustomBranch(Branch): @property def repr_split(self): return f"{self.feature} {'≤' if self.numerical else '='} {self.threshold}"
Custom CSS:
Modify the CSS string for different styling:
from river.tree import viz # Add custom styles custom_css = viz.CSS + """ .tree code { background-color: #f0f0f0; font-family: 'Courier New', monospace; } .tree li:before { outline-color: #0066cc; } """ # Use in manual HTML generation html = f"<div>{tree_html}<style scoped>{custom_css}</style></div>"
Comparison with Graphviz
Feature tree.viz (HTML) tree.draw() (Graphviz) Dependencies None (stdlib only) Requires graphviz library and binary Output format HTML/CSS DOT/SVG/PNG/PDF Jupyter integration Automatic Automatic (if graphviz installed) Customization CSS styling Graphviz attributes Interactivity Static HTML Static images Export HTML/screenshot Multiple formats Complexity Simple, lightweight More features, heavier Advantages
1. No External Dependencies: Works with Python standard library only 2. Jupyter Native: Seamless integration with notebooks 3. Clean Rendering: Professional tree appearance 4. CSS Customizable: Easy to adjust styling 5. Lightweight: Minimal overhead
Limitations
1. No Exports: Cannot easily save to file formats like PNG or PDF 2. Static Only: No interactive features (zoom, pan, collapse) 3. Large Trees: May become unwieldy for very deep/wide trees 4. Browser Dependent: Rendering quality depends on browser CSS support
Related Pages
Example Output
When displayed in Jupyter, a simple tree might render as:
```
age ≤ 30 / \ income ≤ 40k Leaf: Class=1 / \ n=200 Leaf: Leaf: Class=0 Class=1 n=150 n=100```
With proper HTML/CSS styling including borders, alignment, and connecting lines.
- ` with `