text: user2842: 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
  
  alignment = AlignIO.read('MotifSeqAligned.fasta', 'fasta') # reading the alignment file
  
  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
  newickFile = open("TreeToCutOff.nwk", 'r').read()
  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):
      img1 = mpimg.imread(files)
      ax1 = fig.add_subplot(len(orderedLogos), 1, 1+i)
      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")
  
  # load figures
  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
  ---SSNDTTTCCAGGAAD-
  >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.
  
  user581: 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
          faces.add_face_to_node(logo_face, node, column=0)
      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
  
original_text: 2842: <p>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.</p>
  
  <p>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)</p>
  
  <pre><code># 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
  
  alignment = AlignIO.read('MotifSeqAligned.fasta', 'fasta') # reading the alignment file
  
  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)
  </code></pre>
  
  <p>From this code I could get the tree:
  <a href="https://i.stack.imgur.com/eLc0c.png" rel="noreferrer"><img src="https://i.stack.imgur.com/eLc0c.png" alt="enter image description here"></a></p>
  
  <p>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:</p>
  
  <pre><code>#Extract filename from newick
  newickFile = open("TreeToCutOff.nwk", 'r').read()
  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):
      img1 = mpimg.imread(files)
      ax1 = fig.add_subplot(len(orderedLogos), 1, 1+i)
      ax1.imshow(img1)
      ax1.set_xticks([])
      ax1.set_yticks([])
  
  # plt.show()
  plt.savefig("RowsOfLogos.svg", format='svg', dpi=1200)
  plt.clf()
  plt.cla()
  </code></pre>
  
  <p><a href="https://i.stack.imgur.com/tamkV.png" rel="noreferrer"><img src="https://i.stack.imgur.com/tamkV.png" alt="enter image description here"></a></p>
  
  <p>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)</p>
  
  <pre><code>import svgutils.transform as sg
  # Assemble
  #create new SVG figure
  fig = sg.SVGFigure("14cm", "14cm")
  
  # load figures
  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])
  </code></pre>
  
  <p>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.</p>
  
  <p>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.</p>
  
  <p>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?</p>
  
  <p><a href="https://i.stack.imgur.com/M7p7a.png" rel="noreferrer"><img src="https://i.stack.imgur.com/M7p7a.png" alt="enter image description here"></a></p>
  
  <p>Following is a subset of "MotifSeqAligned.fasta" containing the aligned sequences used to build the trees:</p>
  
  <pre><code>&gt;ProfileCluster0.meme
  ---SSNDTTTCCAGGAAD-
  &gt;ProfileCluster1.meme
  YBNRD---TTCYYGGAAT-
  &gt;ProfileCluster10.meme
  ---VDKDWTTCTYGGAAT-
  </code></pre>
  
  <p>With the 3 corresponding logos:
  <a href="https://i.stack.imgur.com/4GChu.png" rel="noreferrer"><img src="https://i.stack.imgur.com/4GChu.png" alt="enter image description here"></a>
  <a href="https://i.stack.imgur.com/ATI9L.png" rel="noreferrer"><img src="https://i.stack.imgur.com/ATI9L.png" alt="enter image description here"></a>
  <a href="https://i.stack.imgur.com/TjhTt.png" rel="noreferrer"><img src="https://i.stack.imgur.com/TjhTt.png" alt="enter image description here"></a></p>
  
  <p>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 <a href="https://github.com/bschnide/Tree-Logos" rel="noreferrer">here</a>.</p>
   581: <p>To expand on my comment from yesterday. You could do this with the <a href="http://etetoolkit.org" rel="noreferrer">ETE Toolkit</a> (I just copied one logo file rather than converting all 26 to <code>png</code>):</p>
  
  <pre><code>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
          faces.add_face_to_node(logo_face, node, column=0)
      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
  </code></pre>
  
  <p><a href="https://i.stack.imgur.com/Yd8z6.png" rel="noreferrer"><img src="https://i.stack.imgur.com/Yd8z6.png" alt="enter image description here"></a></p>
  
  <p>If you want all of the logos lined up in a column add <code>aligned=True</code> to <code>faces.add_face_to_node</code></p>
  