Skip to content

Commit f517522

Browse files
authored
Improve API (#406)
* feat: nested_key_dict to tree to support child_key=None * feat: tree to nested_key_dict to support child_key=None * feat: intuitive API with Tree class * docs: add docs * feat: Tree WIP, Added BinaryTree * feat: Tree completed with helper, query search methods * docs: update docs * feat: Add DAG * docs: update docstring for BinaryTree and DAG * docs: update doctest to use Tree class * docs: update doctest to use Tree class * docs: update doctest to use Tree class * docs: update CHANGELOG * docs: update docstring * docs: update docs to use new API * fix: resolve conflict * feat: undo changes for backwards compatibility * feat: enhance Tree/BinaryTree/DAG methods * refactor: Tree.root is renamed to Tree.node for clarity * docs: update mkdocs and README * docs: update docstring * docs: update docstring + add plot to Tree * test: save to folder * docs: update CHANGELOG * docs: update docs to introduce difference between Tree and Node * docs: update docs to introduce difference between Tree and Node
1 parent fa50586 commit f517522

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+3166
-1096
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ site/
1313

1414
tests/*.html
1515
tests/*.png
16+
tests/files
1617
docs/_static/playground-config.js

CHANGELOG.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
66

77
## [Unreleased]
88

9+
## [1.0.0] - 2025-09-26
10+
### Added:
11+
- Improved API: Introduced BinaryTree, DAG, and Tree classes as a wrapper for all construct, export, helper, iterator
12+
methods instead of calling the various functions.
13+
### Changed:
14+
- Tests: Save images/files to a folder defined in Constants.
15+
916
## [0.31.2] - 2025-09-25
1017
### Fixed:
1118
- Docs: Upgrade docs to use Python 3.10.
@@ -830,7 +837,8 @@ ignore null attribute columns.
830837
- Utility Iterator: Tree traversal methods.
831838
- Workflow To Do App: Tree use case with to-do list implementation.
832839

833-
[Unreleased]: https://github.com/kayjan/bigtree/compare/0.31.2...HEAD
840+
[Unreleased]: https://github.com/kayjan/bigtree/compare/1.0.0...HEAD
841+
[1.0.0]: https://github.com/kayjan/bigtree/compare/0.31.2...1.0.0
834842
[0.31.2]: https://github.com/kayjan/bigtree/compare/0.31.1...0.31.2
835843
[0.31.1]: https://github.com/kayjan/bigtree/compare/0.31.0...0.31.1
836844
[0.31.0]: https://github.com/kayjan/bigtree/compare/0.30.1...0.31.0

README.md

Lines changed: 34 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,14 @@ Related Links:
2727
## Components
2828
There are 3 segments to Big Tree consisting of Tree, Binary Tree, and Directed Acyclic Graph (DAG) implementation.
2929

30-
For **Tree** implementation, there are 11 main components.
30+
For **Tree** implementation, there are 12 main components.
3131

32-
1. [**🌺 Node**](https://bigtree.readthedocs.io/stable/bigtree/node/node)
32+
1. [**🌺 Node**](https://bigtree.readthedocs.io/stable/bigtree/node/node/)
3333
1. ``BaseNode``, extendable class
3434
2. ``Node``, BaseNode with node name attribute
35-
2. [**✨ Constructing Tree**](https://bigtree.readthedocs.io/stable/bigtree/tree/construct/)
35+
2. [**🎄 Tree**](https://bigtree.readthedocs.io/stable/bigtree/tree/tree/)
36+
1. ``Tree``, wrapper around ``Node``, providing high-level APIs to build, iterate, query, and export the entire tree structure
37+
3. [**✨ Constructing Tree**](https://bigtree.readthedocs.io/stable/bigtree/tree/construct/)
3638
1. From `Node`, using parent and children constructors
3739
2. From *str*, using tree display or Newick string notation
3840
3. From *list*, using paths or parent-child tuples
@@ -43,74 +45,78 @@ For **Tree** implementation, there are 11 main components.
4345
8. Add nodes to existing tree using path string
4446
9. Add nodes and attributes to existing tree using *dictionary*, *pandas DataFrame*, or *polars DataFrame*, using path
4547
10. Add only attributes to existing tree using *dictionary*, *pandas DataFrame*, or *polars DataFrame*, using node name
46-
3. [**➰ Traversing Tree**](https://bigtree.readthedocs.io/stable/bigtree/utils/iterators/)
48+
4. [**➰ Traversing Tree**](https://bigtree.readthedocs.io/stable/bigtree/utils/iterators/)
4749
1. Pre-Order Traversal
4850
2. Post-Order Traversal
4951
3. Level-Order Traversal
5052
4. Level-Order-Group Traversal
5153
5. ZigZag Traversal
5254
6. ZigZag-Group Traversal
53-
4. [**🧩 Parsing Tree**](https://bigtree.readthedocs.io/stable/bigtree/tree/parsing/)
55+
5. [**🧩 Parsing Tree**](https://bigtree.readthedocs.io/stable/bigtree/tree/parsing/)
5456
1. Get common ancestors between nodes
5557
2. Get path from one node to another node
56-
5. [**📝 Modifying Tree**](https://bigtree.readthedocs.io/stable/bigtree/tree/modify/)
58+
6. [**📝 Modifying Tree**](https://bigtree.readthedocs.io/stable/bigtree/tree/modify/)
5759
1. Copy nodes from location to destination
5860
2. Shift nodes from location to destination
5961
3. Shift and replace nodes from location to destination
6062
4. Copy nodes from one tree to another
6163
5. Copy and replace nodes from one tree to another
62-
6. [**📌 Querying Tree**](https://bigtree.readthedocs.io/stable/bigtree/tree/query/)
64+
7. [**📌 Querying Tree**](https://bigtree.readthedocs.io/stable/bigtree/tree/query/)
6365
1. Filter tree using Tree Query Language
64-
7. [**🔍 Tree Search**](https://bigtree.readthedocs.io/stable/bigtree/tree/search/)
66+
8. [**🔍 Tree Search**](https://bigtree.readthedocs.io/stable/bigtree/tree/search/)
6567
1. Find multiple nodes based on name, partial path, relative path, attribute value, user-defined condition
6668
2. Find single nodes based on name, partial path, relative path, full path, attribute value, user-defined condition
6769
3. Find multiple child nodes based on user-defined condition
6870
4. Find single child node based on name, user-defined condition
69-
8. [**🔧 Helper Function**](https://bigtree.readthedocs.io/stable/bigtree/tree/helper/)
71+
9. [**🔧 Helper Function**](https://bigtree.readthedocs.io/stable/bigtree/tree/helper/)
7072
1. Cloning tree to another `Node` type
7173
2. Get subtree (smaller tree with different root)
7274
3. Prune tree (smaller tree with same root)
7375
4. Get difference between two trees
74-
9. [**📊 Plotting Tree**](https://bigtree.readthedocs.io/stable/bigtree/utils/plot/)
76+
10. [**📊 Plotting Tree**](https://bigtree.readthedocs.io/stable/bigtree/utils/plot/)
7577
1. Enhanced Reingold Tilford Algorithm to retrieve (x, y) coordinates for a tree structure
7678
2. Plot tree using matplotlib (optional dependency)
77-
10. [**🔨 Exporting Tree**](https://bigtree.readthedocs.io/stable/bigtree/tree/export/)
78-
1. Print to console, in vertical or horizontal orientation
79-
2. Export to *Newick string notation*, *dictionary*, *nested dictionary*, *pandas DataFrame*, or *polars DataFrame*
80-
3. Export tree to *dot* (can save to .dot, .png, .svg, .jpeg files)
81-
4. Export tree to *Pillow* (can save to .png, .jpg)
82-
5. Export tree to *Mermaid Flowchart* (can display on .md)
83-
6. Export tree to *Pyvis Network* (can display interactive .html)
84-
11. [**✔️ Workflows**](https://bigtree.readthedocs.io/stable/bigtree/workflows/app_todo)
85-
1. Sample workflows for tree demonstration!
79+
11. [**🔨 Exporting Tree**](https://bigtree.readthedocs.io/stable/bigtree/tree/export/)
80+
1. Print to console, in vertical or horizontal orientation
81+
2. Export to *Newick string notation*, *dictionary*, *nested dictionary*, *pandas DataFrame*, or *polars DataFrame*
82+
3. Export tree to *dot* (can save to .dot, .png, .svg, .jpeg files)
83+
4. Export tree to *Pillow* (can save to .png, .jpg)
84+
5. Export tree to *Mermaid Flowchart* (can display on .md)
85+
6. Export tree to *Pyvis Network* (can display interactive .html)
86+
12. [**✔️ Workflows**](https://bigtree.readthedocs.io/stable/bigtree/workflows/app_todo)
87+
1. Sample workflows for tree demonstration!
8688

8789
--------
8890

89-
For **Binary Tree** implementation, there are 3 main components.
91+
For **Binary Tree** implementation, there are 4 main components.
9092
Binary Node inherits from Node, so the components in Tree implementation are also available in Binary Tree.
9193

9294
1. [**🌿 Node**](https://bigtree.readthedocs.io/stable/bigtree/node/binarynode)
9395
1. ``BinaryNode``, Node with binary tree rules
94-
2. [**✨ Constructing Binary Tree**](https://bigtree.readthedocs.io/stable/bigtree/binarytree/construct/)
96+
2. [**🎄 Binary Tree**](https://bigtree.readthedocs.io/stable/bigtree/binarytree/binarytree/)
97+
1. ``BinaryTree``, wrapper around ``BinaryNode``, providing high-level APIs to build, iterate, query, and export the entire tree structure
98+
3. [**✨ Constructing Binary Tree**](https://bigtree.readthedocs.io/stable/bigtree/binarytree/construct/)
9599
1. From *list*, using flattened list structure
96-
3. [**➰ Traversing Binary Tree**](https://bigtree.readthedocs.io/stable/bigtree/utils/iterators/)
100+
4. [**➰ Traversing Binary Tree**](https://bigtree.readthedocs.io/stable/bigtree/utils/iterators/)
97101
1. In-Order Traversal
98102

99103
-----
100104

101-
For **Directed Acyclic Graph (DAG)** implementation, there are 5 main components.
105+
For **Directed Acyclic Graph (DAG)** implementation, there are 6 main components.
102106

103-
1. [**🌼 Node**](https://bigtree.readthedocs.io/stable/bigtree/node/dagnode)
107+
1. [**🌼 Node**](https://bigtree.readthedocs.io/stable/bigtree/node/dagnode/)
104108
1. ``DAGNode``, extendable class for constructing Directed Acyclic Graph (DAG)
105-
2. [**✨ Constructing DAG**](https://bigtree.readthedocs.io/stable/bigtree/dag/construct/)
109+
2. [**🎄 DAG**](https://bigtree.readthedocs.io/stable/bigtree/dag/dag/)
110+
1. ``DAG``, wrapper around ``DAGNode``, providing high-level APIs to build, export, and iterate the entire DAG
111+
3. [**✨ Constructing DAG**](https://bigtree.readthedocs.io/stable/bigtree/dag/construct/)
106112
1. From *list*, containing parent-child tuples
107113
2. From *nested dictionary*
108114
3. From *pandas DataFrame*
109-
3. [**➰ Traversing DAG**](https://bigtree.readthedocs.io/stable/bigtree/utils/iterators/)
115+
4. [**➰ Traversing DAG**](https://bigtree.readthedocs.io/stable/bigtree/utils/iterators/)
110116
1. Generic traversal method
111-
4. [**🧩 Parsing DAG**](https://bigtree.readthedocs.io/stable/bigtree/dag/parsing/)
117+
5. [**🧩 Parsing DAG**](https://bigtree.readthedocs.io/stable/bigtree/dag/parsing/)
112118
1. Get possible paths from one node to another node
113-
5. [**🔨 Exporting DAG**](https://bigtree.readthedocs.io/stable/bigtree/dag/export/)
119+
6. [**🔨 Exporting DAG**](https://bigtree.readthedocs.io/stable/bigtree/dag/export/)
114120
1. Export to *list*, *dictionary*, or *pandas DataFrame*
115121
2. Export DAG to *dot* (can save to .dot, .png, .svg, .jpeg files)
116122

bigtree/__init__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
__version__ = "0.31.2"
1+
__version__ = "1.0.0"
22

3+
from bigtree.binarytree.binarytree import BinaryTree
34
from bigtree.binarytree.construct import list_to_binarytree
45
from bigtree.dag.construct import dataframe_to_dag, dict_to_dag, list_to_dag
6+
from bigtree.dag.dag import DAG
57
from bigtree.dag.export import dag_to_dataframe, dag_to_dict, dag_to_dot, dag_to_list
68
from bigtree.dag.parsing import get_path_dag
79
from bigtree.node.basenode import BaseNode
@@ -83,6 +85,7 @@
8385
find_relative_paths,
8486
findall,
8587
)
88+
from bigtree.tree.tree import Tree
8689
from bigtree.utils.constants import (
8790
ANSIBorderStyle,
8891
ANSIHPrintStyle,

bigtree/binarytree/binarytree.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
from typing import Any, Iterable, Sequence
2+
3+
from bigtree.binarytree import construct
4+
from bigtree.node import binarynode
5+
from bigtree.tree.tree import Tree
6+
from bigtree.utils import iterators
7+
8+
9+
class BinaryTree(Tree):
10+
"""
11+
BinaryTree wraps around BinaryNode class to provide a quick, intuitive, Pythonic API for
12+
13+
* Construction with dataframe, dictionary, list, or string
14+
* Export to dataframe, dictionary, list, string, or images
15+
* Helper methods for cloning, pruning, getting tree diff
16+
* Query and Search methods to find one or more Nodes
17+
18+
Do refer to the various modules respectively on the keyword parameters.
19+
"""
20+
21+
construct_kwargs: dict[str, Any] = dict(node_type=binarynode.BinaryNode)
22+
23+
def __init__(self, root: binarynode.BinaryNode):
24+
super().__init__(root)
25+
26+
@classmethod
27+
def from_heapq_list(
28+
cls, heapq_list: Sequence[int], *args: Any, **kwargs: Any
29+
) -> "BinaryTree":
30+
"""See `list_to_binarytree` for full details.
31+
32+
Accepts the same arguments as `list_to_binarytree`.
33+
"""
34+
construct_kwargs = {**cls.construct_kwargs, **kwargs}
35+
root_node = construct.list_to_binarytree(heapq_list, *args, **construct_kwargs)
36+
return cls(root_node)
37+
38+
# Iterator methods
39+
def inorder_iter(
40+
self, *args: Any, **kwargs: Any
41+
) -> Iterable[binarynode.BinaryNode]:
42+
"""See `inorder_iter` for full details.
43+
44+
Accepts the same arguments as `inorder_iter`.
45+
"""
46+
self.node: binarynode.BinaryNode
47+
return iterators.inorder_iter(self.node, *args, **kwargs)

bigtree/binarytree/construct.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ def list_to_binarytree(
1515
"""Construct tree from a list of numbers (int or float) in heapq format.
1616
1717
Examples:
18-
>>> from bigtree import list_to_binarytree, tree_to_dot
18+
>>> from bigtree import BinaryTree
1919
>>> nums_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
20-
>>> root = list_to_binarytree(nums_list)
21-
>>> root.show()
20+
>>> tree = BinaryTree.from_heapq_list(nums_list)
21+
>>> tree.show()
2222
1
2323
├── 2
2424
│ ├── 4
@@ -29,7 +29,7 @@ def list_to_binarytree(
2929
└── 3
3030
├── 6
3131
└── 7
32-
>>> graph = tree_to_dot(root, node_colour="gold")
32+
>>> graph = tree.to_dot(node_colour="gold")
3333
>>> graph.write_png("assets/construct_binarytree.png")
3434
3535
![Sample Binary Tree](https://github.com/kayjan/bigtree/raw/master/assets/construct_binarytree.png)

bigtree/dag/construct.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@ def list_to_dag(
2424
"""Construct DAG from list of tuples containing parent-child names. Note that node names must be unique.
2525
2626
Examples:
27-
>>> from bigtree import list_to_dag, dag_iterator
27+
>>> from bigtree import DAG, dag_iterator
2828
>>> relations_list = [("a", "c"), ("a", "d"), ("b", "c"), ("c", "d"), ("d", "e")]
29-
>>> dag = list_to_dag(relations_list)
30-
>>> [(parent.node_name, child.node_name) for parent, child in dag_iterator(dag)]
29+
>>> dag = DAG.from_list(relations_list)
30+
>>> [(parent.node_name, child.node_name) for parent, child in dag.iterate()]
3131
[('a', 'd'), ('c', 'd'), ('d', 'e'), ('a', 'c'), ('b', 'c')]
3232
3333
Args:
@@ -59,16 +59,16 @@ def dict_to_dag(
5959
Note that node names must be unique.
6060
6161
Examples:
62-
>>> from bigtree import dict_to_dag, dag_iterator
62+
>>> from bigtree import DAG
6363
>>> relation_dict = {
6464
... "a": {"step": 1},
6565
... "b": {"step": 1},
6666
... "c": {"parents": ["a", "b"], "step": 2},
6767
... "d": {"parents": ["a", "c"], "step": 2},
6868
... "e": {"parents": ["d"], "step": 3},
6969
... }
70-
>>> dag = dict_to_dag(relation_dict, parent_key="parents")
71-
>>> [(parent.node_name, child.node_name) for parent, child in dag_iterator(dag)]
70+
>>> dag = DAG.from_dict(relation_dict, parent_key="parents")
71+
>>> [(parent.node_name, child.node_name) for parent, child in dag.iterate()]
7272
[('a', 'd'), ('c', 'd'), ('d', 'e'), ('a', 'c'), ('b', 'c')]
7373
7474
Args:
@@ -125,7 +125,7 @@ def dataframe_to_dag(
125125
126126
Examples:
127127
>>> import pandas as pd
128-
>>> from bigtree import dataframe_to_dag, dag_iterator
128+
>>> from bigtree import DAG
129129
>>> relation_data = pd.DataFrame([
130130
... ["a", None, 1],
131131
... ["b", None, 1],
@@ -137,8 +137,8 @@ def dataframe_to_dag(
137137
... ],
138138
... columns=["child", "parent", "step"]
139139
... )
140-
>>> dag = dataframe_to_dag(relation_data)
141-
>>> [(parent.node_name, child.node_name) for parent, child in dag_iterator(dag)]
140+
>>> dag = DAG.from_dataframe(relation_data)
141+
>>> [(parent.node_name, child.node_name) for parent, child in dag.iterate()]
142142
[('a', 'd'), ('c', 'd'), ('d', 'e'), ('a', 'c'), ('b', 'c')]
143143
144144
Args:

0 commit comments

Comments
 (0)