Coverage for /home/deng/Projects/ete4/hackathon/ete4/ete4/smartview/renderer/layouts/domain_layouts.py: 45%

51 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2024-03-21 09:19 +0100

1# TODO: This file needs reviewing. No need to do all this just to get 

2# classes LayoutPfamDomains and LayoutSmartDomains. 

3import os 

4import json 

5 

6from ..treelayout import TreeLayout, cased_name 

7from ..faces import SeqMotifFace 

8from ..draw_helpers import Padding 

9 

10from ete4.config import ETE_DATA_HOME, update_ete_data 

11 

12 

13class _LayoutDomains(TreeLayout): 

14 def __init__(self, prop, name, column=10, min_fsize=4, max_fsize=15, 

15 padding_x=5, padding_y=0): 

16 super().__init__(name or "Domains layout") 

17 self.prop = prop 

18 self.column = column 

19 self.aligned_faces = True 

20 self.min_fsize = min_fsize 

21 self.max_fsize = max_fsize 

22 self.padding = Padding(padding_x, padding_y) 

23 

24 # Load colormap from file if necessary. 

25 color_file = ETE_DATA_HOME + f'/{prop}2color.json' 

26 

27 if not os.path.exists(color_file): 

28 url = ('https://github.com/etetoolkit/ete-data/raw/main' 

29 f'/layouts/{prop}2color.json') 

30 update_ete_data(color_file, url) 

31 

32 with open(color_file) as handle: 

33 self.colormap = json.load(handle) 

34 

35 def get_doms(self, node): 

36 leaf = next(node.leaves()) # 1st leaf 

37 return leaf.props.get(self.prop, []) 

38 

39 def parse_doms(self, dom_list): 

40 def translate(dom): 

41 name, start, end = dom 

42 color = self.colormap.get(name, 'lightgray') 

43 return [int(start), int(end), '()', None, None, color, color, 

44 f'arial|20|black|{name}'] 

45 

46 return [translate(dom) for dom in dom_list] 

47 

48 def set_node_style(self, node): 

49 doms = self.parse_doms(self.get_doms(node)) 

50 fake_seq = '-' * int(node.props.get('len_alg', 0)) 

51 if doms or fake_seq: 

52 seqFace = SeqMotifFace(seq=fake_seq, motifs=doms, width=250, height=10) 

53 node.add_face(seqFace, column=self.column, position='aligned', 

54 collapsed_only=(not node.is_leaf)) 

55 

56 

57def create_domain_layout(prop, name, active, column): 

58 """Add a layout named Layout<name> to the globals, and return it.""" 

59 # Because this is the wild west, apparently. 

60 class Layout(_LayoutDomains): 

61 def __init__(self, prop=prop, name=name, column=column, *args, **kwargs): 

62 super().__init__(prop=prop, name=name, column=column, *args, **kwargs) 

63 self.active = active 

64 

65 def __name__(self): 

66 return layout_name 

67 

68 # Let's play with the environment like there's no tomorrow! 

69 layout_name = "Layout" + cased_name(name) 

70 Layout.__name__ = layout_name 

71 globals()[layout_name] = Layout 

72 return Layout 

73 

74 

75domain_layout_args = [ 

76 ["pfam", "Pfam domains", True], 

77 ["smart", "Smart domains", False], 

78] 

79 

80col0 = 20 

81domain_layouts = [create_domain_layout(*args, i+col0) 

82 for i, args in enumerate(domain_layout_args)] 

83 

84__all__ = [ *[layout.__name__ for layout in domain_layouts] ]