Skip to content

Commit 65855ff

Browse files
authored
Merge pull request #118 from dengzq1234/desktop_v2
Desktop v2
2 parents abd4dc2 + 651b28e commit 65855ff

File tree

3 files changed

+313
-13
lines changed

3 files changed

+313
-13
lines changed

treeprofiler/layouts/text_layouts.py

Lines changed: 133 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -222,23 +222,22 @@ def set_tree_style(self, tree, tree_style):
222222
)
223223

224224
def set_node_style(self, node):
225-
if node.is_leaf and node.props.get(self.prop):
225+
if node.is_leaf and node.props.get(self.prop) is not '':
226226
prop_text = node.props.get(self.prop)
227-
if prop_text:
228-
if type(prop_text) == list:
229-
prop_text = ",".join(prop_text)
230-
else:
231-
pass
232-
if self.color_dict:
233-
prop_face = TextFace(prop_text, color=self.color_dict.get(prop_text, 'black'),min_fsize=self.min_fsize, max_fsize=self.max_fsize, padding_x=self.padding_x, width=self.width )
234-
else:
235-
prop_face = TextFace(prop_text, color='black', min_fsize=self.min_fsize, max_fsize=self.max_fsize, padding_x=self.padding_x, width=self.width )
227+
if type(prop_text) == list:
228+
prop_text = ",".join(prop_text)
229+
else:
230+
pass
231+
if self.color_dict:
232+
prop_face = TextFace(prop_text, color=self.color_dict.get(prop_text, 'black'),min_fsize=self.min_fsize, max_fsize=self.max_fsize, padding_x=self.padding_x, width=self.width )
233+
else:
234+
prop_face = TextFace(prop_text, color='black', min_fsize=self.min_fsize, max_fsize=self.max_fsize, padding_x=self.padding_x, width=self.width )
236235
node.add_face(prop_face, column=self.column, position="aligned")
237236

238237
elif node.is_leaf and node.props.get(self.internal_prop):
239238
stackedbar_face = get_stackedbarface(node, self.internal_prop, self.color_dict, width=self.width, padding_x=self.padding_x, padding_y=self.padding_y)
240239
node.add_face(stackedbar_face, column = self.column, position = "aligned", collapsed_only=False)
241-
240+
242241
elif node.props.get(self.internal_prop):
243242
stackedbar_face = get_stackedbarface(node, self.internal_prop, self.color_dict, width=self.width, padding_x=self.padding_x, padding_y=self.padding_y)
244243
node.add_face(stackedbar_face, column = self.column, position = "aligned", collapsed_only=True)
@@ -250,7 +249,67 @@ def set_node_style(self, node):
250249
prop_face = RectFace(width=self.width, height=self.height, color=self.absence_color, \
251250
padding_x=self.padding_x , padding_y=self.padding_y, tooltip=None)
252251
node.add_face(prop_face, column=self.column, position="aligned", collapsed_only=True)
252+
# if not node.is_leaf and node.props.get(self.prop):
253+
# prop_text = node.props.get(self.prop)
254+
# if type(prop_text) == list:
255+
# prop_text = ",".join(prop_text)
256+
# else:
257+
# pass
258+
# if self.color_dict:
259+
# prop_face = TextFace(prop_text, color=self.color_dict.get(prop_text, 'black'),min_fsize=self.min_fsize, max_fsize=self.max_fsize, padding_x=self.padding_x, width=self.width )
260+
# else:
261+
# prop_face = TextFace(prop_text, color='black', min_fsize=self.min_fsize, max_fsize=self.max_fsize, padding_x=self.padding_x, width=self.width )
262+
# node.add_face(prop_face, column=self.column, position="branch_right")
263+
# node.add_face(prop_face, column=self.column, position="branch_right", collapsed_only=True)
264+
265+
class LayoutTextbranch(TreeLayout):
266+
def __init__(self, name, column, text_color, color_dict, prop, width=70, min_fsize=5, max_fsize=15, padding_x=1, padding_y=0, legend=True, aligned_faces=True):
267+
super().__init__(name, aligned_faces=aligned_faces)
268+
self.aligned_faces = True
269+
self.prop = prop
270+
self.column = column
271+
self.text_color = text_color
272+
self.color_dict = color_dict
273+
self.legend = legend
274+
self.width = width
275+
self.height = None
276+
self.min_fsize = min_fsize
277+
self.max_fsize = max_fsize
278+
self.padding_x = padding_x
279+
self.padding_y = padding_y
253280

281+
def set_tree_style(self, tree, tree_style):
282+
super().set_tree_style(tree, tree_style)
283+
text = TextFace(self.prop, min_fsize=self.min_fsize, max_fsize=self.max_fsize, padding_x=self.padding_x, width=self.width, rotation=315)
284+
tree_style.aligned_panel_header.add_face(text, column=self.column)
285+
286+
if self.legend:
287+
if self.color_dict:
288+
tree_style.add_legend(title=self.prop,
289+
variable='discrete',
290+
colormap=self.color_dict
291+
)
292+
else:
293+
tree_style.add_legend(title=self.prop,
294+
variable='discrete',
295+
colormap={
296+
self.prop: self.text_color
297+
}
298+
)
299+
def set_node_style(self, node):
300+
prop_text = node.props.get(self.prop)
301+
if prop_text is not None and prop_text != '':
302+
if type(prop_text) == list:
303+
prop_text = ",".join(prop_text)
304+
else:
305+
pass
306+
if self.text_color:
307+
prop_face = TextFace(prop_text, color=self.text_color, min_fsize=self.min_fsize, max_fsize=self.max_fsize, padding_x=self.padding_x, width=self.width)
308+
else:
309+
prop_face = TextFace(prop_text, color='black', min_fsize=self.min_fsize, max_fsize=self.max_fsize, padding_x=self.padding_x, width=self.width )
310+
node.add_face(prop_face, position="branch_bottom")
311+
node.add_face(prop_face, position="branch_bottom", collapsed_only=True)
312+
254313
class LayoutColorbranch(TreeLayout):
255314
def __init__(self, name, column, color_dict, prop, legend=True, width=70, padding_x=1, padding_y=0):
256315
super().__init__(name)
@@ -540,4 +599,67 @@ def set_node_style(self, node):
540599
node.add_face(prop_face, column=self.column,
541600
position="branch_right", collapsed_only=False)
542601

602+
class LayoutSymbolbranch(TreeLayout):
603+
def __init__(self, name=None, prop=None, position="branch_right",
604+
column=0, symbol='circle', symbol_color=None, color_dict=None,
605+
max_radius=1, symbol_size=5, fgopacity=0.8,
606+
padding_x=2, padding_y=0,
607+
scale=True, legend=True, active=True):
543608

609+
name = name or f'{symbol}Branch_{prop}'
610+
super().__init__(name)
611+
612+
self.aligned_faces = True
613+
self.prop = prop
614+
self.symbol = symbol # circle, square and triangle
615+
self.symbol_color = symbol_color
616+
617+
self.column = column
618+
self.position = position
619+
self.color_dict = color_dict
620+
621+
self.max_radius = float(max_radius)
622+
self.symbol_size = float(symbol_size)
623+
self.fgopacity = float(fgopacity)
624+
625+
self.padding_x = padding_x
626+
self.padding_y = padding_y
627+
628+
self.legend = legend
629+
self.active = active
630+
631+
def set_tree_style(self, tree, tree_style):
632+
super().set_tree_style(tree, tree_style)
633+
if self.legend:
634+
if self.color_dict and len(self.color_dict) > 1:
635+
# self.color_dict['NA'] = self.absence_color
636+
tree_style.add_legend(title=self.prop,
637+
variable='discrete',
638+
colormap=self.color_dict
639+
)
640+
else:
641+
tree_style.add_legend(title=self.prop,
642+
variable='discrete',
643+
colormap={
644+
self.prop: self.symbol_color
645+
}
646+
)
647+
648+
def set_node_style(self, node):
649+
prop_text = node.props.get(self.prop)
650+
if prop_text is not None and prop_text != '':
651+
if type(prop_text) == list:
652+
prop_text = ",".join(prop_text)
653+
else:
654+
pass
655+
if self.color_dict and len(self.color_dict) > 1:
656+
node.sm_style['shape'] = self.symbol
657+
node.sm_style["fgcolor"] = self.color_dict.get(prop_text)
658+
node.sm_style['size'] = self.symbol_size
659+
node.sm_style['fgopacity'] = self.fgopacity
660+
else:
661+
node.sm_style['shape'] = self.symbol
662+
node.sm_style["fgcolor"] = self.symbol_color
663+
node.sm_style['size'] = self.symbol_size
664+
node.sm_style['fgopacity'] = self.fgopacity
665+

treeprofiler/tree_plot.py

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,23 @@ def poplulate_plot_args(plot_args_p):
206206
nargs='+',
207207
required=False,
208208
help="<prop1> <prop2> names of properties where branches will be colored based on different values.")
209+
group.add_argument('--textbranch-layout',
210+
nargs='+',
211+
required=False,
212+
help="<prop1> <prop2> names of properties where values will be displayed on the branch in text.")
213+
group.add_argument('--circlebranch-layout',
214+
nargs='+',
215+
required=False,
216+
help="<prop1> <prop2> names of properties where values will be displayed on the branch in the shape of cricle.")
217+
group.add_argument('--squarebranch-layout',
218+
nargs='+',
219+
required=False,
220+
help="<prop1> <prop2> names of properties where values will be displayed on the branch in the shape of square.")
221+
group.add_argument('--trianglebranch-layout',
222+
nargs='+',
223+
required=False,
224+
help="<prop1> <prop2> names of properties where values will be displayed on the branch in the shape of triangle.")
225+
209226
group.add_argument('--label-layout',
210227
nargs='+',
211228
required=False,
@@ -537,6 +554,42 @@ def run(args):
537554
visualized_props.append(prop)
538555
visualized_props.append(utils.add_suffix(prop, internal_num_rep))
539556

557+
if layout == 'textbranch-layout':
558+
textbranch_layouts, level, color_dict = get_textbranch_layouts(tree, args.textbranch_layout,
559+
level, column_width=args.column_width, prop2type=prop2type,
560+
padding_x=args.padding_x, padding_y=args.padding_y, color_config=color_config)
561+
layouts.extend(textbranch_layouts)
562+
for prop in args.textbranch_layout:
563+
visualized_props.append(prop)
564+
565+
if layout == 'circlebranch-layout':
566+
circlebranch_layouts, level, color_dict = get_circlebranch_layouts(tree, args.circlebranch_layout,
567+
level, prop2type=prop2type, padding_x=args.padding_x, padding_y=args.padding_y, color_config=color_config)
568+
layouts.extend(circlebranch_layouts)
569+
for prop in args.circlebranch_layout:
570+
visualized_props.append(prop)
571+
572+
if layout == 'circlebranch-layout':
573+
circlebranch_layouts, level, color_dict = get_circlebranch_layouts(tree, args.circlebranch_layout,
574+
level, prop2type=prop2type, padding_x=args.padding_x, padding_y=args.padding_y, color_config=color_config)
575+
layouts.extend(circlebranch_layouts)
576+
for prop in args.circlebranch_layout:
577+
visualized_props.append(prop)
578+
579+
if layout == 'squarebranch-layout':
580+
squarebranch_layouts, level, color_dict = get_squarebranch_layouts(tree, args.squarebranch_layout,
581+
level, prop2type=prop2type, padding_x=args.padding_x, padding_y=args.padding_y, color_config=color_config)
582+
layouts.extend(squarebranch_layouts)
583+
for prop in args.squarebranch_layout:
584+
visualized_props.append(prop)
585+
586+
if layout == 'trianglebranch-layout':
587+
trianglebranch_layouts, level, color_dict = get_trianglebranch_layouts(tree, args.trianglebranch_layout,
588+
level, prop2type=prop2type, padding_x=args.padding_x, padding_y=args.padding_y, color_config=color_config)
589+
layouts.extend(trianglebranch_layouts)
590+
for prop in args.trianglebranch_layout:
591+
visualized_props.append(prop)
592+
540593
if layout == 'bubble-layout':
541594
categorical_props = [prop for prop in args.bubble_layout if prop2type.get(prop) in [str, list, bool, None]]
542595
if categorical_props:
@@ -1203,6 +1256,133 @@ def get_colorbranch_layouts(tree, props, level, prop2type, column_width=70, padd
12031256
level += 1
12041257
return layouts, level, prop_color_dict
12051258

1259+
def get_textbranch_layouts(tree, props, level, prop2type, column_width=70, padding_x=1, padding_y=0, color_config=None):
1260+
prop_color_dict = {}
1261+
layouts = []
1262+
for prop in props:
1263+
color_dict = {}
1264+
text_color = paired_color[level]
1265+
if color_config and color_config.get(prop):
1266+
if color_config.get(prop).get('value2color'):
1267+
color_dict = color_config.get(prop).get('value2color')
1268+
1269+
layout = text_layouts.LayoutTextbranch(name='TextBranch_'+prop,
1270+
column=level, text_color=text_color, color_dict=color_dict, prop=prop,
1271+
width=column_width, padding_x=padding_x, padding_y=padding_y)
1272+
layouts.append(layout)
1273+
level +=1
1274+
1275+
return layouts, level, prop_color_dict
1276+
1277+
def get_widthbranch_layouts(tree, props, level, prop2type, padding_x=1, padding_y=0, color_config=None):
1278+
return
1279+
1280+
def get_circlebranch_layouts(tree, props, level, prop2type, padding_x=1, padding_y=0, color_config=None):
1281+
prop_color_dict = {}
1282+
layouts = []
1283+
symbol = 'circle'
1284+
symbol_size = 5
1285+
max_radius = 1
1286+
fgopacity = 0.8
1287+
1288+
for prop in props:
1289+
color_dict = {} # key = value, value = color id
1290+
symbol_color = paired_color[level]
1291+
1292+
if color_config and color_config.get(prop):
1293+
if color_config.get(prop).get('value2color'):
1294+
color_dict = color_config.get(prop).get('value2color')
1295+
else:
1296+
if prop2type and prop2type.get(prop) == list:
1297+
leaf_values = list(map(list,set(map(tuple,utils.tree_prop_array(tree, prop)))))
1298+
prop_values = [val for sublist in leaf_values for val in sublist]
1299+
else:
1300+
prop_values = sorted(list(set(utils.tree_prop_array(tree, prop))))
1301+
1302+
# normal text prop
1303+
color_dict = utils.assign_color_to_values(prop_values, paired_color)
1304+
1305+
layout = text_layouts.LayoutSymbolbranch(f'{symbol}Branch_{prop}', prop=prop,
1306+
column=level, symbol=symbol, symbol_color=symbol_color, color_dict=color_dict,
1307+
max_radius=max_radius, symbol_size=symbol_size,
1308+
padding_x=padding_x, padding_y=padding_y, fgopacity=fgopacity,
1309+
scale=True, legend=True, active=True
1310+
)
1311+
layouts.append(layout)
1312+
level +=1
1313+
1314+
return layouts, level, prop_color_dict
1315+
1316+
def get_squarebranch_layouts(tree, props, level, prop2type, padding_x=1, padding_y=0, color_config=None):
1317+
prop_color_dict = {}
1318+
layouts = []
1319+
symbol = 'square'
1320+
symbol_size = 5
1321+
max_radius = 1
1322+
fgopacity = 0.8
1323+
1324+
for prop in props:
1325+
color_dict = {} # key = value, value = color id
1326+
symbol_color = paired_color[level]
1327+
1328+
if color_config and color_config.get(prop):
1329+
if color_config.get(prop).get('value2color'):
1330+
color_dict = color_config.get(prop).get('value2color')
1331+
else:
1332+
if prop2type and prop2type.get(prop) == list:
1333+
leaf_values = list(map(list,set(map(tuple,utils.tree_prop_array(tree, prop)))))
1334+
prop_values = [val for sublist in leaf_values for val in sublist]
1335+
else:
1336+
prop_values = sorted(list(set(utils.tree_prop_array(tree, prop))))
1337+
1338+
# normal text prop
1339+
color_dict = utils.assign_color_to_values(prop_values, paired_color)
1340+
1341+
layout = text_layouts.LayoutSymbolbranch(f'{symbol}Branch_{prop}', prop=prop,
1342+
column=level, symbol=symbol, symbol_color=symbol_color, color_dict=color_dict,
1343+
max_radius=max_radius, symbol_size=symbol_size,
1344+
padding_x=padding_x, padding_y=padding_y, fgopacity=fgopacity,
1345+
scale=True, legend=True, active=True
1346+
)
1347+
layouts.append(layout)
1348+
level +=1
1349+
return layouts, level, prop_color_dict
1350+
1351+
def get_trianglebranch_layouts(tree, props, level, prop2type, padding_x=1, padding_y=0, color_config=None):
1352+
prop_color_dict = {}
1353+
layouts = []
1354+
symbol = 'triangle'
1355+
symbol_size = 5
1356+
max_radius = 1
1357+
fgopacity = 0.8
1358+
1359+
for prop in props:
1360+
color_dict = {} # key = value, value = color id
1361+
symbol_color = paired_color[level]
1362+
1363+
if color_config and color_config.get(prop):
1364+
if color_config.get(prop).get('value2color'):
1365+
color_dict = color_config.get(prop).get('value2color')
1366+
else:
1367+
if prop2type and prop2type.get(prop) == list:
1368+
leaf_values = list(map(list,set(map(tuple,utils.tree_prop_array(tree, prop)))))
1369+
prop_values = [val for sublist in leaf_values for val in sublist]
1370+
else:
1371+
prop_values = sorted(list(set(utils.tree_prop_array(tree, prop))))
1372+
1373+
# normal text prop
1374+
color_dict = utils.assign_color_to_values(prop_values, paired_color)
1375+
1376+
layout = text_layouts.LayoutSymbolbranch(f'{symbol}Branch_{prop}', prop=prop,
1377+
column=level, symbol=symbol, symbol_color=symbol_color, color_dict=color_dict,
1378+
max_radius=max_radius, symbol_size=symbol_size,
1379+
padding_x=padding_x, padding_y=padding_y, fgopacity=fgopacity,
1380+
scale=True, legend=True, active=True
1381+
)
1382+
layouts.append(layout)
1383+
level +=1
1384+
return layouts, level, prop_color_dict
1385+
12061386
def get_rectangle_layouts(tree, props, level, prop2type, column_width=70, padding_x=1, padding_y=0, color_config=None, precomputed_props={}):
12071387
prop_color_dict = {}
12081388
layouts = []

treeprofiler/views/upload_tree.html

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -355,8 +355,6 @@ <h5>Pfam Annotation from emapper (Optional)</h5>
355355
</div>
356356
</div>
357357

358-
359-
360358
<!-- Submit Button -->
361359
<button type="button" class="btn btn-primary" onclick="submitForm()">Annotate and Visualize Tree!</button>
362360
</form>

0 commit comments

Comments
 (0)