ete2.treeview.faces

Package ete2 :: Package treeview :: Module faces |
[hide private]
[frames] | no frames]

# Source Code for Module ete2.treeview.faces

      1  __VERSION__="ete2-2.0rev95"
      2  # #START_LICENSE###########################################################
      3  #
      4  # Copyright (C) 2009 by Jaime Huerta Cepas. All rights reserved.
      5  # email: jhcepas@gmail.com
      6  #
      7  # This file is part of the Environment for Tree Exploration program (ETE).
      8  # http://ete.cgenomics.org
      9  #
     10  # ETE is free software: you can redistribute it and/or modify it
     11  # under the terms of the GNU General Public License as published by
     12  # the Free Software Foundation, either version 3 of the License, or
     13  # (at your option) any later version.
     14  #
     15  # ETE is distributed in the hope that it will be useful,
     16  # but WITHOUT ANY WARRANTY; without even the implied warranty of
     17  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     18  # GNU General Public License for more details.
     19  #
     20  # You should have received a copy of the GNU General Public License
     21  # along with ETE.  If not, see <http://www.gnu.org/licenses/>.
     22  #
     23  # #END_LICENSE#############################################################
     24
     25  try:
     26      from PyQt4 import QtCore, QtGui
     27  except:
     28      import QtCore, QtGui
     29
     30  import numpy
     31
     32  aafgcolors = {
     33  'A':"#000000" ,
     34  'R':"#000000" ,
     35  'N':"#000000" ,
     36  'D':"#000000" ,
     37  'C':"#000000" ,
     38  'Q':"#000000" ,
     39  'E':"#000000" ,
     40  'G':"#000000" ,
     41  'H':"#000000" ,
     42  'I':"#000000" ,
     43  'L':"#000000" ,
     44  'K':"#000000" ,
     45  'M':"#000000" ,
     46  'F':"#000000" ,
     47  'P':"#000000" ,
     48  'S':"#000000" ,
     49  'T':"#000000" ,
     50  'W':"#000000" ,
     51  'Y':"#000000" ,
     52  'V':"#000000" ,
     53  'B':"#000000" ,
     54  'Z':"#000000" ,
     55  'X':"#000000",
     56  '.':"#000000",
     57  '-':"#000000",
     58  }
     59
     60  aabgcolors = {
     61  'A':"#C8C8C8" ,
     62  'R':"#145AFF" ,
     63  'N':"#00DCDC" ,
     64  'D':"#E60A0A" ,
     65  'C':"#E6E600" ,
     66  'Q':"#00DCDC" ,
     67  'E':"#E60A0A" ,
     68  'G':"#EBEBEB" ,
     69  'H':"#8282D2" ,
     70  'I':"#0F820F" ,
     71  'L':"#0F820F" ,
     72  'K':"#145AFF" ,
     73  'M':"#E6E600" ,
     74  'F':"#3232AA" ,
     75  'P':"#DC9682" ,
     76  'S':"#FA9600" ,
     77  'T':"#FA9600" ,
     78  'W':"#B45AB4" ,
     79  'Y':"#3232AA" ,
     80  'V':"#0F820F" ,
     81  'B':"#FF69B4" ,
     82  'Z':"#FF69B4" ,
     83  'X':"#BEA06E",
     84  '.':"#FFFFFF",
     85  '-':"#FFFFFF",
     86  }
     87
     88  ntfgcolors = {
     89  'A':'#000000',
     90  'G':'#000000',
     91  'I':'#000000',
     92  'C':'#000000',
     93  'T':'#000000',
     94  'U':'#000000',
     95  '.':"#000000",
     96  '-':"#000000",
     97  ' ':"#000000"
     98
     99  }
    100
    101  ntbgcolors = {
    102  'A':'#A0A0FF',
    103  'G':'#FF7070',
    104  'I':'#80FFFF',
    105  'C':'#FF8C4B',
    106  'T':'#A0FFA0',
    107  'U':'#FF8080',
    108  '.':"#FFFFFF",
    109  '-':"#FFFFFF",
    110  ' ':"#FFFFFF"
    111
    112  }
    113
    114  __all__ = ["add_face_to_node", "Face", "TextFace", "AttrFace", "ImgFace", "ProfileFace", "ValidationFace", "SequenceFace"]
    115
    116  try:
    117      import psyco
    118      pysco.full()
    119  except:
    120      pass
    121
    122 -def add_face_to_node(face, node, column, aligned=False):
    123      """ Links a node with a given face instance.  """
    124
    125      if column >= len(node.img_style["faces"]):
    126          for i in xrange(len(node.img_style["faces"]), column+1):
    127              node.img_style["faces"].append([])
    128      # None value will be the pointer to a pixmap
    129      node.img_style["faces"][column].append([face, aligned, None])
    130
    131 -class Face(object):
    132      """ Standard definition of a face node object.
    133
    134      This class is not functional and it should only be used to create
    135      other faces objects. By inheriting this class, you set all the
    136      essential attributes, however the update_pixmap() function is
    137      required to be reimplemented for convenience.
    138
    139      """
    140
    141 -    def __init__(self):
    142          self.node        = None
    143          self.type        = "pixmap"
    144          self.name        = "unknown"
    145          self.xmargin     = 0
    146          self.ymargin     = 0
    147          self.pixmap      = None
    148          # self.aligned     = False
    149
    150 -    def _size(self):
    151          if self.pixmap:
    152              return self._width(),self._height()
    153          else:
    154              return 0, 0
    155
    156 -    def _width(self):
    157          if self.pixmap:
    158              return self.pixmap.width() #+ self.xmargin*2
    159          else:
    160              return 0
    161
    162 -    def _height(self):
    163          if self.pixmap:
    164              return self.pixmap.height() #+ self.ymargin*2
    165          else:
    166              return 0
    167
    168 -    def load_pixmap_from_file(self, filename):
    169          self.pixmap = QtGui.QPixmap(filename)
    170
    171 -    def update_pixmap(self):
    172          pass
    173
    174 -class TextFace(Face):
    175      """ Creates a new text face object.
    176
    177      Arguments description
    178      ---------------------
    179      text:     Text to be drawn
    180      ftype:    Font type, e.g. Arial, Verdana, Courier, (default="Verdana")
    181      fsize:    Font size, e.g. 10,12,6, (default=10)
    182      fgcolor:  Foreground font color in RGB name format, e.g. #FF00DD,#000000  (default="#000000")
    183      bgcolor:  Backgroung font color in RGB name format, e.g. #FFFFFF,#DDDDDD, (default=None)
    184      penwidth: Penwdith used to draw the text. (default is 0)
    185      """
    186
    187 -    def __init__(self, text, ftype="Verdana", fsize=10, fgcolor="#000000", bgcolor=None, penwidth=0):
    188          Face.__init__(self)
    189
    190          if bgcolor is None:
    191              bgcolor = QtCore.Qt.transparent
    192          self.pixmap      = None
    193          self.type        = "text"
    194          self.text        = str(text)
    195          self.pen         = QtGui.QPen(QtGui.QColor(fgcolor))
    196          self.pen.setWidth(penwidth)
    197          if not bgcolor:
    198              self.bgcolor = QtGui.QColor(None)
    199          else:
    200              self.bgcolor = QtGui.QColor(bgcolor)
    201          self.fgcolor = QtGui.QColor(fgcolor)
    202          self.font    = QtGui.QFont(ftype,fsize)
    203
    204 -    def _height(self):
    205          fm = QtGui.QFontMetrics(self.font)
    206          h =  fm.boundingRect(QtCore.QRect(), \
    207                                   QtCore.Qt.AlignLeft, \
    208                                   self.get_text()).height()
    209          return h
    210          # Other buggy alternatives
    211          # fm = QtGui.QFontMetrics(self.font)
    212          # h = 0
    213          # for l in lines:
    214          #     if l == lines[0]:
    215          #       h+=fm.tightBoundingRect(l).height()
    216          #     else:
    217          #       h+=fm.height()
    218          # return h #+ ((len(lines)-1)*fm.leading())
    219          #
    220          # lines = len(self.get_text().split("\n"))
    221          # return lines*fm.height() + (lines-1 * fm.leading())
    222          #
    223          # h =  fm.boundingRect(QtCore.QRect(), \
    224          #                        QtCore.Qt.AlignLeft, \
    225          #                        self.get_text()).height()
    226          # return h
    227
    228
    229
    230 -    def _width(self):
    231          fm = QtGui.QFontMetrics(self.font)
    232          return fm.size(QtCore.Qt.AlignTop, self.text).width()
    233
    234 -    def get_text(self):
    235          return self.text
    236
    237 -class AttrFace(TextFace):
    238      """ Creates a new text attribute face object.
    239
    240      Arguments description
    241      ---------------------
    242      name:     Face's name
    243      attr:     Node's attribute that will be drawn as text
    244      ftype:    Font type, e.g. Arial, Verdana, Courier, (default="Verdana")
    245      fsize:    Font size, e.g. 10,12,6, (default=10)
    246      fgcolor:  Foreground font color in RGB name format, e.g. #FF00DD,#000000  (default="#000000")
    247      bgcolor:  Backgroung font color in RGB name format, e.g. #FFFFFF,#DDDDDD, (default=None)
    248      penwidth: Penwdith used to draw the text. (default is 0)
    249      """
    250
    251 -    def __init__(self, attr, ftype="Verdana", fsize=10, fgcolor="#000000", bgcolor=None, penwidth=0):
    252          Face.__init__(self)
    253          TextFace.__init__(self, "", ftype, fsize, fgcolor, bgcolor, penwidth)
    254          self.attr     = attr
    255          self.type     = "text"
    256
    257 -    def _width(self):
    258          text = str(getattr(self.node, self.attr))
    259          fm = QtGui.QFontMetrics(self.font)
    260          return fm.size(QtCore.Qt.AlignTop,text).width()
    261
    262 -    def get_text(self):
    263          return str(getattr(self.node, self.attr))
    264
    265
    266
    267 -class ImgFace(Face):
    268      """ Creates a new image face object.
    269
    270      Arguments description
    271      ---------------------
    272
    273      img_file: Image file in png,jpg,bmp format
    274      """
    275 -    def __init__(self,img_file):
    276          Face.__init__(self)
    277          self.img_file = img_file
    278          self.name = "ImageFile"
    279
    280 -    def update_pixmap(self):
    281          self.load_pixmap_from_file(self.img_file)
    282
    283
    284 -class ProfileFace(Face):
    285      """ Creates a new vector profile face object.
    286
    287      Arguments description
    288      ---------------------
    289
    290      max_v:    maximum value used to build the build the plot scale.
    291      max_v:    manimum value used to build the build the plot scale.
    292      center_v: Center value used to scale plot and heat map.
    293      width:    Plot width in pixels. (defaulf=200)
    294      height:   Plot width in pixels. (defaulf=40)
    295      style:    Plot style: "lines", "bars", "cbars" or "heatmap". (default="lines")
    296      """
    297 -    def __init__(self,max_v,min_v,center_v,width=200,height=40,style="lines",colorscheme=2):
    298          Face.__init__(self)
    299
    300          self.width  = width
    301          self.height = height
    302          self.max_value = max_v
    303          self.min_value = min_v
    304          self.center_v  = center_v
    305          self.xmargin = 1
    306          self.ymargin = 1
    307          self.style = style
    308          self.colorscheme = colorscheme
    309
    310 -    def update_pixmap(self):
    311          if self.style=="lines":
    312              self.draw_line_profile()
    313          elif self.style=="heatmap":
    314              self.draw_heatmap_profile()
    315          elif self.style=="bars":
    316              self.draw_bar_profile()
    317          elif self.style=="cbars":
    318              self.draw_centered_bar_profile()
    319
    320 -    def get_color_gradient(self):
    321          colors = []
    322          if self.colorscheme == 0:
    323              # Blue and Green
    324              for a in xrange(100,0,-1):
    325                  color=QtGui.QColor()
    326                  color.setRgb( 200-2*a,255,200-2*a )
    327                  colors.append(color)
    328              for a in xrange(0,100):
    329                  color=QtGui.QColor()
    330                  color.setRgb( 200-2*a,200-2*a,255 )
    331                  colors.append(color)
    332  #            color=QtGui.QColor()
    333  #            color.setRgb( 0,255,255 )
    334  #            colors.append(color)
    335
    336          elif self.colorscheme == 1:
    337              for a in xrange(100,0,-1):
    338                  color=QtGui.QColor()
    339                  color.setRgb( 200-2*a,255,200-2*a )
    340                  colors.append(color)
    341
    342              for a in xrange(0,100):
    343                  color=QtGui.QColor()
    344                  color.setRgb( 255,200-2*a,200-2*a )
    345                  colors.append(color)
    346  #            color=QtGui.QColor()
    347  #            color.setRgb(255,255,0 )
    348  #            colors.append(color)
    349
    350          else:
    351              # Blue and Red
    352              for a in xrange(100,0,-1):
    353                  color=QtGui.QColor()
    354                  color.setRgb( 200-2*a,200-2*a,255 )
    355                  colors.append(color)
    356              for a in xrange(0,100):
    357                  color=QtGui.QColor()
    358                  color.setRgb( 255,200-2*a,200-2*a )
    359                  colors.append(color)
    360  #            color=QtGui.QColor()
    361  #            color.setRgb( 255,0,255 )
    362  #            colors.append(color)
    363          colors.append(QtGui.QColor("white"))
    364
    365          return colors
    366
    367 -    def draw_bar_profile(self):
    368          # Calculate vector
    369          mean_vector = self.node.profile
    370          deviation_vector = self.node.deviation
    371          # If no vector, skip
    372          if mean_vector is None:
    373              return
    374
    375          colors = self.get_color_gradient()
    376
    377          vlength = len(mean_vector)
    378          # pixels per array position
    379          profile_width = self.width - self.xmargin*2 - 40
    380          profile_height= self.height - self.ymargin*2
    381
    382          x_alpha = float( profile_width / (len(mean_vector)) )
    383          y_alpha = float ( profile_height / (self.max_value-self.min_value) )
    384
    385          # Creates a pixmap
    386          self.pixmap = QtGui.QPixmap(self.width,self.height)
    387          self.pixmap.fill(QtGui.QColor("white"))
    388          p = QtGui.QPainter(self.pixmap)
    389
    390          x2 = self.xmargin
    391          y  = self.ymargin
    392
    393          # Mean and quartiles y positions
    394          mean_line_y = y + profile_height/2
    395          line2_y     = mean_line_y + profile_height/4
    396          line3_y     = mean_line_y - profile_height/4
    397
    398          # Draw axis and scale
    399          p.setPen(QtGui.QColor("black"))
    400          p.drawRect(x2,y,profile_width, profile_height-1)
    401          p.setFont(QtGui.QFont("Verdana",8))
    402          p.drawText(self.xmargin+profile_width,y+10,"%0.3f" %self.max_value)
    403          p.drawText(self.xmargin+profile_width,y+profile_height,"%0.3f" %self.min_value)
    404
    405          dashedPen = QtGui.QPen(QtGui.QBrush(QtGui.QColor("#ddd")), 0)
    406          dashedPen.setStyle(QtCore.Qt.DashLine)
    407
    408          # Draw hz grid
    409          p.setPen(dashedPen)
    410          p.drawLine(x2+1, mean_line_y, profile_width-2, mean_line_y )
    411          p.drawLine(x2+1, line2_y, profile_width-2, line2_y )
    412          p.drawLine(x2+1, line3_y, profile_width-2, line3_y )
    413
    414
    415          # Draw bars
    416          for pos in xrange(vlength):
    417              # first and second X pixel positions
    418              x1 = x2
    419              x2 = x1 + x_alpha
    420
    421              dev1 =  self.fit_to_scale( deviation_vector[pos]   )
    422              mean1 = self.fit_to_scale( mean_vector[pos]        )
    423
    424              # If nan value, skip
    425              if not numpy.isfinite(mean1):
    426                  continue
    427
    428              # Set heatmap color
    429              if mean1>self.center_v:
    430                  color_index = int(abs(((self.center_v-mean1)*100)/(self.max_value-self.center_v)))
    431                  customColor = colors[100+color_index]
    432              elif mean1<self.center_v:
    433                  color_index = int(abs(((self.center_v-mean1)*100)/(self.min_value-self.center_v)))
    434                  customColor = colors[100-color_index]
    435              else:
    436                  customColor = colors[0]
    437
    438              # mean bar high
    439              mean_y1     = int ( (mean1 - self.min_value) * y_alpha)
    440
    441              # Draw bar border
    442              p.setPen(QtGui.QColor("black"))
    443              #p.drawRect(x1+2,mean_y1, x_alpha-3, profile_height-mean_y1+1)
    444              # Fill bar with custom color
    445              p.fillRect(x1+3,profile_height-mean_y1, x_alpha-4, mean_y1-1, QtGui.QBrush(customColor))
    446
    447              # Draw error bars
    448              if dev1 != 0:
    449                  dev_up_y1   = int((mean1+dev1 - self.min_value) * y_alpha)
    450                  dev_down_y1 = int((mean1-dev1 - self.min_value) * y_alpha)
    451                  p.drawLine(x1+x_alpha/2, profile_height-dev_up_y1 ,x1+x_alpha/2, profile_height-dev_down_y1 )
    452                  p.drawLine(x1-1+x_alpha/2,  profile_height-dev_up_y1, x1+1+x_alpha/2, profile_height-dev_up_y1 )
    453                  p.drawLine(x1-1+x_alpha/2,  profile_height-dev_down_y1, x1+1+x_alpha/2, profile_height-dev_down_y1 )
    454
    455 -    def draw_centered_bar_profile(self):
    456          # Calculate vector
    457          mean_vector  = self.node.profile
    458          deviation_vector = self.node.deviation
    459          # If no vector, skip
    460          if mean_vector is None:
    461              return
    462
    463          colors = self.get_color_gradient()
    464
    465          vlength = len(mean_vector)
    466          # pixels per array position
    467          profile_width = self.width - self.xmargin*2 - 40
    468          profile_height= self.height - self.ymargin*2
    469
    470          x_alpha = float( profile_width / (len(mean_vector)) )
    471          y_alpha_up = float ( (profile_height/2) / (self.max_value-self.center_v) )
    472          y_alpha_down = float ( (profile_height/2) / (self.min_value-self.center_v) )
    473
    474          # Creates a pixmap
    475          self.pixmap = QtGui.QPixmap(self.width,self.height)
    476          self.pixmap.fill(QtGui.QColor("white"))
    477          p = QtGui.QPainter(self.pixmap)
    478
    479          x2 = self.xmargin
    480          y  = self.ymargin
    481
    482          # Mean and quartiles y positions
    483          mean_line_y = y + profile_height/2
    484          line2_y     = mean_line_y + profile_height/4
    485          line3_y     = mean_line_y - profile_height/4
    486
    487          # Draw axis and scale
    488          p.setPen(QtGui.QColor("black"))
    489          p.drawRect(x2,y,profile_width, profile_height-1)
    490          p.setFont(QtGui.QFont("Verdana",8))
    491          p.drawText(self.xmargin+profile_width,y+10,"%0.3f" %self.max_value)
    492          p.drawText(self.xmargin+profile_width,y+profile_height,"%0.3f" %self.min_value)
    493          p.drawText(self.xmargin+profile_width,mean_line_y,"%0.3f" %self.center_v)
    494
    495          dashedPen = QtGui.QPen(QtGui.QBrush(QtGui.QColor("#ddd")), 0)
    496          dashedPen.setStyle(QtCore.Qt.DashLine)
    497
    498          # Draw hz grid
    499          p.setPen(dashedPen)
    500          p.drawLine(x2+1, mean_line_y, profile_width-2, mean_line_y )
    501          p.drawLine(x2+1, line2_y, profile_width-2, line2_y )
    502          p.drawLine(x2+1, line3_y, profile_width-2, line3_y )
    503
    504
    505          # Draw bars
    506          for pos in xrange(vlength):
    507              # first and second X pixel positions
    508              x1 = x2
    509              x2 = x1 + x_alpha
    510
    511              dev1 =  self.fit_to_scale( deviation_vector[pos]   )
    512              mean1 = self.fit_to_scale( mean_vector[pos]        )
    513
    514              # If nan value, skip
    515              if not numpy.isfinite(mean1):
    516                  continue
    517
    518              # Set heatmap color
    519              if mean1>self.center_v:
    520                  color_index = int(abs(((self.center_v-mean1)*100)/(self.max_value-self.center_v)))
    521                  customColor = colors[100+color_index]
    522              elif mean1<self.center_v:
    523                  color_index = int(abs(((self.center_v-mean1)*100)/(self.min_value-self.center_v)))
    524                  customColor = colors[100-color_index]
    525              else:
    526                  customColor = colors[0]
    527
    528              # mean bar high
    529              if mean1<self.center_v:
    530                  mean_y1 = int(abs((mean1 - self.center_v) * y_alpha_down))
    531              else:
    532                  mean_y1 = int(abs((mean1 - self.center_v) * y_alpha_up))
    533
    534              # Draw bar border
    535              p.setPen(QtGui.QColor("black"))
    536              #p.drawRect(x1+2,mean_y1, x_alpha-3, profile_height-mean_y1+1)
    537              # Fill bar with custom color
    538              if mean1<self.center_v:
    539                  p.fillRect(x1+3, mean_line_y, x_alpha-4, mean_y1, QtGui.QBrush(customColor))
    540              else:
    541                  p.fillRect(x1+3, mean_line_y-mean_y1, x_alpha-4, mean_y1+1, QtGui.QBrush(customColor))
    542
    543              # Draw error bars
    544              if dev1 != 0:
    545                  if mean1<self.center_v:
    546                      dev_up_y1   = int((mean1+dev1 - self.center_v) * y_alpha_down)
    547                      dev_down_y1 = int((mean1-dev1 - self.center_v) * y_alpha_down)
    548                      p.drawLine(x1+x_alpha/2, mean_line_y+dev_up_y1 ,x1+x_alpha/2, mean_line_y+dev_down_y1 )
    549                      p.drawLine(x1-1+x_alpha/2, mean_line_y+dev_up_y1 ,x1+1+x_alpha/2, mean_line_y+dev_up_y1 )
    550                      p.drawLine(x1-1+x_alpha/2, mean_line_y+dev_down_y1 ,x1+1+x_alpha/2, mean_line_y+dev_down_y1 )
    551                  else:
    552                      dev_up_y1   = int((mean1+dev1 - self.center_v) * y_alpha_up)
    553                      dev_down_y1 = int((mean1-dev1 - self.center_v) * y_alpha_up)
    554                      p.drawLine(x1+x_alpha/2, mean_line_y-dev_up_y1 ,x1+x_alpha/2, mean_line_y-dev_down_y1 )
    555                      p.drawLine(x1-1+x_alpha/2, mean_line_y-dev_up_y1 ,x1+1+x_alpha/2, mean_line_y-dev_up_y1 )
    556                      p.drawLine(x1-1+x_alpha/2, mean_line_y-dev_down_y1 ,x1+1+x_alpha/2, mean_line_y-dev_down_y1 )
    557
    558 -    def draw_line_profile(self):
    559          # Calculate vector
    560          mean_vector = self.node.profile
    561          deviation_vector = self.node.deviation
    562          if mean_vector is None:
    563              return
    564
    565          vlength = len(mean_vector)
    566          # pixels per array position
    567          profile_width = self.width - self.xmargin*2 - 40
    568          profile_height= self.height - self.ymargin*2
    569
    570
    571          x_alpha = float( profile_width / (len(mean_vector)-1) )
    572          y_alpha = float ( profile_height / (self.max_value-self.min_value) )
    573
    574          # Creates a pixmap
    575          self.pixmap = QtGui.QPixmap(self.width,self.height)
    576          self.pixmap.fill(QtGui.QColor("white"))
    577          p = QtGui.QPainter(self.pixmap)
    578
    579          x2 = self.xmargin
    580          y  = self.ymargin
    581
    582          # Mean and quartiles y positions
    583          mean_line_y = (self.center_v - self.min_value) * y_alpha
    584          line2_y     = ((self.center_v+abs(self.min_value/2)) - self.min_value) * y_alpha
    585          line3_y     = ((self.center_v-abs(self.max_value/2)) - self.min_value) * y_alpha
    586
    587          # Draw axis and scale
    588          p.setPen(QtGui.QColor("black"))
    589          p.drawRect(x2,y,profile_width, profile_height-1)
    590          p.setFont(QtGui.QFont("Verdana",8))
    591          p.drawText(self.xmargin+profile_width,y+10,"%0.3f" %self.max_value)
    592          p.drawText(self.xmargin+profile_width,y+profile_height,"%0.3f" %self.min_value)
    593          p.drawText(self.xmargin+profile_width,mean_line_y+5,"%0.3f" %self.center_v)
    594
    595          dashedPen = QtGui.QPen(QtGui.QBrush(QtGui.QColor("#ddd")), 0)
    596          dashedPen.setStyle(QtCore.Qt.DashLine)
    597
    598          # Draw hz grid
    599          p.setPen(dashedPen)
    600          p.drawLine(x2+1, mean_line_y, profile_width-2, mean_line_y )
    601          p.drawLine(x2+1, line2_y, profile_width-2, line2_y )
    602          p.drawLine(x2+1, line3_y, profile_width-2, line3_y )
    603
    604          # Draw lines
    605          for pos in xrange(0,vlength-1):
    606              dev1 =  self.fit_to_scale( deviation_vector[pos]   )
    607              dev2 =  self.fit_to_scale( deviation_vector[pos+1] )
    608              mean1 = self.fit_to_scale( mean_vector[pos]        )
    609              mean2 = self.fit_to_scale( mean_vector[pos+1]      )
    610              # first and second X pixel positions
    611              x1 = x2
    612              x2 = x1 + x_alpha
    613
    614              # Draw vt grid
    615              if x2 < profile_width:
    616                  p.setPen(dashedPen)
    617                  p.drawLine(x2, y+1, x2, profile_height-2)
    618
    619              # If nan values, continue
    620              if not numpy.isfinite(mean1) or not numpy.isfinite(mean2):
    621                  continue
    622
    623              # First Y postions for mean
    624              mean_y1     = (mean1 - self.min_value) * y_alpha
    625              # Second Y postions for mean
    626              mean_y2     = (mean2 - self.min_value) * y_alpha
    627              # Draw blue mean line
    628              p.setPen(QtGui.QColor("blue"))
    629              p.drawLine(x1,mean_y1, x2, mean_y2)
    630
    631              if dev1!= 0 and dev2!=0:
    632                  # First Y postions for deviations
    633                  dev_up_y1   = (mean1+dev1 - self.min_value) * y_alpha
    634                  dev_down_y1 = (mean1-dev1 - self.min_value) * y_alpha
    635                  # Second Y postions for deviations
    636                  dev_up_y2   = (mean2+dev2 - self.min_value) * y_alpha
    637                  dev_down_y2 = (mean2-dev2 - self.min_value) * y_alpha
    638                  # Draw red deviation lines
    639                  p.setPen(QtGui.QColor("red"))
    640                  p.drawLine(x1,dev_up_y1, x2, dev_up_y2)
    641                  p.setPen(QtGui.QColor("red"))
    642                  p.drawLine(x1,dev_down_y1, x2, dev_down_y2)
    643
    644
    645 -    def draw_heatmap_profile(self):
    646          # Calculate vector
    647          vector = self.node.profile
    648          deviation = self.node.deviation
    649          # If no vector, skip
    650          if vector is None:
    651              return
    652
    653          colors = self.get_color_gradient()
    654
    655          leaves = self.node.get_leaves()
    656
    657          vlength = len(vector)
    658          # pixels per array position
    659          img_height = self.height * len(leaves)
    660          profile_width = self.width - self.xmargin*2
    661          profile_height= img_height - self.ymargin*2
    662
    663          x_alpha = float( profile_width / (len(vector)) )
    664
    665          # Creates a pixmap
    666          self.pixmap = QtGui.QPixmap(self.width,img_height)
    667          self.pixmap.fill(QtGui.QColor("white"))
    668          p = QtGui.QPainter(self.pixmap)
    669
    670          x2 = self.xmargin
    671          y  = self.ymargin
    672          y_step = self.height
    673          for leaf in leaves:
    674              mean_vector = leaf.profile
    675              deviation_vector = leaf.deviation
    676              # Draw heatmap
    677              for pos in xrange(vlength):
    678                  # first and second X pixel positions
    679                  x1 = x2
    680                  x2 = x1 + x_alpha
    681                  dev1 =  self.fit_to_scale( deviation_vector[pos]   )
    682                  mean1 = self.fit_to_scale( mean_vector[pos]        )
    683                  # Set heatmap color
    684                  if not numpy.isfinite(mean1):
    685                      customColor = QtGui.QColor("#000000")
    686                  elif mean1>self.center_v:
    687                      color_index = int(abs(((self.center_v-mean1)*100)/(self.max_value-self.center_v)))
    688                      customColor = colors[100+color_index]
    689                  elif mean1<self.center_v:
    690                      color_index = int(abs(((self.center_v-mean1)*100)/(self.min_value-self.center_v)))
    691                      customColor = colors[100-color_index]
    692                  else:
    693                      customColor = colors[-1]
    694
    695                  # Fill bar with custom color
    696                  p.fillRect(x1, y, x_alpha, y_step, QtGui.QBrush(customColor))
    697              y+= y_step
    698              x2 = self.xmargin
    699
    700 -    def fit_to_scale(self,v):
    701          if v<self.min_value:
    702              return float(self.min_value)
    703          elif v>self.max_value:
    704              return float(self.max_value)
    705          else:
    706              return float(v)
    707
    708 -class ValidationFace(Face):
    709      """ Creates a new clustering validation face """
    710
    711 -    def __init__(self,fsize=10):
    712          Face.__init__(self)
    713          self.seq  = seq
    714          self.name = "validation"
    715          self.fsize= fsize
    716          self.font = QtGui.QFont("Courier",self.fsize)
    717          self.style = seqtype
    718
    719 -    def update_pixmap(self):
    720          pass
    721
    722 -class SequenceFace(Face):
    723      """ Creates a new molecular sequence face object.
    724
    725      Arguments description
    726      ---------------------
    727      seq:     Sequence string to be drawn
    728      seqtype: Type of sequence: "nt" or "aa"
    729      fsize:   Font size,  (default=10)
    730      """
    731
    732 -    def __init__(self, seq, seqtype, fsize=10, aafg=aafgcolors,  aabg=aabgcolors, ntfg=ntfgcolors, ntbg=ntbgcolors):
    733          Face.__init__(self)
    734          self.seq  = seq
    735          self.name = "sequence"
    736          self.fsize= fsize
    737          self.font = QtGui.QFont("Courier", self.fsize)
    738          self.style = seqtype
    739          self.aafg = aafg
    740          self.aabg = aabg
    741          self.ntfg = ntfg
    742          self.ntbg = ntbg
    743
    744 -    def update_pixmap(self):
    745
    746
    747          fm = QtGui.QFontMetrics(self.font)
    748          height = fm.leading() + fm.overlinePos() + fm.underlinePos()
    749          width  = fm.size(QtCore.Qt.AlignTop, self.seq).width()
    750
    751          self.pixmap = QtGui.QPixmap(width,height)
    752          self.pixmap.fill()
    753          p = QtGui.QPainter(self.pixmap)
    754          x = 0
    755          y = height - fm.underlinePos()*2
    756
    757          p.setFont(self.font)
    758
    759          for letter in self.seq:
    760              letter = letter.upper()
    761              if self.style=="nt":
    762                  letter_brush = QtGui.QBrush(QtGui.QColor(self.ntbg.get(letter,"#ffffff" )))
    763                  letter_pen = QtGui.QPen(QtGui.QColor(self.ntfg.get(letter, "#000000")))
    764              else:
    765                  letter_brush = QtGui.QBrush(QtGui.QColor(self.aabg.get(letter,"#ffffff" )))
    766                  letter_pen = QtGui.QPen(QtGui.QColor(self.aafg.get(letter,"#000000" )))
    767
    768              p.setPen(letter_pen)
    769              p.fillRect(x,0,width, height,letter_brush)
    770              p.drawText(x, y, letter)
    771              x += float(width)/len(self.seq)
    772          p.end()
    773