1 __VERSION__="ete2-2.0rev94"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 from sys import stderr, stdout
26 import time
27 import re
28 import math
29 import random
30 import types
31 import copy
32 import string
33 import numpy
34 try:
35 from PyQt4 import QtCore, QtGui
36 from PyQt4.QtGui import QPrinter
37 except ImportError:
38 import QtCore, QtGui
39 from QtGui import QPrinter
40 import layouts
41 import _mainwindow, _search_dialog, _show_newick, _open_newick, _about
42
43 try:
44 from PyQt4 import QtOpenGL
45
46 USE_GL = False
47 except ImportError:
48 USE_GL = False
49
50 from ete2 import Tree, PhyloTree, ClusterTree
51
52 __all__ = ["show_tree", "render_tree", "TreeImageProperties"]
53
54 DEBUG = 0
55 _QApp = None
56
57 _MIN_NODE_STYLE = {
58 "fgcolor": "#0030c1",
59 "bgcolor": "#FFFFFF",
60 "vt_line_color": "#000000",
61 "hz_line_color": "#000000",
62 "line_type": 0,
63 "vlwidth": 1,
64 "hlwidth": 1,
65 "size":6,
66 "shape": "sphere",
67 "faces": None,
68 "draw_descendants": 1,
69 "ymargin": 0
70 }
74 self.force_topology = False
75 self.draw_branch_length = False
76 self.align_leaf_faces = False
77 self.orientation = 0
78 self.style = 0
79 self.general_font_type = "Verdana"
80 self.branch_length_font_color = "#222"
81 self.branch_length_font_size = 6
82 self.branch_support_font_color = "red"
83 self.branch_support_font_size = 9
84 self.tree_width = 200
85
86 self.min_branch_separation = 1
87 self.search_node_bg = "#cccccc"
88 self.search_node_fg = "#ff0000"
89
91 """ Just to manage how to print messages """
92 msg = map(str, msg)
93
94 if level == -1:
95 print >>stderr,"* Error: ", " ".join(msg)
96
97 elif level == 0:
98 print >>stderr,"* Warning: ", " ".join(msg)
99
100 elif level == 1:
101 if DEBUG == 1:
102 print >>stdout,"* Info: ", " ".join(msg)
103
104 elif level == 2:
105 if DEBUG == 1:
106 print >>stderr,"* Debug: ", " ".join(msg)
107 else:
108 print >>stderr,"* ", " ".join(msg)
109 return
110
111 -def show_tree(t, style=None, img_properties=None):
112 """ Interactively shows a tree."""
113 global _QApp
114
115 if not style:
116 if t.__class__ == PhyloTree:
117 style = "phylogeny"
118 elif t.__class__ == ClusterTree:
119 style = "large"
120 else:
121 style = "basic"
122
123 if not _QApp:
124 _QApp = QtGui.QApplication(["ETE"])
125
126 scene = _TreeScene()
127 mainapp = _MainApp(scene)
128
129
130 if not img_properties:
131 img_properties = TreeImageProperties()
132 scene.initialize_tree_scene(t, style, \
133 tree_properties=img_properties)
134 scene.draw()
135
136 mainapp.show()
137 _QApp.exec_()
138
139 -def render_tree(t, imgName, w=None, h=None, style=None, \
140 img_properties = None, header=None):
141 """ Render tree image into a PNG file."""
142
143 if not style:
144 if t.__class__ == PhyloTree:
145 style = "phylogeny"
146 elif t.__class__ == ClusterTree:
147 style = "large"
148 else:
149 style = "basic"
150
151
152 global _QApp
153 if not _QApp:
154 _QApp = QtGui.QApplication(["ETE"])
155
156 scene = _TreeScene()
157 if not img_properties:
158 img_properties = TreeImageProperties()
159 scene.initialize_tree_scene(t, style,
160 tree_properties=img_properties)
161 scene.draw()
162 scene.save(imgName, w=w, h=h, header=header)
163
164
165
166
167
168
169
170
171
172 -class NewickDialog(QtGui.QDialog):
174 QtGui.QDialog.__init__(self, *args)
175 self.node = node
176
178 f= int(self._conf.nwFormat.currentText())
179 self._conf.features_list.selectAll()
180 if self._conf.useAllFeatures.isChecked():
181 features = []
182 elif self._conf.features_list.count()==0:
183 features = None
184 else:
185 features = set()
186 for i in self._conf.features_list.selectedItems():
187 features.add(str(i.text()))
188
189 nw = self.node.write(format=f, features=features)
190 self._conf.newickBox.setText(nw)
191
193 aName = str(self._conf.attrName.text()).strip()
194 if aName != '':
195 self._conf.features_list.addItem( aName)
196 self.update_newick()
198 r = self._conf.features_list.currentRow()
199 self._conf.features_list.takeItem(r)
200 self.update_newick()
201
203 state = self._conf.useAllFeatures.isChecked()
204 self._conf.features_list.setDisabled(state)
205 self._conf.attrName.setDisabled(state)
206 self.update_newick()
207
208 -class _MainApp(QtGui.QMainWindow):
209 - def __init__(self, scene, *args):
210 QtGui.QMainWindow.__init__(self, *args)
211 self.scene = scene
212 self.view = _MainView(scene)
213 scene.view = self.view
214 _mainwindow.Ui_MainWindow().setupUi(self)
215 scene.view = self.view
216 self.view.centerOn(0,0)
217 splitter = QtGui.QSplitter()
218 splitter.addWidget(self.view)
219 splitter.addWidget(scene.propertiesTable)
220 self.setCentralWidget(splitter)
221
222
223 self.searchDialog = QtGui.QDialog()
224
225
226 self.searchDialog._conf = _search_dialog.Ui_Dialog()
227 self.searchDialog._conf.setupUi(self.searchDialog)
228
229
230 @QtCore.pyqtSignature("")
232 try:
233 __VERSION__
234 except:
235 __VERSION__= "developmnet branch"
236
237 d = QtGui.QDialog()
238 d._conf = _about.Ui_About()
239 d._conf.setupUi(d)
240 d._conf.version.setText("Version: %s" %__VERSION__)
241 d._conf.version.setAlignment(QtCore.Qt.AlignHCenter)
242 d.exec_()
243
244 @QtCore.pyqtSignature("")
246 self.view.safe_scale(0.8,0.8)
247
248 @QtCore.pyqtSignature("")
250 self.view.safe_scale(1.2,1.2)
251
252 @QtCore.pyqtSignature("")
254 self.scene.props.tree_width += 20
255 self.scene.draw()
256
257 @QtCore.pyqtSignature("")
259 if self.scene.props.tree_width >20:
260 self.scene.props.tree_width -= 20
261 self.scene.draw()
262
263 @QtCore.pyqtSignature("")
265 if self.scene.props.min_branch_separation < \
266 self.scene.min_real_branch_separation:
267 self.scene.props.min_branch_separation = \
268 self.scene.min_real_branch_separation
269 self.scene.props.min_branch_separation += 5
270 self.scene.draw()
271
272 @QtCore.pyqtSignature("")
274 if self.scene.props.min_branch_separation > 5:
275 self.scene.props.min_branch_separation -= 5
276 self.scene.draw()
277
278 @QtCore.pyqtSignature("")
280 self.view.fitInView(self.scene.sceneRect(), QtCore.Qt.KeepAspectRatio)
281
282 @QtCore.pyqtSignature("")
284 if self.scene.highlighter.isVisible():
285 R = self.scene.highlighter.rect()
286 else:
287 R = self.scene.selector.rect()
288 if R.width()>0 and R.height()>0:
289
290
291 self.view.fitInView(R.x(), R.y(), R.width(),\
292 R.height(), QtCore.Qt.KeepAspectRatio)
293
294 @QtCore.pyqtSignature("")
296 ok = self.searchDialog.exec_()
297 if ok:
298 setup = self.searchDialog._conf
299 mType = setup.attrType.currentIndex()
300 aName = str(setup.attrName.text())
301 if mType >= 2 and mType <=6:
302 try:
303 aValue = float(setup.attrValue.text())
304 except ValueError:
305 QtGui.QMessageBox.information(self, "!",\
306 "A numeric value is expected")
307 return
308 elif mType == 7:
309 aValue = re.compile(str(setup.attrValue.text()))
310 elif mType == 0 or mType == 1:
311 aValue = str(setup.attrValue.text())
312
313 if mType == 0 or mType == 2:
314 cmpFn = lambda x,y: x == y
315 elif mType == 1:
316 cmpFn = lambda x,y: y in x
317 elif mType == 3:
318 cmpFn = lambda x,y: x >= y
319 elif mType == 4:
320 cmpFn = lambda x,y: x > y
321 elif mType == 5:
322 cmpFn = lambda x,y: x <= y
323 elif mType == 6:
324 cmpFn = lambda x,y: x < y
325 elif mType == 7:
326 cmpFn = lambda x,y: re.search(y, x)
327
328 for n in self.scene.startNode.traverse():
329 if setup.leaves_only.isChecked() and not n.is_leaf():
330 continue
331 if hasattr(n, aName) \
332 and cmpFn(getattr(n, aName), aValue ):
333 self.scene.highlight_node(n)
334
335 @QtCore.pyqtSignature("")
337
338 for n in self.scene._highlighted_nodes.keys():
339 self.scene.unhighlight_node(n)
340
341 @QtCore.pyqtSignature("")
343 self.scene.props.draw_branch_length ^= True
344 self.scene.draw()
345
346 @QtCore.pyqtSignature("")
348 self.scene.props.force_topology ^= True
349 self.scene.draw()
350
351 @QtCore.pyqtSignature("")
353 d = NewickDialog(self.scene.startNode)
354 d._conf = _show_newick.Ui_Newick()
355 d._conf.setupUi(d)
356 d.update_newick()
357 d.exec_()
358
359 @QtCore.pyqtSignature("")
361 self.scene.props.orientation ^= 1
362 self.scene.draw()
363
364 @QtCore.pyqtSignature("")
366 self.scene.props.style = 0
367 self.scene.draw()
368
369 @QtCore.pyqtSignature("")
371 self.scene.props.style = 1
372 self.scene.draw()
373
374 @QtCore.pyqtSignature("")
376
377 d = QtGui.QFileDialog()
378 d._conf = _open_newick.Ui_OpenNewick()
379 d._conf.setupUi(d)
380 d.exec_()
381 return
382
383
384 fname = QtGui.QFileDialog.getOpenFileName(self ,"Open File",
385 "/home",
386 )
387
388
389 try:
390 t = Tree(str(fname))
391 except Exception, e:
392 print e
393 else:
394 self.scene.initialize_tree_scene(t, "basic", TreeImageProperties())
395 self.scene.draw()
396
397 @QtCore.pyqtSignature("")
399 fname = QtGui.QFileDialog.getSaveFileName(self ,"Save File",
400 "/home",
401 "Newick (*.nh *.nhx *.nw )")
402 nw = self.scene.startNode.write()
403 try:
404 OUT = open(fname,"w")
405 except Exception, e:
406 print e
407 else:
408 OUT.write(nw)
409 OUT.close()
410
411 @QtCore.pyqtSignature("")
413 F = QtGui.QFileDialog(self)
414 if F.exec_():
415 imgName = str(F.selectedFiles()[0])
416 if not imgName.endswith(".pdf"):
417 imgName += ".pdf"
418 self.scene.save(imgName)
419
420
421 @QtCore.pyqtSignature("")
423 if not self.scene.selector.isVisible():
424 return QtGui.QMessageBox.information(self, "!",\
425 "You must select a region first")
426
427 F = QtGui.QFileDialog(self)
428 if F.exec_():
429 imgName = str(F.selectedFiles()[0])
430 if not imgName.endswith(".pdf"):
431 imgName += ".pdf"
432 self.scene.save(imgName, take_region=True)
433
434
435 @QtCore.pyqtSignature("")
437 text,ok = QtGui.QInputDialog.getText(self,\
438 "Paste Newick",\
439 "Newick:")
440 if ok:
441 try:
442 t = Tree(str(text))
443 except Exception,e:
444 print e
445 else:
446 self.scene.initialize_tree_scene(t,"basic", TreeImageProperties())
447 self.scene.draw()
448
449
450
451
452
453 -class _TableItem(QtGui.QItemDelegate):
455 QtGui.QItemDelegate.__init__(self, parent)
456 self.propdialog = parent
457
458 - def paint(self, painter, option, index):
459 self.propdialog.tableView.setRowHeight(index.row(), 18)
460 QtGui.QItemDelegate.paint(self, painter, option, index)
461
463
464 if index.column() != 1:
465 logger(2, "NOT EDITABLE COLUMN")
466 return None
467
468 originalValue = index.model().data(index)
469 if not self.isSupportedType(originalValue.type()):
470 logger(2, "data type not suppoerted for editting")
471 return None
472
473 if re.search("^#[0-9ABCDEFabcdef]{6}$",str(originalValue.toString())):
474 origc = QtGui.QColor(str(originalValue.toString()))
475 color = QtGui.QColorDialog.getColor(origc)
476 if color.isValid():
477 self.propdialog._edited_indexes.add( (index.row(), index.column()) )
478 index.model().setData(index,QtCore.QVariant(color.name()))
479 self.propdialog.apply_changes()
480
481 return None
482 else:
483 editField = QtGui.QLineEdit(parent)
484 editField.setFrame(False)
485 validator = QtGui.QRegExpValidator(QtCore.QRegExp(".+"), editField)
486 editField.setValidator(validator)
487 self.connect(editField, QtCore.SIGNAL("returnPressed()"),
488 self.commitAndCloseEditor)
489 self.connect(editField, QtCore.SIGNAL("returnPressed()"),
490 self.propdialog.apply_changes)
491 self.propdialog._edited_indexes.add( (index.row(), index.column()) )
492 return editField
493
495 value = index.model().data(index)
496 if editor is not None:
497 editor.setText(self.displayText(value))
498
501
502 isSupportedType = staticmethod(isSupportedType)
503 - def displayText(self,value):
504 return value.toString()
505
507 editor = self.sender()
508 self.emit(QtCore.SIGNAL("commitData(QWidget *)"), editor)
509 self.emit(QtCore.SIGNAL("closeEditor(QWidget *)"), editor)
510
514
517 QtGui.QWidget.__init__(self,*args)
518 self.scene = scene
519 self._mode = 0
520 self.layout = QtGui.QVBoxLayout()
521 self.tableView = QtGui.QTableView()
522 self.tableView.verticalHeader().setVisible(False)
523 self.tableView.horizontalHeader().setVisible(False)
524 self.tableView.setVerticalHeader(None)
525 self.layout.addWidget(self.tableView)
526 self.setLayout(self.layout)
527 self.tableView.setGeometry ( 0, 0, 200,200 )
528
529
531 self.node = node
532 self._edited_indexes = set([])
533 self._style_indexes = set([])
534 self._prop_indexes = set([])
535
536 self.get_prop_table(node)
537
539
540 self.prop2nodes = {}
541 self.prop2values = {}
542 self.style2nodes = {}
543 self.style2values = {}
544
545 for n in nodes:
546 for pname in n.features:
547 pvalue = getattr(n,pname)
548 if type(pvalue) == int or \
549 type(pvalue) == float or \
550 type(pvalue) == str :
551 self.prop2nodes.setdefault(pname,[]).append(n)
552 self.prop2values.setdefault(pname,[]).append(pvalue)
553
554 for pname,pvalue in n.img_style.iteritems():
555 if type(pvalue) == int or \
556 type(pvalue) == float or \
557 type(pvalue) == str :
558 self.style2nodes.setdefault(pname,[]).append(n)
559 self.style2values.setdefault(pname,[]).append(pvalue)
560
562 if self._mode == 0:
563 self.get_props_in_nodes([node])
564 elif self._mode == 1:
565 self.get_props_in_nodes(node.get_leaves())
566 elif self._mode == 2:
567 self.get_props_in_nodes([node]+node.get_descendants())
568
569 total_props = len(self.prop2nodes) + len(self.style2nodes.keys())
570 self.model = QtGui.QStandardItemModel(total_props, 2)
571
572 self.tableView.setModel(self.model)
573 self.delegate = _TableItem(self)
574 self.tableView.setItemDelegate(self.delegate)
575
576 row = 0
577 for name,nodes in self.prop2nodes.iteritems():
578 value= getattr(nodes[0],name)
579
580 index1 = self.model.index(row, 0, QtCore.QModelIndex())
581 index2 = self.model.index(row, 1, QtCore.QModelIndex())
582
583 self.model.setData(index1, QtCore.QVariant(name))
584 v = QtCore.QVariant(value)
585 self.model.setData(index2, v)
586
587 self._prop_indexes.add( (index1, index2) )
588 row +=1
589
590 for name in self.style2nodes.iterkeys():
591 value= self.style2values[name][0]
592
593 index1 = self.model.index(row, 0, QtCore.QModelIndex())
594 index2 = self.model.index(row, 1, QtCore.QModelIndex())
595
596 self.model.setData(index1, QtCore.QVariant(name))
597 v = QtCore.QVariant(value)
598 self.model.setData(index2, v)
599
600 self._style_indexes.add( (index1, index2) )
601 row +=1
602 return
603
605
606 for i1, i2 in self._style_indexes:
607 if (i2.row(), i2.column()) not in self._edited_indexes:
608 continue
609 name = str(self.model.data(i1).toString())
610 value = str(self.model.data(i2).toString())
611 for n in self.style2nodes[name]:
612 typedvalue = type(n.img_style[name])(value)
613 try:
614 n.img_style[name] = typedvalue
615 except:
616 logger(-1, "Wrong format for attribute:", name)
617 break
618
619
620 for i1, i2 in self._prop_indexes:
621 if (i2.row(), i2.column()) not in self._edited_indexes:
622 continue
623 name = str(self.model.data(i1).toString())
624 value = str(self.model.data(i2).toString())
625 for n in self.prop2nodes[name]:
626 try:
627 setattr(n, name, type(getattr(n,name))(value))
628 except Exception, e:
629 logger(-1, "Wrong format for attribute:", name)
630 print e
631 break
632 self.update_properties(self.node)
633 self.scene.draw()
634 return
635
636 -class _TextItem(QtGui.QGraphicsSimpleTextItem):
637 """ Manage faces on Scene"""
638 - def __init__(self,face,node,*args):
639 QtGui.QGraphicsSimpleTextItem.__init__(self,*args)
640 self.node = node
641 self.face = face
642
643 - def hoverEnterEvent (self,e):
644
645
646
647 R = self.node.fullRegion.getRect()
648 if self.scene().props.orientation == 0:
649 width = self.scene().i_width-self.node._x
650 self.scene().highlighter.setRect(QtCore.QRectF(self.node._x,self.node._y,width,R[3]))
651 elif self.scene().props.orientation == 1:
652 width = self.node._x-self.scene().i_width
653 self.scene().highlighter.setRect(QtCore.QRectF(width,self.node._y,width,R[3]))
654 self.scene().highlighter.setVisible(True)
655
656 - def hoverLeaveEvent (self,e):
657 self.scene().highlighter.setVisible(False)
658
659 - def mousePressEvent(self,e):
661
662 - def mouseReleaseEvent(self,e):
663 logger(2,"released in scene", e.button)
664 if e.button() == QtCore.Qt.RightButton:
665 self.node._QtItem_.showActionPopup()
666 elif e.button() == QtCore.Qt.LeftButton:
667 self.scene().propertiesTable.update_properties(self.node)
668
669
670 -class _FaceItem(QtGui.QGraphicsPixmapItem):
671 """ Manage faces on Scene"""
673 QtGui.QGraphicsPixmapItem.__init__(self,*args)
674 self.node = node
675 self.face = face
676
678
679
680
681 R = self.node.fullRegion.getRect()
682 if self.scene().props.orientation == 0:
683 width = self.scene().i_width-self.node._x
684 self.scene().highlighter.setRect(QtCore.QRectF(self.node._x,self.node._y,width,R[3]))
685 elif self.scene().props.orientation == 1:
686 width = self.node._x-self.scene().i_width
687 self.scene().highlighter.setRect(QtCore.QRectF(width,self.node._y,width,R[3]))
688 self.scene().highlighter.setVisible(True)
689
691 self.scene().highlighter.setVisible(False)
692
695
697 logger(2,"released in scene", e.button)
698 if e.button() == QtCore.Qt.RightButton:
699 self.node._QtItem_.showActionPopup()
700 elif e.button() == QtCore.Qt.LeftButton:
701 self.scene().propertiesTable.update_properties(self.node)
702
703
704 -class _NodeItem(QtGui.QGraphicsRectItem):
706 self.node = node
707 self.radius = node.img_style["size"]/2
708 QtGui.QGraphicsRectItem.__init__(self,0,0,self.radius*2,self.radius*2)
709
710 - def paint(self, p, option, widget):
711 if self.node.img_style["shape"] == "sphere":
712 r = self.radius
713 gradient = QtGui.QRadialGradient(r, r, r,(r*2)/3,(r*2)/3)
714 gradient.setColorAt(0.05, QtCore.Qt.white);
715 gradient.setColorAt(0.9, QtGui.QColor(self.node.img_style["fgcolor"]));
716 p.setBrush(QtGui.QBrush(gradient))
717 p.setPen(QtCore.Qt.NoPen)
718 p.drawEllipse(self.rect())
719 elif self.node.img_style["shape"] == "square":
720 p.fillRect(self.rect(),QtGui.QBrush(QtGui.QColor(self.node.img_style["fgcolor"])))
721 elif self.node.img_style["shape"] == "circle":
722 p.setBrush(QtGui.QBrush(QtGui.QColor(self.node.img_style["fgcolor"])))
723 p.setPen(QtGui.QPen(QtGui.QColor(self.node.img_style["fgcolor"])))
724 p.drawEllipse(self.rect())
725
726
728 R = self.node.fullRegion.getRect()
729 if self.scene().props.orientation == 0:
730 width = self.scene().i_width-self.node._x
731 self.scene().highlighter.setRect(QtCore.QRectF(self.node._x,self.node._y,width,R[3]))
732 elif self.scene().props.orientation == 1:
733 width = self.node._x-self.scene().i_width
734 self.scene().highlighter.setRect(QtCore.QRectF(width,self.node._y,width,R[3]))
735 self.scene().highlighter.setVisible(True)
736
738 self.scene().highlighter.setVisible(False)
739
741 logger(2,"Pressed in scene", e.button)
742
744 logger(2,"released in scene", e.button)
745 if e.button() == QtCore.Qt.RightButton:
746 self.showActionPopup()
747 elif e.button() == QtCore.Qt.LeftButton:
748 self.scene().propertiesTable.update_properties(self.node)
749
750
752 contextMenu = QtGui.QMenu()
753 if self.node.collapsed:
754 contextMenu.addAction( "Expand" , self.toggle_collapse)
755 else:
756 contextMenu.addAction( "Collapse" , self.toggle_collapse)
757
758 contextMenu.addAction( "Set as outgroup" , self.set_as_outgroup)
759 contextMenu.addAction( "Swap branches" , self.swap_branches)
760 contextMenu.addAction( "Delete node" , self.delete_node)
761 contextMenu.addAction( "Delete partition" , self.detach_node)
762 contextMenu.addAction( "Add childs" , self.add_childs)
763 contextMenu.addAction( "Populate partition" , self.populate_partition)
764 if self.node.up is not None and\
765 self.scene().startNode == self.node:
766 contextMenu.addAction( "Back to parent", self.back_to_parent_node)
767 else:
768 contextMenu.addAction( "Extract" , self.set_start_node)
769
770 if self.scene().buffer_node:
771 contextMenu.addAction( "Paste partition" , self.paste_partition)
772
773 contextMenu.addAction( "Cut partition" , self.cut_partition)
774 contextMenu.addAction( "Show newick" , self.show_newick)
775 contextMenu.exec_(QtGui.QCursor.pos())
776
784
788
792
796
798 n,ok = QtGui.QInputDialog.getInteger(None,"Add childs","Number of childs to add:",1,1)
799 if ok:
800 for i in xrange(n):
801 ch = self.node.add_child()
802 self.scene().set_style_from(self.scene().startNode,self.scene().layout_func)
803
805 logger(0,"Not implemented yet")
806 return True
807
809 self.scene().startNode.set_outgroup(self.node)
810 self.scene().set_style_from(self.scene().startNode, self.scene().layout_func)
811 self.scene().draw()
812
814 self.node.collapsed ^= True
815 self.scene().draw()
816
818 self.scene().buffer_node = self.node
819 self.node.detach()
820 self.scene().draw()
821
823 if self.scene().buffer_node:
824 self.node.add_child(self.scene().buffer_node)
825 self.scene().set_style_from(self.scene().startNode,self.scene().layout_func)
826 self.scene().buffer_node= None
827 self.scene().draw()
828
830 n, ok = QtGui.QInputDialog.getInteger(None,"Populate partition","Number of nodes to add:",2,1)
831 if ok:
832 self.node.populate(n)
833 self.scene().set_style_from(self.scene().startNode,self.scene().layout_func)
834 self.scene().draw()
835
837 self.scene().startNode = self.node
838 self.scene().draw()
839
841 self.scene().startNode = self.node.up
842 self.scene().draw()
843
847 self.Color = QtGui.QColor("blue")
848 self._active = False
849 QtGui.QGraphicsRectItem.__init__(self,0,0,0,0)
850
851 - def paint(self, p, option, widget):
852 p.setPen(self.Color)
853 p.drawRect(self.rect().x(),self.rect().y(),self.rect().width(),self.rect().height())
854 return
855
856 font = QtGui.QFont("Arial",13)
857 text = "%d selected." % len(self.get_selected_nodes())
858 textR = QtGui.QFontMetrics(font).boundingRect(text)
859 if self.rect().width() > textR.width() and \
860 self.rect().height() > textR.height()/2 and 0:
861 p.setPen(QtGui.QPen(self.Color))
862 p.setFont(QtGui.QFont("Arial",13))
863 p.drawText(self.rect().bottomLeft().x(),self.rect().bottomLeft().y(),text)
864
866 selPath = QtGui.QPainterPath()
867 selPath.addRect(self.rect())
868 self.scene().setSelectionArea(selPath)
869 return [i.node for i in self.scene().selectedItems()]
870
873
876
880 self.Color = QtGui.QColor("red")
881 self._active = False
882 QtGui.QGraphicsRectItem.__init__(self,0,0,0,0)
883
884 - def paint(self, p, option, widget):
885 p.setPen(self.Color)
886 p.drawRect(self.rect().x(),self.rect().y(),self.rect().width(),self.rect().height())
887 return
888
889
890
891 -class _MainView(QtGui.QGraphicsView):
892 - def __init__(self,*args):
893 QtGui.QGraphicsView.__init__(self,*args)
894
895
896
897
898
899
900 if USE_GL:
901 F = QtOpenGL.QGLFormat()
902 F.setSampleBuffers(True)
903 print F.sampleBuffers()
904 self.setViewport(QtOpenGL.QGLWidget(F))
905 self.setRenderHints(QtGui.QPainter.Antialiasing)
906 else:
907 self.setRenderHints(QtGui.QPainter.Antialiasing or QtGui.QPainter.SmoothPixmapTransform )
908 self.setViewportUpdateMode(QtGui.QGraphicsView.SmartViewportUpdate)
909
910
911 - def resizeEvent(self, e):
912 QtGui.QGraphicsView.resizeEvent(self, e)
913 logger(2, "RESIZE VIEW!!")
914
915
916 - def safe_scale(self, xfactor, yfactor):
917 self.setTransformationAnchor(self.AnchorUnderMouse)
918
919 xscale = self.matrix().m11()
920 yscale = self.matrix().m22()
921 srect = self.sceneRect()
922
923 if (xfactor>1 and xscale>200000) or \
924 (yfactor>1 and yscale>200000):
925 QtGui.QMessageBox.information(self, "!",\
926 "Hey! I'm not an electron microscope?")
927 return
928
929
930
931 if (yfactor<1 and srect.width() * yscale < 20):
932 pass
933 elif (xfactor<1 and srect.width() * xscale < 20):
934 pass
935 else:
936 self.scale(xfactor, yfactor)
937
938
939 - def wheelEvent(self,e):
940 factor = (-e.delta() / 360.0)
941
942
943 if (e.modifiers() & QtCore.Qt.ControlModifier) and (e.modifiers() & QtCore.Qt.ShiftModifier):
944 self.safe_scale(1+factor, 1)
945
946
947 elif (e.modifiers() & QtCore.Qt.ControlModifier) and (e.modifiers() & QtCore.Qt.AltModifier):
948 self.safe_scale(1,1+factor)
949
950
951 elif e.modifiers() & QtCore.Qt.ControlModifier:
952 self.safe_scale(1-factor, 1-factor)
953
954
955 elif e.modifiers() & QtCore.Qt.ShiftModifier:
956 if e.delta()>0:
957 self.horizontalScrollBar().setValue(self.horizontalScrollBar().value()-20 )
958 else:
959 self.horizontalScrollBar().setValue(self.horizontalScrollBar().value()+20 )
960
961 else:
962 if e.delta()>0:
963 self.verticalScrollBar().setValue(self.verticalScrollBar().value()-20 )
964 else:
965 self.verticalScrollBar().setValue(self.verticalScrollBar().value()+20 )
966
967 - def keyPressEvent(self,e):
968 key = e.key()
969 logger(1, "****** Pressed key: ", key, QtCore.Qt.LeftArrow)
970 if key == QtCore.Qt.Key_Left:
971 self.horizontalScrollBar().setValue(self.horizontalScrollBar().value()-20 )
972 self.update()
973 elif key == QtCore.Qt.Key_Right:
974 self.horizontalScrollBar().setValue(self.horizontalScrollBar().value()+20 )
975 self.update()
976 elif key == QtCore.Qt.Key_Up:
977 self.verticalScrollBar().setValue(self.verticalScrollBar().value()-20 )
978 self.update()
979 elif key == QtCore.Qt.Key_Down:
980 self.verticalScrollBar().setValue(self.verticalScrollBar().value()+20 )
981 self.update()
982 QtGui.QGraphicsView.keyPressEvent(self,e)
983
985 - def __init__(self, rootnode=None, style=None, *args):
986 QtGui.QGraphicsScene.__init__(self,*args)
987
988 self.view = None
989
990 self.buffer_node = None
991 self.layout_func = None
992 self.startNode = rootnode
993 self.scale = 0
994 self.max_w_aligned_face = 0
995 self.min_real_branch_separation = 0
996 self.selectors = []
997 self._highlighted_nodes = {}
998
999
1000 self.selector = None
1001 self.mainItem = None
1002 self.propertiesTable = _PropertiesDialog(self)
1003
1005 self.tree = tree
1006 self.startNode = tree
1007 self.max_w_aligned_face = 0
1008
1009
1010 self.props = tree_properties
1011
1012
1013 if type(style) == types.FunctionType or\
1014 type(style) == types.MethodType:
1015 self.layout_func = style
1016 else:
1017 try:
1018 self.layout_func = getattr(layouts,style)
1019 except:
1020 raise ValueError, "Required layout is not a function pointer nor a valid layout name."
1021
1022
1023 self.setBackgroundBrush(QtGui.QColor("white"))
1024
1025
1026 self.set_style_from(self.startNode,self.layout_func)
1027
1028 self.propertiesTable.update_properties(self.startNode)
1029
1031 self.unhighlight_node(n)
1032 r = QtGui.QGraphicsRectItem(self.mainItem)
1033 self._highlighted_nodes[n] = r
1034
1035 R = n.fullRegion.getRect()
1036 width = self.i_width-n._x
1037 r.setRect(QtCore.QRectF(n._x,n._y,width,R[3]))
1038
1039
1040
1041
1042
1043
1044 r.setZValue(-1)
1045 r.setPen(QtGui.QColor(self.props.search_node_fg))
1046 r.setBrush(QtGui.QColor(self.props.search_node_bg))
1047
1048
1049
1050
1052 if n in self._highlighted_nodes and \
1053 self._highlighted_nodes[n] is not None:
1054 self.removeItem(self._highlighted_nodes[n])
1055 del self._highlighted_nodes[n]
1056
1057
1059 logger(2, "Press en view")
1060 self.selector.setRect(e.scenePos().x(),e.scenePos().y(),0,0)
1061 self.selector.startPoint = QtCore.QPointF(e.scenePos().x(),e.scenePos().y())
1062 self.selector.setActive(True)
1063 self.selector.setVisible(True)
1064 QtGui.QGraphicsScene.mousePressEvent(self,e)
1065
1067 logger(2, "Release en view")
1068 curr_pos = e.scenePos()
1069 x = min(self.selector.startPoint.x(),curr_pos.x())
1070 y = min(self.selector.startPoint.y(),curr_pos.y())
1071 w = max(self.selector.startPoint.x(),curr_pos.x()) - x
1072 h = max(self.selector.startPoint.y(),curr_pos.y()) - y
1073 if self.selector.startPoint == curr_pos:
1074 self.selector.setVisible(False)
1075 else:
1076 logger(2, self.selector.get_selected_nodes())
1077 self.selector.setActive(False)
1078 QtGui.QGraphicsScene.mouseReleaseEvent(self,e)
1079
1081
1082 curr_pos = e.scenePos()
1083 if self.selector.isActive():
1084 x = min(self.selector.startPoint.x(),curr_pos.x())
1085 y = min(self.selector.startPoint.y(),curr_pos.y())
1086 w = max(self.selector.startPoint.x(),curr_pos.x()) - x
1087 h = max(self.selector.startPoint.y(),curr_pos.y()) - y
1088 self.selector.setRect(x,y,w,h)
1089 QtGui.QGraphicsScene.mouseMoveEvent(self, e)
1090
1094
1095 - def save(self, imgName, w=None, h=None, header=None, \
1096 dpi=150, take_region=False):
1097 ext = imgName.split(".")[-1].upper()
1098
1099
1100 root = self.startNode
1101 aspect_ratio = root.fullRegion.height() / root.fullRegion.width()
1102
1103
1104 if w is None and h is None:
1105 w = dpi * 6.4
1106 h = w * aspect_ratio
1107 if h>dpi * 11:
1108 h = dpi * 11
1109 w = h / aspect_ratio
1110
1111 elif h is None:
1112 h = w * aspect_ratio
1113 elif w is None:
1114 w = h / aspect_ratio
1115
1116 if ext == "PDF" or ext == "PS":
1117 format = QPrinter.PostScriptFormat if ext == "PS" else QPrinter.PdfFormat
1118 printer = QPrinter(QPrinter.HighResolution)
1119 printer.setResolution(dpi)
1120 printer.setOutputFormat(format)
1121 printer.setPageSize(QPrinter.A4)
1122
1123 pageTopLeft = printer.pageRect().topLeft()
1124 paperTopLeft = printer.paperRect().topLeft()
1125
1126
1127
1128
1129 topleft = pageTopLeft - paperTopLeft
1130
1131 printer.setFullPage(True);
1132 printer.setOutputFileName(imgName);
1133 pp = QtGui.QPainter(printer)
1134 if header:
1135 pp.setFont(QtGui.QFont("Verdana",12))
1136 pp.drawText(topleft.x(),20, header)
1137 targetRect = QtCore.QRectF(topleft.x(), 20 + (topleft.y()*2), w, h)
1138 else:
1139 targetRect = QtCore.QRectF(topleft.x(), topleft.y()*2, w, h)
1140
1141 if take_region:
1142 self.selector.setVisible(False)
1143 self.render(pp, targetRect, self.selector.rect())
1144 self.selector.setVisible(True)
1145 else:
1146 self.render(pp, targetRect, self.sceneRect())
1147 pp.end()
1148 return
1149 else:
1150 targetRect = QtCore.QRectF(0, 0, w, h)
1151 ii= QtGui.QImage(w, \
1152 h, \
1153 QtGui.QImage.Format_ARGB32)
1154 pp = QtGui.QPainter(ii)
1155 pp.setRenderHint(QtGui.QPainter.Antialiasing )
1156 pp.setRenderHint(QtGui.QPainter.TextAntialiasing)
1157 pp.setRenderHint(QtGui.QPainter.SmoothPixmapTransform)
1158 if take_region:
1159 self.selector.setVisible(False)
1160 self.render(pp, targetRect, self.selector.rect())
1161 self.selector.setVisible(True)
1162 else:
1163 self.render(pp, targetRect, self.sceneRect())
1164 pp.end()
1165 ii.save(imgName)
1166
1167
1169 max_width = 10000
1170 max_height = 10000
1171 if imgName.endswith(".png"):
1172 imgName = ''.join(imgName.split('.')[:-1])
1173
1174 if rect is None:
1175 rect = self.sceneRect()
1176
1177 width = int(rect.width())
1178 height = int(rect.height())
1179
1180 start_x = 0
1181 missing_width = width
1182 counter_column = 1
1183 for w in xrange(start_x, width, max_width):
1184 start_y = 0
1185 missing_height = height
1186 counter_row = 1
1187 for h in xrange(start_y, height, max_height):
1188 chunk_width = min( missing_width, max_width )
1189 chunk_height = min( missing_height, max_height )
1190 temp_rect = QtCore.QRectF( rect.x()+w, \
1191 rect.y()+h,
1192 chunk_width, \
1193 chunk_height )
1194 if chunk_height<=0 or chunk_width <=0:
1195 break
1196 ii= QtGui.QImage(chunk_width, \
1197 chunk_height, \
1198 QtGui.QImage.Format_RGB32)
1199 pp = QtGui.QPainter(ii)
1200 targetRect = QtCore.QRectF(0, 0, temp_rect.width(), temp_rect.height())
1201 self.render(pp, targetRect, temp_rect)
1202 ii.saves("%s-%s_%s.png" %(imgName,counter_row,counter_column))
1203 counter_row += 1
1204
1205 missing_height -= chunk_height
1206 pp.end()
1207 counter_column += 1
1208 missing_width -= chunk_width
1209
1211
1212 if self.mainItem:
1213 self.removeItem(self.mainItem)
1214
1215
1216 for n in self._highlighted_nodes:
1217 self._highlighted_nodes[n] = None
1218
1219
1220 self.mainItem = QtGui.QGraphicsRectItem()
1221 self.addItem(self.mainItem)
1222
1223 self.selector = _SelectorItem()
1224 self.selector.setParentItem(self.mainItem)
1225 self.selector.setVisible(False)
1226 self.selector.setZValue(2)
1227
1228 self.highlighter = _HighlighterItem()
1229 self.highlighter.setParentItem(self.mainItem)
1230 self.highlighter.setVisible(False)
1231 self.highlighter.setZValue(2)
1232 self.min_real_branch_separation = 0
1233
1234
1235 fnode, max_dist = self.startNode.get_farthest_leaf(topology_only=\
1236 self.props.force_topology)
1237
1238 if max_dist>0:
1239 self.scale = self.props.tree_width / max_dist
1240 else:
1241 self.scale = 1
1242
1243
1244 t1 = time.time()
1245 self.update_node_areas(self.startNode)
1246 logger(2, "Ellapsed time for updating node areas:",time.time()-t1)
1247
1248 self.i_width = self.startNode.fullRegion.width()
1249 self.i_height = self.startNode.fullRegion.height()
1250
1251
1252 logger(1, "IMAGE dimension=",self.i_width,"x",self.i_height)
1253
1254 t2 = time.time()
1255 self.render_node(self.startNode,0,0)
1256 logger(2, "Time for rendering", time.time()-t2)
1257
1258
1259 self.i_width += self.max_w_aligned_face
1260
1261 if self.props.orientation == 1:
1262 self.startNode._QtItem_.moveBy(self.max_w_aligned_face,0)
1263
1264
1265
1266
1267
1268
1269 self.add_scale(1 ,self.i_height+4)
1270
1271
1272 for n in self._highlighted_nodes:
1273 self.highlight_node(n)
1274
1275 self.setSceneRect(-2,-2,self.i_width+4,self.i_height+50)
1276 logger(2, "Number of items in scene:", len(self.items()))
1277
1279 size = 50
1280 customPen = QtGui.QPen(QtGui.QColor("black"),1)
1281
1282 line = QtGui.QGraphicsLineItem(self.mainItem)
1283 line2 = QtGui.QGraphicsLineItem(self.mainItem)
1284 line3 = QtGui.QGraphicsLineItem(self.mainItem)
1285 line.setPen(customPen)
1286 line2.setPen(customPen)
1287 line3.setPen(customPen)
1288
1289 line.setLine(x,y+20,size,y+20)
1290 line2.setLine(x,y+15,x,y+25)
1291 line3.setLine(size,y+15,size,y+25)
1292
1293 scale_text = "%0.2f" % float(size/ self.scale)
1294 scale = QtGui.QGraphicsSimpleTextItem(scale_text)
1295 scale.setParentItem(self.mainItem)
1296 scale.setPos(x,y+20)
1297
1298 if self.props.force_topology:
1299 wtext = "Force topology is enabled!\nBranch lengths does not represent original values."
1300 warning_text = QtGui.QGraphicsSimpleTextItem(wtext)
1301 warning_text.setFont( QtGui.QFont("Arial", 8))
1302 warning_text.setBrush( QtGui.QBrush(QtGui.QColor("darkred")))
1303 warning_text.setPos(x, y+32)
1304 warning_text.setParentItem(self.mainItem)
1305
1311
1313 """ This recursive function scans all nodes hunging from the given
1314 root node and calculates the coordinates and room necessary to
1315 draw a rectangular tree. IT reads the face content of each
1316 node, which ones have to be drawn, and how much room they
1317 use. """
1318 child_rects = []
1319
1320 if not node.is_leaf() and node.img_style["draw_descendants"]==1:
1321 for ch in node.children:
1322
1323 rect = self.update_node_areas(ch)
1324 child_rects.append(rect)
1325
1326
1327
1328
1329 if self.props.force_topology:
1330 node.dist_xoffset = 60
1331 else:
1332 node.dist_xoffset = float(node.dist * self.scale)
1333
1334 min_node_height = max(node.img_style["size"], node.img_style["hlwidth"]*2)
1335 max_w = 0
1336 max_aligned_w = 0
1337 max_h = 0
1338
1339 for stack in node.img_style["faces"]:
1340 stack_h = 0
1341 stack_w = 0
1342 aligned_f_w = 0
1343 aligned_f_h = 0
1344 for face in stack:
1345 f, aligned, pixmap = face
1346 if aligned and not node.is_leaf():
1347 continue
1348
1349
1350 f.node = node
1351
1352 if f.type == "pixmap":
1353 f.update_pixmap()
1354 face[2] = f.pixmap
1355
1356 if node.is_leaf() and aligned:
1357 aligned_f_w = max(aligned_f_w, f._width())
1358 aligned_f_h += f._height()
1359 else:
1360 stack_w = max(stack_w, f._width())
1361 stack_h += f._height()
1362
1363 max_aligned_w += aligned_f_w
1364 max_w += stack_w
1365 max_h = numpy.max([aligned_f_h, stack_h, max_h])
1366 max_w +=1
1367
1368 if max_aligned_w > self.max_w_aligned_face:
1369 self.max_w_aligned_face = max_aligned_w
1370
1371
1372 node.facesRegion = QtCore.QRectF(0,0,max_w,max_h)
1373 w = node.dist_xoffset + max_w + node.img_style["size"]
1374 h = max(max_h, min_node_height, self.props.min_branch_separation) + node.img_style["ymargin"]*2
1375 if self.min_real_branch_separation < h:
1376 self.min_real_branch_separation = h
1377
1378 node.nodeRegion = QtCore.QRectF(0,0,w,h)
1379
1380
1381
1382
1383 if not node.is_leaf() and node.img_style["draw_descendants"] == 1:
1384 max_child_w = 0
1385 sum_child_h = 0
1386
1387
1388
1389
1390
1391
1392 node._y_correction = 0
1393 start2 = 0
1394 for ch in node.children:
1395
1396 if ch.fullRegion.width()>max_child_w:
1397 max_child_w = ch.fullRegion.width()
1398
1399 if ch == node.children[0]:
1400 start1 = ch.__center
1401
1402 elif ch == node.children[-1]:
1403 start2 = sum_child_h + ch.__center
1404 sum_child_h += ch.fullRegion.height()
1405
1406
1407
1408
1409
1410 above = (start1 +((start2 - start1)/2.0))
1411 bellow = sum_child_h - above
1412 newh = 0
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423 if above < (h/2):
1424 newh = sum_child_h + ((h/2.0) - above)
1425 node._y_correction = ((h/2.0) - above)
1426 if bellow < h/2:
1427 if newh >0:
1428 newh += ((h/2.0) - bellow)
1429 else:
1430 newh = sum_child_h + ((h/2) - bellow)
1431
1432
1433
1434
1435 if newh == 0:
1436 newh = sum_child_h
1437 h = newh
1438
1439 w += max_child_w
1440
1441
1442
1443 node.__center = (start1 +((start2 - start1)/2.0)) + node._y_correction
1444 else:
1445 node.__center = h/2
1446 node._y_correction = 0
1447
1448
1449 node.fullRegion = QtCore.QRectF(0,0,w,h)
1450
1451
1452 return node.fullRegion
1453
1455 if x and y:
1456 x = node.fullRegion.width()/2
1457 y = node.fullRegion.height()/2
1458 node._QtItem_.setTransform(QtGui.QTransform().translate(x, y).rotate(angle).translate(-x, -y));
1459 else:
1460 node._QtItem_.rotate(angle)
1461
1463 """ Traverse the tree structure and render each node using the
1464 regions, sizes, and faces previously loaded. """
1465
1466
1467 orientation = self.props.orientation
1468 r = node.img_style["size"]/2
1469 fh = node.facesRegion.width()
1470
1471 node._QtItem_ = _NodeItem(node)
1472 node._QtItem_.setAcceptsHoverEvents(True)
1473
1474
1475 if orientation == 1:
1476 if node == self.startNode:
1477 x = self.i_width-x
1478
1479
1480
1481 if node==self.startNode:
1482 node._QtItem_.setParentItem(self.mainItem)
1483 scene_pos = node._QtItem_.pos()
1484 node.scene_pos = scene_pos
1485
1486
1487 node._x = x
1488 node._y = y
1489
1490
1491 if node.img_style["bgcolor"].upper() != "#FFFFFF":
1492 background = QtGui.QGraphicsRectItem(self.mainItem)
1493 background.setZValue(-1000+level)
1494 color = QtGui.QColor(node.img_style["bgcolor"])
1495 background.setBrush(color)
1496 background.setPen(color)
1497 if orientation == 0:
1498 background.setRect(node._x,node._y,self.i_width-node._x+self.max_w_aligned_face,node.fullRegion.height())
1499 elif orientation == 1:
1500 background.setRect(node._x-node.fullRegion.width(),node._y,self.i_width,node.fullRegion.height())
1501
1502 if not node.is_leaf() and node.img_style["draw_descendants"]==1:
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515 next_y = y + node._y_correction
1516 for ch in node.get_children():
1517 dist_to_child = ch.dist * self.scale
1518 if orientation == 0:
1519 next_x = x+node.nodeRegion.width()
1520 elif orientation == 1:
1521 next_x = x-node.nodeRegion.width()
1522
1523 self.render_node(ch,next_x, next_y,level+1)
1524 next_y += ch.fullRegion.height()
1525
1526 node._centered_y = ((node.children[0]._centered_y + node.children[-1]._centered_y)/2)
1527
1528
1529
1530 ch._QtItem_.setParentItem(node._QtItem_)
1531 if orientation == 0:
1532 node._QtItem_.setPos(x+node.dist_xoffset,node._centered_y-node.img_style["size"]/2)
1533 elif orientation == 1:
1534 node._QtItem_.setPos(x-node.dist_xoffset-node.img_style["size"],node._centered_y-node.img_style["size"]/2)
1535 for ch in node.children:
1536 scene_pos = ch._QtItem_.pos()
1537 ch.scene_pos = scene_pos
1538 ch._QtItem_.setParentItem(node._QtItem_)
1539 ch._QtItem_.setPos(node._QtItem_.mapFromScene(scene_pos) )
1540
1541
1542 if node == self.startNode:
1543 y = node._QtItem_.pos().y()+ node.img_style["size"]/2
1544 self.add_branch(self.mainItem,0,y,node.dist_xoffset,y,node.dist,node.support, node.img_style["hz_line_color"], node.img_style["hlwidth"], node.img_style["line_type"])
1545
1546
1547 if self.props.style == 0:
1548 vt_line = QtGui.QGraphicsLineItem(node._QtItem_)
1549 customPen = QtGui.QPen(QtGui.QBrush(QtGui.QColor(node.img_style["vt_line_color"])), node.img_style["vlwidth"])
1550 if node.img_style["line_type"]==1:
1551 customPen.setStyle(QtCore.Qt.DashLine)
1552 vt_line.setPen(customPen)
1553
1554 ch1_y = node._QtItem_.mapFromScene(0,node.children[0]._centered_y).y()
1555 ch2_y = node._QtItem_.mapFromScene(0,node.children[-1]._centered_y).y()
1556
1557
1558 for ch in node.children:
1559 ch_pos = node._QtItem_.mapFromScene(ch._x, ch._centered_y)
1560 if orientation == 0:
1561 self.add_branch(node._QtItem_,fh+r*2,ch_pos.y(),fh+r*2+ch.dist_xoffset ,ch_pos.y(),ch.dist, ch.support, ch.img_style["hz_line_color"], ch.img_style["hlwidth"], ch.img_style["line_type"])
1562 elif orientation == 1:
1563 self.add_branch(node._QtItem_,-fh,ch_pos.y(),-fh-ch.dist_xoffset ,ch_pos.y(),ch.dist,ch.support,ch.img_style["hz_line_color"], ch.img_style["hlwidth"], ch.img_style["line_type"])
1564
1565 if orientation == 0:
1566 vt_line.setLine(fh+r*2,ch1_y,fh+(r*2),ch2_y)
1567 elif orientation == 1:
1568 vt_line.setLine(-fh,ch1_y,-fh,ch2_y)
1569
1570
1571 elif self.props.style == 1:
1572
1573 for ch in node.children:
1574 if orientation == 0:
1575 ch_x = ch._QtItem_.x()
1576 ch_y = ch._QtItem_.y()+ch.img_style["size"]/2
1577 self.add_branch(node._QtItem_,fh+node.img_style["size"],r,ch_x,ch_y,ch.dist,ch.support, ch.img_style["hz_line_color"], 1, ch.img_style["line_type"])
1578 elif orientation == 1:
1579 ch_x = ch._QtItem_.x()
1580 ch_y = ch._QtItem_.y()+ch.img_style["size"]/2
1581 self.add_branch(node._QtItem_,-fh,r,ch_x+(r*2),ch_y,ch.dist,ch.support, ch.img_style["hz_line_color"], 1, ch.img_style["line_type"])
1582
1583 self.add_faces(node,orientation)
1584
1585 else:
1586
1587 node._centered_y = y+node.fullRegion.height()/2
1588 if orientation == 0:
1589 node._QtItem_.setPos(x+node.dist_xoffset, node._centered_y-r)
1590 elif orientation == 1:
1591 node._QtItem_.setPos(x-node.dist_xoffset-node.img_style["size"], node._centered_y-r)
1592
1593 self.add_faces(node,orientation)
1594
1595 - def add_branch(self,parent_item,x1,y1,x2,y2,dist,support,color,width,line_type):
1596 hz_line = QtGui.QGraphicsLineItem(parent_item)
1597 customPen = QtGui.QPen(QtGui.QBrush(QtGui.QColor(color)), width)
1598 if line_type == 1:
1599 customPen.setStyle(QtCore.Qt.DashLine)
1600 hz_line.setPen(customPen)
1601 hz_line.setLine(x1,y1,x2,y2)
1602
1603 if self.props.draw_branch_length:
1604 distText = "%0.3f" % dist
1605 if support is not None:
1606 distText += "(%0.2f)" % support
1607 font = QtGui.QFont(self.props.general_font_type,self.props.branch_length_font_size)
1608 rect = QtGui.QFontMetrics(font).boundingRect(0,0,0,0,QtCore.Qt.AlignTop,distText)
1609 b_length = QtGui.QGraphicsSimpleTextItem(distText)
1610 b_length.setFont(font)
1611 b_length.setBrush(QtGui.QColor(self.props.branch_length_font_color))
1612 b_length.setParentItem(hz_line)
1613 b_length.setPos(x1,y1)
1614 if y1 != y2:
1615 offset = 0
1616 angle = math.atan((y2-y1)/(x2-x1))*360/ (2*math.pi)
1617 if y1>y2:
1618 offset = rect.height()
1619 b_length.setTransform(QtGui.QTransform().translate(0, y1-offset).rotate(angle).translate(0,-y1));
1620
1622
1623 r = node.img_style["size"]/2
1624
1625
1626 if orientation==0:
1627 aligned_start_x = node._QtItem_.mapFromScene(self.i_width,0).x()
1628 start_x = node.img_style["size"]
1629 elif orientation==1:
1630 start_x = 0
1631 aligned_start_x = node._QtItem_.mapFromScene(0,0).x()
1632
1633 for stack in node.img_style["faces"]:
1634
1635 stack_h = 0
1636 stack_w = 0
1637 aligned_stack_w = 0
1638 aligned_stack_h = 0
1639
1640
1641 for f, aligned, pixmap in stack:
1642 if aligned and not node.is_leaf():
1643 continue
1644 f.node = node
1645 if node.is_leaf() and aligned:
1646 aligned_stack_w = max(aligned_stack_w , f._width())
1647 aligned_stack_h += f._height()
1648 else:
1649 stack_w = max(stack_w ,f._width() )
1650 stack_h += f._height()
1651
1652
1653 cumulated_y = 0
1654 cumulated_aligned_y = 0
1655 for j, face in enumerate(stack):
1656 f, aligned, pixmap = face
1657 if aligned and not node.is_leaf():
1658 continue
1659
1660 f.node = node
1661
1662 if node.is_leaf() and aligned:
1663 start_y = cumulated_aligned_y + (-aligned_stack_h/2)+r
1664 else:
1665 start_y = cumulated_y - (stack_h/2) +r
1666
1667
1668 if f.type == "text":
1669 obj = _TextItem(f, node, f.get_text())
1670 obj.setFont(f.font)
1671 obj.setBrush(QtGui.QBrush(f.fgcolor))
1672 obj.setParentItem(node._QtItem_)
1673 obj.setAcceptsHoverEvents(True)
1674
1675
1676
1677
1678
1679 else:
1680
1681 obj = _FaceItem(f, node, pixmap)
1682 obj.setAcceptsHoverEvents(True)
1683 obj.setParentItem(node._QtItem_)
1684
1685
1686
1687 if node.is_leaf() and aligned:
1688
1689 if orientation ==0:
1690 obj.setPos(aligned_start_x + f.xmargin, start_y)
1691 elif orientation ==1:
1692 obj.setPos(aligned_start_x-f._width() - f.xmargin , start_y)
1693 cumulated_aligned_y += f._height()
1694
1695 else:
1696
1697 if orientation ==0:
1698 obj.setPos(start_x, start_y)
1699 elif orientation ==1:
1700 obj.setPos(start_x-f._width(),start_y)
1701 cumulated_y += f._height()
1702
1703
1704 if orientation == 0:
1705 start_x += stack_w
1706 aligned_start_x += aligned_stack_w
1707 elif orientation ==1:
1708 start_x -= stack_w
1709 aligned_start_x -= aligned_start_x
1710