source: orange/orange/OrangeWidgets/Visualize/OWLinProj.py @ 3483:c628d1e304b8

Revision 3483:c628d1e304b8, 24.2 KB checked in by Gregor <Gregor@…>, 6 years ago (diff)
  • faster drawing with less curves
  • modified tab names
  • changed signal names and their handler functions
Line 
1"""
2<name>Linear Projection</name>
3<description>Create a linear projection.</description>
4<contact>Gregor Leban (gregor.leban@fri.uni-lj.si)</contact>
5<icon>icons/LinearProjection.png</icon>
6<priority>2000</priority>
7"""
8# LinProj.py
9#
10# Show a linear projection of the data
11#
12
13from OWVisWidget import *
14from OWLinProjGraph import *
15from OWkNNOptimization import OWVizRank
16##from OWClusterOptimization import *
17from OWFreeVizOptimization import *
18import OWToolbars, OWGUI, orngTest
19import orngVisFuncts, OWDlgs
20import orngVizRank
21
22###########################################################################################
23##### WIDGET : Linear Projection
24###########################################################################################
25class OWLinProj(OWVisWidget):
26    settingsList = ["graph.pointWidth", "graph.jitterSize", "graph.globalValueScaling", "graph.showFilledSymbols", "graph.scaleFactor",
27                    "graph.showLegend", "graph.useDifferentSymbols", "autoSendSelection", "graph.useDifferentColors",
28                    "graph.tooltipKind", "graph.tooltipValue", "toolbarSelection",
29                    "showProbabilitiesDetails", "graph.showProbabilities", "graph.squareGranularity", "graph.spaceBetweenCells",
30                    "valueScalingType", "showAllAttributes", "colorSettings", "selectedSchemaIndex", "addProjectedPositions"]
31    jitterSizeNums = [0.0, 0.01, 0.1, 0.5, 1, 2, 3, 4, 5, 7, 10, 15, 20]
32    jitterSizeList = [str(x) for x in jitterSizeNums]
33
34    contextHandlers = {"": DomainContextHandler("", [ContextField("shownAttributes", DomainContextHandler.RequiredList, selected="selectedShown", reservoir="hiddenAttributes")])}
35
36    def __init__(self,parent=None, signalManager = None, name = "Linear Projection", graphClass = None):
37        OWVisWidget.__init__(self, parent, signalManager, name, TRUE)
38
39        self.inputs = [("Examples", ExampleTable, self.setData, Default), ("Example Subset", ExampleTable, self.setSubsetData), ("Attribute Selection List", AttributeList, self.setShownAttributes), ("Evaluation Results", orngTest.ExperimentResults, self.setTestResults), ("VizRank Learner", orange.Learner, self.setVizRankLearner)]
40        self.outputs = [("Selected Examples", ExampleTable), ("Unselected Examples", ExampleTable), ("Attribute Selection List", AttributeList), ("FreeViz Learner", orange.Learner)]
41
42        # local variables
43        self.showAllAttributes = 0
44        self.valueScalingType = 0
45        self.autoSendSelection = 1
46        self.data = None
47        self.unprocessedSubsetData = None
48        self.toolbarSelection = 0
49        self.classificationResults = None
50        self.outlierValues = None
51        self.attributeSelectionList = None
52        self.colorSettings = None
53        self.selectedSchemaIndex = 0
54        self.addProjectedPositions = 0
55        self.resetAnchors = 0
56
57        self.showProbabilitiesDetails = 0
58        self.boxGeneral = 1
59
60        #add a graph widget
61        self.box = QVBoxLayout(self.mainArea)
62        if graphClass:
63            self.graph = graphClass(self, self.mainArea, name)
64        else:
65            self.graph = OWLinProjGraph(self, self.mainArea, name)
66        self.box.addWidget(self.graph)
67
68        # graph variables
69        self.graph.manualPositioning = 0
70        self.graph.hideRadius = 0
71##        self.graph.showClusters = 0
72        self.graph.showAnchors = 1
73        self.graph.jitterContinuous = 0
74        self.graph.showProbabilities = 0
75        self.graph.useDifferentSymbols = 0
76        self.graph.useDifferentColors = 1
77        self.graph.tooltipKind = 0
78        self.graph.tooltipValue = 0
79        self.graph.scaleFactor = 1.0
80        self.graph.squareGranularity = 3
81        self.graph.spaceBetweenCells = 1
82        self.graph.showAxisScale = 0
83
84        #load settings
85        self.loadSettings()
86
87##        # cluster dialog
88##        self.clusterDlg = ClusterOptimization(self, self.signalManager, self.graph, name)
89##        self.graph.clusterOptimization = self.clusterDlg
90
91        # freeviz dialog
92        self.freeVizDlg = FreeVizOptimization(self, self.signalManager, self.graph, name)
93        if name.lower() == "linear projection":
94            self.freeVizLearner = FreeVizLearner(self.freeVizDlg)
95            self.send("FreeViz Learner", self.freeVizLearner)
96
97        # optimization dialog
98        if name.lower() == "radviz":
99            self.vizrank = OWVizRank(self, self.signalManager, self.graph, orngVizRank.RADVIZ, name)
100            self.connect(self.graphButton, SIGNAL("clicked()"), self.saveToFile)
101        elif name.lower() == "polyviz":
102            self.vizrank = OWVizRank(self, self.signalManager, self.graph, orngVizRank.POLYVIZ, name)
103            self.connect(self.graphButton, SIGNAL("clicked()"), self.graph.saveToFile)
104        else:
105            self.vizrank = OWVizRank(self, self.signalManager, self.graph, orngVizRank.LINEAR_PROJECTION, name)
106            self.connect(self.graphButton, SIGNAL("clicked()"), self.saveToFile)
107
108        self.optimizationDlg = self.vizrank  # for backward compatibility
109
110        self.graph.normalizeExamples = (name.lower() == "radviz")       # ignore settings!! if we have radviz then normalize, otherwise not.
111
112        #GUI
113        # add a settings dialog and initialize its values
114        self.tabs = QTabWidget(self.space, 'tabWidget')
115        self.GeneralTab = QVGroupBox(self)
116        #self.GeneralTab.setFrameShape(QFrame.NoFrame)
117        self.SettingsTab = QVGroupBox(self)
118        self.tabs.insertTab(self.GeneralTab, "Main")
119        self.tabs.insertTab(self.SettingsTab, "Settings")
120
121        #add controls to self.controlArea widget
122        self.createShowHiddenLists(self.GeneralTab, callback = self.updateGraphAndAnchors)
123
124        self.optimizationButtons = OWGUI.widgetBox(self.GeneralTab, "Optimization Dialogs", orientation = "horizontal")
125        self.vizrankButton = OWGUI.button(self.optimizationButtons, self, "VizRank", callback = self.vizrank.reshow, tooltip = "Opens VizRank dialog, where you can search for interesting projections with different subsets of attributes.", debuggingEnabled = 0)
126        self.freeVizDlgButton = OWGUI.button(self.optimizationButtons, self, "FreeViz", callback = self.freeVizDlg.reshow, tooltip = "Opens FreeViz dialog, where the position of attribute anchors is optimized so that class separation is improved", debuggingEnabled = 0)
127##        self.clusterDetectionDlgButton = OWGUI.button(self.optimizationButtons, self, "Cluster", callback = self.clusterDlg.reshow, debuggingEnabled = 0)
128##        self.vizrankButton.setMaximumWidth(63)
129##        self.clusterDetectionDlgButton.setMaximumWidth(63)
130##        self.freeVizDlgButton.setMaximumWidth(63)
131##        self.connect(self.clusterDlg.startOptimizationButton , SIGNAL("clicked()"), self.optimizeClusters)
132##        self.connect(self.clusterDlg.resultList, SIGNAL("selectionChanged()"),self.showSelectedCluster)
133
134        self.zoomSelectToolbar = OWToolbars.ZoomSelectToolbar(self, self.GeneralTab, self.graph, self.autoSendSelection)
135        self.graph.selectionChangedCallback = self.selectionChanged
136        self.connect(self.zoomSelectToolbar.buttonSendSelections, SIGNAL("clicked()"), self.sendSelections)
137
138        # ####################################
139        # SETTINGS TAB
140        # #####
141        self.extraTopBox = OWGUI.widgetBox(self.SettingsTab, orientation = "vertical")
142        self.extraTopBox.hide()
143        OWGUI.hSlider(self.SettingsTab, self, 'graph.pointWidth', box=' Point Size ', minValue=1, maxValue=15, step=1, callback = self.updateGraph)
144
145        box = OWGUI.widgetBox(self.SettingsTab, "Jittering Options")
146        box2 = OWGUI.widgetBox(self.SettingsTab, "Scaling Options")
147        box3 = OWGUI.collapsableWidgetBox(self.SettingsTab, "General Graph Settings", self, "boxGeneral")
148        box8 = OWGUI.widgetBox(self.SettingsTab, "Colors", orientation = "horizontal")
149        box9 = OWGUI.widgetBox(self.SettingsTab, "Tooltips Settings")
150        box10 = OWGUI.widgetBox(self.SettingsTab, "Sending Selection")
151
152        OWGUI.comboBox(box9, self, "graph.tooltipKind", items = ["Show line tooltips", "Show visible attributes", "Show all attributes"], callback = self.updateGraph)
153        OWGUI.comboBox(box9, self, "graph.tooltipValue", items = ["Tooltips show data values", "Tooltips show spring values"], callback = self.updateGraph, tooltip = "Do you wish that tooltips would show you original values of visualized attributes or the 'spring' values (values between 0 and 1). \nSpring values are scaled values that are used for determining the position of shown points. Observing these values will therefore enable you to \nunderstand why the points are placed where they are.")
154
155        OWGUI.checkBox(box10, self, 'autoSendSelection', 'Auto send selected/unselected data', callback = self.selectionChanged, tooltip = "Send signals with selected data whenever the selection changes.")
156        OWGUI.comboBox(box10, self, "addProjectedPositions", items = ["Do not modify the domain", "Append projection as attributes", "Append projection as meta attributes"], callback = self.sendSelections)
157        self.selectionChanged()
158
159        # this is needed so that the tabs are wide enough!
160        self.safeProcessEvents()
161        self.tabs.updateGeometry()
162
163        OWGUI.comboBoxWithCaption(box, self, "graph.jitterSize", 'Jittering size (% of range):  ', callback = self.resetGraphData, items = self.jitterSizeNums, sendSelectedValue = 1, valueType = float)
164        OWGUI.checkBox(box, self, 'graph.jitterContinuous', 'Jitter continuous attributes', callback = self.resetGraphData, tooltip = "Does jittering apply also on continuous attributes?")
165
166        OWGUI.qwtHSlider(box2, self, "graph.scaleFactor", minValue=1.0, maxValue= 10.0, step=0.1, label ='Inflate points by:     ', callback = self.updateGraph, tooltip="If points lie too much together you can expand their position to improve perception")
167        valueScalingList = ["attribute range", "global range", "attribute variance"]
168        if name.lower() in ["radviz", "polyviz"]:
169            valueScalingList.pop(); self.valueScalingType = min(self.valueScalingType, 1)
170        OWGUI.comboBoxWithCaption(box2, self, "valueScalingType", 'Scale values by: ', callback = self.setValueScaling, items = valueScalingList)
171
172        #OWGUI.checkBox(box3, self, 'graph.normalizeExamples', 'Normalize examples', callback = self.updateGraph)
173        OWGUI.checkBox(box3, self, 'graph.showLegend', 'Show legend', callback = self.updateGraph)
174        OWGUI.checkBox(box3, self, 'graph.useDifferentSymbols', 'Use different symbols', callback = self.updateGraph, tooltip = "Show different class values using different symbols")
175        OWGUI.checkBox(box3, self, 'graph.useDifferentColors', 'Use different colors', callback = self.updateGraph, tooltip = "Show different class values using different colors")
176        OWGUI.checkBox(box3, self, 'graph.showFilledSymbols', 'Show filled symbols', callback = self.updateGraph)
177##        OWGUI.checkBox(box3, self, 'graph.showClusters', 'Show clusters', callback = self.updateGraph, tooltip = "Show a line boundary around a significant cluster")
178
179        box5 = OWGUI.widgetBox(box3, orientation = "horizontal")
180        box6 = OWGUI.widgetBox(box3, orientation = "horizontal")
181        box7 = OWGUI.widgetBox(box3, orientation = "horizontal")
182
183        OWGUI.checkBox(box5, self, 'graph.showProbabilities', 'Show probabilities  ', callback = self.updateGraph, tooltip = "Show a background image with class probabilities")
184        hider = OWGUI.widgetHider(box5, self, "showProbabilitiesDetails", tooltip = "Show/hide extra settings")
185        rubb = OWGUI.rubber(box5)
186        rubb.setSizePolicy(QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Maximum))
187
188        OWGUI.separator(box6, width=20)
189        OWGUI.label(box6, self, "Granularity:  ")
190        OWGUI.hSlider(box6, self, 'graph.squareGranularity', minValue=1, maxValue=10, step=1, callback = self.updateGraph)
191
192        OWGUI.separator(box7, width=20)
193        OWGUI.checkBox(box7, self, 'graph.spaceBetweenCells', 'Show space between cells', callback = self.updateGraph)
194        hider.setWidgets([box6, box7])
195
196        OWGUI.button(box8, self, "Set Colors", self.setColors, tooltip = "Set the canvas background color and color palette for coloring continuous variables", debuggingEnabled = 0)
197
198        self.icons = self.createAttributeIconDict()
199        self.debugSettings = ["hiddenAttributes", "shownAttributes"]
200
201        # add a settings dialog and initialize its values
202        self.activateLoadedSettings()
203        self.setValueScaling() # XXX is there any better way to do this?!
204        self.resize(900, 700)
205
206
207    def saveToFile(self):
208        self.graph.saveToFile([("Save PixTex", self.graph.savePicTeX)])
209
210    def activateLoadedSettings(self):
211        dlg = self.createColorDialog()
212        self.graph.contPalette = dlg.getContinuousPalette("contPalette")
213        self.graph.discPalette = dlg.getDiscretePalette()
214        self.graph.setCanvasBackground(dlg.getColor("Canvas"))
215
216        apply([self.zoomSelectToolbar.actionZooming, self.zoomSelectToolbar.actionRectangleSelection, self.zoomSelectToolbar.actionPolygonSelection][self.toolbarSelection], [])
217
218        self.cbShowAllAttributes()
219        self.setValueScaling()
220
221
222    # #########################
223    # KNN OPTIMIZATION BUTTON EVENTS
224    # #########################
225    def saveCurrentProjection(self):
226        qname = QFileDialog.getSaveFileName( os.path.realpath(".") + "/Linear_projection.tab", "Orange Example Table (*.tab)", self, "", "Save File")
227        if qname.isEmpty(): return
228        name = str(qname)
229        if len(name) < 4 or name[-4] != ".":
230            name = name + ".tab"
231        self.graph.saveProjectionAsTabData(name, self.getShownAttributeList())
232
233
234##    # ################################################################################################
235##    # find projections that have tight clusters of points that belong to the same class value
236##    def optimizeClusters(self):
237##        if self.data == None: return
238##        if not self.hasDiscreteClass(self.data):
239##            QMessageBox.critical( None, "Cluster Detection Dialog", 'Clusters can be detected only in data sets with a discrete class value', QMessageBox.Ok)
240##            return
241##
242##        self.clusterDlg.clearResults()
243##        self.clusterDlg.clusterStabilityButton.setOn(0)
244##        self.clusterDlg.pointStability = None
245##
246##        try:
247##            listOfAttributes = self.vizrank.getEvaluatedAttributes(self.data)
248##            text = str(self.vizrank.attributeCountCombo.currentText())
249##            if text == "ALL": maxLen = len(listOfAttributes)
250##            else:             maxLen = int(text)
251##
252##            if self.clusterDlg.getOptimizationType() == self.clusterDlg.EXACT_NUMBER_OF_ATTRS: minLen = maxLen
253##            else: minLen = 3
254##
255##            possibilities = 0
256##            for i in range(minLen, maxLen+1): possibilities += orngVisFuncts.combinationsCount(i, len(listOfAttributes))* orngVisFuncts.fact(i-1)/2
257##
258##            self.graph.totalPossibilities = possibilities
259##            self.graph.triedPossibilities = 0
260##
261##            if self.graph.totalPossibilities > 20000:
262##                proj = str(self.graph.totalPossibilities)
263##                l = len(proj)
264##                for i in range(len(proj)-2, 0, -1):
265##                    if (l-i)%3 == 0: proj = proj[:i] + "," + proj[i:]
266##                self.printEvent("OWLinProj: Warning: There are %s possible projections using currently visualized attributes"% (proj), eventVerbosity = 1)
267##
268##            self.clusterDlg.disableControls()
269##
270##            self.graph.getOptimalClusters(listOfAttributes, minLen, maxLen, self.clusterDlg.addResult)
271##        except:
272##            type, val, traceback = sys.exc_info()
273##            sys.excepthook(type, val, traceback)  # print the exception
274##
275##        self.clusterDlg.enableControls()
276##        self.clusterDlg.finishedAddingResults()
277##        self.showSelectedCluster()
278
279
280    # send signals with selected and unselected examples as two datasets
281    def sendSelections(self):
282        if not self.data: return
283        (selected, unselected) = self.graph.getSelectionsAsExampleTables(self.getShownAttributeList(), addProjectedPositions = self.addProjectedPositions)
284
285        self.send("Selected Examples",selected)
286        self.send("Unselected Examples",unselected)
287
288    def sendShownAttributes(self):
289        self.send("Attribute Selection List", [a[0] for a in self.shownAttributes])
290
291
292    # show selected interesting projection
293    def showSelectedAttributes(self):
294        val = self.vizrank.getSelectedProjection()
295        if val:
296            (accuracy, other_results, tableLen, attrList, tryIndex, generalDict) = val
297            self.updateGraph(attrList, setAnchors= 1, XAnchors = generalDict.get("XAnchors"), YAnchors = generalDict.get("YAnchors"))
298            self.graph.removeAllSelections()
299
300
301##    def showSelectedCluster(self):
302##        val = self.clusterDlg.getSelectedCluster()
303##        if not val: return
304##        (value, closure, vertices, attrList, classValue, enlargedClosure, other, strList) = val
305##
306##        if self.clusterDlg.clusterStabilityButton.isOn():
307##            validData = self.graph.getValidList([self.graph.attributeNames.index(attr) for attr in attrList])
308##            insideColors = (numpy.compress(validData, self.clusterDlg.pointStability), "Point inside a cluster in %.2f%%")
309##        else: insideColors = None
310##
311##        self.updateGraph(attrList, 1, insideColors, clusterClosure = (closure, enlargedClosure, classValue))
312##        self.graph.removeAllSelections()
313
314
315    def updateGraphAndAnchors(self):
316        self.updateGraph(setAnchors = 1)
317
318    def updateGraph(self, attrList = None, setAnchors = 0, insideColors = None, clusterClosure = None, **args):
319        if not attrList:
320            attrList = self.getShownAttributeList()
321        else:
322            self.setShownAttributeList(self.data, attrList)
323
324        self.graph.showKNN = 0
325        if self.hasDiscreteClass(self.data):
326            self.graph.showKNN = self.vizrank.showKNNCorrectButton.isOn() and 1 or  self.vizrank.showKNNCorrectButton.isOn() and 2
327
328        self.graph.insideColors = insideColors or self.classificationResults or self.outlierValues
329##        self.graph.clusterClosure = clusterClosure
330
331        self.graph.updateData(attrList, setAnchors, **args)
332        self.graph.repaint()
333
334
335    # ###############################################################################################################
336    # INPUT SIGNALS
337
338    # receive new data and update all fields
339    def setData(self, data):
340        if data and data.domain.classVar:
341            name = getattr(data, "name", "")
342            data = data.filterref(orange.Filter_hasClassValue())
343            data.name = name
344        if self.data and data and self.data.checksum() == data.checksum():
345            return    # check if the new data set is the same as the old one
346
347        self.closeContext()
348        exData = self.data
349        self.data = data
350        self.vizrank.setData(data)
351##        self.clusterDlg.setData(data)
352        self.freeVizDlg.setData(data)
353        self.classificationResults = None
354        self.outlierValues = None
355
356        sameDomain = self.data and exData and exData.domain.checksum() == self.data.domain.checksum() # preserve attribute choice if the domain is the same
357        if not sameDomain:
358            self.setShownAttributeList(self.data, self.attributeSelectionList)
359        self.resetAnchors += not sameDomain
360
361        self.openContext("", data)
362        self.resetAttrManipulation()
363
364        if data and self.unprocessedSubsetData:        # if we first received subset data we now have to call setSubsetData to process it
365            self.setSubsetData(self.unprocessedSubsetData)
366            self.unprocessedSubsetData = None
367
368
369    def setSubsetData(self, data, update = 1):
370        if not self.data:
371            self.unprocessedSubsetData = data
372            self.warning(10)
373            return
374
375        if self.graph.subsetData != None and data != None and self.graph.subsetData.checksum() == data.checksum():
376            return    # check if the new data set is the same as the old one
377
378        try:
379            subsetData = data.select(self.data.domain)
380            self.warning(10)
381        except:
382            subsetData = None
383            self.warning(10, data and "'Examples' and 'Example Subset' data do not have copatible domains. Unable to draw 'Example Subset' data." or "")
384
385        self.vizrank.setSubsetData(subsetData)
386#        if update: self.updateGraph()
387##        self.clusterDlg.setSubsetData(data)
388#        qApp.processEvents()
389
390
391    # attribute selection signal - info about which attributes to show
392    def setShownAttributes(self, attributeSelectionList):
393        self.attributeSelectionList = attributeSelectionList
394        if self.data and self.attributeSelectionList:
395            for attr in self.attributeSelectionList:
396                if not self.graph.attributeNameIndex.has_key(attr):  # this attribute list belongs to a new dataset that has not come yet
397                    return
398
399            self.setShownAttributeList(self.data, self.attributeSelectionList)
400            self.attributeSelectionList = None
401            self.selectionChanged()
402        self.resetAnchors += 1
403
404    # visualize the results of the classification
405    def setTestResults(self, results):
406        self.classificationResults = None
407        if isinstance(results, orngTest.ExperimentResults) and len(results.results) > 0 and len(results.results[0].probabilities) > 0:
408            self.classificationResults = ([results.results[i].probabilities[0][results.results[i].actualClass] for i in range(len(results.results))], "Probability of correct classificatioin = %.2f%%")
409        self.resetAnchors += 1
410
411
412    # set the learning method to be used in VizRank
413    def setVizRankLearner(self, learner):
414        self.vizrank.externalLearner = learner
415
416    # this is called by OWBaseWidget after setData and setSubsetData are called. this way the graph is updated only once
417    def handleNewSignals(self):
418        self.updateGraph(setAnchors = self.resetAnchors)
419        self.sendSelections()
420        self.resetAnchors = 0
421
422    # EVENTS
423    def resetBmpUpdateValues(self):
424        self.graph.potentialsBmp = None
425        self.updateGraph()
426
427    def resetGraphData(self):
428        orngScaleLinProjData.setData(self.graph, self.data)
429        #self.graph.setData(self.data)
430        self.updateGraph()
431
432    def setValueScaling(self):
433        self.graph.insideColors = self.graph.clusterClosure = None
434        if self.valueScalingType == 0:
435            self.graph.globalValueScaling = self.graph.scalingByVariance = 0
436        elif self.valueScalingType == 1:
437            self.graph.globalValueScaling = 1
438            self.graph.scalingByVariance = 0
439        else:
440            self.graph.globalValueScaling = 0
441            self.graph.scalingByVariance = 1
442        #self.graph.setData(self.data)
443        orngScaleLinProjData.setData(self.graph, self.data)
444        self.graph.potentialsBmp = None
445        self.updateGraph()
446
447
448    def selectionChanged(self):
449        self.zoomSelectToolbar.buttonSendSelections.setEnabled(not self.autoSendSelection)
450        if self.autoSendSelection:
451            self.sendSelections()
452
453    def setColors(self):
454        dlg = self.createColorDialog()
455        if dlg.exec_loop():
456            self.colorSettings = dlg.getColorSchemas()
457            self.selectedSchemaIndex = dlg.selectedSchemaIndex
458            self.graph.contPalette = dlg.getContinuousPalette("contPalette")
459            self.graph.discPalette = dlg.getDiscretePalette()
460            self.graph.setCanvasBackground(dlg.getColor("Canvas"))
461            self.updateGraph()
462
463    def createColorDialog(self):
464        c = OWDlgs.ColorPalette(self, "Color Palette")
465        c.createDiscretePalette(" Discrete Palette ")
466        c.createContinuousPalette("contPalette", " Continuous palette ")
467        box = c.createBox("otherColors", " Other Colors ")
468        c.createColorButton(box, "Canvas", "Canvas color", Qt.white)
469        c.setColorSchemas(self.colorSettings, self.selectedSchemaIndex)
470        box.addSpace(5)
471        box.adjustSize()
472        return c
473
474    def destroy(self, dw = 1, dsw = 1):
475##        self.clusterDlg.hide()
476        self.vizrank.hide()
477        self.freeVizDlg.hide()
478        OWVisWidget.destroy(self, dw, dsw)
479
480
481#test widget appearance
482if __name__=="__main__":
483    a=QApplication(sys.argv)
484    ow=OWLinProj()
485    a.setMainWidget(ow)
486    ow.show()
487    ow.setData(orange.ExampleTable("..\\..\\doc\\datasets\\zoo"))
488    a.exec_loop()
489
490    #save settings
491    ow.saveSettings()
Note: See TracBrowser for help on using the repository browser.