Ignore:
Location:
Orange/OrangeWidgets
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • Orange/OrangeWidgets/Data/OWDataTable.py

    r11096 r11358  
    22<name>Data Table</name> 
    33<description>Shows data in a spreadsheet.</description> 
    4 <icon>icons/DataTable.png</icon> 
     4<icon>icons/DataTable.svg</icon> 
    55<priority>100</priority> 
    66<contact>Peter Juvan (peter.juvan@fri.uni-lj.si)</contact> 
  • Orange/OrangeWidgets/Unsupervised/OWHierarchicalClustering.py

    r11217 r11357  
    11""" 
    22<name>Hierarchical Clustering</name> 
    3 <description>Hierarchical clustering based on distance matrix, and a dendrogram viewer.</description> 
     3<description>Hierarchical clustering based on distance matrix, and 
     4a dendrogram viewer.</description> 
    45<icon>icons/HierarchicalClustering.svg</icon> 
    5 <contact>Ales Erjavec (ales.erjavec(@at@)fri.uni-lj.si)</contact>  
     6<contact>Ales Erjavec (ales.erjavec(@at@)fri.uni-lj.si)</contact> 
    67<priority>2100</priority> 
    78""" 
    89from __future__ import with_statement 
    910 
    10 from OWWidget import * 
     11import sys 
     12import os 
     13from operator import add 
     14 
     15import numpy 
     16 
     17from PyQt4.QtGui import * 
     18from PyQt4.QtCore import * 
     19from PyQt4.QtSvg import QSvgGenerator 
     20 
     21from OWWidget import OWWidget, DomainContextHandler, ContextField 
    1122from OWQCanvasFuncts import * 
    1223import OWClustering 
    1324import OWGUI 
    1425import OWColorPalette 
    15 import math 
    16 import numpy 
    17 import os 
    18  
    19 import orange 
    20 from Orange.clustering import hierarchical  
    2126 
    2227from OWDlgs import OWChooseImageSizeDlg 
    23  
    24 from PyQt4.QtCore import * 
    25 from PyQt4.QtGui import * 
     28from OWGraphics import GraphicsSimpleTextList 
     29 
     30import Orange 
     31from Orange.clustering import hierarchical 
     32 
    2633 
    2734class OWHierarchicalClustering(OWWidget): 
    2835    settingsList = ["Linkage", "Annotation", "PrintDepthCheck", 
    29                     "PrintDepth", "HDSize", "VDSize", "ManualHorSize","AutoResize", 
    30                     "TextSize", "LineSpacing", "SelectionMode", 
    31                     "AppendClusters", "CommitOnChange", "ClassifyName", "addIdAs"] 
    32      
    33     contextHandlers={"":DomainContextHandler("", [ContextField("Annotation", DomainContextHandler.Required)])} 
    34      
     36                    "PrintDepth", "HDSize", "VDSize", "ManualHorSize", 
     37                    "AutoResize", "TextSize", "LineSpacing", "SelectionMode", 
     38                    "AppendClusters", "CommitOnChange", "ClassifyName", 
     39                    "addIdAs"] 
     40 
     41    contextHandlers = { 
     42        "": DomainContextHandler( 
     43            "", [ContextField("Annotation", DomainContextHandler.Required)] 
     44        ) 
     45    } 
     46 
    3547    def __init__(self, parent=None, signalManager=None): 
    36         OWWidget.__init__(self, parent, signalManager, 'Hierarchical Clustering', wantGraph=True) 
    37          
    38         self.inputs = [("Distances", orange.SymMatrix, self.set_matrix)] 
    39         self.outputs = [("Selected Data", ExampleTable), ("Other Data", ExampleTable), ("Centroids", ExampleTable)] 
    40         self.linkage = [("Single linkage", orange.HierarchicalClustering.Single), 
    41                         ("Average linkage", orange.HierarchicalClustering.Average), 
    42                         ("Ward's linkage", orange.HierarchicalClustering.Ward), 
    43                         ("Complete linkage", orange.HierarchicalClustering.Complete), 
    44                        ] 
     48        OWWidget.__init__(self, parent, signalManager, 
     49                          'Hierarchical Clustering', wantGraph=True) 
     50 
     51        self.inputs = [("Distances", Orange.misc.SymMatrix, self.set_matrix)] 
     52 
     53        self.outputs = [("Selected Data", Orange.data.Table), 
     54                        ("Other Data", Orange.data.Table), 
     55                        ("Centroids", Orange.data.Table)] 
     56 
     57        self.linkage = [ 
     58            ("Single linkage", hierarchical.HierarchicalClustering.Single), 
     59            ("Average linkage", hierarchical.HierarchicalClustering.Average), 
     60            ("Ward's linkage", hierarchical.HierarchicalClustering.Ward), 
     61            ("Complete linkage", hierarchical.HierarchicalClustering.Complete), 
     62        ] 
     63 
    4564        self.Linkage = 3 
    4665        self.Annotation = 0 
    4766        self.PrintDepthCheck = 0 
    4867        self.PrintDepth = 10 
    49         self.HDSize = 500         #initial horizontal and vertical dendrogram size 
     68        # initial horizontal and vertical dendrogram size 
     69        self.HDSize = 500 
    5070        self.VDSize = 800 
    5171        self.ManualHorSize = 0 
     
    5878        self.ClassifyName = "HC_class" 
    5979        self.addIdAs = 0 
    60          
     80 
    6181        self.loadSettings() 
    62          
     82 
    6383        self.inputMatrix = None 
    64         self.matrixSource = "Unknown" 
    6584        self.root_cluster = None 
    6685        self.selectedExamples = None 
    67          
     86 
    6887        self.selectionChanged = False 
    6988 
     
    7392        ##GUI 
    7493        ################################# 
    75          
     94 
    7695        #HC Settings 
    7796        OWGUI.comboBox(self.controlArea, self, "Linkage", box="Linkage", 
    78                 items=self.linkageMethods, tooltip="Choose linkage method", 
    79                 callback=self.run_clustering, addSpace = True) 
     97                       items=self.linkageMethods, 
     98                       tooltip="Choose linkage method", 
     99                       callback=self.run_clustering, 
     100                       addSpace=True) 
    80101        #Label 
    81         box = OWGUI.widgetBox(self.controlArea, "Annotation", addSpace = True) 
    82         self.labelCombo = OWGUI.comboBox(box, self, "Annotation", 
    83                 items=["None"],tooltip="Choose label attribute", 
    84                 callback=self.update_labels) 
     102        box = OWGUI.widgetBox(self.controlArea, "Annotation", addSpace=True) 
     103        self.labelCombo = OWGUI.comboBox( 
     104            box, self, "Annotation", 
     105            items=["None"], 
     106            tooltip="Choose label attribute", 
     107            callback=self.update_labels 
     108        ) 
    85109 
    86110        OWGUI.spin(box, self, "TextSize", label="Text size", 
    87                         min=5, max=15, step=1,  
    88                         callback=self.update_font, 
    89                         controlWidth=40, 
    90                         keyboardTracking=False) 
    91 #        OWGUI.spin(box,self, "LineSpacing", label="Line spacing", 
    92 #                        min=2,max=8,step=1,  
    93 #                        callback=self.update_spacing,  
    94 #                        controlWidth=40, 
    95 #                        keyboardTracking=False) 
     111                   min=5, max=15, step=1, 
     112                   callback=self.update_font, 
     113                   controlWidth=40, 
     114                   keyboardTracking=False) 
    96115 
    97116        # Dendrogram graphics settings 
    98         dendrogramBox = OWGUI.widgetBox(self.controlArea, "Limits",  
     117        dendrogramBox = OWGUI.widgetBox(self.controlArea, "Limits", 
    99118                                        addSpace=True) 
    100          
     119 
    101120        form = QFormLayout() 
    102121        form.setLabelAlignment(Qt.AlignLeft) 
    103          
    104         # Depth settings  
     122 
     123        # Depth settings 
    105124        sw = OWGUI.widgetBox(dendrogramBox, orientation="horizontal", 
    106125                             addToLayout=False) 
    107         cw = OWGUI.widgetBox(dendrogramBox, orientation="horizontal",  
     126        cw = OWGUI.widgetBox(dendrogramBox, orientation="horizontal", 
    108127                             addToLayout=False) 
    109          
    110         sllp = OWGUI.hSlider(sw, self, "PrintDepth", minValue=1, maxValue=50,  
    111                              callback=self.on_depth_change) 
    112         cblp = OWGUI.checkBox(cw, self, "PrintDepthCheck", "Show to depth",  
    113                               callback = self.on_depth_change,  
     128 
     129        OWGUI.hSlider(sw, self, "PrintDepth", minValue=1, maxValue=50, 
     130                      callback=self.on_depth_change) 
     131 
     132        cblp = OWGUI.checkBox(cw, self, "PrintDepthCheck", "Show to depth", 
     133                              callback=self.on_depth_change, 
    114134                              disables=[sw]) 
    115135        form.addRow(cw, sw) 
    116          
     136 
    117137        checkWidth = OWGUI.checkButtonOffsetHint(cblp) 
    118          
     138 
    119139        # Width settings 
    120         sw = OWGUI.widgetBox(dendrogramBox, orientation="horizontal",  
     140        sw = OWGUI.widgetBox(dendrogramBox, orientation="horizontal", 
    121141                             addToLayout=False) 
    122         cw = OWGUI.widgetBox(dendrogramBox, orientation="horizontal",  
     142        cw = OWGUI.widgetBox(dendrogramBox, orientation="horizontal", 
    123143                             addToLayout=False) 
    124          
    125         hsb = OWGUI.spin(sw, self, "HDSize", min=200, max=10000, step=10,  
    126                          callback=self.on_width_changed,  
    127                          callbackOnReturn = False, 
     144 
     145        hsb = OWGUI.spin(sw, self, "HDSize", min=200, max=10000, step=10, 
     146                         callback=self.on_width_changed, 
     147                         callbackOnReturn=False, 
    128148                         keyboardTracking=False) 
    129         cbhs = OWGUI.checkBox(cw, self, "ManualHorSize", "Horizontal size",  
    130                               callback=self.on_width_changed,  
    131                               disables=[sw]) 
    132          
     149 
     150        OWGUI.checkBox(cw, self, "ManualHorSize", "Horizontal size", 
     151                       callback=self.on_width_changed, 
     152                       disables=[sw]) 
     153 
     154        sw.setEnabled(self.ManualHorSize) 
     155 
    133156        self.hSizeBox = hsb 
    134157        form.addRow(cw, sw) 
    135158        dendrogramBox.layout().addLayout(form) 
    136159 
    137         # Selection settings  
     160        # Selection settings 
    138161        box = OWGUI.widgetBox(self.controlArea, "Selection") 
    139162        OWGUI.checkBox(box, self, "SelectionMode", "Show cutoff line", 
    140163                       callback=self.update_cutoff_line) 
     164 
    141165        cb = OWGUI.checkBox(box, self, "AppendClusters", "Append cluster IDs", 
    142166                            callback=self.commit_data_if) 
    143          
     167 
    144168        self.classificationBox = ib = OWGUI.widgetBox(box, margin=0) 
    145          
     169 
    146170        form = QWidget() 
    147171        le = OWGUI.lineEdit(form, self, "ClassifyName", None, callback=None, 
     
    155179                                   "Meta attribute"], 
    156180                            callback=self.commit_data_if) 
    157          
     181 
    158182        layout = QFormLayout() 
    159183        layout.setSpacing(8) 
     
    163187        layout.addRow("Name  ", le) 
    164188        layout.addRow("Place  ", aa) 
    165          
     189 
    166190        form.setLayout(layout) 
    167          
     191 
    168192        ib.layout().addWidget(form) 
    169193        ib.layout().setContentsMargins(checkWidth, 5, 5, 5) 
    170          
     194 
    171195        cb.disables.append(ib) 
    172196        cb.makeConsistent() 
    173          
     197 
    174198        OWGUI.separator(box) 
    175         cbAuto = OWGUI.checkBox(box, self, "CommitOnChange", "Commit on change") 
    176         btCommit = OWGUI.button(box, self, "&Commit", self.commit_data, default=True) 
    177         OWGUI.setStopper(self, btCommit, cbAuto, "selectionChanged", self.commit_data) 
    178          
    179          
     199        cbAuto = OWGUI.checkBox(box, self, "CommitOnChange", 
     200                                "Commit on change") 
     201        btCommit = OWGUI.button(box, self, "&Commit", self.commit_data, 
     202                                default=True) 
     203        OWGUI.setStopper(self, btCommit, cbAuto, "selectionChanged", 
     204                         self.commit_data) 
     205 
    180206        OWGUI.rubber(self.controlArea) 
    181207        self.connect(self.graphButton, SIGNAL("clicked()"), self.saveGraph) 
     
    184210        self.headerView = ScaleView(scale, self) 
    185211        self.footerView = ScaleView(scale, self) 
    186          
     212 
    187213        self.dendrogram = DendrogramScene(self) 
    188214        self.dendrogramView = DendrogramView(self.dendrogram, self.mainArea) 
    189          
    190         self.connect(self.dendrogram, SIGNAL("clusterSelectionChanged()"), self.on_selection_change) 
    191         self.connect(self.dendrogram, SIGNAL("sceneRectChanged(QRectF)"), scale.scene_rect_update) 
    192         self.connect(self.dendrogram, SIGNAL("dendrogramGeometryChanged(QRectF)"), self.on_dendrogram_geometry_change) 
    193         self.connect(self.dendrogram, SIGNAL("cutoffValueChanged(float)"), self.on_cuttof_value_changed) 
    194          
    195         self.connect(self.dendrogramView, SIGNAL("viewportResized(QSize)"), self.on_width_changed) 
    196         self.connect(self.dendrogramView, SIGNAL("transformChanged(QTransform)"), self.headerView.setTransform) 
    197         self.connect(self.dendrogramView, SIGNAL("transformChanged(QTransform)"), self.footerView.setTransform) 
    198          
     215 
     216        self.connect(self.dendrogram, 
     217                     SIGNAL("clusterSelectionChanged()"), 
     218                     self.on_selection_change) 
     219 
     220        self.connect(self.dendrogram, 
     221                     SIGNAL("sceneRectChanged(QRectF)"), 
     222                     scale.scene_rect_update) 
     223 
     224        self.connect(self.dendrogram, 
     225                     SIGNAL("dendrogramGeometryChanged(QRectF)"), 
     226                     self.on_dendrogram_geometry_change) 
     227 
     228        self.connect(self.dendrogram, 
     229                     SIGNAL("cutoffValueChanged(float)"), 
     230                     self.on_cuttof_value_changed) 
     231 
     232        self.connect(self.dendrogramView, 
     233                     SIGNAL("viewportResized(QSize)"), 
     234                     self.on_width_changed) 
     235 
     236        self.connect(self.dendrogramView, 
     237                     SIGNAL("transformChanged(QTransform)"), 
     238                     self.headerView.setTransform) 
     239        self.connect(self.dendrogramView, 
     240                     SIGNAL("transformChanged(QTransform)"), 
     241                     self.footerView.setTransform) 
     242 
    199243        self.mainArea.layout().addWidget(self.headerView) 
    200244        self.mainArea.layout().addWidget(self.dendrogramView) 
    201245        self.mainArea.layout().addWidget(self.footerView) 
    202          
     246 
    203247        self.dendrogram.header = self.headerView 
    204248        self.dendrogram.footer = self.footerView 
    205249 
    206         self.connect(self.dendrogramView.horizontalScrollBar(),SIGNAL("valueChanged(int)"), 
    207                 self.footerView.horizontalScrollBar().setValue) 
    208         self.connect(self.dendrogramView.horizontalScrollBar(),SIGNAL("valueChanged(int)"), 
    209                 self.headerView.horizontalScrollBar().setValue) 
    210         self.dendrogram.setSceneRect(0, 0, self.HDSize,self.VDSize) 
     250        self.connect(self.dendrogramView.horizontalScrollBar(), 
     251                     SIGNAL("valueChanged(int)"), 
     252                     self.footerView.horizontalScrollBar().setValue) 
     253 
     254        self.connect(self.dendrogramView.horizontalScrollBar(), 
     255                     SIGNAL("valueChanged(int)"), 
     256                     self.headerView.horizontalScrollBar().setValue) 
     257 
     258        self.dendrogram.setSceneRect(0, 0, self.HDSize, self.VDSize) 
    211259        self.dendrogram.update() 
    212260        self.resize(800, 500) 
    213          
    214         self.natural_dendrogram_width = 800  
     261 
     262        self.natural_dendrogram_width = 800 
    215263        self.dendrogramView.set_fit_to_width(not self.ManualHorSize) 
    216          
     264 
    217265        self.matrix = None 
    218266        self.selectionList = [] 
    219         self.selected_clusters = []  
    220  
    221     def sendReport(self): 
    222         self.reportSettings("Settings", 
    223                             [("Linkage", self.linkageMethods[self.Linkage]), 
    224                              ("Annotation", self.labelCombo.currentText()), 
    225                              self.PrintDepthCheck and ("Shown depth limited to", self.PrintDepth), 
    226                              self.SelectionMode and hasattr(self, "cutoff_height") and ("Cutoff line at", self.cutoff_height)]) 
    227          
    228         self.reportSection("Dendrogram") 
    229         canvases = header, graph, footer = self.headerView.scene(), self.dendrogramView.scene(), self.footerView.scene() 
    230         buffer = QPixmap(max(c.width() for c in canvases), sum(c.height() for c in canvases)) 
    231         painter = QPainter(buffer) 
    232         painter.fillRect(buffer.rect(), QBrush(QColor(255, 255, 255))) 
    233         header.render(painter, QRectF(0, 0, header.width(), header.height()), QRectF(0, 0, header.width(), header.height())) 
    234         graph.render(painter, QRectF(0, header.height(), graph.width(), graph.height()), QRectF(0, 0, graph.width(), graph.height())) 
    235         footer.render(painter, QRectF(0, header.height()+graph.height(), footer.width(), footer.height()), QRectF(0, 0, footer.width(), footer.height())) 
    236         painter.end() 
    237         self.reportImage(lambda filename: buffer.save(filename, os.path.splitext(filename)[1][1:])) 
    238          
     267        self.selected_clusters = [] 
     268 
    239269    def clear(self): 
     270        """ 
     271        Clear the widget state. 
     272        """ 
    240273        self.matrix = None 
    241274        self.root_cluster = None 
     
    243276        self.dendrogram.clear() 
    244277        self.labelCombo.clear() 
    245          
     278 
    246279    def set_matrix(self, data): 
     280        """ 
     281        Set the input data matrix. 
     282        """ 
    247283        self.clear() 
    248284        self.matrix = data 
     
    255291            self.send("Selected Data", None) 
    256292            self.send("Other Data", None) 
     293            self.send("Centroids", None) 
    257294            self.classificationBox.setDisabled(True) 
    258295            return 
    259296 
    260         self.matrixSource = "Unknown" 
    261         items = getattr(self.matrix, "items") 
    262         if isinstance(items, orange.ExampleTable): #Example Table from Example Distance 
    263  
    264             self.labels = ["None", "Default"]+ \ 
    265                           [a.name for a in items.domain.attributes] 
    266             if items.domain.classVar: 
    267                 self.labels.append(items.domain.classVar.name) 
     297        items = getattr(self.matrix, "items", None) 
     298        if isinstance(items, Orange.data.Table): 
     299            # Data table (from Example Distance) 
     300            domain = items.domain 
     301            self.labels = ["None", "Default"] + \ 
     302                          [a.name for a in domain.attributes] 
     303            if domain.class_var: 
     304                self.labels.append(domain.class_var.name) 
    268305 
    269306            self.labelInd = range(len(self.labels) - 2) 
    270             self.labels.extend([m.name for m in items.domain.getmetas().values()]) 
    271             self.labelInd.extend(items.domain.getmetas().keys()) 
    272             self.numMeta = len(items.domain.getmetas()) 
    273             self.metaLabels = items.domain.getmetas().values() 
    274             self.matrixSource = "Example Distance" 
    275         elif isinstance(items, list):   # a list of item (most probably strings) 
    276             self.labels = ["None", "Default", "Name", "Strain"] 
    277             self.Annotation = 0 
    278             self.matrixSource = "Data Distance" 
    279         else:   #From Attribute Distance 
     307            self.labels.extend([m.name for m in domain.getmetas().values()]) 
     308 
     309            self.labelInd.extend(domain.getmetas().keys()) 
     310            self.numMeta = len(domain.getmetas()) 
     311            self.metaLabels = domain.getmetas().values() 
     312 
     313        elif isinstance(items, Orange.core.VarList): 
     314            # Attribute list (for Attribute Distance) 
    280315            self.labels = ["None", "Attribute Name"] 
    281316            self.Annotation = 1 
    282             self.matrixSource="Attribute Distance" 
    283              
     317        elif isinstance(items, list): 
     318            # a list of items (most probably strings) 
     319            self.labels = ["None", "Default"] 
     320            self.Annotation = 0 
     321        else: 
     322            self.labels = ["None", "Default"] 
     323            self.Annotation = 0 
     324 
    284325        self.labelCombo.clear() 
    285326        self.labelCombo.addItems(self.labels) 
     327 
    286328        if len(self.labels) < self.Annotation - 1: 
    287                 self.Annotation = 0 
     329            self.Annotation = 0 
     330 
    288331        self.labelCombo.setCurrentIndex(self.Annotation) 
    289         if self.matrixSource == "Example Distance": 
     332        if isinstance(items, Orange.data.Table): 
    290333            self.classificationBox.setDisabled(False) 
     334            self.openContext("", items) 
    291335        else: 
    292336            self.classificationBox.setDisabled(True) 
    293         if self.matrixSource == "Example Distance": 
    294             self.openContext("", items) 
     337 
    295338        self.error(0) 
     339 
    296340        try: 
    297341            self.run_clustering() 
    298         except orange.KernelException, ex: 
     342        except Orange.core.KernelException, ex: 
    299343            self.error(0, "Could not cluster data! %s" % ex.message) 
    300344            self.setMatrix(None) 
    301          
     345 
    302346    def update_labels(self): 
    303         """ Change the labels in the scene. 
     347        """ 
     348        Change (update) the labels in the scene. 
    304349        """ 
    305350        if self.matrix is None: 
    306351            return 
    307          
     352 
    308353        items = getattr(self.matrix, "items", range(self.matrix.dim)) 
    309          
     354 
    310355        if self.Annotation == 0: 
     356            # 'None' is selected 
    311357            labels = [""] * len(items) 
    312358        elif self.Annotation == 1: 
     359            # 'Default' or 'Name' 
    313360            try: 
    314361                labels = [item.name for item in items] 
    315                 if not any(labels): raise AttributeError("No labels.") 
     362                if not any(labels): 
     363                    raise AttributeError("No labels.") 
    316364            except AttributeError: 
    317365                labels = [str(item) for item in items] 
    318         elif self.Annotation > 1 and isinstance(items, ExampleTable): 
    319             attr = self.labelInd[min(self.Annotation - 2, len(self.labelInd) - 1)] 
     366 
     367        elif self.Annotation > 1 and isinstance(items, Orange.data.Table): 
     368            # feature or meta values 
     369            attr = self.labelInd[min(self.Annotation - 2, 
     370                                     len(self.labelInd) - 1)] 
    320371            labels = [str(ex[attr]) for ex in items] 
    321372        else: 
    322373            labels = [str(item) for item in items] 
    323              
     374 
    324375        self.dendrogram.set_labels(labels) 
    325376        self.dendrogram.set_tool_tips(labels) 
     
    327378    def run_clustering(self): 
    328379        if self.matrix: 
     380            def callback(value, *args): 
     381                self.progressBarSet(value * 100) 
     382 
    329383            self.progressBarInit() 
    330             self.root_cluster = orange.HierarchicalClustering(self.matrix, 
     384            self.root_cluster = hierarchical.HierarchicalClustering( 
     385                self.matrix, 
    331386                linkage=self.linkage[self.Linkage][1], 
    332                 progressCallback=lambda value, a: self.progressBarSet(value*100)) 
     387                progressCallback=callback 
     388            ) 
     389 
    333390            self.progressBarFinished() 
    334391            self.display_tree() 
     
    339396            root = hierarchical.pruned(root, level=self.PrintDepth) 
    340397        self.display_tree1(root) 
    341          
     398 
    342399    def display_tree1(self, tree): 
    343400        self.dendrogram.clear() 
     
    347404        self.update_labels() 
    348405        self.update_cutoff_line() 
    349          
     406 
    350407    def update_font(self): 
    351408        font = self.font() 
     
    354411        if self.dendrogram.widget: 
    355412            self.update_labels() 
    356              
     413 
    357414    def update_spacing(self): 
    358415        if self.dendrogram.labels_widget: 
    359416            layout = self.dendrogram.labels_widget.layout() 
    360417            layout.setSpacing(self.LineSpacing) 
    361          
     418 
    362419    def on_width_changed(self, size=None): 
    363420        if size is not None: 
     
    365422        else: 
    366423            auto_width = self.natural_dendrogram_width 
    367              
     424 
    368425        self.dendrogramView.set_fit_to_width(not self.ManualHorSize) 
    369426        if self.ManualHorSize: 
     
    373430            self.dendrogram.set_scene_width_hint(auto_width) 
    374431            self.update_labels() 
    375              
     432 
    376433    def on_dendrogram_geometry_change(self, geometry): 
    377434        if self.root_cluster and self.dendrogram.widget: 
     
    379436            left, top, right, bottom = widget.layout().getContentsMargins() 
    380437            geometry = geometry.adjusted(left, top, -right, -bottom) 
    381             self.scale_scene.set_scale_bounds(geometry.left(), geometry.right()) 
     438            self.scale_scene.set_scale_bounds(geometry.left(), 
     439                                              geometry.right()) 
    382440            self.scale_scene.set_scale(self.root_cluster.height, 0.0) 
    383441            pos = widget.pos_at_height(self.cutoff_height) 
    384442            self.scale_scene.set_marker(pos) 
    385              
     443 
    386444    def on_depth_change(self): 
    387445        if self.root_cluster and self.dendrogram.widget: 
     
    392450                root = hierarchical.pruned(root, level=self.PrintDepth) 
    393451            self.display_tree1(root) 
    394              
    395             selected = [c for c in hierarchical.preorder(root) if (c.first, c.last) in selected] 
    396             self.dendrogram.widget.set_selected_clusters(selected)  
     452 
     453            selected = [c for c in hierarchical.preorder(root) 
     454                        if (c.first, c.last) in selected] 
     455            self.dendrogram.widget.set_selected_clusters(selected) 
    397456 
    398457    def set_cuttof_position_from_scale(self, pos): 
    399         """ Cuttof position changed due to a mouse event in the scale scene. 
     458        """ 
     459        Cuttof position changed due to a mouse event in the scale scene. 
    400460        """ 
    401461        if self.root_cluster and self.dendrogram.cutoff_line: 
     
    403463            self.cutoff_height = height 
    404464            line = self.dendrogram.cutoff_line.set_cutoff_at_height(height) 
    405              
     465 
    406466    def on_cuttof_value_changed(self, height): 
    407         """ Cuttof value changed due to line drag in the dendrogram. 
     467        """ 
     468        Cuttof value changed due to line drag in the dendrogram. 
    408469        """ 
    409470        if self.root_cluster and self.dendrogram.widget: 
     
    412473            pos = widget.pos_at_height(height) 
    413474            self.scale_scene.set_marker(pos) 
    414              
     475 
    415476    def update_cutoff_line(self): 
    416477        if self.matrix: 
     
    421482                self.dendrogram.cutoff_line.hide() 
    422483                self.scale_scene.marker.hide() 
    423              
     484 
    424485    def on_selection_change(self): 
    425486        if self.matrix: 
     
    428489                self.selected_clusters = [item.cluster for item in items] 
    429490                self.commit_data_if() 
    430             except RuntimeError: # underlying C/C++ object has been deleted 
     491            except RuntimeError: 
     492                # underlying C/C++ object has been deleted 
    431493                pass 
    432          
     494 
    433495    def commit_data_if(self): 
    434496        if self.CommitOnChange: 
     
    440502        items = getattr(self.matrix, "items", None) 
    441503        if not items: 
    442             return # nothing to commit 
    443          
     504            # nothing to commit 
     505            return 
     506 
    444507        self.selectionChanged = False 
    445508        self.selectedExamples = None 
    446509        selection = self.selected_clusters 
    447510        selection = sorted(selection, key=lambda c: c.first) 
    448         maps = [list(self.root_cluster.mapping[c.first: c.last]) for c in selection] 
    449          
    450         from operator import add 
     511        maps = [list(self.root_cluster.mapping[c.first: c.last]) 
     512                for c in selection] 
     513 
    451514        selected_indices = reduce(add, maps, []) 
    452         unselected_indices = sorted(set(self.root_cluster.mapping) - set(selected_indices)) 
    453          
     515        unselected_indices = sorted(set(self.root_cluster.mapping) - \ 
     516                                    set(selected_indices)) 
     517 
    454518        self.selection = selected = [items[k] for k in selected_indices] 
    455519        unselected = [items[k] for k in unselected_indices] 
    456          
     520 
    457521        if not selected: 
    458522            self.send("Selected Data", None) 
     
    460524            self.send("Centroids", None) 
    461525            return 
    462          
    463         if isinstance(items, ExampleTable):  
     526 
     527        new_meta_id = Orange.feature.Descriptor.new_meta_id 
     528 
     529        if isinstance(items, Orange.data.Table): 
    464530            c = [i for i in range(len(maps)) for j in maps[i]] 
    465531            aid = clustVar = None 
    466532            if self.AppendClusters: 
    467                 clustVar = orange.EnumVariable(str(self.ClassifyName) , 
    468                             values=["Cluster " + str(i) for i in range(len(maps))] + ["Other"]) 
     533                clustVar = Orange.feature.Discrete( 
     534                    str(self.ClassifyName), 
     535                    values=["Cluster " + str(i) for i in range(len(maps))] + \ 
     536                           ["Other"] 
     537                ) 
     538 
    469539                origDomain = items.domain 
    470540                if self.addIdAs == 0: 
    471                     domain = orange.Domain(origDomain.attributes, clustVar) 
    472                     if origDomain.classVar: 
    473                         domain.addmeta(orange.newmetaid(), origDomain.classVar) 
     541                    domain = Orange.data.Domain(origDomain.attributes, 
     542                                                clustVar) 
     543                    if origDomain.class_var: 
     544                        domain.addmeta(new_meta_id(), origDomain.class_var) 
    474545                    aid = -1 
    475546                elif self.addIdAs == 1: 
    476                     domain = orange.Domain(origDomain.attributes + [clustVar], origDomain.classVar) 
     547                    domain = Orange.data.Domain(origDomain.attributes + \ 
     548                                                [clustVar], 
     549                                                origDomain.class_var) 
     550 
    477551                    aid = len(origDomain.attributes) 
    478552                else: 
    479                     domain = orange.Domain(origDomain.attributes, origDomain.classVar) 
    480                     aid = orange.newmetaid() 
     553                    domain = Orange.data.Domain(origDomain.attributes, 
     554                                                origDomain.class_var) 
     555 
     556                    aid = new_meta_id() 
    481557                    domain.addmeta(aid, clustVar) 
    482558 
     
    484560                table1 = table2 = None 
    485561                if selected: 
    486                     table1 = orange.ExampleTable(domain, selected) 
     562                    table1 = Orange.data.Table(domain, selected) 
    487563                    for i in range(len(selected)): 
    488564                        table1[i][clustVar] = clustVar("Cluster " + str(c[i])) 
    489                  
     565 
    490566                if unselected: 
    491                     table2 = orange.ExampleTable(domain, unselected) 
     567                    table2 = Orange.data.Table(domain, unselected) 
    492568                    for ex in table2: 
    493569                        ex[clustVar] = clustVar("Other") 
     
    496572                self.unselectedExamples = table2 
    497573            else: 
    498                 self.selectedExamples = orange.ExampleTable(selected) if selected else None 
    499                 self.unselectedExamples = orange.ExampleTable(unselected) if unselected else None 
    500                  
     574                self.selectedExamples = \ 
     575                    Orange.data.Table(selected) if selected else None 
     576 
     577                self.unselectedExamples = \ 
     578                    Orange.data.Table(unselected) if unselected else None 
     579 
    501580            self.send("Selected Data", self.selectedExamples) 
    502581            self.send("Other Data", self.unselectedExamples) 
     
    504583            self.centroids = None 
    505584            if self.selectedExamples: 
    506                 self.centroids = orange.ExampleTable(self.selectedExamples.domain) 
     585                domain = self.selectedExamples.domain 
     586                self.centroids = Orange.data.Table(domain) 
    507587                for i in range(len(maps)): 
    508                     clusterEx = [ex for cluster, ex in zip(c, self.selectedExamples) if cluster == i] 
    509                     clusterEx = orange.ExampleTable(clusterEx) 
    510                     contstat = orange.DomainBasicAttrStat(clusterEx) 
    511                     discstat = orange.DomainDistributions(clusterEx, 0, 0, 1) 
    512                     ex = [cs.avg if cs else (ds.modus() if ds else "?") for cs, ds in zip(contstat, discstat)] 
    513                     example = orange.Example(self.centroids.domain, ex) 
     588                    clusterEx = [ex for cluster, ex in \ 
     589                                 zip(c, self.selectedExamples) 
     590                                 if cluster == i] 
     591                    clusterEx = Orange.data.Table(clusterEx) 
     592                    contstat = Orange.statistics.basic.Domain(clusterEx) 
     593                    discstat = Orange.statistics.distribution.Domain( 
     594                        clusterEx, 0, 0, 1 
     595                    ) 
     596 
     597                    ex = [cs.avg if cs else (ds.modus() if ds else "?") 
     598                          for cs, ds in zip(contstat, discstat)] 
     599 
     600                    example = Orange.data.Instance(domain, ex) 
    514601                    if clustVar is not None: 
    515602                        example[clustVar] = clustVar(i) 
    516603                    self.centroids.append(ex) 
     604 
    517605            self.send("Centroids", self.centroids) 
    518              
    519         elif self.matrixSource=="Data Distance": 
    520             names=list(set([d.strain for d in self.selection])) 
    521             data=[(name, [d for d in filter(lambda a:a.strain==name, self.selection)]) for name in names] 
    522             self.send("Structured Data Files",data) 
    523              
     606 
     607    def sendReport(self): 
     608        self.reportSettings( 
     609            "Settings", 
     610            [("Linkage", self.linkageMethods[self.Linkage]), 
     611             ("Annotation", self.labelCombo.currentText()), 
     612             self.PrintDepthCheck and ("Shown depth limited to", 
     613                                       self.PrintDepth), 
     614             self.SelectionMode and hasattr(self, "cutoff_height") and 
     615             ("Cutoff line at", self.cutoff_height)] 
     616        ) 
     617 
     618        self.reportSection("Dendrogram") 
     619 
     620        header = self.headerView.scene() 
     621        graph = self.dendrogramView.scene() 
     622        footer = self.footerView.scene() 
     623        canvases = header, graph, footer 
     624 
     625        pixmap = QPixmap(max(c.width() for c in canvases), 
     626                         sum(c.height() for c in canvases)) 
     627        pixmap.fill(Qt.white) 
     628        painter = QPainter(pixmap) 
     629        painter.setRenderHint(QPainter.Antialiasing) 
     630        self.renderDendrogram(painter) 
     631        painter.end() 
     632 
     633        def save_to(filename): 
     634            _, ext = os.path.splitext(filename) 
     635            pixmap.save(filename, ext[1:]) 
     636 
     637        self.reportImage(save_to) 
     638 
    524639    def saveGraph(self): 
    525        sizeDlg = OWChooseImageSizeDlg(self.dendrogram, parent=self) 
    526        sizeDlg.exec_() 
    527         
     640        sizeDlg = OWChooseImageSizeDlg(self.dendrogram, parent=self) 
     641        filename = sizeDlg.getFileName( 
     642            "graph", 
     643            "Portable Network Graphics (*.PNG);;" 
     644            "Windows Bitmap (*.BMP);;" 
     645            "Graphics Interchange Format (*.GIF);;" 
     646            "Scalable Vector Graphics (*.SVG)", 
     647            ".png" 
     648        ) 
     649        _, ext = os.path.splitext(filename) 
     650        ext = ext.lower() 
     651 
     652        canvases = (self.headerView.scene(), 
     653                    self.dendrogramView.scene(), 
     654                    self.footerView.scene()) 
     655        width = max([c.width() for c in canvases]) 
     656        height = sum([c.height() for c in canvases]) 
     657 
     658        size = QSize(width, height) 
     659 
     660        if ext == ".svg": 
     661            device = QSvgGenerator() 
     662            device.setTitle("Dendrogram Plot") 
     663            device.setFileName(filename) 
     664            device.setSize(size) 
     665            device.setViewBox(QRect(QPoint(0, 0), size)) 
     666        else: 
     667            device = QPixmap(size) 
     668            device.fill(Qt.white) 
     669 
     670        painter = QPainter() 
     671        painter.begin(device) 
     672        painter.setRenderHint(QPainter.Antialiasing) 
     673 
     674        self.renderDendrogram(painter) 
     675        painter.end() 
     676 
     677        if ext != ".svg": 
     678            device.save(filename) 
     679 
     680    def renderDendrogram(self, painter): 
     681        """ 
     682        Render the dendrogram onto the `painter`, including both axis. 
     683        """ 
     684        header = self.headerView.scene() 
     685        graph = self.dendrogramView.scene() 
     686        footer = self.footerView.scene() 
     687 
     688        header.render(painter, 
     689                      QRectF(0, 0, header.width(), header.height()), 
     690                      QRectF(0, 0, header.width(), header.height())) 
     691 
     692        graph.render(painter, 
     693                     QRectF(0, header.height(), graph.width(), graph.height()), 
     694                     QRectF(0, 0, graph.width(), graph.height())) 
     695 
     696        footer.render(painter, 
     697                      QRectF(0, header.height() + graph.height(), 
     698                             footer.width(), footer.height()), 
     699                      QRectF(0, 0, footer.width(), footer.height())) 
     700 
    528701 
    529702class DendrogramView(QGraphicsView): 
     
    534707        self.setAlignment(Qt.AlignLeft | Qt.AlignCenter) 
    535708        self.setFocusPolicy(Qt.WheelFocus) 
    536 #        self.setRenderHints(QPainter.Antialiasing | QPainter.TextAntialiasing) 
     709 
    537710        self.setRenderHints(QPainter.TextAntialiasing) 
    538711        self.fit_contents = True 
    539         self.connect(self, SIGNAL("viewportResized(QSize)"), self.updateTransform) 
    540         self.connect(self.scene(), SIGNAL("sceneRectChanged(QRectF)"), lambda: self.updateTransform(self.viewport().size())) 
     712        self.connect(self, 
     713                     SIGNAL("viewportResized(QSize)"), 
     714                     self.updateTransform) 
     715        self.connect(self.scene(), 
     716                     SIGNAL("sceneRectChanged(QRectF)"), 
     717                     lambda: self.updateTransform(self.viewport().size())) 
    541718 
    542719    def resizeEvent(self, e): 
    543720        QGraphicsView.resizeEvent(self, e) 
    544721        self.emit(SIGNAL("viewportResized(QSize)"), e.size()) 
    545          
     722 
    546723    def updateTransform(self, size): 
    547724        return 
     
    555732#            self.setTransform(QTransform()) 
    556733#        self.emit(SIGNAL("transformChanged(QTransform)"), self.transform()) 
    557          
     734 
    558735    def set_fit_to_width(self, state): 
    559736        self.fit_contents = state 
    560737        self.updateTransform(self.viewport().size()) 
    561738 
    562 from OWGraphics import GraphicsSimpleTextList 
    563739 
    564740class DendrogramScene(QGraphicsScene): 
     
    568744        self.header = None 
    569745        self.footer = None 
    570          
     746 
    571747        self.grid_widget = None 
    572748        self.widget = None 
     
    576752 
    577753    def set_cluster(self, root): 
    578         """ Set the cluster to display  
     754        """ 
     755        Set the cluster to display 
    579756        """ 
    580757        self.clear() 
    581758        self.root_cluster = root 
    582759        self.cutoff_line = None 
    583          
     760 
    584761        if not self.root_cluster: 
    585762            return 
    586          
     763 
    587764        # the main widget containing the dendrogram and labels 
    588765        self.grid_widget = QGraphicsWidget() 
     
    590767        layout = QGraphicsGridLayout() 
    591768        self.grid_widget.setLayout(layout) 
    592          
     769 
    593770        # dendrogram widget 
    594         self.widget = widget = OWClustering.DendrogramWidget(root=root, orientation=Qt.Vertical, parent=self.grid_widget) 
    595         self.connect(widget, SIGNAL("dendrogramGeometryChanged(QRectF)"),  
    596                      lambda rect: self.emit(SIGNAL("dendrogramGeometryChanged(QRectF)"), 
    597                                             rect)) 
    598         self.connect(widget, SIGNAL("selectionChanged()"), 
    599                      lambda: self.emit(SIGNAL("clusterSelectionChanged()")) 
    600                      ) 
    601          
     771        self.widget = widget = OWClustering.DendrogramWidget( 
     772            root=root, orientation=Qt.Vertical, parent=self.grid_widget 
     773        ) 
     774 
     775        self.connect(widget, 
     776                     SIGNAL("dendrogramGeometryChanged(QRectF)"), 
     777                     lambda rect: self.emit( 
     778                         SIGNAL("dendrogramGeometryChanged(QRectF)"), 
     779                         rect 
     780                     )) 
     781 
     782        self.connect(widget, 
     783                     SIGNAL("selectionChanged()"), 
     784                     lambda: self.emit(SIGNAL("clusterSelectionChanged()"))) 
     785 
    602786        widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) 
    603          
     787 
    604788        layout.addItem(self.widget, 0, 0) 
    605789        self.grid_widget.setMinimumWidth(self.scene_width_hint) 
    606790        self.grid_widget.setMaximumWidth(self.scene_width_hint) 
    607          
     791 
    608792        spacing = QFontMetrics(self.font()).lineSpacing() 
    609793        left, top, right, bottom = widget.layout().getContentsMargins() 
    610         widget.layout().setContentsMargins(0.0, spacing / 2.0, 0.0, spacing / 2.0) 
    611          
    612         labels = [self.cluster_text(leaf.cluster) for leaf in widget.leaf_items()] 
    613          
     794        widget.layout().setContentsMargins(0.0, spacing / 2.0, 
     795                                           0.0, spacing / 2.0) 
     796 
     797        labels = [self.cluster_text(leaf.cluster) for 
     798                  leaf in widget.leaf_items()] 
     799 
    614800        # Labels widget 
    615         labels = GraphicsSimpleTextList(labels, orientation=Qt.Vertical, parent=self.grid_widget) 
     801        labels = GraphicsSimpleTextList(labels, orientation=Qt.Vertical, 
     802                                        parent=self.grid_widget) 
    616803        labels.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) 
    617804        labels.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.MinimumExpanding) 
    618805        labels.setFont(self.font()) 
    619806        layout.addItem(labels, 0, 1) 
    620          
    621         # Cutoff line     
     807 
     808        # Cutoff line 
    622809        self.cutoff_line = OWClustering.CutoffLine(widget) 
    623         self.connect(self.cutoff_line.emiter, SIGNAL("cutoffValueChanged(float)"), 
    624                      lambda val: self.emit(SIGNAL("cutoffValueChanged(float)"), val)) 
     810        self.connect(self.cutoff_line.emiter, 
     811                     SIGNAL("cutoffValueChanged(float)"), 
     812                     lambda val: self.emit(SIGNAL("cutoffValueChanged(float)"), 
     813                                           val)) 
     814 
    625815        self.cutoff_line.set_cutoff_at_height(self.root_cluster.height * 0.95) 
    626              
     816 
    627817        self.labels_widget = labels 
    628          
    629         layout.activate()  
     818 
     819        layout.activate() 
    630820        self._update_scene_rect() 
    631          
     821 
    632822    def cluster_text(self, cluster): 
    633         """ Return the text to display next to the cluster. 
     823        """ 
     824        Return the text to display next to the cluster. 
    634825        """ 
    635826        if cluster in self.leaf_labels: 
     
    644835 
    645836    def set_labels(self, labels): 
    646         """ Set the item labels. 
     837        """ 
     838        Set the item labels. 
    647839        """ 
    648840        assert(len(labels) == len(self.root_cluster.mapping)) 
     
    658850                    text = text[0] 
    659851                label_items.append(text) 
    660                  
     852 
    661853            self.labels_widget.set_labels(label_items) 
    662854        self._update_scene_rect() 
    663855 
    664856    def set_tool_tips(self, tool_tips): 
    665         """ Set the item tool tips. 
     857        """ 
     858        Set the item tool tips. 
    666859        """ 
    667860        assert(len(tool_tips) == len(self.root_cluster.mapping)) 
    668861        if self.labels_widget: 
    669             for leaf, label in zip(self.widget.leaf_items(), self.labels_widget): 
     862            for leaf, label in zip(self.widget.leaf_items(), 
     863                                   self.labels_widget): 
    670864                cluster = leaf.cluster 
    671865                indices = cluster.mapping[cluster.first: cluster.last] 
     
    673867                text = "<br>".join(text) 
    674868                label.setToolTip(text) 
    675                  
     869 
    676870    def set_scene_width_hint(self, width): 
    677871        self.scene_width_hint = width 
     
    679873            self.grid_widget.setMinimumWidth(self.scene_width_hint) 
    680874            self.grid_widget.setMaximumWidth(self.scene_width_hint) 
    681              
     875 
    682876    def clear(self): 
    683877        self.widget = None 
     
    687881        self.cutoff_line = None 
    688882        QGraphicsScene.clear(self) 
    689          
     883 
    690884    def setFont(self, font): 
    691885        QGraphicsScene.setFont(self, font) 
     
    695889            # Fix widget top and bottom margins. 
    696890            spacing = QFontMetrics(self.font()).lineSpacing() 
    697             left, top, right, bottom = self.widget.layout().getContentsMargins() 
    698             self.widget.layout().setContentsMargins(left, spacing / 2.0, right, spacing / 2.0) 
    699             self.grid_widget.resize(self.grid_widget.sizeHint(Qt.PreferredSize)) 
    700              
     891            left, _, right, _ = self.widget.layout().getContentsMargins() 
     892            self.widget.layout().setContentsMargins(left, spacing / 2.0, right, 
     893                                                    spacing / 2.0) 
     894            self.grid_widget.resize( 
     895                self.grid_widget.sizeHint(Qt.PreferredSize) 
     896            ) 
     897 
    701898    def _update_scene_rect(self): 
    702         self.setSceneRect(reduce(QRectF.united, [item.sceneBoundingRect() for item in self.items()], QRectF()).adjusted(-10, -10, 10, 10)) 
    703          
    704      
     899        items_rect = reduce(QRectF.united, 
     900                            [item.sceneBoundingRect() 
     901                             for item in self.items()], 
     902                            QRectF()) 
     903 
     904        self.setSceneRect(items_rect.adjusted(-10, -10, 10, 10)) 
     905 
     906 
    705907class AxisScale(QGraphicsWidget): 
    706     """ A graphics widget for an axis scale 
     908    """ 
     909    A graphics widget for an axis scale 
    707910    """ 
    708911    # Defaults 
    709912    orientation = Qt.Horizontal 
    710     tick_count=5 
     913    tick_count = 5 
    711914    tick_align = Qt.AlignTop 
    712915    text_align = Qt.AlignHCenter | Qt.AlignBottom 
    713916    axis_scale = (0.0, 1.0) 
    714      
     917 
    715918    def __init__(self, parent=None, orientation=Qt.Horizontal, tick_count=5, 
    716                  tick_align = Qt.AlignBottom, 
    717                  text_align = Qt.AlignHCenter | Qt.AlignBottom, 
    718                  axis_scale = (0.0, 1.0)): 
    719         QGraphicsWidget.__init__(self, parent)  
     919                 tick_align=Qt.AlignBottom, 
     920                 text_align=Qt.AlignHCenter | Qt.AlignBottom, 
     921                 axis_scale=(0.0, 1.0)): 
     922        QGraphicsWidget.__init__(self, parent) 
    720923        self.orientation = orientation 
    721924        self.tick_count = tick_count 
     
    723926        self.text_align = text_align 
    724927        self.axis_scale = axis_scale 
    725          
     928 
    726929    def set_orientation(self, orientation): 
    727930        self.orientation = orientation 
     
    731934            self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.MinimumExpanding) 
    732935        self.updateGeometry() 
    733          
     936 
    734937    def ticks(self): 
    735938        minval, maxval = self.axis_scale 
    736         ticks = ["%.2f" % val for val in numpy.linspace(minval, maxval, self.tick_count)] 
     939        ticks = ["%.2f" % val 
     940                 for val in numpy.linspace(minval, maxval, self.tick_count)] 
    737941        return ticks 
    738          
     942 
    739943    def paint(self, painter, option, widget=0): 
    740944        painter.setFont(self.font()) 
     
    743947        minval, maxval = self.axis_scale 
    744948        tick_count = self.tick_count 
    745          
     949 
    746950        if self.orientation == Qt.Horizontal: 
    747951            spanx, spany = size.width(), 0.0 
    748             xadv, yadv =  spanx / tick_count, 0.0 
     952            xadv, yadv = spanx / tick_count, 0.0 
    749953            tick_w, tick_h = 0.0, -5.0 
    750954            tick_offset = QPointF(0.0, tick_h) 
     
    753957            xadv, yadv = 0.0, spany / tick_count 
    754958            tick_w, tick_h = 5.0, 0.0 
    755             tick_func = lambda : (y / spany) 
    756             tick_offset = QPointF(tick_w + 1.0, metrics.ascent()/2) 
    757              
     959            tick_func = lambda: (y / spany) 
     960            tick_offset = QPointF(tick_w + 1.0, metrics.ascent() / 2) 
     961 
    758962        ticks = self.ticks() 
    759              
     963 
    760964        xstart, ystart = 0.0, 0.0 
    761          
     965 
    762966        if self.orientation == Qt.Horizontal: 
    763967            painter.translate(0.0, size.height()) 
    764              
    765         painter.drawLine(xstart, ystart, xstart + tick_count*xadv, ystart + tick_count*yadv) 
    766          
     968 
     969        painter.drawLine(xstart, ystart, 
     970                         xstart + tick_count * xadv, 
     971                         ystart + tick_count * yadv) 
     972 
    767973        linspacex = numpy.linspace(0.0, spanx, tick_count) 
    768974        linspacey = numpy.linspace(0.0, spany, tick_count) 
    769          
     975 
    770976        metrics = painter.fontMetrics() 
    771977        for x, y, tick in zip(linspacex, linspacey, ticks): 
     
    773979            if self.orientation == Qt.Horizontal: 
    774980                rect = QRectF(metrics.boundingRect(tick)) 
    775                 rect.moveCenter(QPointF(x, y) + tick_offset + QPointF(0.0, -rect.height()/2.0)) 
     981                rect.moveCenter(QPointF(x, y) + tick_offset + \ 
     982                                QPointF(0.0, -rect.height() / 2.0)) 
    776983                painter.drawText(rect, tick) 
    777984            else: 
    778985                painter.drawText(QPointF(x, y) + tick_offset, tick) 
    779                  
    780 #        rect =  self.geometry() 
    781 #        rect.translate(-self.pos()) 
    782 #        painter.drawRect(rect) 
    783          
     986 
    784987    def setGeometry(self, rect): 
    785988        self.prepareGeometryChange() 
    786989        return QGraphicsWidget.setGeometry(self, rect) 
    787          
     990 
    788991    def sizeHint(self, which, *args): 
    789992        if which == Qt.PreferredSize: 
     
    793996            if self.orientation == Qt.Horizontal: 
    794997                h = metrics.height() + 5 
    795                 w = 100  
     998                w = 100 
    796999            else: 
    7971000                h = 100 
     
    8071010        if self.orientation == Qt.Horizontal: 
    8081011            h = 5 + metrics.height() 
    809             left = - metrics.boundingRect(ticks[0]).width()/2.0 #+ geometry.left()  
    810             right = geometry.width() + metrics.boundingRect(ticks[-1]).width()/2.0 
     1012            left = - metrics.boundingRect(ticks[0]).width() / 2.0 
     1013            right = geometry.width() + \ 
     1014                    metrics.boundingRect(ticks[-1]).width() / 2.0 
     1015 
    8111016            rect = QRectF(left, 0.0, right - left, h) 
    8121017        else: 
    8131018            h = geometry.height() 
    8141019            w = max([metrics.width(t) for t in ticks]) + 5 
    815             rect = QRectF(0.0, 0.0, w, h)  
     1020            rect = QRectF(0.0, 0.0, w, h) 
    8161021        return rect 
    817      
     1022 
    8181023    def set_axis_scale(self, min, max): 
    8191024        self.axis_scale = (min, max) 
    8201025        self.updateGeometry() 
    821          
     1026 
    8221027    def set_axis_ticks(self, ticks): 
    8231028        if isinstance(ticks, dict): 
    8241029            self.ticks = ticks 
    8251030        self.updateGeometry() 
    826              
     1031 
    8271032    def tick_layout(self): 
    828         """ Return the tick layout 
     1033        """ 
     1034        Return the tick layout 
    8291035        """ 
    8301036        minval, maxval = self.axis_scale 
    8311037        ticks = numpy.linspace(minval, maxval, self.tick_count) 
    8321038        return zip(ticks, self.ticks()) 
    833      
    834 #        min, max = self.axis_scale 
    835 #        ticks = self.ticks() 
    836 #        span = max - min 
    837 #        span_log = math.log10(span) 
    838 #        log_sign = -1 if log_sign < 0.0 else 1 
    839 #        span_log = math.floor(span_log) 
    840 #        major_ticks = [(x, 5.0, tick(i, span_log)) for i in range(self.tick_count)] 
    841 #        minor_ticks = [(x, 3.0, tick(i, span_log + log_sign))  for i in range(self.tick_count * 2)] 
    842 #        return [(i, major, label) for i, tick, label in major_ticks] 
    843      
    844      
     1039 
     1040 
    8451041class ScaleScene(QGraphicsScene): 
    8461042    def __init__(self, widget, parent=None): 
     
    8591055        self.addItem(self.scale_widget) 
    8601056        self.addItem(self.marker) 
    861         self.setSceneRect(QRectF(0, 0, self.scale_widget.size().height(), 25.0)) 
    862          
     1057        self.setSceneRect(QRectF(0, 0, 
     1058                                 self.scale_widget.size().height(), 25.0)) 
     1059 
    8631060    def set_scale(self, min, max): 
    8641061        self.scale_widget.set_axis_scale(min, max) 
    865          
     1062 
    8661063    def set_scale_bounds(self, start, end): 
    8671064        self.scale_widget.setPos(start, 0) 
    8681065        size_hint = self.scale_widget.sizeHint(Qt.PreferredSize) 
    869         self.scale_widget.resize(end - start, self.scale_widget.size().height()) 
    870          
     1066        self.scale_widget.resize(end - start, 
     1067                                 self.scale_widget.size().height()) 
     1068 
    8711069    def scene_rect_update(self, rect): 
    8721070        scale_rect = self.scale_widget.sceneBoundingRect() 
    873         rect = QRectF(rect.x(), scale_rect.y(), rect.width(), scale_rect.height()) 
     1071        rect = QRectF(rect.x(), scale_rect.y(), 
     1072                      rect.width(), scale_rect.height()) 
    8741073        rect = QRectF(rect.x(), 0.0, rect.width(), scale_rect.height()) 
    8751074        self.marker.setLine(0, 0, 0, scale_rect.height()) 
    8761075        self.setSceneRect(rect) 
    877          
     1076 
    8781077    def set_marker(self, pos): 
    8791078        pos = self.scale_widget.mapToScene(pos) 
    8801079        self.marker.setPos(pos.x(), 0.0) 
    881          
     1080 
    8821081    def mousePressEvent(self, event): 
    8831082        if event.button() == Qt.LeftButton: 
    8841083            pos = self.scale_widget.mapFromScene(event.scenePos()) 
    8851084            self.widget.set_cuttof_position_from_scale(pos) 
    886              
     1085 
    8871086    def mouseMoveEvent(self, event): 
    8881087        if event.buttons() & Qt.LeftButton: 
    8891088            pos = self.scale_widget.mapFromScene(event.scenePos()) 
    8901089            self.widget.set_cuttof_position_from_scale(pos) 
    891          
     1090 
    8921091    def mouseReleaseEvent(self, event): 
    8931092        if event.button() == Qt.LeftButton: 
    8941093            pos = self.scale_widget.mapFromScene(event.scenePos()) 
    8951094            self.widget.set_cuttof_position_from_scale(pos) 
    896              
    897                  
     1095 
     1096 
    8981097class ScaleView(QGraphicsView): 
    8991098    def __init__(self, scene=None, parent=None): 
     
    9061105 
    9071106def test(): 
    908     app=QApplication(sys.argv) 
    909     w=OWHierarchicalClustering() 
     1107    app = QApplication(sys.argv) 
     1108    w = OWHierarchicalClustering() 
    9101109    w.show() 
    911     data=orange.ExampleTable("../../doc/datasets/iris.tab") 
    912     id=orange.newmetaid() 
    913     data.domain.addmeta(id, orange.FloatVariable("a")) 
     1110    data = Orange.data.Table("iris") 
     1111    id = Orange.feature.Descriptor.new_meta_id() 
     1112    data.domain.addmeta(id, Orange.feature.Continuous("a")) 
    9141113    data.addMetaAttribute(id) 
    915     matrix = orange.SymMatrix(len(data)) 
    916     dist = orange.ExamplesDistanceConstructor_Euclidean(data) 
    917     matrix = orange.SymMatrix(len(data)) 
     1114 
     1115    dist = Orange.distance.Euclidean() 
     1116    matrix = Orange.distance.distance_matrix(data, dist) 
    9181117    matrix.setattr('items', data) 
    919     for i in range(len(data)): 
    920         for j in range(i+1): 
    921             matrix[i, j] = dist(data[i], data[j]) 
    9221118 
    9231119    w.set_matrix(matrix) 
    9241120    app.exec_() 
    925      
    926 if __name__=="__main__": 
     1121 
     1122if __name__ == "__main__": 
    9271123    test() 
Note: See TracChangeset for help on using the changeset viewer.