diff --git a/ete3/coretype/tree.py b/ete3/coretype/tree.py index d0d3e93cd..a7114e561 100644 --- a/ete3/coretype/tree.py +++ b/ete3/coretype/tree.py @@ -2471,7 +2471,7 @@ def add_face(self, face, column, position="branch-right"): :argument column: An integer number starting from 0 :argument "branch-right" position: Posible values are: "branch-right", "branch-top", "branch-bottom", "float", - "aligned" + "aligned", "float-behind", "float-right" """ if not hasattr(self, "_faces"): diff --git a/ete3/tools/common.py b/ete3/tools/common.py index eb75766b9..e736519f1 100644 --- a/ete3/tools/common.py +++ b/ete3/tools/common.py @@ -124,6 +124,7 @@ def _re(q, exp): "b-bottom":"branch-bottom", "float":"float", "float-behind":"float-behind", + "float-right":"float-right", "aligned":"aligned", } diff --git a/ete3/treeview/main.py b/ete3/treeview/main.py index 1c930fa97..b811c1140 100644 --- a/ete3/treeview/main.py +++ b/ete3/treeview/main.py @@ -66,7 +66,7 @@ def a_wrapper_accepting_arguments(*args, **kargs): _NODE_TYPE_CHECKER = lambda x: x in ["sphere", "circle", "square"] _BOOL_CHECKER = lambda x: isinstance(x, bool) or x in (0,1) -FACE_POSITIONS = set(["branch-right", "branch-top", "branch-bottom", "float", "float-behind", "aligned"]) +FACE_POSITIONS = set(["branch-right", "branch-top", "branch-bottom", "float", "float-behind", "float-right", "aligned"]) __all__ = ["NodeStyle", "TreeStyle", "FaceContainer", "_leaf", "add_face_to_node", "COLOR_SCHEMES"] @@ -601,7 +601,8 @@ def add_face_to_node(face, node, column, aligned=False, position="branch-right") :argument node: a tree node instance (:class:`Tree`, :class:`PhyloTree`, etc.) :argument column: An integer number starting from 0 :argument "branch-right" position: Possible values are - "branch-right", "branch-top", "branch-bottom", "float", "float-behind" and "aligned". + "branch-right", "branch-top", "branch-bottom", "float", "float-behind", + "float-right" and "aligned". """ ## ADD HERE SOME TYPE CHECK FOR node and face diff --git a/ete3/treeview/qt4_render.py b/ete3/treeview/qt4_render.py index 10f30aed5..ff1d54472 100644 --- a/ete3/treeview/qt4_render.py +++ b/ete3/treeview/qt4_render.py @@ -315,9 +315,10 @@ def render(root_node, img, hide_root=False): # Add extra layers: aligned faces, floating faces, node # backgrounds, etc. The order by which the following methods are # called IS IMPORTANT - render_floatings(n2i, n2f, img, parent.float_layer, parent.float_behind_layer) - aligned_region_width = render_aligned_faces(img, mainRect, parent.tree_layer, n2i, n2f) + aligned_region_width, tree_end_x = render_aligned_faces(img, mainRect, parent.tree_layer, n2i, n2f) + + render_floatings(n2i, n2f, img, parent.float_layer, parent.float_behind_layer, aligned_region_width, tree_end_x) render_backgrounds(img, mainRect, parent.bg_layer, n2i, n2f) @@ -776,14 +777,15 @@ def set_style(n, layout_func): for func in layout_func: func(n) -def render_floatings(n2i, n2f, img, float_layer, float_behind_layer): +def render_floatings(n2i, n2f, img, float_layer, float_behind_layer, extra_width, tree_end_x): #floating_faces = [ [node, fb["float"]] for node, fb in n2f.iteritems() if "float" in fb] for node, faces in six.iteritems(n2f): - face_set = [ [float_layer, faces.get("float", None)], - [float_behind_layer, faces.get("float-behind",None)]] + face_set = [ [float_layer, faces.get("float", None), False], + [float_behind_layer, faces.get("float-behind",None), False], + [float_layer, faces.get("float-right",None), True]] - for parent_layer,fb in face_set: + for parent_layer,fb, isRight in face_set: if not fb: continue @@ -796,14 +798,24 @@ def render_floatings(n2i, n2f, img, float_layer, float_behind_layer): xtra = 0 if img.mode == "c": - # Floatings are positioned over branches - crender.rotate_and_displace(fb, item.rotation, fb.h, item.radius - item.nodeRegion.width() + xtra) - # Floatings are positioned starting from the node circle - #crender.rotate_and_displace(fb, item.rotation, fb.h, item.radius - item.nodeRegion.width()) + if isRight: + # Floatings are positioned right to all other aligned faces + crender.rotate_and_displace(fb, item.rotation, fb.h, extra_width + tree_end_x) + else: + # Floatings are positioned over branches + crender.rotate_and_displace(fb, item.rotation, fb.h, item.radius - item.nodeRegion.width() + xtra) + # Floatings are positioned starting from the node circle + #crender.rotate_and_displace(fb, item.rotation, fb.h, item.radius - item.nodeRegion.width()) elif img.mode == "r": - start = item.branch_length + xtra - fb.w #if fb.w < item.branch_length else 0.0 - fb.setPos(item.content.mapToScene(start, item.center - (fb.h/2.0))) + if isRight: + # Floatings are positioned right to all other aligned faces + start = extra_width + tree_end_x # This puts it to the right of the column + fb.setPos(start, item.content.mapToScene(start, item.center - (fb.h/2.0)).y()) + else: + # Floatings are positioned over branches + start = item.branch_length + xtra - fb.w #if fb.w < item.branch_length else 0.0 + fb.setPos(item.content.mapToScene(start, item.center - (fb.h/2.0))) z = item.zValue() if not img.children_faces_on_top: @@ -821,7 +833,7 @@ def render_aligned_faces(img, mainRect, parent, n2i, n2f): # If no aligned faces, just return an offset of 0 pixels if not aligned_faces: - return 0 + return 0, 0 # Load header and footer if img.mode == "r": @@ -911,7 +923,7 @@ def render_aligned_faces(img, mainRect, parent, n2i, n2f): mainRect.adjust(-extra_width, -extra_width, extra_width, extra_width) else: mainRect.adjust(0, 0, extra_width, 0) - return extra_width + return extra_width, tree_end_x def get_tree_img_map(n2i, x_scale=1, y_scale=1): MOTIF_ITEMS = set([faces.QGraphicsTriangleItem, diff --git a/sdoc/tutorial/tutorial_drawing.rst b/sdoc/tutorial/tutorial_drawing.rst index 4b76b7b84..da7f5b805 100644 --- a/sdoc/tutorial/tutorial_drawing.rst +++ b/sdoc/tutorial/tutorial_drawing.rst @@ -330,7 +330,8 @@ Faces position ^^^^^^^^^^^^^^^^ Faces can be added to different areas around the node, namely -**branch-right**, **branch-top**, **branch-bottom** or **aligned**. +**branch-right**, **branch-top**, **branch-bottom**, **float**, +**float-behind**, **float-right**, or **aligned**. Each area represents a table in which faces can be added through the :func:`TreeNode.add_face` method. For instance, if two text labels want to be drawn bellow the branch line of a given node, a pair of