Skip to content

Commit bb1ddc8

Browse files
authored
Merge pull request #252 from kayjan/add-dataclass
Add dataclass
2 parents 6f8d410 + b07a986 commit bb1ddc8

File tree

8 files changed

+360
-83
lines changed

8 files changed

+360
-83
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

77
## [Unreleased]
8+
### Changed:
9+
- Tree Exporter: Print functions to accept custom style that is implemented as dataclass, this is a more
10+
object-oriented way of parsing arguments.
11+
This affects functions `print_tree`, `yield_tree`, `hprint_tree`, and `hyield_tree`.
12+
The argument `custom_style` is deprecated, and argument `style` is used instead.
13+
**This might not be backwards-compatible!**
14+
- Misc: Updated docstrings to be more comprehensive for tree constructor and tree exporter.
815

916
## [0.18.3] - 2024-06-05
1017
### Changed:

bigtree/__init__.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,22 @@
6666
find_relative_paths,
6767
findall,
6868
)
69+
from bigtree.utils.constants import (
70+
ANSIHPrintStyle,
71+
ANSIPrintStyle,
72+
ASCIIHPrintStyle,
73+
ASCIIPrintStyle,
74+
BaseHPrintStyle,
75+
BasePrintStyle,
76+
ConstBoldHPrintStyle,
77+
ConstBoldPrintStyle,
78+
ConstHPrintStyle,
79+
ConstPrintStyle,
80+
DoubleHPrintStyle,
81+
DoublePrintStyle,
82+
RoundedHPrintStyle,
83+
RoundedPrintStyle,
84+
)
6985
from bigtree.utils.groot import speak_like_groot, whoami
7086
from bigtree.utils.iterators import (
7187
dag_iterator,

bigtree/tree/construct.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1411,7 +1411,7 @@ def newick_to_tree(
14111411
In the Newick Notation (or New Hampshire Notation)
14121412
14131413
- Tree is represented in round brackets i.e., `(child1,child2,child3)parent`.
1414-
- If there are nested tree, they will be in nested round brackets i.e., `((grandchild1)child1,(grandchild2,grandchild3)child2)parent`.
1414+
- If there are nested trees, they will be in nested round brackets i.e., `((grandchild1)child1,(grandchild2,grandchild3)child2)parent`.
14151415
- If there is length attribute, they will be beside the name i.e., `(child1:0.5,child2:0.1)parent`.
14161416
- If there are other attributes, attributes are represented in square brackets i.e., `(child1:0.5[S:human],child2:0.1[S:human])parent[S:parent]`.
14171417

bigtree/tree/export.py

Lines changed: 108 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,13 @@
1111
assert_tree_type,
1212
isnull,
1313
)
14-
from bigtree.utils.constants import ExportConstants, MermaidConstants, NewickCharacter
14+
from bigtree.utils.constants import (
15+
BaseHPrintStyle,
16+
BasePrintStyle,
17+
ExportConstants,
18+
MermaidConstants,
19+
NewickCharacter,
20+
)
1521
from bigtree.utils.exceptions import (
1622
optional_dependencies_image,
1723
optional_dependencies_pandas,
@@ -66,8 +72,7 @@ def print_tree(
6672
attr_list: Iterable[str] = [],
6773
attr_omit_null: bool = False,
6874
attr_bracket: List[str] = ["[", "]"],
69-
style: str = "const",
70-
custom_style: Iterable[str] = [],
75+
style: Union[str, Iterable[str], BasePrintStyle] = "const",
7176
) -> None:
7277
"""Print tree to console, starting from `tree`.
7378
@@ -76,10 +81,14 @@ def print_tree(
7681
- Able to choose which attributes to show or show all attributes, using `attr_name_filter` and `all_attrs`
7782
- Able to omit showing of attributes if it is null, using `attr_omit_null`
7883
- Able to customize open and close brackets if attributes are shown, using `attr_bracket`
79-
- Able to customize style, to choose from `ansi`, `ascii`, `const`, `const_bold`, `rounded`, `double`, and `custom` style
80-
- Default style is `const` style
81-
- If style is set to custom, user can choose their own style for stem, branch and final stem icons
82-
- Stem, branch, and final stem symbol should have the same number of characters
84+
- Able to customize style, to choose from str, List[str], or inherit from BasePrintStyle, using `style`
85+
86+
For style,
87+
88+
- (str): `ansi`, `ascii`, `const` (default), `const_bold`, `rounded`, `double` style
89+
- (List[str]): Choose own style for stem, branch, and final stem icons, they must have the same number of characters
90+
- (BasePrintStyle): `ANSIPrintStyle`, `ASCIIPrintStyle`, `ConstPrintStyle`, `ConstBoldPrintStyle`, `RoundedPrintStyle`,
91+
`DoublePrintStyle` style or inherit from `BasePrintStyle`
8392
8493
Examples:
8594
**Printing tree**
@@ -169,6 +178,16 @@ def print_tree(
169178
║ ╚══ e
170179
╚══ c
171180
181+
**Custom Styles**
182+
183+
>>> from bigtree import ANSIPrintStyle
184+
>>> print_tree(root, style=ANSIPrintStyle)
185+
a
186+
|-- b
187+
| |-- d
188+
| `-- e
189+
`-- c
190+
172191
Args:
173192
tree (Node): tree to print
174193
node_name_or_path (str): node to print from, becomes the root node of printing
@@ -177,15 +196,13 @@ def print_tree(
177196
attr_list (Iterable[str]): list of node attributes to print, optional
178197
attr_omit_null (bool): indicator whether to omit showing of null attributes, defaults to False
179198
attr_bracket (List[str]): open and close bracket for `all_attrs` or `attr_list`
180-
style (str): style of print, defaults to const style
181-
custom_style (Iterable[str]): style of stem, branch and final stem, used when `style` is set to 'custom'
199+
style (Union[str, Iterable[str], BasePrintStyle]): style of print, defaults to const
182200
"""
183201
for pre_str, fill_str, _node in yield_tree(
184202
tree=tree,
185203
node_name_or_path=node_name_or_path,
186204
max_depth=max_depth,
187205
style=style,
188-
custom_style=custom_style,
189206
):
190207
# Get node_str (node name and attributes)
191208
attr_str = ""
@@ -222,17 +239,20 @@ def yield_tree(
222239
tree: T,
223240
node_name_or_path: str = "",
224241
max_depth: int = 0,
225-
style: str = "const",
226-
custom_style: Iterable[str] = [],
242+
style: Union[str, Iterable[str], BasePrintStyle] = "const",
227243
) -> Iterable[Tuple[str, str, T]]:
228244
"""Generator method for customizing printing of tree, starting from `tree`.
229245
230246
- Able to select which node to print from, resulting in a subtree, using `node_name_or_path`
231247
- Able to customize for maximum depth to print, using `max_depth`
232-
- Able to customize style, to choose from `ansi`, `ascii`, `const`, `const_bold`, `rounded`, `double`, and `custom` style
233-
- Default style is `const` style
234-
- If style is set to custom, user can choose their own style for stem, branch and final stem icons
235-
- Stem, branch, and final stem symbol should have the same number of characters
248+
- Able to customize style, to choose from str, List[str], or inherit from BasePrintStyle, using `style`
249+
250+
For style,
251+
252+
- (str): `ansi`, `ascii`, `const` (default), `const_bold`, `rounded`, `double` style
253+
- (List[str]): Choose own style for stem, branch, and final stem icons, they must have the same number of characters
254+
- (BasePrintStyle): `ANSIPrintStyle`, `ASCIIPrintStyle`, `ConstPrintStyle`, `ConstBoldPrintStyle`, `RoundedPrintStyle`,
255+
`DoublePrintStyle` style or inherit from `BasePrintStyle`
236256
237257
Examples:
238258
**Yield tree**
@@ -315,6 +335,17 @@ def yield_tree(
315335
║ ╚══ e
316336
╚══ c
317337
338+
**Custom Styles**
339+
340+
>>> from bigtree import ANSIPrintStyle
341+
>>> for branch, stem, node in yield_tree(root, style=ANSIPrintStyle):
342+
... print(f"{branch}{stem}{node.node_name}")
343+
a
344+
|-- b
345+
| |-- d
346+
| `-- e
347+
`-- c
348+
318349
**Printing Attributes**
319350
320351
>>> for branch, stem, node in yield_tree(root, style="const"):
@@ -329,30 +360,26 @@ def yield_tree(
329360
tree (Node): tree to print
330361
node_name_or_path (str): node to print from, becomes the root node of printing, optional
331362
max_depth (int): maximum depth of tree to print, based on `depth` attribute, optional
332-
style (str): style of print, defaults to const
333-
custom_style (Iterable[str]): style of stem, branch and final stem, used when `style` is set to 'custom'
363+
style (Union[str, Iterable[str], BasePrintStyle]): style of print, defaults to const
334364
"""
335365
from bigtree.tree.helper import get_subtree
336366

337-
available_styles = ExportConstants.PRINT_STYLES
338-
assert_style_in_dict(style, available_styles)
339-
340367
tree = get_subtree(tree, node_name_or_path, max_depth)
341368

342369
# Set style
343-
if style == "custom":
344-
if len(list(custom_style)) != 3:
345-
raise ValueError(
346-
"Custom style selected, please specify the style of stem, branch, and final stem in `custom_style`"
347-
)
348-
style_stem, style_branch, style_stem_final = custom_style
349-
else:
370+
if isinstance(style, str):
371+
available_styles = ExportConstants.PRINT_STYLES
372+
assert_style_in_dict(style, available_styles)
350373
style_stem, style_branch, style_stem_final = available_styles[style]
351-
352-
if not len(style_stem) == len(style_branch) == len(style_stem_final):
374+
elif isinstance(style, list) and len(list(style)) != 3:
353375
raise ValueError(
354-
"`style_stem`, `style_branch`, and `style_stem_final` are of different length"
376+
"Please specify the style of stem, branch, and final stem in `style`"
355377
)
378+
else:
379+
style_stem, style_branch, style_stem_final = style # type: ignore[misc]
380+
381+
if not len(style_stem) == len(style_branch) == len(style_stem_final):
382+
raise ValueError("`stem`, `branch`, and `stem_final` are of different length")
356383

357384
gap_str = " " * len(style_stem)
358385
unclosed_depth = set()
@@ -388,17 +415,20 @@ def hprint_tree(
388415
node_name_or_path: str = "",
389416
max_depth: int = 0,
390417
intermediate_node_name: bool = True,
391-
style: str = "const",
392-
custom_style: Iterable[str] = [],
418+
style: Union[str, Iterable[str], BaseHPrintStyle] = "const",
393419
) -> None:
394420
"""Print tree in horizontal orientation to console, starting from `tree`.
395421
396422
- Able to select which node to print from, resulting in a subtree, using `node_name_or_path`
397423
- Able to customize for maximum depth to print, using `max_depth`
398-
- Able to customize style, to choose from `ansi`, `ascii`, `const`, `const_bold`, `rounded`, `double`, and `custom` style
399-
- Default style is `const` style
400-
- If style is set to custom, user can choose their own style icons
401-
- Style icons should have the same number of characters
424+
- Able to customize style, to choose from str, List[str], or inherit from BaseHPrintStyle, using `style`
425+
426+
For style,
427+
428+
- (str): `ansi`, `ascii`, `const` (default), `const_bold`, `rounded`, `double` style
429+
- (List[str]): Choose own style icons, they must have the same number of characters
430+
- (BaseHPrintStyle): `ANSIHPrintStyle`, `ASCIIHPrintStyle`, `ConstHPrintStyle`, `ConstBoldHPrintStyle`,
431+
`RoundedHPrintStyle`, `DoubleHPrintStyle` style or inherit from BaseHPrintStyle
402432
403433
Examples:
404434
**Printing tree**
@@ -465,21 +495,28 @@ def hprint_tree(
465495
═ a ═╣ ╚═ e
466496
╚═ c
467497
498+
**Custom Styles**
499+
500+
>>> from bigtree import ANSIHPrintStyle
501+
>>> hprint_tree(root, style=ANSIHPrintStyle)
502+
/- d
503+
/- b -+
504+
- a -+ \\- e
505+
\\- c
506+
468507
Args:
469508
tree (Node): tree to print
470509
node_name_or_path (str): node to print from, becomes the root node of printing
471510
max_depth (int): maximum depth of tree to print, based on `depth` attribute, optional
472511
intermediate_node_name (bool): indicator if intermediate nodes have node names, defaults to True
473-
style (str): style of print, defaults to const style
474-
custom_style (Iterable[str]): style of icons, used when `style` is set to 'custom'
512+
style (Union[str, Iterable[str], BaseHPrintStyle]): style of print, defaults to const
475513
"""
476514
result = hyield_tree(
477515
tree,
478516
node_name_or_path=node_name_or_path,
479517
intermediate_node_name=intermediate_node_name,
480518
max_depth=max_depth,
481519
style=style,
482-
custom_style=custom_style,
483520
)
484521
print("\n".join(result))
485522

@@ -489,17 +526,20 @@ def hyield_tree(
489526
node_name_or_path: str = "",
490527
max_depth: int = 0,
491528
intermediate_node_name: bool = True,
492-
style: str = "const",
493-
custom_style: Iterable[str] = [],
529+
style: Union[str, Iterable[str], BaseHPrintStyle] = "const",
494530
) -> List[str]:
495531
"""Yield tree in horizontal orientation to console, starting from `tree`.
496532
497533
- Able to select which node to print from, resulting in a subtree, using `node_name_or_path`
498534
- Able to customize for maximum depth to print, using `max_depth`
499-
- Able to customize style, to choose from `ansi`, `ascii`, `const`, `const_bold`, `rounded`, `double`, and `custom` style
500-
- Default style is `const` style
501-
- If style is set to custom, user can choose their own style icons
502-
- Style icons should have the same number of characters
535+
- Able to customize style, to choose from str, List[str], or inherit from BaseHPrintStyle, using `style`
536+
537+
For style,
538+
539+
- (str): `ansi`, `ascii`, `const` (default), `const_bold`, `rounded`, `double` style
540+
- (List[str]): Choose own style icons, they must have the same number of characters
541+
- (BaseHPrintStyle): `ANSIHPrintStyle`, `ASCIIHPrintStyle`, `ConstHPrintStyle`, `ConstBoldHPrintStyle`,
542+
`RoundedHPrintStyle`, `DoubleHPrintStyle` style or inherit from BaseHPrintStyle
503543
504544
Examples:
505545
**Printing tree**
@@ -567,13 +607,21 @@ def hyield_tree(
567607
═ a ═╣ ╚═ e
568608
╚═ c
569609
610+
**Custom Styles**
611+
612+
>>> from bigtree import ANSIHPrintStyle
613+
>>> hprint_tree(root, style=ANSIHPrintStyle)
614+
/- d
615+
/- b -+
616+
- a -+ \\- e
617+
\\- c
618+
570619
Args:
571620
tree (Node): tree to print
572621
node_name_or_path (str): node to print from, becomes the root node of printing
573622
max_depth (int): maximum depth of tree to print, based on `depth` attribute, optional
574623
intermediate_node_name (bool): indicator if intermediate nodes have node names, defaults to True
575-
style (str): style of print, defaults to const style
576-
custom_style (Iterable[str]): style of icons, used when `style` is set to 'custom'
624+
style (Union[str, Iterable[str], BaseHPrintStyle]): style of print, defaults to const
577625
578626
Returns:
579627
(List[str])
@@ -582,17 +630,12 @@ def hyield_tree(
582630

583631
from bigtree.tree.helper import get_subtree
584632

585-
available_styles = ExportConstants.HPRINT_STYLES
586-
assert_style_in_dict(style, available_styles)
587-
588633
tree = get_subtree(tree, node_name_or_path, max_depth)
589634

590635
# Set style
591-
if style == "custom":
592-
if len(list(custom_style)) != 7:
593-
raise ValueError(
594-
"Custom style selected, please specify the style of 7 icons in `custom_style`"
595-
)
636+
if isinstance(style, str):
637+
available_styles = ExportConstants.HPRINT_STYLES
638+
assert_style_in_dict(style, available_styles)
596639
(
597640
style_first_child,
598641
style_subsequent_child,
@@ -601,7 +644,9 @@ def hyield_tree(
601644
style_last_child,
602645
style_stem,
603646
style_branch,
604-
) = custom_style
647+
) = available_styles[style]
648+
elif isinstance(style, list) and len(list(style)) != 7:
649+
raise ValueError("Please specify the style of 7 icons in `style`")
605650
else:
606651
(
607652
style_first_child,
@@ -611,7 +656,8 @@ def hyield_tree(
611656
style_last_child,
612657
style_stem,
613658
style_branch,
614-
) = available_styles[style]
659+
) = style # type: ignore[misc]
660+
615661
if (
616662
not len(style_first_child)
617663
== len(style_subsequent_child)
@@ -622,7 +668,7 @@ def hyield_tree(
622668
== len(style_branch)
623669
== 1
624670
):
625-
raise ValueError("For custom style, all style icons must have length 1")
671+
raise ValueError("All style icons must have length 1")
626672

627673
# Calculate padding
628674
space = " "
@@ -1673,15 +1719,15 @@ def tree_to_newick(
16731719
16741720
In the Newick Notation (or New Hampshire Notation),
16751721
- Tree is represented in round brackets i.e., `(child1,child2,child3)parent`.
1676-
- If there are nested tree, they will be in nested round brackets i.e., `((grandchild1)child1,(grandchild2,grandchild3)child2)parent`.
1722+
- If there are nested trees, they will be in nested round brackets i.e., `((grandchild1)child1,(grandchild2,grandchild3)child2)parent`.
16771723
- If there is length attribute, they will be beside the name i.e., `(child1:0.5,child2:0.1)parent`.
16781724
- If there are other attributes, attributes are represented in square brackets i.e., `(child1:0.5[S:human],child2:0.1[S:human])parent[S:parent]`.
16791725
16801726
Customizations include:
16811727
- Omitting names of root and intermediate nodes, default all node names are shown.
1682-
- Changing length separator to other symbol, default is `:`.
1728+
- Changing length separator to another symbol, default is `:`.
16831729
- Adding an attribute prefix, default is `&&NHX:`.
1684-
- Changing the attribute separator to other symbol, default is `:`.
1730+
- Changing the attribute separator to another symbol, default is `:`.
16851731
16861732
Examples:
16871733
>>> from bigtree import Node, tree_to_newick

0 commit comments

Comments
 (0)