Coverage for /home/deng/Projects/metatree_drawer/metatreedrawer/treeprofiler/layouts/seq_layouts.py: 36%

86 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2024-08-07 10:33 +0200

1 

2from ete4 import SeqGroup 

3from ete4.smartview import TreeLayout 

4from ete4.smartview import AlignmentFace, SeqMotifFace, ScaleFace 

5from ete4.smartview.renderer import draw_helpers 

6#from utils import get_consensus_seq 

7from pathlib import Path 

8from io import StringIO 

9import json 

10 

11 

12__all__ = [ "LayoutAlignment" ] 

13DOMAIN2COLOR = 'pfam2color.json' # smart2color.json 

14 

15def get_colormap(): 

16 with open(Path(__file__).parent / DOMAIN2COLOR) as handle: 

17 _pfam2color = json.load(handle) 

18 return _pfam2color 

19 

20class LayoutAlignment(TreeLayout): 

21 def __init__(self, name="Alignment", 

22 alignment=None, alignment_prop=None, format='seq', width=700, height=15, 

23 column=0, scale_range=None, summarize_inner_nodes=True, aligned_faces=True): 

24 super().__init__(name, aligned_faces=aligned_faces) 

25 #self.alignment = SeqGroup(alignment) if alignment else None 

26 self.alignment_prop = alignment_prop 

27 self.width = width 

28 self.height = height 

29 self.column = column 

30 self.aligned_faces = True 

31 self.format = format 

32 

33 #self.length = len(next(self.alignment.iter_entries())[1]) if self.alignment else None 

34 self.scale_range = (0, scale_range) or (0, self.length) 

35 self.summarize_inner_nodes = summarize_inner_nodes 

36 

37 def set_tree_style(self, tree, tree_style): 

38 if self.scale_range: 

39 face = ScaleFace(width=self.width, scale_range=self.scale_range, padding_y=10) 

40 tree_style.aligned_panel_header.add_face(face, column=self.column) 

41 

42 def _get_seq(self, node): 

43 return node.props.get(self.alignment_prop, None) 

44 # if self.alignment: 

45 # return self.alignment.get_seq(node.name) 

46 # else: 

47 # return node.props.get(alignment_prop, None) 

48 

49 def get_seq(self, node): 

50 if node.is_leaf: 

51 return self._get_seq(node) 

52 

53 if self.summarize_inner_nodes: 

54 return self._get_seq(node) 

55 else: 

56 first_leaf = next(node.leaves()) 

57 return self._get_seq(first_leaf) 

58 

59 def set_node_style(self, node): 

60 seq = self.get_seq(node) 

61 

62 if seq: 

63 seq = str(seq) # convert Bio.seq.seq to string seq 

64 seqFace = AlignmentFace(seq, seq_format=self.format, bgcolor='grey', 

65 width=self.width, height=self.height) 

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

67 collapsed_only=(not node.is_leaf)) 

68 

69 

70def get_alnface(seq_prop, level): 

71 def layout_fn(node): 

72 if node.is_leaf: 

73 seq = node.props.get(seq_prop) 

74 seq_face = AlignmentFace(seq, seqtype='aa', 

75 gap_format='line', seq_format='[]', 

76 width=None, height=None, # max height 

77 fgcolor='black', bgcolor='#bcc3d0', gapcolor='gray', 

78 gap_linewidth=0.2, 

79 max_fsize=12, ftype='sans-serif', 

80 padding_x=0, padding_y=0) 

81 node.add_face(seq_face, position="aligned", column=level) 

82 return layout_fn 

83 

84class LayoutDomain(TreeLayout): 

85 def __init__(self, prop, name, 

86 column=10, colormap={}, 

87 min_fsize=4, max_fsize=15, 

88 padding_x=5, padding_y=0): 

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

90 self.prop = prop 

91 self.column = column 

92 self.aligned_faces = True 

93 self.min_fsize = min_fsize 

94 self.max_fsize = max_fsize 

95 self.padding = draw_helpers.Padding(padding_x, padding_y) 

96 if not colormap: 

97 self.colormap = get_colormap() 

98 else: 

99 self.colormap = colormap 

100 

101 def get_doms(self, node): 

102 pair_delimiter = "@" 

103 item_seperator = "||" 

104 dom_list = [] 

105 if node.is_leaf: 

106 dom_prop = node.props.get(self.prop, []) 

107 if dom_prop: 

108 

109 dom_list = [dom.split(pair_delimiter) for dom in dom_prop.split(item_seperator)] 

110 #print(dom_list) 

111 return dom_list 

112 #return node.props.get(self.prop, []) 

113 # else: 

114 # first_node = next(node.leaves()) 

115 # print("here", first_node.props.get(self.prop, [])) 

116 # return first_node.props.get(self.prop, []) 

117 

118 def parse_doms(self, dom_list): 

119 doms = [] 

120 for name, start, end in dom_list: 

121 color = self.colormap.get(name, "lightgray") 

122 dom = [int(start), int(end), "()", 

123 None, None, color, color, 

124 "arial|30|black|%s" %(name)] 

125 doms.append(dom) 

126 return doms 

127 

128 def set_node_style(self, node): 

129 dom_list = self.get_doms(node) 

130 if dom_list: 

131 doms = self.parse_doms(dom_list) 

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

133 if doms or fake_seq: 

134 seqFace = SeqMotifFace(seq=fake_seq, motifs=doms, width=400, 

135 height=30) 

136 node.add_face(seqFace, column=self.column, 

137 position="aligned", 

138 collapsed_only=(not node.is_leaf))