Render fitted TuiML decision trees as figures, ASCII text, or GraphViz DOT.
trees -- DecisionTreeClassifier and DecisionTreeRegressor, RandomForestClassifier / RandomForestRegressor ensembles (one member tree at a time) and DecisionStumpClassifier -- as well as a bare tree-node object.Three output formats
plot_tree A matplotlib figure of rounded/square node boxes joined by edges. export_text A plain ASCII rule listing, for terminals, logs and docstrings. export_graphviz A DOT-language string (or file) for rendering with GraphViz.How the drawing pipeline fits together
Those learners do not share a node class: CART uses TreeNode, the streaming learner uses HoeffdingNode, M5 names its split fields split_attr / split_value, and the stump keeps no nodes at all. Every entry point therefore funnels through one duck-typing shim, _TreeNodeAdapter, before any layout happens:
fitted estimator
| _get_tree_root / _check_is_fitted (unwrap .tree_ or .estimators_)
v
_TreeNodeAdapter (one interface for every node type)
| _build_bigtree_nodes (+ _build_node_label per node)
v
bigtree.Node tree
| bigtree.reingold_tilford (assigns tidy x / y per node)
v
_draw_bigtree (boxes, edges, edge labels -> Axes)
export_text and export_graphviz share the adapter but skip the bigtree layout entirely -- they walk the adapter tree recursively and emit characters instead of artists.
Notes
matplotlib and bigtree are imported lazily at module load and are optional: their absence is recorded in the module flags HAS_MATPLOTLIB and HAS_BIGTREE rather than raised. Only plot_tree needs them, and it raises ImportError at call time if either is missing. The text and DOT exports depend on neither, so they work in a headless install.>>> from tuiml.datasets import load_iris
>>> from tuiml.algorithms.trees import DecisionTreeClassifier
>>> from tuiml.evaluation.visualization import plot_tree
>>> X, y = load_iris()
>>> clf = DecisionTreeClassifier(max_depth=2, random_state=0).fit(X, y)
>>> fig = plot_tree(clf, feature_names=['sl', 'sw', 'pl', 'pw']) # doctest: +SKIP
Functions
Draw a fitted decision tree as a matplotlib figure of labelled boxes.
Each internal node is drawn as a box holding its split condition, each leaf as a box holding its prediction, and edges run from a parent's bottom edge to a child's top edge. Positions come from the Reingold-Tilford tidy tree algorithm, which centres each parent over its children and keeps subtrees from overlapping; box sizes are then measured from the label text and the layout is scaled so no two boxes collide.
The signature follows scikit-learn's plot_tree so existing calls port over, with four TuiML-only additions (tree_index, figsize, save_path, title) at the end.
Parameters
decision_tree
tree_ attribute (for example DecisionTreeClassifier, with estimators_ such as RandomForestClassifier (see tree_index), a fitted DecisionStumpClassifier, or a bare tree node object.
max_depth
feature_names
class_names
label
samples = ... line: 'all' shows it at every node, 'root' only at the top node, 'none' at no node. Split conditions and leaf predictions are always drawn.
filled
True, fill node boxes with a color encoding the node's role: blue for internal nodes, green for classification leaves, orange for regression leaves, gray for max_depth truncation markers.
impurity
node_ids
export_graphviz does honour it.
proportion
rounded
True, draw node boxes with rounded corners instead of square ones. Fonts are unaffected.
precision
%g) used when formatting a floating-point threshold in a node label.
ax
figsize and the TuiML plot style.
fontsize
tree_index
estimators_, which member tree to draw (TuiML extension).
figsize
(width, height) in inches (TuiML extension). Ignored when ax is given. If None, computed from the tree's leaf count and depth as (max(10, 3 * n_leaves), max(6, 2.5 * (depth + 1))).
save_path
title
"Random Forest - Tree <i>" for an ensemble member.
Returns
annotations
plot_tree, which returns the annotation artists; this implementation draws FancyBboxPatch boxes directly onto the axes instead and does not collect them. Retrieve the figure with ax.get_figure() or plt.gcf() if you need it.
Raises
ImportError
matplotlib or bigtree is not installed. Both are optional dependencies imported lazily at module load; install the latter with pip install bigtree.
ValueError
decision_tree is not fitted, or if tree_index is out of range for the ensemble's estimators_.
Notes
plt.show() before returning, so in a script with an interactive backend this call blocks until the window is closed. Set a non-interactive backend (matplotlib.use('Agg')) when plotting headlessly, and pass save_path to keep the result.>>> from tuiml.datasets import load_iris
>>> from tuiml.algorithms.trees import DecisionTreeClassifier
>>> from tuiml.evaluation.visualization import plot_tree
>>> X, y = load_iris()
>>> names = ['sepal_l', 'sepal_w', 'petal_l', 'petal_w']
>>> clf = DecisionTreeClassifier(max_depth=3, random_state=0).fit(X, y)
>>> plot_tree(clf, feature_names=names, filled=True) # doctest: +SKIP
Draw only the top two levels of one tree out of a fitted forest, and save
it instead of inspecting it interactively:
>>> from tuiml.algorithms.trees import RandomForestClassifier
>>> rf = RandomForestClassifier(n_estimators=10, random_state=0).fit(X, y)
>>> plot_tree(rf, tree_index=3, max_depth=2, rounded=True,
... save_path='tree3.png') # doctest: +SKIP
Build a text report showing the rules of a decision tree.
Parameters
decision_tree
tree_ attribute, or the tree root node itself.
feature_names
feature_{i} format.
class_names
max_depth
spacing
decimals
show_weights
Returns
report
>>> from tuiml.algorithms.trees import DecisionTreeClassifier
>>> from tuiml.datasets import load_iris
>>> X, y = load_iris()
>>> from tuiml.evaluation.visualization.trees import export_text
>>> clf = DecisionTreeClassifier().fit(X, y)
>>> print(export_text(clf, feature_names=['a', 'b'])) # doctest: +SKIP
|--- a <= 0.50
| |--- class: 0
|--- a > 0.50
| |--- b <= 1.00
| | |--- class: 1
| |--- b > 1.00
| | |--- class: 2
Export a decision tree in DOT format.
This function generates a GraphViz representation of the decision tree, which can be rendered using the GraphViz dot tool:
$ dot -Tpng tree.dot -o tree.png
Parameters
decision_tree
tree_ attribute, or the tree root node itself.
out_file
None, the result is returned as a string.
feature_names
feature_{i} format.
class_names
label
filled
True, paint nodes to indicate leaf type (classification vs regression).
leaves_parallel
True, draw all leaf nodes at the bottom of the tree.
impurity
True, show the impurity (where available) at each node.
node_ids
True, show the ID number on each node.
proportion
True, change the display of sample counts to be proportions of the total.
rotate
True, orient tree left to right rather than top-down.
rounded
True, draw node boxes with rounded corners.
special_characters
True, use special characters (e.g., Greek letters) for certain symbols.
precision
fontname
max_depth
Returns
dot_data
out_file is None.
>>> from tuiml.algorithms.trees import DecisionTreeClassifier
>>> from tuiml.datasets import load_iris
>>> X, y = load_iris()
>>> from tuiml.evaluation.visualization.trees import export_graphviz
>>> clf = DecisionTreeClassifier().fit(X, y)
>>> dot_data = export_graphviz(clf, feature_names=['a', 'b'])
>>> print(dot_data) # doctest: +SKIP
digraph Tree {
node [shape=box, style="filled", color="black", fontname="helvetica"] ;
...