Exemple #1
0
    def plot(self, placement, togjson, outdir, cfg):
        """
        plot a plcement in the tree
        show all pplacer placements and the LCA and HCA node
        as well as the inferred lineage
        """
        from ete3 import NodeStyle, TreeStyle
        from ete3 import CircleFace, TextFace, RectFace

        logging.debug("Plotting trees now")
        # with no X display this needs to be set
        os.environ["QT_QPA_PLATFORM"] = "offscreen"
        info = self.loadInfo(togjson)

        def defaultNodeStyle():
            return NodeStyle()

        nodeStyles = defaultdict(defaultNodeStyle)

        no = 0
        for LCAp, HPAp in zip(placement["LCA"], placement["HPA"]):

            plotpath = os.path.join(outdir, f"tree_{no}.png")

            # make shallow copy
            t = self.t

            LCA = LCAp["node"]
            HPA = HPAp["node"]
            # define basic tree style
            ts = TreeStyle()
            # hide leave names
            ts.show_leaf_name = False
            ts.root_opening_factor = 1
            # circular tree
            ts.mode = "c"
            ts.rotation = 210
            ts.arc_start = 0  # 0 degrees = 3 o'clock
            ts.arc_span = 350

            highlightsize = 80
            nodesize = 10

            # define styles for special nodes
            # at the moment hard coded, but could be accesible for the user

            # LCA style
            LCAstyle = NodeStyle()
            LCAstyle["fgcolor"] = "#33a02c"
            LCAstyle["bgcolor"] = "#b2df8a"
            LCAstyle["size"] = highlightsize

            # HPA style
            HPAstyle = NodeStyle()
            HPAstyle["fgcolor"] = "#1f78b4"
            HPAstyle["bgcolor"] = "#a6cee3"
            HPAstyle["size"] = highlightsize

            # default node
            defaultStyle = NodeStyle()
            defaultStyle["fgcolor"] = "gray"
            defaultStyle["size"] = nodesize

            # add legend
            ts.legend_position = 1
            ts.legend.add_face(CircleFace(40, LCAstyle["fgcolor"]), column=1)
            ts.legend.add_face(TextFace(f"LCA", fsize=50), column=2)
            ts.legend.add_face(CircleFace(40, HPAstyle["fgcolor"]), column=1)
            ts.legend.add_face(TextFace(f"HPA", fsize=50), column=2)
            i = 1
            ts.legend.add_face(TextFace(f"p = {i}", fsize=50), column=1)
            while i > 0:
                temp_face = RectFace(60,
                                     10,
                                     fgcolor=p_to_color(i),
                                     bgcolor=p_to_color(i))
                temp_face.margin_top = -4
                ts.legend.add_face(temp_face, column=1)
                i -= 0.01
            ts.legend.add_face(TextFace(f"p = {cfg['minPlacementLikelyhood']}",
                                        fsize=50),
                               column=1)

            # add highlights for each placed protein
            for n in t.traverse():
                if n.name.startswith("PTHR"):
                    # set color based on posterior prob:
                    x = (info[n.name]["post_prob"] -
                         cfg["minPlacementLikelyhood"]) / (
                             1 - cfg["minPlacementLikelyhood"])
                    # orange to purple gradient from 0 to 1 posterior propability
                    he = p_to_color(x)
                    nodeStyles[he]["bgcolor"] = he
                    # define back color of locations
                    n.set_style(nodeStyles[he])

                elif n.name == LCA:
                    n.set_style(LCAstyle)
                elif n.name == HPA:
                    n.set_style(HPAstyle)
                else:
                    n.set_style(defaultStyle)

            # plot to disk
            _ = t.render(plotpath, w=320, units="mm", tree_style=ts)
            no = no + 1
            def nodeLayoutFunc(node):
                taxid = int(node.name)

                if taxid in taxidsToKeep:
                    taxGroupName = ncbiTaxa.get_taxid_translator(
                        [taxid]
                    )[taxid]  # There has to be an easier way to look up names...

                    row = None
                    rangeRows = None

                    print(len(ranges))

                    if (len(ranges) == 1):
                        row = df[(df['ExplanatoryVar'] == var)
                                 & (df['TaxGroup'] == taxid) &
                                 (df['Range'] == ranges[0])]
                        assert (len(row) == len(ranges))
                    elif len(ranges) > 1:
                        row = df[(df['ExplanatoryVar'] == var)
                                 & (df['TaxGroup'] == taxid) &
                                 (df['Range'] == 0)]
                        assert (len(row) == 1)
                        rangeRows = df[(df['ExplanatoryVar'] == var)
                                       & (df['TaxGroup'] == taxid) &
                                       (df['Range'].isin(set(ranges)))]
                    else:
                        assert (False)

                    overallPval = float(row['Pvalue'].values[0])

                    name = TextFace("%s" % taxGroupName,
                                    fsize=baseFontSize * 2.5)
                    name.tight_text = True
                    name.margin_left = 20
                    name.margin_right = 0
                    name.margin_top = 40
                    name.margin_bottom = 12
                    faces.add_face_to_node(name, node, column=0)

                    #print(rangeRows)

                    # For each range to be included in this plot, add a bar
                    for rangeId in ranges:
                        #print("rangeId = %s" % (rangeId))

                        rowForThisRange = None

                        if len(ranges) == 1:
                            rowForThisRange = row
                        else:
                            rowForThisRange = rangeRows[rangeRows['Range'] ==
                                                        rangeId]

                        assert (len(rowForThisRange) == 1)

                        # Extract p-value and "effect-size" (signed R^2)
                        effectSize = float(
                            rowForThisRange['EffectSize'].values[0])
                        pval = float(rowForThisRange['Pvalue'].values[0])

                        # Set bar-graph color and significance markers
                        barColor = ""
                        significanceMarker = ""
                        if (pval < significanceLevel):
                            significanceMarker = " %s" % unichr(0x2731)

                            if effectSize < 0:
                                barColor = "#1133ff"
                            else:
                                barColor = "#ff3311"
                        else:  # not significant
                            if effectSize < 0:
                                barColor = "#b0b0f0"
                            else:
                                barColor = "#ccb090"

                        # Add the minus sign if needed
                        signChar = ""
                        if effectSize < 0:
                            signChar = unichr(
                                0x2212
                            )  # minus sign (more legible than a hypen...)

                        v = RectFace(width=abs(effectSize) * barScale,
                                     height=baseFontSize * 3.5,
                                     fgcolor=barColor,
                                     bgcolor=barColor,
                                     label={
                                         "text":
                                         "%s%.2g %s" %
                                         (signChar, abs(effectSize),
                                          significanceMarker),
                                         "fontsize":
                                         baseFontSize * 1.8,
                                         "color":
                                         "black"
                                     })
                        #v.rotation = -90
                        v.margin_top = 1
                        v.margin_left = 30
                        v.margin_right = 8
                        v.margin_bottom = 12
                        faces.add_face_to_node(v, node, column=0)

                    details = TextFace(
                        "N=%d" % row['NumSpecies'], fsize=baseFontSize *
                        1.5)  #, fsize=baseFontSize) #, fstyle="italic")
                    details.background.color = "#dfdfdf"
                    details.margin_left = 6
                    details.margin_right = 20
                    #details.margin_top=5
                    #details.margin_bottom=0
                    faces.add_face_to_node(details, node, column=1)

                    nstyle = NodeStyle()
                    nstyle["size"] = 0

                    node.set_style(nstyle)