Coverage for /home/deng/Projects/ete4/hackathon/ete4/ete4/smartview/renderer/nodestyle.py: 60%
25 statements
« prev ^ index » next coverage.py v7.2.7, created at 2024-03-21 09:19 +0100
« prev ^ index » next coverage.py v7.2.7, created at 2024-03-21 09:19 +0100
1import re
3from ete4.utils import SVG_COLORS
5_LINE_TYPE_CHECKER = lambda x: x in (0, 1, 2) # 0 solid, 1 dashed, 2 dotted
6_SIZE_CHECKER = lambda x: isinstance(x, int)
7_COLOR_MATCH = re.compile("^#[A-Fa-f\d]{6}$")
8_COLOR_CHECKER = lambda x: x.lower() in SVG_COLORS or re.match(_COLOR_MATCH, x)
9_NODE_TYPE_CHECKER = lambda x: x in ["triangle", "circle", "square"]
10_BOOL_CHECKER = lambda x: isinstance(x, bool) or x in (0, 1)
11_FLOAT_CHECKER = lambda x: isinstance(x, float) or isinstance(x, int)
14NODE_STYLE_DEFAULT = [
15 ["fgcolor", "#0030c1", _COLOR_CHECKER],
16 ["bgcolor", "transparent", _COLOR_CHECKER],
17 ["fgopacity", 1, _FLOAT_CHECKER],
18 ["outline_line_color", "#000000", _COLOR_CHECKER],
19 ["outline_line_width", 0.5, _SIZE_CHECKER],
20 ["outline_color", "#e5e5e5", _COLOR_CHECKER],
21 ["outline_opacity", 0.3, _FLOAT_CHECKER],
22 ["vt_line_color", "#000000", _COLOR_CHECKER],
23 ["hz_line_color", "#000000", _COLOR_CHECKER],
24 ["hz_line_type", 0, _LINE_TYPE_CHECKER],
25 ["vt_line_type", 0, _LINE_TYPE_CHECKER],
26 ["size", 0, _SIZE_CHECKER], # node circle size
27 ["shape", "circle", _NODE_TYPE_CHECKER], # circle, square, triangle
28 ["draw_descendants", True, _BOOL_CHECKER],
29 ["hz_line_width", 0.5, _SIZE_CHECKER],
30 ["vt_line_width", 0.5, _SIZE_CHECKER]
31]
34# _smfaces and faces are registered to allow deepcopy to work on nodes
35VALID_NODE_STYLE_KEYS = {i[0] for i in NODE_STYLE_DEFAULT} | {"_smfaces"}
37class NodeStyle(dict):
38 """
39 Dictionary with all valid node graphical attributes.
40 """
42 def __init__(self, *args, **kargs):
43 """
44 For all possible parameters, see NODE_STYLE_DEFAULT. Some descriptions:
46 :param True draw_descendants: Mark an internal node as a leaf.
47 :param 0 hz_line_width: Horizontal line width in pixels. If 0
48 it is automatic (normally 1 pixel).
49 :param 0 vt_line_width: Vertical line width in pixels. If 0 it
50 is automatic (normally 1 pixel).
51 """
52 super().__init__(*args, **kargs)
53 self.init()
55 def init(self):
56 for key, dvalue, checker in NODE_STYLE_DEFAULT:
57 if key not in self:
58 self[key] = dvalue
59 elif not checker(self[key]):
60 raise ValueError("'%s' attribute in node style has not a valid value: %s" %
61 (key, self[key]))
63 def __setitem__(self, i, v):
64 if i not in VALID_NODE_STYLE_KEYS:
65 raise ValueError("'%s' is not a valid keyword for a NodeStyle instance" % i)
67 super().__setitem__(i, v)