# Biopython Phylogenetic Tree replace branch tip labels by sequence logos

Having recently constructed a lot of phylogenetic trees with the module TreeConstruction from Phylo package from Biopython, I've been asked to replace the branch tip labels by the corresponding sequence logos (which I have in the same folder). I thought that it would be more efficient to make a code to generate the logo-trees automatically, as I would have to make a lot of them.

The first idea that I came up with was to see whether the functions used to build the tree had an argument to replace the branch tip labels or to remove them, which I couldn't find. Therefore, I removed the branch tip labels by setting their font size to 0: (following is the code to build the tree)

# Modules to build the tree
from Bio.Phylo.TreeConstruction import DistanceCalculator, DistanceTreeConstructor
from Bio.Phylo import draw
from Bio import Phylo, AlignIO
import subprocess
import matplotlib
import matplotlib.pyplot as plt

calculator = DistanceCalculator('ident')
dm = calculator.get_distance(alignment) # distance matrix

constructor = DistanceTreeConstructor()
tree = constructor.nj(dm) # build with neighbour joining algorithm a tree from dm

Phylo.write(tree, 'TreeToCutOff.nwk', 'newick')

plt.rc('font', size=0)          # controls default text sizes #HERE IS THE SETTING FOR THAT ALLOWS ME TO HIDE THE BRANCH TIP LABELS
plt.rc('axes', titlesize=14)     # fontsize of the axes title
plt.rc('xtick', labelsize=10)    # fontsize of the tick labels
plt.rc('ytick', labelsize=10)    # fontsize of the tick labels
plt.rc('figure', titlesize=18)   # fontsize of the figure title

draw(tree, do_show=False)
plt.savefig("TreeToCutOff.svg", format='svg', dpi=1200)


From this code I could get the tree:

Since I don't know how to get the y coordinates of the branches to add the logos one by one, I built a column of logos with matplotlib, that I intended then to paste on the tree in python. The code to build the column of logos is the following:

#Extract filename from newick
orderedLogos = ["{}.eps".format(i) for i in re.split('(\W)', newickFile) if "Profile" in i]

#Initialize the figure
fig = plt.figure()

#Add each image one after the other in the right order
for i, files in enumerate(orderedLogos):
ax1.imshow(img1)
ax1.set_xticks([])
ax1.set_yticks([])

# plt.show()
plt.savefig("RowsOfLogos.svg", format='svg', dpi=1200)
plt.clf()
plt.cla()


Having my tree and the column of logos in .svg or .png, I couldn't find any way to stack them properly. My first idea was to use the library svgutils which seemed to be easy to handle, with the following code: (taken from svgutils tutorials)

import svgutils.transform as sg
# Assemble
#create new SVG figure
fig = sg.SVGFigure("14cm", "14cm")

fig1 = sg.fromfile('TreeToCutOff.svg')
fig2 = sg.fromfile('RowsOfLogos.svg')

# get the plot objects
plot1 = fig1.getroot()
plot2 = fig2.getroot()
plot2.moveto(280, 100, scale=0.05)

# append plots and labels to figure
fig.append([plot1, plot2])


But the issue with the output was that the background of the column of logos was white and thus, I was pasting a huge white image with a thin column of logos on the tree. And I couldn't find a way to crop the column of logos with svgutils. I tried the module Image from PIL package to build a tree of logos from .png files but couldn't see the tree used as background after pasting the column of logos.

There may be a way to do what I'm aiming for with matplotlib (which would be to stack 2 files .png, and place the logos all the time at the same distance), but I couldn't work it out.

Does anyone know what the best solution is to make a tree of logos (as in the following image which I could only build manually with inkscape) with python libraries, allowing to automate the process without having to adapt the code depending on the number of branches?

Following is a subset of "MotifSeqAligned.fasta" containing the aligned sequences used to build the trees:

>ProfileCluster0.meme
>ProfileCluster1.meme
YBNRD---TTCYYGGAAT-
>ProfileCluster10.meme
---VDKDWTTCTYGGAAT-


With the 3 corresponding logos:

The full "MotifSeqAligned.fasta" and all the logos.eps (as I used them instead of .png which is the format asked by the forum) can be found here.

• Thank you for putting so much effort into your question! If I could ask for one more thing though, it would be great if you could give us a minimal, complete and verifiable example, code that we can use directly on our system to replicate your issue so we can play with it and see if we can find a solution. – terdon May 21 '18 at 13:59
• Thank you for the suggestion, I added the inputs at the end of the topic. Note that the logos are .eps files and here I added them as images (.png). The full inputs are on the link at the end of the topic. – Boris Schnider May 21 '18 at 14:53
• If there's no obvious biopython solution have a look at the ETE Toolkit – heathobrien May 21 '18 at 15:23

To expand on my comment from yesterday. You could do this with the ETE Toolkit (I just copied one logo file rather than converting all 26 to png):

from ete3 import Tree, TreeStyle, faces
def mylayout(node):
if node.is_leaf():
logo_face = faces.ImgFace(str.split(node.name, '.')[0] + ".png") # this doesn't seem to work with eps files. You could try other formats
node.img_style["size"] = 0  # remove blue dots from nodes

t = Tree("tree.nwk", format=3)
ts = TreeStyle()
ts.layout_fn = mylayout
ts.show_leaf_name=False # remove sequence labels
ts.scale =  10000 # rescale branch lengths so they are longer than the width of the logos
t.render("formatted.png", tree_style = ts, h=3000, w=3000) # you may need to fiddle with dimensions and scaling to get the look you want


If you want all of the logos lined up in a column add aligned=True to faces.add_face_to_node

• Thanks! That's exactly what I was looking for! I will try with all my logos and let you know if I have further issues. – Boris Schnider May 22 '18 at 11:11