source: orange/Orange/OrangeWidgets/OWkNNOptimization.py @ 9671:a7b056375472

Revision 9671:a7b056375472, 94.1 KB checked in by anze <anze.staric@…>, 2 years ago (diff)

Moved orange to Orange (part 2)

Line 
1from OWWidget import *
2import OWGUI, OWDlgs, numpy, user, sys
3from orngVizRank import *
4from orngScaleData import getVariableValuesSorted
5
6_graph_dialogs = True
7try:
8    from OWGraph import *
9except ImportError:
10    _graph_dialogs = False
11
12
13class OWVizRank(VizRank, OWWidget):
14    settingsList = ["kValue", "resultListLen", "percentDataUsed", "qualityMeasure", "qualityMeasureCluster", "qualityMeasureContClass", "testingMethod",
15                    "lastSaveDirName", "attrCont", "attrDisc", "showRank", "showAccuracy", "showInstances",
16                    "evaluationAlgorithm", "evaluationTime", "learnerName", "attrContContClass", "attrDiscContClass", "attrContNoClass", "attrDiscNoClass",
17                    "argumentCount", "optimizeBestProjection", "optimizeBestProjectionTime",
18                    "locOptMaxAttrsInProj", "locOptAttrsToTry", "locOptProjCount", "locOptAllowAddingAttributes",
19                    "useExampleWeighting", "projOptimizationMethod", "attrSubsetSelection", "optimizationType", "attributeCount",
20                    "locOptOptimizeProjectionByPermutingAttributes", "timeLimit", "projectionLimit", "storeEachPermutation",
21                    "boxLocalOptimization", "boxStopOptimization", "clearPreviousProjections"]
22    resultsListLenNums = [ 10, 100 ,  500 ,  1000 ,  5000 ,  10000, 20000, 50000, 100000, 500000 ]
23    percentDataNums = [ 5 ,  10 ,  15 ,  20 ,  30 ,  40 ,  50 ,  60 ,  70 ,  80 ,  90 ,  100 ]
24    kNeighboursNums = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 15, 17, 20, 25, 30,35, 40, 50, 60, 70, 80, 100, 120, 150, 200]
25    argumentCounts = [1, 3, 5, 10, 15, 20, 30, 50, 100, 200]
26    evaluationTimeNums = [0.1, 0.5, 1, 2, 5, 10, 20, 30, 40, 60, 80, 120]
27    moreArgumentsNums = [50, 55, 60, 65, 70, 75, 80, 85, 90, 95]
28
29    def __init__(self, parentWidget = None, signalManager = None, graph = None, visualizationMethod = SCATTERPLOT, parentName = "Visualization widget"):
30        OWWidget.__init__(self, None, signalManager, "VizRank Dialog", savePosition = True, wantMainArea = 0, wantStatusBar = 1)
31        VizRank.__init__(self, visualizationMethod, graph)
32
33        self.parentWidget = parentWidget
34        self.parentName = parentName
35        self.visualizationMethod = visualizationMethod
36
37        self.resultListLen = 1000
38        self.cancelOptimization = 0
39        self.cancelEvaluation = 0
40        self.learnerName = "VizRank Learner"
41
42        self.useTimeLimit = 0
43        self.useProjectionLimit = 0
44        self.evaluationTime = 10
45        self.optimizeBestProjection = 0                     # do we want to try to locally improve the best projections
46        self.optimizeBestProjectionTime = 10                 # how many minutes do we want to try to locally optimize the best projections
47        self.clearPreviousProjections = 1
48
49        self.maxResultListLen = self.resultsListLenNums[len(self.resultsListLenNums)-1]
50        self.lastSaveDirName = os.getcwd()
51
52        self.evaluatedAttributes = None   # save last evaluated attributes
53        self.evaluatedAttributesByClass = None
54
55        self.showRank = 0
56        self.showAccuracy = 1
57        self.showInstances = 0
58        self.shownResults = []
59        self.attrLenDict = {}
60
61        self.interactionAnalysisDlg = None
62        self.identifyOutliersDlg = None
63        self.attributeHistogramDlg = None
64
65        self.loadSettings()
66        self.attrCont = min(self.attrCont, 3)
67
68        self.layout().setMargin(0)
69        self.tabs = OWGUI.tabWidget(self.controlArea)
70        self.MainTab = OWGUI.createTabPage(self.tabs, "Main")
71        self.SettingsTab = OWGUI.createTabPage(self.tabs, "Settings")
72        self.ArgumentationTab = OWGUI.createTabPage(self.tabs, "Argumentation")
73        self.ManageTab = OWGUI.createTabPage(self.tabs, "Manage && Save")
74
75        # ###########################
76        # MAIN TAB
77        self.optimizationBox = OWGUI.widgetBox(self.MainTab, "Evaluate")   
78        self.buttonBox = OWGUI.widgetBox(self.optimizationBox, orientation = "horizontal")
79
80        if visualizationMethod != SCATTERPLOT and visualizationMethod != SCATTERPLOT3D:
81            self.label1 = OWGUI.widgetLabel(self.buttonBox, 'Projections with ' )
82            self.optimizationTypeCombo = OWGUI.comboBox(self.buttonBox, self, "optimizationType", items = ["    exactly    ", "  maximum  "] )
83            self.attributeCountCombo = OWGUI.comboBox(self.buttonBox, self, "attributeCount", items = range(3, 20), tooltip = "Evaluate only projections with exactly (or maximum) this number of attributes", sendSelectedValue = 1, valueType = int, debuggingEnabled = 0)
84            self.attributeLabel = OWGUI.widgetLabel(self.buttonBox, ' attributes')
85
86        self.startOptimizationButton = OWGUI.button(self.optimizationBox, self, "Start Evaluating Projections", callback = self.evaluateProjections)
87        f = self.startOptimizationButton.font(); f.setBold(1);   self.startOptimizationButton.setFont(f)
88        self.optimizeGivenProjectionButton = OWGUI.button(self.optimizationBox, self, "Locally Optimize Best Projections", callback = self.optimizeBestProjections)
89
90        box = OWGUI.widgetBox(self.MainTab, "Projection List, Most Interesting Projections First")
91        self.resultList = OWGUI.listBox(box, self, callback = self.parentWidget and self.parentWidget.showSelectedAttributes or None)
92        #self.resultList.setMinimumSize(200,200)
93
94        self.resultsDetailsBox = OWGUI.widgetBox(self.MainTab, "Shown Details in Projections List" , orientation = "horizontal")
95        self.showRankCheck = OWGUI.checkBox(self.resultsDetailsBox, self, 'showRank', 'Rank', callback = self.updateShownProjections, tooltip = "Show projection ranks")
96        self.showAccuracyCheck = OWGUI.checkBox(self.resultsDetailsBox, self, 'showAccuracy', 'Score', callback = self.updateShownProjections, tooltip = "Show prediction accuracy of a k-NN classifier on the projection")
97        self.showInstancesCheck = OWGUI.checkBox(self.resultsDetailsBox, self, 'showInstances', '# Instances', callback = self.updateShownProjections, tooltip = "Show number of instances in the projection")
98
99        # ##########################
100        # SETTINGS TAB
101        self.optimizationSettingsDiscClassBox = OWGUI.widgetBox(self.SettingsTab, "VizRank Evaluation Settings")
102        self.methodTypeCombo = OWGUI.comboBoxWithCaption(self.optimizationSettingsDiscClassBox, self, "evaluationAlgorithm", "Projection evaluation method: ", tooltip = "Which learning method to use to use to evaluate given projections.", items = ["k-Nearest Neighbor", "Heuristic (very fast)"])
103        self.attrKNeighboursEdit = OWGUI.lineEdit(self.optimizationSettingsDiscClassBox, self, "kValue", "Number of neighbors (k):  ", orientation = "horizontal", tooltip = "Number of neighbors used in k-NN algorithm to evaluate the projection", valueType = int, validator = QIntValidator(self))
104        self.percentDataUsedCombo= OWGUI.comboBoxWithCaption(self.optimizationSettingsDiscClassBox, self, "percentDataUsed", "Percent of data used: ", items = self.percentDataNums, sendSelectedValue = 1, valueType = int, tooltip = "In case that we have a large dataset the evaluation of each projection can take a lot of time.\nWe can therefore use only a subset of randomly selected examples, evaluate projection on them and thus make evaluation faster.")
105        self.testingCombo = OWGUI.comboBox(self.optimizationSettingsDiscClassBox, self, "testingMethod", label = "Testing method:                             ", orientation = "horizontal", items = ["Leave one out (slowest)", "10 fold cross validation", "Test on learning set (fastest)"], tooltip = "Method for evaluating the classifier. Slower are more accurate while faster give only a rough approximation.")
106        OWGUI.checkBox(self.optimizationSettingsDiscClassBox, self, 'useExampleWeighting', 'Use example weighting', tooltip = "For datasets where we have uneven class distribution we can weight examples")
107        if visualizationMethod != SCATTERPLOT and visualizationMethod != SCATTERPLOT3D:
108            OWGUI.checkBox(self.optimizationSettingsDiscClassBox, self, 'storeEachPermutation', 'Save all projections for each permutation of attributes', tooltip = "Do you want to see in the projection list all evaluated projections or only the best projection for each attribute permutation.\nUsually this value is unchecked.")
109
110        if visualizationMethod == LINEAR_PROJECTION or visualizationMethod == LINEAR_PROJECTION3D:
111            OWGUI.comboBox(self.SettingsTab, self, "projOptimizationMethod", "Projection Optimization Method", items = ["None", "Supervised projection pursuit", "Partial least square"], sendSelectedValue = 0, tooltip = "What method do you want to use to find an interesting projection with good class separation?")
112        else:
113            self.projOptimizationMethod = 0
114           
115        self.optimizationSettingsNoClassBox = OWGUI.widgetBox(self.SettingsTab, "VizRank Evaluation Settings")
116       
117        self.measureComboDiscClassBox = OWGUI.widgetBox(self.SettingsTab, "Measure of Classification Success")
118        OWGUI.comboBox(self.measureComboDiscClassBox, self, "qualityMeasure", items = ["Classification accuracy", "Average Probability Assigned to the Correct Class", "Brier Score", "Area under Curve (AUC)"], tooltip = "Measure to evaluate prediction accuracy of k-NN method on the projected data set.")
119       
120#        self.measureComboContClassBox = OWGUI.widgetBox(self.SettingsTab, "Measure of Regression Accuracy")
121#        OWGUI.comboBox(self.measureComboDiscClassBox, self, "qualityMeasureContClass", items = ["Classification accuracy", "Average Probability Assigned to the Correct Class", "Brier Score", "Area under Curve (AUC)"], tooltip = "Measure to evaluate prediction accuracy of k-NN method on the projected data set.")
122#       
123#        self.measureComboNoClassBox = OWGUI.widgetBox(self.SettingsTab, "Measure of Cluster Interestingness")
124#        OWGUI.comboBox(self.measureComboNoClassBox, self, "qualityMeasureCluster", items = ["Example distance"], tooltip = "Measure to evaluate how well are points in the projection separated into clusters.")
125
126        self.attributeSelectionBox = OWGUI.widgetBox(self.SettingsTab, "Attribute Subset Selection")
127        OWGUI.comboBox(self.attributeSelectionBox, self, "attrSubsetSelection", items = ["Deterministically Using the Selected Attribute Ranking Measures", "Use Gamma Distribution and Test All Possible Placements", "Use Gamma Distribution and Test Only One Possible Placement"])
128
129        self.heuristicsSettingsDiscClassBox = OWGUI.widgetBox(self.SettingsTab, "Measures for Attribute Ranking")
130        OWGUI.comboBoxWithCaption(self.heuristicsSettingsDiscClassBox, self, "attrCont", "For continuous attributes:", items = [val for (val, m) in contMeasuresDiscClass], callback = self.removeEvaluatedAttributes)
131        OWGUI.comboBoxWithCaption(self.heuristicsSettingsDiscClassBox, self, "attrDisc", "For discrete attributes:", items = [val for (val, m) in discMeasuresDiscClass], callback = self.removeEvaluatedAttributes)
132       
133#        self.heuristicsSettingsNoClassBox = OWGUI.widgetBox(self.SettingsTab, "Measures for Attribute Ranking")
134#        OWGUI.comboBoxWithCaption(self.heuristicsSettingsNoClassBox, self, "attrContNoClass", "For continuous attributes:", items = [val for (val, m) in contMeasuresNoClass], callback = self.removeEvaluatedAttributes)
135#        OWGUI.comboBoxWithCaption(self.heuristicsSettingsNoClassBox, self, "attrDiscNoClass", "For discrete attributes:", items = [val for (val, m) in discMeasuresNoClass], callback = self.removeEvaluatedAttributes)
136#       
137#        self.heuristicsSettingsContClassBox = OWGUI.widgetBox(self.SettingsTab, "Measures for Attribute Ranking")
138#        OWGUI.comboBoxWithCaption(self.heuristicsSettingsContClassBox, self, "attrContContClass", "For continuous attributes:", items = [val for (val, m) in contMeasuresContClass], callback = self.removeEvaluatedAttributes)
139#        OWGUI.comboBoxWithCaption(self.heuristicsSettingsContClassBox, self, "attrDiscContClass", "For discrete attributes:", items = [val for (val, m) in discMeasuresContClass], callback = self.removeEvaluatedAttributes)
140       
141        self.miscSettingsBox = OWGUI.widgetBox(self.SettingsTab, "Projection List")
142        self.resultListCombo = OWGUI.comboBoxWithCaption(self.miscSettingsBox, self, "resultListLen", "Maximum length of projection list:   ", tooltip = 'Maximum number of top-ranked projections that are shown in the list box. This is also the number of projections that will be saved if you click "Save" button.', items = self.resultsListLenNums, callback = self.updateShownProjections, sendSelectedValue = 1, valueType = int)
143        OWGUI.checkBox(self.miscSettingsBox, self, 'clearPreviousProjections', 'Remove previously evaluated projections', tooltip = 'Do you want to continue projection evaluation from where it was stopped or do \nyou want to evaluate them from the start (by first clearing the list of evaluated projections)?')
144
145        smallWidget = OWGUI.SmallWidgetButton(OWGUI.widgetBox(self.SettingsTab, box = 1), text = "Show advanced settings")
146        self.stopOptimizationBox = OWGUI.widgetBox(smallWidget.widget, "When to automatically stop evaluation?", self)
147        OWGUI.checkWithSpin(self.stopOptimizationBox, self, "Time limit:                     ", 1, 1000, "useTimeLimit", "timeLimit", "  (minutes)", debuggingEnabled = 0)      # disable debugging. we always set this to 1 minute
148        OWGUI.checkWithSpin(self.stopOptimizationBox, self, "Use projection count limit:  ", 1, 1000000, "useProjectionLimit", "projectionLimit", "  (projections)", debuggingEnabled = 0)
149
150        self.localOptimizationSettingsBox = OWGUI.widgetBox(smallWidget.widget, "Local optimization settings", self)
151        bbb = OWGUI.checkBox(self.localOptimizationSettingsBox, self, 'locOptOptimizeProjectionByPermutingAttributes', 'Try improving projection by permuting attributes in projection')
152        self.localOptimizationProjCountCombo = OWGUI.comboBoxWithCaption(self.localOptimizationSettingsBox , self, "locOptProjCount", "Number of best projections to optimize:           ", items = range(1,30), tooltip = "Specify the number of best projections in the list that you want to try to locally optimize.\nIf you select 1 only the currently selected projection will be optimized.", sendSelectedValue = 1, valueType = int)
153        self.localOptimizationAttrsCount = OWGUI.lineEdit(self.localOptimizationSettingsBox, self, "locOptAttrsToTry", "Number of best attributes to try:                       ", orientation = "horizontal", tooltip = "How many of the top ranked attributes do you want to try in the projections?", valueType = int, validator = QIntValidator(self))
154        locOptBox = OWGUI.widgetBox(self.localOptimizationSettingsBox, orientation = "horizontal")
155        self.localOptimizationAddAttrsCheck  = OWGUI.checkBox(locOptBox, self, 'locOptAllowAddingAttributes', 'Allow adding attributes. Max attrs in proj:', tooltip = "Should local optimization only try to replace some attributes in a projection or is it also allowed to add new attributes?")
156        self.localOptimizationProjMaxAttr    = OWGUI.comboBox(locOptBox, self, "locOptMaxAttrsInProj", items = range(3,50), tooltip = "What is the maximum number of attributes in a projection?", sendSelectedValue = 1, valueType = int)
157
158        self.SettingsTab.layout().addStretch(100)
159
160        # ##########################
161        # ARGUMENTATION TAB
162        self.argumentationBox = OWGUI.widgetBox(self.ArgumentationTab, "Arguments")
163        self.findArgumentsButton = OWGUI.button(self.argumentationBox, self, "Find Arguments", callback = self.findArguments, debuggingEnabled = 0)
164        f = self.findArgumentsButton.font(); f.setBold(1);  self.findArgumentsButton.setFont(f)
165        self.argumentCountEdit = OWGUI.lineEdit(self.argumentationBox , self, "argumentCount", "Number of best projections to consider:     ", orientation = "horizontal", tooltip = "How many of the top ranked projections do you wish to consider?", valueType = int, validator = QIntValidator(self))
166
167        self.classValueCombo = OWGUI.comboBox(self.ArgumentationTab, self, "argumentationClassValue", box = "Arguments for Class:", tooltip = "Select the class value that you wish to see arguments for", callback = self.argumentationClassChanged, debuggingEnabled = 0)
168        self.argumentBox = OWGUI.widgetBox(self.ArgumentationTab, "Arguments for the Selected Class Value")
169        self.argumentList = OWGUI.listBox(self.argumentBox, self, callback = self.argumentSelected)
170        self.argumentList.setMinimumSize(200,200)
171       
172       
173        #Remove and hide the argumentation tab (It does not work)
174        self.tabs.removeTab(2)
175        self.ArgumentationTab.hide()
176       
177
178
179        # ##########################
180        # SAVE & MANAGE TAB
181        self.classesBox = OWGUI.widgetBox(self.ManageTab, "Class Values You Wish to See Separated")
182        self.classesBox.setFixedHeight(130)
183        self.visualizedAttributesBox = OWGUI.widgetBox(self.ManageTab, "Number of Concurrently Visualized Attributes")
184           
185        if _graph_dialogs:
186            self.dialogsBox = OWGUI.widgetBox(self.ManageTab, "Dialogs")
187
188            self.buttonBox7 = OWGUI.widgetBox(self.dialogsBox, orientation = "horizontal")
189            self.attributeRankingButton = OWGUI.button(self.buttonBox7, self, "Attribute Ranking", self.attributeAnalysis, debuggingEnabled = 0)
190            self.attributeInteractionsButton = OWGUI.button(self.buttonBox7, self, "Attribute Interactions", self.interactionAnalysis, debuggingEnabled = 0)
191
192            self.buttonBox8 = OWGUI.widgetBox(self.dialogsBox, orientation = "horizontal")
193            self.projectionScoresButton = OWGUI.button(self.buttonBox8, self, "Graph Projection Scores", self.graphProjectionQuality, debuggingEnabled = 0)
194            self.outlierIdentificationButton = OWGUI.button(self.buttonBox8, self, "Outlier Identification", self.identifyOutliers, debuggingEnabled = 0)
195       
196        self.manageResultsBox = OWGUI.widgetBox(self.ManageTab, "Manage Projections")
197
198        self.classesList = OWGUI.listBox(self.classesBox, self, selectionMode = QListWidget.MultiSelection, callback = self.classesListChanged)
199        self.classesList.setMinimumSize(60,60)
200
201        self.attrLenList = OWGUI.listBox(self.visualizedAttributesBox, self, selectionMode = QListWidget.MultiSelection, callback = self.attrLenListChanged)
202        self.attrLenList.setMinimumSize(60,60)
203
204        #self.removeSelectedButton = OWGUI.button(self.buttonBox5, self, "Remove selection", self.removeSelected)
205        #self.filterButton = OWGUI.button(self.buttonBox5, self, "Save best graphs", self.exportMultipleGraphs)
206       
207        self.buttonBox6 = OWGUI.widgetBox(self.manageResultsBox, orientation = "horizontal")
208        self.loadButton = OWGUI.button(self.buttonBox6, self, "Load", self.loadProjections, debuggingEnabled = 0)
209        self.saveButton = OWGUI.button(self.buttonBox6, self, "Save", self.saveProjections, debuggingEnabled = 0)
210
211        self.buttonBox9 = OWGUI.widgetBox(self.manageResultsBox, orientation = "horizontal")
212        self.saveBestButton = OWGUI.button(self.buttonBox9, self, "Save Best", self.exportMultipleGraphs, debuggingEnabled = 0)
213        OWGUI.button(self.buttonBox9, self, "Remove Similar", callback = self.removeTooSimilarProjections, debuggingEnabled = 0)
214
215        self.buttonBox3 = OWGUI.widgetBox(self.manageResultsBox, orientation = "horizontal")
216        if self.parentWidget:
217            self.evaluateProjectionButton = OWGUI.button(self.buttonBox3, self, 'Evaluate Projection', callback = self.evaluateCurrentProjection, debuggingEnabled = 0)
218        self.reevaluateResults = OWGUI.button(self.buttonBox3, self, "Reevaluate", callback = self.reevaluateAllProjections)
219
220        self.buttonBox4 = OWGUI.widgetBox(self.manageResultsBox, orientation = "horizontal")
221        self.showKNNCorrectButton = OWGUI.button(self.buttonBox4, self, 'Show k-NN Correct', self.showKNNCorect)
222        self.showKNNWrongButton = OWGUI.button(self.buttonBox4, self, 'Show k-NN Wrong', self.showKNNWrong)
223        self.showKNNCorrectButton.setCheckable(1); self.showKNNWrongButton.setCheckable(1)
224
225        self.buttonBox5 = OWGUI.widgetBox(self.manageResultsBox, orientation = "horizontal")
226        self.clearButton = OWGUI.button(self.buttonBox5, self, "Clear Results", self.clearResults)
227
228        self.removeEvaluatedAttributes()
229
230        self.setMinimumWidth(375)
231        self.tabs.setMinimumWidth(375)
232        self.resize(375, 700)
233       
234        # reset some parameters if we are debugging so that it won't take too much time
235        if orngDebugging.orngDebuggingEnabled:
236            self.useTimeLimit = 1
237            self.useProjectionLimit = 1
238            self.timeLimit = 0.3
239            self.optimizeTimeLimit = 0.3
240            self.projectionLimit = 20
241            self.optimizeProjectionLimit = 20
242            self.attributeCount = 6
243           
244        self.subsetData = None
245
246
247    # ##############################################################
248    # EVENTS
249
250    # the heuristic checkbox is enabled only if the signal to noise OVA measure is selected
251    def removeEvaluatedAttributes(self):
252        # clear the list of evaluated attributes
253        self.evaluatedAttributes = None
254        self.evaluatedAttributesByClass = None
255
256
257    # result list can contain projections with different number of attributes
258    # user clicked in the listbox that shows possible number of attributes of result list
259    # result list must be updated accordingly
260    def attrLenListChanged(self):
261        # check which attribute lengths do we want to show
262        self.attrLenDict = {}
263        for i in range(self.attrLenList.count()):
264            intVal = int(str(self.attrLenList.item(i).text()))
265            selected = self.attrLenList.item(i).isSelected()
266            self.attrLenDict[intVal] = selected
267        self.updateShownProjections()
268
269    def classesListChanged(self):
270        results = self.results
271        self.clearResults()
272
273        self.selectedClasses = self.getSelectedClassValues()
274        if len(self.selectedClasses) in [self.classesList.count(), 0]:
275            for i in range(len(results)):
276                self.insertItem(i, results[i][OTHER_RESULTS][0], results[i][OTHER_RESULTS], results[i][LEN_TABLE], results[i][ATTR_LIST], results[i][TRY_INDEX], results[i][GENERAL_DICT])
277        else:
278            for result in results:
279                acc = 0.0; sum = 0.0
280                for index in self.selectedClasses:
281                    acc += result[OTHER_RESULTS][OTHER_PREDICTIONS][index] * result[OTHER_RESULTS][OTHER_DISTRIBUTION][index]
282                    sum += result[OTHER_RESULTS][OTHER_DISTRIBUTION][index]
283                self.insertItem(self.findTargetIndex(acc/max(sum,1.)), acc/max(sum,1.), result[OTHER_RESULTS], result[LEN_TABLE], result[ATTR_LIST], result[TRY_INDEX], result[GENERAL_DICT])
284
285        self.finishedAddingResults()
286
287    def clearResults(self):
288        VizRank.clearResults(self)
289        self.clearArguments()
290        self.shownResults = []
291        self.resultList.clear()
292        self.attrLenDict = {}
293        self.attrLenList.clear()
294
295    def clearArguments(self):
296        VizRank.clearArguments(self)
297        self.argumentList.clear()
298
299    # remove projections that are selected
300    def removeSelected(self):
301        for i in range(self.resultList.count()-1, -1, -1):
302            if self.resultList.item(i).isSelected():
303                # remove from listbox and original list of results
304                self.resultList.takeItem(i)
305                self.shownResults.remove(self.shownResults[i])
306       
307    # ##############################################################
308
309    def getSelectedClassValues(self):
310        selectedClasses = []
311        for i in range(self.classesList.count()):
312            if self.classesList.item(i).isSelected(): selectedClasses.append(i)
313        return selectedClasses
314
315
316    # a function that is meaningful when visualizing using radviz or polyviz
317    # it removes projections that don't have different at least two attributes in comparison with some better ranked projection
318    def removeTooSimilarProjections(self, allowedPercentOfEqualAttributes = -1):
319        if allowedPercentOfEqualAttributes == -1:
320            (text, ok) = QInputDialog.getText('Allowed Similarity', 'How many attributes can be present in some better projection for a projection to be still considered as different (in pecents. Default = 70)?')
321            if not ok: return
322            allowedPercentOfEqualAttributes = int(str(text))
323
324        qApp.setOverrideCursor(Qt.WaitCursor)
325        self.setStatusBarText("Removing similar projections")
326        i=0
327        while i < self.resultList.count():
328            qApp.processEvents()
329            if self.existsABetterSimilarProjection(i, allowedPercentOfEqualAttributes = allowedPercentOfEqualAttributes):
330                self.results.pop(i)
331                self.shownResults.pop(i)
332                self.resultList.takeItem(i)
333            else:
334                i += 1
335
336        self.setStatusBarText("")
337        qApp.restoreOverrideCursor()
338
339
340    def updateShownProjections(self, *args):
341        if hasattr(self, "dontUpdate"): return
342
343        self.resultList.clear()
344        self.shownResults = []
345        i = 0
346        qApp.setOverrideCursor(Qt.WaitCursor)
347
348        while self.resultList.count() < self.resultListLen and i < len(self.results):
349            if self.attrLenDict[len(self.results[i][ATTR_LIST])] == 1:
350                string = ""
351                if self.showRank: string += str(i+1) + ". "
352                if self.showAccuracy: string += "%.2f" % (self.results[i][ACCURACY])
353                if not self.showInstances and self.showAccuracy: string += " : "
354                elif self.showInstances: string += " (%d) : " % (self.results[i][LEN_TABLE])
355                string += self.buildAttrString(self.results[i][ATTR_LIST], self.results[i][GENERAL_DICT].get("reverse", []))
356
357                self.resultList.addItem(string)
358                self.shownResults.append(self.results[i])
359            i+=1
360        qApp.processEvents()
361        qApp.restoreOverrideCursor()
362
363        if self.resultList.count() > 0: self.resultList.setCurrentRow(0)
364
365    # set value of k to sqrt(n)
366    def resetDialog(self):
367        self.setStatusBarText("")
368
369        self.removeEvaluatedAttributes()
370
371        #self.startOptimizationButton.setEnabled(self.graph.dataHasDiscreteClass)
372        #self.optimizeGivenProjectionButton.setEnabled(self.graph.dataHasDiscreteClass)
373        #self.evaluateProjectionButton.setEnabled(self.graph.dataHasDiscreteClass)
374        self.showKNNCorrectButton.setEnabled(self.graph.dataHasDiscreteClass)
375        self.showKNNWrongButton.setEnabled(self.graph.dataHasDiscreteClass)
376       
377        if _graph_dialogs:
378            self.attributeRankingButton.setEnabled(self.graph.dataHasDiscreteClass)
379            self.attributeInteractionsButton.setEnabled(self.graph.dataHasDiscreteClass)
380            self.projectionScoresButton.setEnabled(self.graph.dataHasDiscreteClass)
381            self.outlierIdentificationButton.setEnabled(self.graph.dataHasDiscreteClass)
382        #self.findArgumentsButton.setEnabled(self.graph.dataHasDiscreteClass)
383       
384        self.optimizationSettingsDiscClassBox.setVisible(self.graph.dataHasDiscreteClass)
385        self.optimizationSettingsNoClassBox.setVisible(not self.graph.dataHasClass)
386        self.measureComboDiscClassBox.setVisible(self.graph.dataHasDiscreteClass)
387#        self.measureComboNoClassBox.setVisible(not self.graph.dataHasClass)
388#        self.measureComboContClassBox.setVisible(self.graph.dataHasContinuousClass)
389        self.tabs.setTabEnabled(2, self.graph.dataHasDiscreteClass)
390#        self.heuristicsSettingsContClassBox.setVisible(self.graph.dataHasContinuousClass)
391        self.heuristicsSettingsDiscClassBox.setVisible(self.graph.dataHasDiscreteClass)
392#        self.heuristicsSettingsNoClassBox.setVisible(not self.graph.dataHasClass)
393       
394       
395        if not self.graph.dataHasDiscreteClass:
396            self.classesList.clear()
397            self.classValueCombo.clear()
398            self.selectedClasses = []
399            return
400       
401        classes = [val for val in self.graph.dataDomain.classVar.values]
402        existing = [str(self.classesList.item(i).text()) for i in range(self.classesList.count())]
403        if classes == existing:
404            return
405
406        # set new class values
407        self.classesList.clear()
408        self.classValueCombo.clear()
409        self.selectedClasses = []
410        self.classesList.addItems(classes)
411        self.classValueCombo.addItems(classes)
412        self.classesList.selectAll()
413        self.selectedClasses = range(len(self.graph.dataDomain.classVar.values))
414
415
416    # given a dataset return a list of attributes where attribute are sorted by their decreasing importance for class discrimination
417    def getEvaluatedAttributes(self):
418        self.setStatusBarText("Evaluating attributes...")
419        qApp.setOverrideCursor(Qt.WaitCursor)
420        attrs = VizRank.getEvaluatedAttributes(self)
421        self.setStatusBarText("")
422        qApp.restoreOverrideCursor()
423        return attrs
424
425
426    # insert new result - give parameters: accuracy of projection, number of examples in projection and list of attributes.
427    def insertItem(self, index, accuracy, other_results, lenTable, attrList, tryIndex, generalDict = {}, updateStatusBar = 0):
428        VizRank.insertItem(self, index, accuracy, other_results, lenTable, attrList, tryIndex, generalDict, updateStatusBar = 0)
429
430        if index < self.resultListLen:
431            string = ""
432            if self.showRank: string += str(index+1) + ". "
433            if self.showAccuracy: string += "%.2f" % (accuracy)
434            if not self.showInstances and self.showAccuracy: string += " : "
435            elif self.showInstances: string += " (%d) : " % (lenTable)
436
437            string += self.buildAttrString(attrList, generalDict.get("reverse", []))
438
439            self.resultList.insertItem(index, string)
440            self.shownResults.insert(index, (accuracy, lenTable, other_results, attrList, tryIndex, generalDict))
441
442            # remove worst projection if list is too long
443            if self.resultList.count() > self.resultListLen:
444                self.resultList.takeItem(self.resultList.count()-1)
445                self.shownResults.pop()
446            if updateStatusBar: self.setStatusBarText("Inserted %s projections" % (orngVisFuncts.createStringFromNumber(index)))
447            qApp.processEvents()        # allow processing of other events
448
449
450    def finishedAddingResults(self):
451        self.cancelOptimization = 0
452        self.cancelEvaluation = 0
453
454        self.attrLenList.clear()
455        self.attrLenDict = {}
456        maxLen = -1
457        for i in range(len(self.results)):
458            if len(self.results[i][ATTR_LIST]) > maxLen:
459                maxLen = len(self.results[i][ATTR_LIST])
460        if maxLen == -1: return
461        if maxLen == 2: vals = [2]
462        else: vals = range(3, maxLen+1)
463       
464        for val in vals:
465            self.attrLenList.addItem(str(val))
466            self.attrLenDict[val] = 1
467       
468        self.attrLenList.selectAll()
469        self.resultList.setCurrentRow(0)
470
471        # make sure that if the dialogs are shown we show the updated results
472        if self.attributeHistogramDlg and self.attributeHistogramDlg.isVisible():
473            self.attributeHistogramDlg.setResults(self.shownResults)
474        if self.interactionAnalysisDlg and self.interactionAnalysisDlg.isVisible():
475            self.interactionAnalysisDlg.setResults(self.shownResults)
476        if self.identifyOutliersDlg and self.identifyOutliersDlg.isVisible():
477            self.identifyOutliersDlg.setResults(self.results)
478
479
480    # reevaluate projections in result list with the current VizRank settings (different k value, different measure of classification succes, ...)
481    def reevaluateAllProjections(self):
482        results = list(self.getShownResults())
483        self.clearResults()
484
485        self.parentWidget.progressBarInit()
486        self.disableControls()
487
488        testIndex = 0
489        strTotal = orngVisFuncts.createStringFromNumber(len(results))
490        for (acc, other, tableLen, attrList, tryIndex, generalDict) in results:
491            if self.isOptimizationCanceled(): break
492            testIndex += 1
493            self.parentWidget.progressBarSet(100.0*testIndex/float(len(results)))
494
495            table = self.graph.createProjectionAsExampleTable([self.graph.attributeNameIndex[attr] for attr in attrList], settingsDict = generalDict)
496            accuracy, other_results = self.kNNComputeAccuracy(table)
497            self.addResult(accuracy, other_results, tableLen, attrList, tryIndex, generalDict)
498            self.setStatusBarText("Reevaluated %s/%s projections..." % (orngVisFuncts.createStringFromNumber(testIndex), strTotal))
499
500        self.setStatusBarText("")
501        self.parentWidget.progressBarFinished()
502        self.enableControls()
503        self.finishedAddingResults()
504
505    # evaluate knn accuracy on current projection
506    def evaluateCurrentProjection(self):
507        acc, other_results = self.getProjectionQuality(self.parentWidget.getShownAttributeList(), useAnchorData = 1)
508
509        if self.graph.dataHasContinuousClass:
510            QMessageBox.information( None, self.parentName, 'Mean square error of kNN model is %.2f'%(acc), QMessageBox.Ok + QMessageBox.Default)
511        else:
512            if self.qualityMeasure == CLASS_ACCURACY:
513                QMessageBox.information( None, self.parentName, 'Classification accuracy of kNN model is %.2f %%'%(acc), QMessageBox.Ok + QMessageBox.Default)
514            elif self.qualityMeasure == AVERAGE_CORRECT:
515                QMessageBox.information( None, self.parentName, 'Average probability of correct classification is %.2f %%'%(acc), QMessageBox.Ok + QMessageBox.Default)
516            elif self.qualityMeasure == AUC:
517                QMessageBox.information( None, self.parentName, 'AUC is %.3f'%(acc), QMessageBox.Ok + QMessageBox.Default)
518            elif self.qualityMeasure == BRIER_SCORE:
519                QMessageBox.information( None, self.parentName, 'Brier score of kNN model is %.3f' % (acc), QMessageBox.Ok + QMessageBox.Default)
520            else:
521                QMessageBox.information( None, self.parentName, 'Accuracy of the model is %.3f' % (acc), QMessageBox.Ok + QMessageBox.Default)
522
523
524
525    # ##############################################################
526    # Loading and saving projection files
527    def abortOperation(self):
528        self.abortCurrentOperation = 1
529
530    # save the list into a file - filename can be set if you want to call this function without showing the dialog
531    def saveProjections(self):
532        self.setStatusBarText("Saving projections")
533
534        # get file name
535        datasetName = getattr(self.graph.rawData, "name", "")
536        if datasetName != "":
537            filename = "%s - %s" % (os.path.splitext(os.path.split(datasetName)[1])[0], self.parentName)
538        else:
539            filename = "%s" % (self.parentName)
540        qname = QFileDialog.getSaveFileName(self, "Save Projections",  os.path.join(self.lastSaveDirName, filename), "Interesting projections (*.proj)")
541        if qname.isEmpty(): return
542        name = str(qname)
543
544        self.lastSaveDirName = os.path.split(name)[0]
545
546        # show button to stop saving
547        butt = OWGUI.button(self.widgetStatusArea, self, "Stop Saving", callback = self.abortOperation); butt.show()
548
549        self.save(name, self.shownResults, len(self.shownResults))
550
551        self.setStatusBarText("Saved %s projections" % (orngVisFuncts.createStringFromNumber(len(self.shownResults))))
552        butt.hide()
553
554
555    # load projections from a file
556    def loadProjections(self, name = None, ignoreCheckSum = 0, maxCount = -1):
557        self.setStatusBarText("Loading projections")
558        if not self.graph.haveData:
559            QMessageBox.critical(None,'Load','There is no data. First load a data set and then load projection file',QMessageBox.Ok)
560            return
561
562        if name == None:
563            name = QFileDialog.getOpenFileName(self, "Open Projections", self.lastSaveDirName, "Interesting projections (*.proj)")
564            if name.isEmpty(): return
565            name = str(name)
566
567        dirName, shortFileName = os.path.split(name)
568        self.lastSaveDirName = dirName
569
570        # show button to stop loading
571        butt = OWGUI.button(self.widgetStatusArea, self, "Stop Loading", callback = self.abortOperation); butt.show()
572
573        selectedClasses, count = self.load(name, ignoreCheckSum, maxCount)
574
575        self.dontUpdate = 1
576        if self.graph.dataHasDiscreteClass:
577            for i in range(len(self.graph.dataDomain.classVar.values)): self.classesList.item(i).setSelected(i in selectedClasses)
578        del self.dontUpdate
579        self.finishedAddingResults()
580
581        self.setStatusBarText("Loaded %s projections" % (orngVisFuncts.createStringFromNumber(count)))
582        butt.hide()
583
584    def showKNNCorect(self):
585        self.showKNNWrongButton.setChecked(0)
586        if self.parentWidget: self.parentWidget.updateGraph()
587
588    # show quality of knn model by coloring accurate predictions with lighter color and bad predictions with dark color
589    def showKNNWrong(self):
590        self.showKNNCorrectButton.setChecked(0)
591        if self.parentWidget: self.parentWidget.updateGraph()
592
593
594    # disable all controls while evaluating projections
595    def disableControls(self):
596        for control in [self.buttonBox, self.resultsDetailsBox, self.optimizeGivenProjectionButton, self.SettingsTab, self.ManageTab, self.ArgumentationTab]:
597            control.setEnabled(0)
598
599    def enableControls(self):
600        for control in [self.buttonBox, self.resultsDetailsBox, self.optimizeGivenProjectionButton, self.SettingsTab, self.ManageTab, self.ArgumentationTab]:
601            control.setEnabled(1)
602
603
604    # ##############################################################
605    # exporting multiple pictures
606    def exportMultipleGraphs(self):
607        (text, ok) = QInputDialog.getText('Graph count', 'How many of the best projections do you wish to save?')
608        if not ok: return
609        self.bestGraphsCount = int(str(text))
610
611        self.sizeDlg = OWDlgs.OWChooseImageSizeDlg(self.graph, parent=self)
612        self.sizeDlg.printButton.setEnabled(0)
613        self.sizeDlg.saveMatplotlibButton.setEnabled(0)
614        self.sizeDlg.disconnect(self.sizeDlg.saveImageButton, SIGNAL("clicked()"), self.sizeDlg.saveImage)
615        self.sizeDlg.connect(self.sizeDlg.saveImageButton, SIGNAL("clicked()"), self.saveToFileAccept)
616        self.sizeDlg.exec_()
617
618    def saveToFileAccept(self):
619        fileName = self.sizeDlg.getFileName("Graph", "Portable Network Graphics (*.PNG);;Windows Bitmap (*.BMP);;Graphics Interchange Format (*.GIF)", ".png")
620        if not fileName: return
621        (fil,ext) = os.path.splitext(fileName)
622        ext = ext.replace(".","")
623        if ext == "":
624            ext = "PNG"     # if no format was specified, we choose png
625            fileName = fileName + ".png"
626        ext = ext.upper()
627
628        (fil, extension) = os.path.splitext(fileName)
629        for i in range(0, min(self.resultList.count(), self.bestGraphsCount)):
630            self.resultList.item(i).setSelected(1)
631            self.graph.replot()
632            name = fil + " (%02d, %.2f, %d)" % (i+1, self.shownResults[i][ACCURACY], self.shownResults[i][LEN_TABLE]) + extension
633            self.sizeDlg.saveImage(name, closeDialog = 0)
634        QDialog.accept(self.sizeDlg)
635
636    # ##############################################################
637    # create different dialogs
638    def interactionAnalysis(self):
639        if not self.interactionAnalysisDlg:
640            self.interactionAnalysisDlg = OWInteractionAnalysis(self, VIZRANK_POINT, signalManager = self.signalManager)
641        self.interactionAnalysisDlg.setResults(self.graph.rawData, self.shownResults)
642        self.interactionAnalysisDlg.show()
643
644    def attributeAnalysis(self):
645        if not self.attributeHistogramDlg:
646            self.attributeHistogramDlg = OWGraphAttributeHistogram(self, VIZRANK_POINT, signalManager = self.signalManager)
647        self.attributeHistogramDlg.show()
648        self.attributeHistogramDlg.setResults(self.graph.rawData, self.shownResults)
649
650    def graphProjectionQuality(self):
651        dialog = OWGraphProjectionQuality(self, VIZRANK_POINT, signalManager = self.signalManager)
652        dialog.show()
653        dialog.setResults(self.results)
654
655    def identifyOutliers(self):
656        if not self.identifyOutliersDlg:
657            self.identifyOutliersDlg = OWGraphIdentifyOutliers(self, VIZRANK_POINT, signalManager = self.signalManager, widget = self.parentWidget)
658        self.identifyOutliersDlg.show()
659        self.identifyOutliersDlg.setResults(self.graph.rawData, self.shownResults)
660
661    def closeEvent(self, ce):
662        if self.interactionAnalysisDlg: self.interactionAnalysisDlg.close()
663        if self.attributeHistogramDlg: self.attributeHistogramDlg.close()
664        if self.identifyOutliersDlg: self.identifyOutliersDlg.close()
665        OWWidget.closeEvent(self, ce)
666
667    # ######################################################
668    # Auxiliary functions
669
670    # from a list of attributes build a nice string with attribute names
671    def buildAttrString(self, attrList, attrReverseList = []):
672        if len(attrList) == 0: return ""
673
674        if attrReverseList != []:
675            strList = ""
676            for i in range(len(attrList)):
677                strList += attrList[i]
678                if attrReverseList[i]: strList += "-"
679                strList += ", "
680            strList = strList[:-2]
681        else:
682            strList = reduce(lambda x,y: x+', '+y, attrList)
683        return strList
684
685    def getOptimizationType(self):
686        return self.optimizationType
687
688    def getQualityMeasure(self):
689        return self.qualityMeasure
690
691    def getQualityMeasureStr(self):
692        if self.qualityMeasure ==0: return "Classification accuracy"
693        elif self.qualityMeasure==1: return "Average probability of correct classification"
694        else: return "Brier score"
695
696    def getAllResults(self):
697        return self.results
698
699    def getShownResults(self):
700        return self.shownResults
701
702    def getSelectedProjection(self):
703        if self.resultList.selectedItems() == []: return None
704        return self.shownResults[self.resultList.row(self.resultList.selectedItems()[0])]
705
706    def evaluateProjections(self):
707        if str(self.startOptimizationButton.text()) == "Start Evaluating Projections":
708            if self.attributeCount >= 10 and self.projOptimizationMethod == 0 and self.visualizationMethod not in [SCATTERPLOT, SCATTERPLOT3D] and self.attrSubsetSelection != GAMMA_SINGLE and QMessageBox.critical(self, 'VizRank', 'You chose to evaluate projections with a high number of attributes. Since VizRank has to evaluate different placements\nof these attributes there will be a high number of projections to evaluate. Do you still want to proceed?','Continue','Cancel', '', 0,1):
709                return
710            if not self.graph.dataHasDiscreteClass:
711                if not orngDebugging.orngDebuggingEnabled:
712                    QMessageBox.information( None, self.parentName, "Projections can be evaluated only for data with a discrete class.", QMessageBox.Ok + QMessageBox.Default)
713                return
714            self.startOptimizationButton.setText("Stop Evaluation")
715            self.parentWidget.progressBarInit()
716            self.disableControls()
717
718            try:
719                evaluatedProjections = VizRank.evaluateProjections(self, self.clearPreviousProjections)
720            except:
721                evaluatedProjections = 0
722                type, val, traceback = sys.exc_info()
723                sys.excepthook(type, val, traceback)  # print the exception
724
725            self.enableControls()
726            self.parentWidget.progressBarFinished()
727
728            secs = time.time() - self.startTime
729            self.setStatusBarText("Finished evaluation (evaluated %s projections in %d min, %d sec)" % (orngVisFuncts.createStringFromNumber(evaluatedProjections), secs/60, secs%60))
730            self.finishedAddingResults()
731            #qApp.processEvents()
732            #if self.parentWidget:
733            #    self.parentWidget.showSelectedAttributes()
734            self.startOptimizationButton.setText("Start Evaluating Projections")
735        else:
736            self.cancelEvaluation = 1
737            self.cancelOptimization = 1
738
739
740    def optimizeBestProjections(self, restartWhenImproved = 1):
741        self.startOptimizationButton.setText("Stop Optimization")
742        self.disableControls()
743        try:
744            evaluatedProjections = VizRank.optimizeBestProjections(self, restartWhenImproved)
745        except:
746            evaluatedProjections = 0
747            type, val, traceback = sys.exc_info()
748            sys.excepthook(type, val, traceback)  # print the exception
749
750        self.enableControls()
751        secs = time.time() - self.startTime
752        self.setStatusBarText("Finished evaluation (evaluated %s projections in %d min, %d sec)" % (orngVisFuncts.createStringFromNumber(evaluatedProjections), secs/60, secs%60))
753        self.finishedAddingResults()
754        qApp.processEvents()
755        if self.parentWidget:
756            self.parentWidget.showSelectedAttributes()
757        self.startOptimizationButton.setText("Start Evaluating Projections")
758
759
760    def isEvaluationCanceled(self):
761        stop = self.cancelEvaluation
762        if self.useTimeLimit:       stop = stop or (time.time() - self.startTime) / 60 >= self.timeLimit
763        if self.useProjectionLimit: stop = stop or self.evaluatedProjectionsCount >= self.projectionLimit
764        return stop
765
766    def isOptimizationCanceled(self):
767        stop = self.cancelOptimization
768        if self.useTimeLimit:       stop = stop or (time.time() - self.startTime) / 60 >= self.timeLimit
769        if self.useProjectionLimit: stop = stop or self.optimizedProjectionsCount >= self.projectionLimit
770        return stop
771
772    # ######################################################
773    # Argumentation functions
774    def findArguments(self, example = None, selectBest = 1, showClassification = 1):
775        self.clearArguments()
776        self.arguments = [[] for i in range(len(self.graph.dataDomain.classVar.values))]
777
778        if not example and self.subsetData == None:
779            QMessageBox.information( None, "VizRank Argumentation", 'To find arguments you first have to provide a new example that you wish to classify. You can do this by sending the example through the "Example Subset" input signal. \n\nNext, you should press the "Start Evaluating Projections" button in the Main tab to evaluate some projections. \n\nBy pressing "Find Arguments" you will then find arguments why the given example should belong to a selected class.', QMessageBox.Ok + QMessageBox.Default)
780            return (None,None)
781        if len(self.shownResults) == 0:
782            QMessageBox.information( None, "VizRank Argumentation", 'To find arguments you first have to evaluate some projections by clicking "Start evaluating projections" in the Main tab.', QMessageBox.Ok + QMessageBox.Default)
783            return (None,None)
784        if not example:
785            example = self.subsetData[0]
786
787        # call VizRank's function for finding arguments
788        classValue, dist = VizRank.findArguments(self, example)
789
790        if not self.arguments: return
791        classIndex = self.classValueCombo.currentIndex() #currentItem()
792        for i in range(len(self.arguments[0])):
793            prob, d, attrList, index = self.arguments[classIndex][i]
794            self.argumentList.insertItem(i, "%.3f - %s" %(prob, attrList))
795
796        if self.argumentList.count() > 0 and selectBest:
797            values = getVariableValuesSorted(self.graph.dataDomain[self.graph.dataClassIndex])
798            self.argumentationClassValue = values.index(classValue)     # activate the class that has the highest probability
799            self.argumentationClassChanged()
800            self.argumentList.setCurrentRow(0)
801            self.argumentSelected()
802
803        if showClassification or (example.getclass() and example.getclass().value != classValue):
804            s = '<nobr>Based on current classification settings, the example would be classified </nobr><br><nobr>to class <b>%s</b> with probability <b>%.2f%%</b>.</nobr><br><nobr>Predicted class distribution is:</nobr><br>' % (classValue, dist[classValue]*100)
805            for key in dist.keys(): s += "<nobr>&nbsp &nbsp &nbsp &nbsp %s : %.2f%%</nobr><br>" % (key, dist[key]*100)
806            QMessageBox.information(None, "Classification results", s[:-4], QMessageBox.Ok + QMessageBox.Default)
807
808        #qApp.processEvents()
809        return classValue, dist
810
811
812    def argumentationClassChanged(self):
813        self.argumentList.clear()
814        if len(self.arguments) == 0: return
815        ind = self.classValueCombo.currentIndex() #currentItem()
816        for i in range(len(self.arguments[ind])):
817            val = self.arguments[ind][i]
818            self.argumentList.addItem("%.2f - %s" %(val[0], val[2]))
819
820    def argumentSelected(self):
821        if self.argumentList.selectedItems() == []: return
822        ind = self.argumentList.row(self.argumentList.selectedItems()[0])
823        classInd = self.classValueCombo.currentIndex() #currentItem()
824        generalDict = self.results[self.arguments[classInd][ind][3]][GENERAL_DICT]
825        if self.visualizationMethod == SCATTERPLOT:
826            attrs = self.arguments[classInd][ind][2]
827            self.graph.updateData(attrs[0], attrs[1], self.graph.dataDomain.classVar.name)
828        elif self.visualizationMethod == SCATTERPLOT3D:
829            attrs = self.arguments[classInd][ind][2]
830            self.graph.updateData(attrs[0], attrs[1], attrs[3], self.graph.dataDomain.classVar.name)
831        elif self.visulizationMethod == LINEAR_PROJECTION3D or self.visualizationMethod == SPHEREVIZ3D:
832            self.graph.updateData(self.arguments[classInd][ind][2], setAnchors = 1, XAnchors = generalDict.getX("XAnchors"), YAnchors = generalDict.get("YAnchors"), ZAnchors = generalDict.get("ZAnchors"))
833        else:
834            self.graph.updateData(self.arguments[classInd][ind][2], setAnchors = 1, XAnchors = generalDict.get("XAnchors"), YAnchors = generalDict.get("YAnchors"))
835        self.graph.repaint()
836
837
838# #############################################################################
839# analyse the attributes that appear in the top projections. show how often do they appear also in other top projections
840class OWInteractionAnalysis(OWWidget):
841    settingsList = ["onlyLower", "rectColoring", "sortAttributesByQuality", "useGeneSets", "recentGeneSets"]
842    def __init__(self,parent = None, dialogType = VIZRANK_POINT, signalManager = None):
843        OWWidget.__init__(self, parent, signalManager, "VizRank's Interaction Analysis", wantGraph = 1, savePosition = True)
844
845        self.parent = parent
846        self.dialogType = dialogType
847        self.attributeCount = 15
848        self.projectionCount = 100
849        self.rotateXAttributes = 1
850        self.onlyLower = 0
851        self.results = None
852        self.sortAttributesByQuality = 0
853        self.rectColoring = 1
854
855        self.recentGeneSets = []
856        self.geneToSet, self.setToGenes = None, None
857        self.useGeneSets = 0
858
859        self.graph = OWGraph(self.mainArea)
860        self.mainArea.layout().addWidget(self.graph)
861
862        self.connect(self.graphButton, SIGNAL("clicked()"), self.graph.saveToFile)
863
864        b1 = OWGUI.widgetBox(self.controlArea, 'Number of attributes')
865        b2 = OWGUI.widgetBox(self.controlArea, 'Number of projections')
866        b3 = OWGUI.widgetBox(self.controlArea, "Settings")
867        b4 = OWGUI.widgetBox(self.controlArea, "Use color to represent ...")
868        b5 = OWGUI.widgetBox(self.controlArea, "Gene Sets")
869
870        OWGUI.qwtHSlider(b1, self, 'attributeCount', minValue = 5, maxValue = 100, step=0, callback = self.updateGraph, precision = 0, maxWidth = 170)
871        self.projectionCountSlider = OWGUI.qwtHSlider(b2, self, 'projectionCount', minValue = 5, maxValue = 1000, step = 5, callback = self.updateGraph, precision = 0, maxWidth = 170)
872        OWGUI.checkBox(b3, self, 'rotateXAttributes', label = "Rotate X labels", callback = self.updateGraph)
873        OWGUI.checkBox(b3, self, 'onlyLower', label = "Show only lower diagonal", callback = self.updateGraph)
874        OWGUI.checkBox(b3, self, 'sortAttributesByQuality', 'Sort attributes according to quality', callback = self.updateGraph, tooltip = "Do you want to show the attributes as they are ranked according to some quality measure\nor as they appear in the top ranked projections?")
875
876        OWGUI.comboBox(b4, self, "rectColoring", tooltip = "What should darkness of color of rectangles represent?", items = ["(don't use color)", "projection quality", "frequency of occurence in projections", "both"], callback = self.updateGraph)
877
878        OWGUI.checkBox(b5, self, "useGeneSets", label = "Use gene sets", callback = self.updateGraph)
879        bb5 = OWGUI.widgetBox(b5, orientation  = "horizontal")
880        self.fileCombo = OWGUI.comboBox(bb5, self, "geneSets")
881        OWGUI.button(bb5, self, '...', callback = self.browseGeneFile, disabled=0, width=25)
882        self.connect(self.fileCombo, SIGNAL('activated(int)'), self.selectGeneFile)
883
884        self.controlArea.layout().addSpacing(100)
885
886        #qApp.processEvents()
887        self.updateGraph()
888        self.updateGeneCombo()
889        self.loadGeneSet()
890
891    # ------- gene set functions ------------- #
892    def selectGeneFile(self,n):
893        name = self.recentGeneSets[n]
894        self.recentGeneSets.remove(name)
895        self.recentGeneSets.insert(0, name)
896        if len(self.recentGeneSets) > 0:
897            self.updateGeneCombo()
898            self.loadGeneSet()
899
900    def browseGeneFile(self):
901        d = os.getcwd()
902        if len(self.recentGeneSets) == 0 or self.recentGeneSets[0] == "(none)":
903            if sys.platform == "darwin":
904                startfile = user.home
905            else:
906                startfile = "."
907        else:
908            startfile = self.recentGeneSets[0]
909        filename = str(QFileDialog.getOpenFileName(None, 'Open Gene Set File', startfile, 'Gene set files (*.gmt)\nAll files(*.*)'))
910        if filename == "": return
911        if filename in self.recentGeneSets: self.recentGeneSets.remove(filename)
912        self.recentGeneSets.insert(0, filename)
913        self.updateGeneCombo()
914        self.loadGeneSet()
915
916    def updateGeneCombo(self):
917        self.fileCombo.clear()
918        for file in self.recentGeneSets:
919            self.fileCombo.addItem(os.path.split(file)[1])
920
921    def loadGeneSet(self):
922        if len(self.recentGeneSets) == 0: return
923        self.geneToSet, self.setToGenes = loadGeneSetFile(self.recentGeneSets[0])
924        self.updateGraph()
925    # ----------------------------------- #
926
927    def setResults(self, data, results):
928        self.results = results
929        if results:
930            self.projectionCountSlider.setScale(0, (len(results)/50) * 50, 0) # the third parameter for logaritmic scale
931        if self.dialogType in [VIZRANK_POINT, CLUSTER_POINT]:
932            if self.parent.attrCont == CONT_MEAS_S2NMIX:
933                self.attributes, attrsByClass = orngVisFuncts.findAttributeGroupsForRadviz(data, orngVisFuncts.S2NMeasureMix())
934            else:
935                self.attributes = self.parent.getEvaluatedAttributes()
936            self.ATTR_LIST = ATTR_LIST
937            self.ACCURACY = ACCURACY
938        elif self.dialogType == VIZRANK_MOSAIC:
939            relieff = orange.MeasureAttribute_relief(k=10, m=50)
940            self.attributes = orngVisFuncts.evaluateAttributes(data, relieff, relieff)
941            import orngMosaic
942            self.ATTR_LIST = orngMosaic.ATTR_LIST
943            self.ACCURACY = orngMosaic.SCORE
944        self.updateGraph()
945
946    def updateGraph(self):
947        black = QColor(0,0,0)
948        white = QColor(255,255,255)
949        self.graph.clear()
950        #self.graph.removeMarkers()
951        self.graph.tips.removeAll()
952
953        if not self.results or self.dialogType not in [VIZRANK_POINT, CLUSTER_POINT, VIZRANK_MOSAIC]: return
954
955        self.projectionCount = int(self.projectionCount)
956        self.attributeCount = int(self.attributeCount)
957
958        attributes = []
959        attrDict = {}
960        countDict = {}
961        bestDict = {}
962
963        if self.sortAttributesByQuality:
964            attributes = self.attributes[:self.attributeCount]
965        else:
966            attrCountDict = {}
967            for index in range(min(self.projectionCount, len(self.results))):
968                for attr in self.results[index][self.ATTR_LIST]:
969                    attrCountDict[attr] = attrCountDict.get(attr, 0) + 1
970            attrCounts = [(attrCountDict[attr], attr) for attr in attrCountDict.keys()]
971            attrCounts.sort()
972            attrCounts.reverse()
973            attributes = [attr[1] for attr in attrCounts[:self.attributeCount]]
974
975        for index in range(min(len(self.results), self.projectionCount)):
976            attrs = self.results[index][self.ATTR_LIST]
977
978            for i in range(len(attrs)):
979                for j in range(i+1, len(attrs)):
980                    if attrs[i] not in attributes or attrs[j] not in attributes: continue
981
982                    Min = min(attrs[i], attrs[j])
983                    Max = max(attrs[i], attrs[j])
984
985                    # frequency of occurence
986                    countDict[(Min, Max)] = countDict.get((Min, Max), 0) + 1
987
988                    # projection quality
989                    if not bestDict.has_key((Min, Max)):
990                        bestDict[(Min, Max)] = self.results[index][self.ACCURACY]
991            index += 1
992
993        bestCount = max([1] + countDict.values())
994        worstCount = -1  # we could use 0 but those with 1 would be barely visible
995        bestAcc = self.results[0][self.ACCURACY]
996        worstAcc= self.results[min(len(self.results)-1, self.projectionCount)][self.ACCURACY]
997
998        eps = 0.05 + 0.15 * self.useGeneSets
999        eps2 = 0.05
1000        num = len(attributes)
1001
1002        for x in range(num):
1003            for y in range(num-x):
1004                yy = num-y-1
1005                countVal = None; bestVal = None
1006
1007                if countDict.has_key((attributes[x], attributes[yy])):
1008                    countVal = countDict[(attributes[x], attributes[yy])]
1009                elif countDict.has_key((attributes[yy], attributes[x])):
1010                    countVal = countDict[(attributes[yy], attributes[x])]
1011
1012                if bestDict.has_key((attributes[x], attributes[yy])):
1013                    accVal = bestDict[(attributes[x], attributes[yy])]
1014                elif bestDict.has_key((attributes[yy], attributes[x])):
1015                    accVal = bestDict[(attributes[yy], attributes[x])]
1016
1017                if countVal == bestVal == None:
1018                    continue
1019
1020                if self.rectColoring == 0:
1021                    color = black
1022                elif self.rectColoring == 1:
1023                    v = int(255 - 255*((accVal-worstAcc)/float(bestAcc - worstAcc)))
1024                    color = QColor(v,v,v)
1025                elif self.rectColoring == 2:
1026                    v = int(255 - 255*((countVal-worstCount)/float(bestCount - worstCount)))
1027                    color = QColor(v,v,v)
1028                elif self.rectColoring == 3:
1029                    v1 = int(255 - 255*((accVal-worstAcc)/float(bestAcc - worstAcc)))
1030                    v2 = int(255 - 255*((countVal-worstCount)/float(bestCount - worstCount)))
1031                    color1 = QColor(v1,v1,v1)
1032                    color2 = QColor(v2,v2,v2)
1033
1034                s = "Pair: <b>%s</b> and <b>%s</b>" % (attributes[x], attributes[yy])
1035                if self.rectColoring in [1,3]:    # projection quality
1036                    s += "<br>Best projection quality: <b>%.3f</b>" % (accVal)
1037                if self.rectColoring in [2,3]:    # count
1038                    s += "<br>Number of appearances: <b>%d</b>" % (countVal)
1039
1040                sharedGeneSets = []
1041                if self.useGeneSets and self.geneToSet:
1042                    set1 = getGeneSet(self.geneToSet, attributes[x])
1043                    set2 = getGeneSet(self.geneToSet, attributes[yy])
1044                    for s1 in set2:
1045                        if s1 in set1: sharedGeneSets.append(s1)
1046
1047                if self.useGeneSets and self.geneToSet:
1048                    if sharedGeneSets != []:
1049                        s += "<hr>"+"Shared gene sets: %s"+"<br>" % (sharedGeneSets)
1050                    s += "<hr>"+"Gene sets for individual genes:"+"<br>&nbsp; &nbsp; <b>%s</b>: %s<br>&nbsp; &nbsp; <b>%s</b>: %s" % (attributes[x], getGeneSet(self.geneToSet, attributes[x]), attributes[yy], getGeneSet(self.geneToSet, attributes[yy]))
1051
1052                if self.rectColoring != 3:
1053                    RectangleCurve(QPen(color, 1), QBrush(color), [x-0.5+eps, x+0.5-eps, x+0.5-eps, x-0.5+eps], [y+1-0.5+eps, y+1-0.5+eps, y+1+0.5-eps, y+1+0.5-eps]).attach(self.graph)
1054                else:
1055                    PolygonCurve(QPen(color1, 1), QBrush(color1), [x-0.5+eps, x+0.5-eps, x-0.5+eps, x-0.5+eps], [y+1-0.5+eps, y+1-0.5+eps, y+1+0.5-eps, y+1-0.5+eps]).attach(self.graph)
1056                    PolygonCurve(QPen(color2, 1), QBrush(color2), [x-0.5+eps, x+0.5-eps, x+0.5-eps, x-0.5+eps], [y+1+0.5-eps, y+1-0.5+eps, y+1+0.5-eps, y+1+0.5-eps]).attach(self.graph)
1057
1058                if self.useGeneSets and self.geneToSet and sharedGeneSets != []:
1059                    RectangleCurve(QPen(color, 1), QBrush(Qt.NoBrush), [x-0.5+eps2, x+0.5-eps2, x+0.5-eps2, x-0.5+eps2], [y+1-0.5+eps2, y+1-0.5+eps2, y+1+0.5-eps2, y+1+0.5-eps2]).attach(self.graph)
1060                if s != "":
1061                    self.graph.tips.addToolTip(x, y+1, s, 0.5, 0.5)
1062
1063                if not self.onlyLower:
1064                    if self.rectColoring != 3:
1065                        RectangleCurve(QPen(color, 1), QBrush(color), [num-1-0.5-y+eps, num-1-0.5-y+eps, num-1+0.5-y-eps, num-1+0.5-y-eps], [num-0.5-x+eps, num+0.5-x-eps, num+0.5-x-eps, num-0.5-x+eps]).attach(self.graph)
1066                    else:
1067                        PolygonCurve(QPen(color1, 1), QBrush(color1), [num-1-0.5-y+eps, num-1+0.5-y-eps, num-1-0.5-y+eps, num-1-0.5-y+eps], [num-0.5-x+eps, num-0.5-x+eps, num+0.5-x-eps, num-0.5-x+eps]).attach(self.graph)
1068                        PolygonCurve(QPen(color2, 1), QBrush(color2), [num-1-0.5-y+eps, num-1+0.5-y-eps, num-1+0.5-y-eps, num-1-0.5-y+eps], [num+0.5-x-eps, num-0.5-x+eps, num+0.5-x-eps, num+0.5-x-eps]).attach(self.graph)
1069
1070                    if self.useGeneSets and self.geneToSet and sharedGeneSets != []:
1071                        RectangleCurve(QPen(color, 1), QBrush(Qt.NoBrush), [num-1-0.5-y+eps2, num-1-0.5-y+eps2, num-1+0.5-y-eps2, num-1+0.5-y-eps2], [num-0.5-x+eps2, num+0.5-x-eps2, num+0.5-x-eps2, num-0.5-x+eps2]).attach(self.graph)
1072                    if s != "":
1073                        self.graph.tips.addToolTip(num-1-y, num-x, s, 0.5, 0.5)
1074
1075        # draw empty boxes at the diagonal
1076        for x in range(num):
1077            RectangleCurve(QPen(black), QBrush(Qt.NoBrush), [x-0.5+2*eps2, x+0.5-2*eps2, x+0.5-2*eps2, x-0.5+2*eps2], [num-x-0.5+2*eps2, num-x-0.5+2*eps2, num-x+0.5-2*eps2, num-x+0.5-2*eps2]).attach(self.graph)
1078
1079        """
1080        # draw x markers
1081        for x in range(num):
1082            marker = RotatedMarker(self.graph, attributes[x], x + 0.5, -0.3, 90*self.rotateXAttributes)
1083            mkey = self.graph.insertMarker(marker)
1084            if self.rotateXAttributes: self.graph.marker(mkey).setLabelAlignment(Qt.AlignLeft + Qt.AlignHCenter)
1085            else: self.graph.marker(mkey).setLabelAlignment(Qt.AlignCenter)
1086
1087        # draw y markers
1088        for y in range(num):
1089            mkey = self.graph.insertMarker(attributes[num-y-1])
1090            self.graph.marker(mkey).setXValue(-0.3)
1091            self.graph.marker(mkey).setYValue(y + 0.5)
1092            self.graph.marker(mkey).setLabelAlignment(Qt.AlignLeft + Qt.AlignHCenter)
1093
1094        self.graph.setAxisScaleDraw(QwtPlot.xBottom, HiddenScaleDraw())
1095        self.graph.setAxisScaleDraw(QwtPlot.yLeft, HiddenScaleDraw())
1096        self.graph.axisScaleDraw(QwtPlot.xBottom).setTickLength(0, 0, 0)
1097        self.graph.axisScaleDraw(QwtPlot.yLeft).setTickLength(0, 0, 0)
1098        self.graph.axisScaleDraw(QwtPlot.xBottom).setOptions(0)
1099        self.graph.axisScaleDraw(QwtPlot.yLeft).setOptions(0)
1100        self.graph.setAxisScale(QwtPlot.xBottom, - 1.2 - 0.1*len(attributes) , num, 1)
1101        self.graph.setAxisScale(QwtPlot.yLeft, - 0.9 - 0.1*len(attributes) , num, 1)
1102        """
1103
1104        self.graph.setAxisScaleDraw(QwtPlot.xBottom, OWGraphTools.DiscreteAxisScaleDraw(attributes))
1105        self.graph.axisScaleDraw(QwtPlot.xBottom).enableComponent(QwtScaleDraw.Ticks, 0)
1106        self.graph.axisScaleDraw(QwtPlot.xBottom).enableComponent(QwtScaleDraw.Backbone, 0)
1107        self.graph.setAxisMaxMajor(QwtPlot.xBottom, len(attributes))
1108        self.graph.setAxisMaxMinor(QwtPlot.xBottom, 0)
1109        self.graph.setAxisScale(QwtPlot.xBottom, -1, len(attributes), 1)
1110        if self.rotateXAttributes:
1111            self.graph.axisScaleDraw(QwtPlot.xBottom).setLabelRotation(-90)
1112            self.graph.axisScaleDraw(QwtPlot.xBottom).setLabelAlignment(Qt.AlignLeft)
1113
1114        self.graph.setAxisScaleDraw(QwtPlot.yLeft, OWGraphTools.DiscreteAxisScaleDraw([""] + attributes[::-1]))
1115        self.graph.axisScaleDraw(QwtPlot.yLeft).enableComponent(QwtScaleDraw.Ticks, 0)
1116        self.graph.axisScaleDraw(QwtPlot.yLeft).enableComponent(QwtScaleDraw.Backbone, 0)
1117        self.graph.setAxisMaxMajor(QwtPlot.yLeft, len(attributes))
1118        self.graph.setAxisMaxMinor(QwtPlot.yLeft, 0)
1119        self.graph.setAxisScale(QwtPlot.yLeft, 0, len(attributes)+1, 1)
1120
1121        self.graph.update()  # don't know if this is necessary
1122        self.graph.replot()
1123
1124    def hideEvent(self, ev):
1125        self.saveSettings()
1126        OWWidget.hideEvent(self, ev)
1127
1128
1129class OWGraphAttributeHistogram(OWWidget):
1130    settingsList = ["attributeCount", "projectionCount", "rotateXAttributes", "colorAttributes", "progressLines", "useGeneSets", "recentGeneSets"]
1131    def __init__(self, parent=None, dialogType=VIZRANK_POINT, signalManager = None):
1132        OWWidget.__init__(self, parent, signalManager, "Attribute Histogram", wantGraph = 1, savePosition = True)
1133
1134        self.results = None
1135        self.dialogType = dialogType
1136        self.parent = parent
1137        self.results = None
1138        self.data = None
1139        self.evaluatedAttributes = None
1140        self.evaluatedAttributesByClass = None
1141
1142        self.graph = OWGraph(self.mainArea)
1143        self.mainArea.layout().addWidget(self.graph)
1144
1145        self.graph.showYLaxisTitle = 1
1146
1147        self.connect(self.graphButton, SIGNAL("clicked()"), self.graph.saveToFile)
1148
1149        self.attributeCount = 10
1150        self.projectionCount = 100
1151        self.rotateXAttributes = 1
1152        self.colorAttributes = 1
1153        self.progressLines = 1
1154        self.geneToSet = None
1155        self.useGeneSets = 0
1156        self.recentGeneSets = []
1157        self.useProjectionWeighting = 1
1158
1159        b1 = OWGUI.widgetBox(self.controlArea, box = 1)
1160        b2 = OWGUI.widgetBox(self.controlArea, 'Number of attributes')
1161        b3 = OWGUI.widgetBox(self.controlArea, 'Number of projections')
1162        b4 = OWGUI.widgetBox(self.controlArea, "Gene sets")
1163        box = OWGUI.widgetBox(self.controlArea)
1164
1165        OWGUI.checkBox(b1, self, 'useProjectionWeighting', label = "Weight projections according to rank", callback = self.updateGraph, tooltip = "Projections contribute to attribute ranking according to their rank in the list of projections.")
1166        OWGUI.checkBox(b1, self, 'colorAttributes', label = "Color attributes according to class vote", callback = self.updateGraph)
1167        OWGUI.checkBox(b1, self, 'progressLines', label = "Show intermediate lines", callback = self.updateGraph)
1168        OWGUI.checkBox(b1, self, 'rotateXAttributes', label = "Show attribute names vertically", callback = self.updateGraph)
1169        OWGUI.qwtHSlider(b2, self, 'attributeCount', minValue = 5, maxValue = 100, step = 1, callback = self.updateGraph, precision = 0, maxWidth = 170)
1170        OWGUI.qwtHSlider(b3, self, 'projectionCount', minValue = 10, maxValue = 5000, step=10, callback = self.updateGraph, precision = 0, maxWidth = 170)
1171        OWGUI.checkBox(b4, self, "useGeneSets", label = "Use gene sets", callback = self.updateGraph)
1172        bb4 = OWGUI.widgetBox(b4, orientation  = "horizontal")
1173        self.fileCombo = OWGUI.comboBox(bb4, self, "geneSets")
1174        OWGUI.button(bb4, self, '...', callback = self.browseGeneFile, disabled=0, width=25)
1175        self.connect(self.fileCombo, SIGNAL('activated(int)'), self.selectGeneFile)
1176
1177        self.controlArea.layout().addSpacing(100)
1178       
1179        if self.dialogType in [VIZRANK_POINT, CLUSTER_POINT]:
1180            self.ATTR_LIST = ATTR_LIST
1181        elif dialogType == VIZRANK_MOSAIC:
1182            import orngMosaic
1183            self.ATTR_LIST = orngMosaic.ATTR_LIST
1184
1185        qApp.processEvents()
1186        self.updateGeneCombo()
1187        self.loadGeneSet()
1188
1189    # ------- gene set functions ------------- #
1190    def selectGeneFile(self,n):
1191        name = self.recentGeneSets[n]
1192        self.recentGeneSets.remove(name)
1193        self.recentGeneSets.insert(0, name)
1194        if len(self.recentGeneSets) > 0:
1195            self.updateGeneCombo()
1196            self.loadGeneSet()
1197
1198    def browseGeneFile(self):
1199        if len(self.recentGeneSets) == 0 or self.recentGeneSets[0] == "(none)":
1200            startfile = "."
1201        else:
1202            startfile = self.recentGeneSets[0]
1203        filename = str(QFileDialog.getOpenFileName(None,'Open Gene Set File', startfile, 'Gene set files (*.gmt)\nAll files(*.*)'))
1204        if filename == "": return
1205        if filename in self.recentGeneSets: self.recentGeneSets.remove(filename)
1206        self.recentGeneSets.insert(0, filename)
1207        self.updateGeneCombo()
1208        self.loadGeneSet()
1209
1210    def updateGeneCombo(self):
1211        self.fileCombo.clear()
1212        for file in self.recentGeneSets:
1213            self.fileCombo.addItem(os.path.split(file)[1])
1214
1215    def loadGeneSet(self):
1216        if len(self.recentGeneSets) == 0: return
1217        self.geneToSet, self.setToGenes = loadGeneSetFile(self.recentGeneSets[0])
1218        self.updateGraph()
1219    # ----------------------------------- #
1220
1221    def setResults(self, data, results):
1222        self.data = data
1223        self.results = results
1224        self.evaluatedAttributes = None
1225        self.evaluatedAttributesByClass = None
1226        self.updateGraph()
1227
1228    def updateGraph(self):
1229        black = QColor(0,0,0)
1230        white = QColor(255,255,255)
1231        self.graph.clear()
1232        #self.graph.removeMarkers()
1233        if self.results == None: return
1234        eps = 0.1 + self.progressLines * 0.1
1235        self.projectionCount = int(self.projectionCount)
1236        self.attributeCount = int(self.attributeCount)
1237
1238        attrCountDict = {}
1239        count = min(self.projectionCount, len(self.results))
1240        part = 0
1241        diff = count / 5
1242        import math
1243        s = math.sqrt(-count**2 / math.log(0.001))      # normalizing factor
1244
1245        for index in range(count):
1246            if index > (part+1) * diff+1:
1247                part += 1
1248            attrs = self.results[index][self.ATTR_LIST]
1249            if self.useGeneSets and self.geneToSet:    # replace genes with the sets in which the genes appear
1250                newAttrs = []
1251                for attr in attrs:
1252                    newAttrs += getGeneSet(self.geneToSet, attr)
1253                attrs = newAttrs
1254
1255            if self.useProjectionWeighting: val = math.e ** (-index*index/(s*s))    # top ranked projections have greater val than lower ranked
1256            else:                           val = 1         # all projections have the same influence
1257            for attr in attrs:
1258                if not attrCountDict.has_key(attr):
1259                    attrCountDict[attr] = [0, {}]
1260                attrCountDict[attr][0] += val
1261                attrCountDict[attr][1][part] = attrCountDict[attr][1].get(part, 0) + val
1262
1263        attrs = [(attrCountDict[key][0], attrCountDict[key][1], key) for key in attrCountDict.keys()]
1264        attrs.sort()
1265        attrs.reverse()
1266        attrs = attrs[:self.attributeCount]
1267        if not attrs: return
1268       
1269        classVariableValues = getVariableValuesSorted(self.data.domain.classVar)
1270        classColors = ColorPaletteHSV(len(classVariableValues))
1271        if self.colorAttributes and self.evaluatedAttributes == None and self.dialogType in [VIZRANK_POINT, CLUSTER_POINT]:
1272            evalAttrs, attrsByClass = orngVisFuncts.findAttributeGroupsForRadviz(self.data, orngVisFuncts.S2NMeasureMix())
1273            classColors = ColorPaletteHSV(len(classVariableValues))
1274            self.evaluatedAttributes = evalAttrs
1275            self.evaluatedAttributesByClass = attrsByClass
1276        else:
1277            (evalAttrs, attrsByClass) = (self.evaluatedAttributes, self.evaluatedAttributesByClass)
1278           
1279        attrNames = []
1280        maxProjCount = attrs[0][0]      # the number of appearances of the most frequent attribute. used to determine when to stop drawing the progress lines
1281        for (ind, (count, progressCountDict, attr)) in enumerate(attrs):
1282            if self.colorAttributes and self.dialogType in [VIZRANK_POINT, CLUSTER_POINT]:
1283                if attr in evalAttrs:
1284                    classIndex = evalAttrs.index(attr) % len(classVariableValues)
1285                    color = classColors[classVariableValues.index(self.data.domain.classVar.values[classIndex])]
1286                else:
1287                    color = black
1288            else:
1289                color = black
1290
1291            RectangleCurve(QPen(color, 1), QBrush(color), [ind-0.5+eps, ind+0.5-eps, ind+0.5-eps, ind-0.5+eps], [0, 0, count, count]).attach(self.graph)
1292
1293            if self.progressLines and count*8 > maxProjCount:
1294                curr = 0
1295                for i in range(4):
1296                    c = progressCountDict.get(i, 0)
1297                    curr += c
1298                    self.graph.addCurve("", black, black, 2, QwtPlotCurve.Lines, QwtSymbol.NoSymbol, xData = [ind-0.5+0.5*eps,ind+0.5-0.5*eps], yData = [curr, curr], lineWidth = 3)
1299
1300            attrNames.append(attr)
1301            """
1302            y = -attrs[0][0] * 0.03
1303            if self.rotateXAttributes: marker = RotatedMarker(self.graph, attr, ind + 0.5, y, 90)
1304            else: marker = RotatedMarker(self.graph, attr, ind + 0.5, y, 0)
1305            mkey = self.graph.insertMarker(marker)
1306            if self.rotateXAttributes: self.graph.marker(mkey).setLabelAlignment(Qt.AlignLeft+ Qt.AlignVCenter)
1307            else: self.graph.marker(mkey).setLabelAlignment(Qt.AlignCenter + Qt.AlignBottom)
1308            """
1309
1310        # draw attribute names
1311        self.graph.setAxisScaleDraw(QwtPlot.xBottom, OWGraphTools.DiscreteAxisScaleDraw(attrNames))
1312        self.graph.axisScaleDraw(QwtPlot.xBottom).enableComponent(QwtScaleDraw.Ticks, 0)
1313        self.graph.axisScaleDraw(QwtPlot.xBottom).enableComponent(QwtScaleDraw.Backbone, 0)
1314        self.graph.setAxisMaxMajor(QwtPlot.xBottom, len(attrNames))
1315        self.graph.setAxisMaxMinor(QwtPlot.xBottom, 0)
1316        self.graph.setAxisScale(QwtPlot.xBottom, -1, len(attrNames), 1)
1317        if self.rotateXAttributes:
1318            self.graph.axisScaleDraw(QwtPlot.xBottom).setLabelRotation(-90)
1319            self.graph.axisScaleDraw(QwtPlot.xBottom).setLabelAlignment(Qt.AlignLeft)
1320        else:
1321            self.graph.axisScaleDraw(QwtPlot.xBottom).setLabelRotation(0)
1322            self.graph.axisScaleDraw(QwtPlot.xBottom).setLabelAlignment(Qt.AlignHCenter)
1323
1324        self.graph.setYLaxisTitle("Number of appearances in top projections")
1325
1326        if self.colorAttributes:
1327            classVariableValues = getVariableValuesSorted(self.data.domain.classVar)
1328            classColors = ColorPaletteHSV(len(classVariableValues))
1329            self.graph.addCurve("<b>" + self.data.domain.classVar.name + ":</b>", QColor(0,0,0), QColor(0,0,0), 0, symbol = QwtSymbol.NoSymbol, enableLegend = 1)
1330            for i,val in enumerate(classVariableValues):
1331                self.graph.addCurve(val, classColors[i], classColors[i], 15, symbol = QwtSymbol.Rect, enableLegend = 1)
1332
1333        self.graph.updateLayout()
1334        self.graph.replot()  # don't know if this is necessary
1335
1336    def hideEvent(self, ev):
1337        self.saveSettings()
1338        OWWidget.hideEvent(self, ev)
1339
1340# #############################################################################
1341# draw a graph for all the evaluated projections that shows how is the classification accuracy falling when we are moving from the best to the worst evaluated projections
1342class OWGraphProjectionQuality(OWWidget):
1343    def __init__(self,parent=None, dialogType = VIZRANK_POINT, signalManager = None):
1344        OWWidget.__init__(self, parent, signalManager, "Projection Quality", wantGraph = 1)
1345
1346        self.lineWidth = 1
1347        self.showDistributions = 0
1348        self.smoothingParameter = 1
1349
1350        self.results = None
1351        self.dialogType = dialogType
1352
1353        b1 = OWGUI.widgetBox(self.controlArea, box = "Show...")
1354        self.smoothingBox = OWGUI.widgetBox(self.controlArea, 'Smoothing parameter')
1355        b3 = OWGUI.widgetBox(self.controlArea, 'Line width')
1356
1357        OWGUI.comboBox(b1, self, "showDistributions", items = ["Drop in scores", "Distribution of scores"], callback = self.updateGraph)
1358        OWGUI.qwtHSlider(self.smoothingBox, self, "smoothingParameter", minValue = 0.0, maxValue = 5, step = 0.1, callback = self.updateGraph)
1359        OWGUI.comboBox(b3, self, "lineWidth", items = range(1,5), callback = self.updateGraph, sendSelectedValue = 1, valueType = int)
1360        self.controlArea.layout().addStretch(100)
1361
1362        self.graph = OWGraph(self.mainArea)
1363        self.mainArea.layout().addWidget(self.graph)
1364        self.graph.showXaxisTitle = 1
1365        self.graph.showYLaxisTitle = 1
1366       
1367        if dialogType in [VIZRANK_POINT, CLUSTER_POINT]:
1368            self.ACCURACY = ACCURACY
1369        elif dialogType == VIZRANK_MOSAIC:
1370            import orngMosaic
1371            self.ACCURACY = orngMosaic.SCORE
1372
1373        self.connect(self.graphButton, SIGNAL("clicked()"), self.graph.saveToFile)
1374        self.updateGraph()
1375
1376    def setResults(self, results):
1377        self.results = results
1378        self.updateGraph()
1379
1380    def updateGraph(self):
1381        #colors = ColorPaletteHSV(2)
1382        #c = colors.getColor(0)
1383        c = QColor(0,0,0)
1384        self.graph.clear()
1385        if self.results == None or self.dialogType not in [VIZRANK_POINT, CLUSTER_POINT, VIZRANK_MOSAIC]: return
1386
1387        yVals = [result[self.ACCURACY] for result in self.results]
1388        if not yVals: return
1389
1390        if self.showDistributions:
1391            try:
1392                from numpy.numarray.nd_image import gaussian_filter1d
1393            except:
1394                self.showDistributions = 0
1395                QMessageBox.information( None, "Missing library", 'In order to show distibution of scores gaussian smoothing has to be applied and a module called numarray is needed.\nIt can be downloaded at http://sourceforge.net/projects/numpy', QMessageBox.Ok + QMessageBox.Default)
1396
1397        self.smoothingBox.setEnabled(self.showDistributions)
1398
1399        if not self.showDistributions:
1400            xVals = range(len(yVals))
1401            if len(yVals) > 10:
1402                fact = len(yVals)/200
1403                if fact > 0:        # make the array of data smaller
1404                    pos = 0
1405                    xTemp = []; yTemp = []
1406                    while pos < len(yVals):
1407                        xTemp.append(xVals[pos])
1408                        yTemp.append(yVals[pos])
1409                        pos += fact
1410                    xVals = xTemp; yVals = yTemp
1411            self.graph.addCurve("", c, c, 1, QwtPlotCurve.Lines, QwtSymbol.NoSymbol, xData = xVals, yData = yVals, lineWidth = self.lineWidth)
1412            self.graph.setAxisScale(QwtPlot.yLeft, min(yVals), max(yVals))
1413            self.graph.setAxisScale(QwtPlot.xBottom, min(xVals), max(xVals))
1414            self.graph.setXaxisTitle("Evaluated projections")
1415            self.graph.setYLaxisTitle("Projection score")
1416        else:
1417            ymax = yVals[0]
1418            ymin = yVals[-1]
1419            yVals.reverse()
1420            diff = (ymax-ymin) / 100.
1421            xs = [ymin + diff/2.]
1422            ys = [0]
1423            x = ymin
1424            for index in range(len(yVals)):
1425                if yVals[index] > x + diff:     # if we stepped into another part, we start counting elements in here from 0
1426                    ys.append(0)
1427                    x = x + diff
1428                    xs.append(x + diff/2.)
1429                ys[-1] += 1
1430            ys = gaussian_filter1d(ys, self.smoothingParameter).tolist()
1431            self.graph.addCurve("", c, c, 1, QwtPlotCurve.Lines, QwtSymbol.NoSymbol, xData = xs, yData = ys, lineWidth = self.lineWidth)
1432            self.graph.setAxisScale(QwtPlot.yLeft, min(ys), max(ys))
1433            self.graph.setAxisScale(QwtPlot.xBottom, min(xs), max(xs))
1434            self.graph.setXaxisTitle("Projection score")
1435            self.graph.setYLaxisTitle("Number of projections")
1436
1437        self.graph.updateLayout()
1438        self.graph.replot()
1439
1440
1441# #############################################################################
1442# draw a graph for all the evaluated projections that shows how is the classification accuracy falling when we are moving from the best to the worst evaluated projections
1443class OWGraphIdentifyOutliers(VizRankOutliers, OWWidget):
1444    settingsList = ["projectionCountList", "showLegend", "showAllClasses", "sortProjections", "showClickedProjection"]
1445    def __init__(self, vizrank, dialogType, signalManager = None, widget = None):
1446        OWWidget.__init__(self, vizrank, signalManager, "Outlier Identification", wantGraph = 1, wantStatusBar = 1, savePosition = True)
1447        VizRankOutliers.__init__(self, vizrank, dialogType)
1448
1449        self.projectionCountList = ["5", "10", "20", "50", "100", "200", "500", "1000", "2000", "5000", "10000", "Other..."]
1450        self.projectionCountStr = "20"
1451        self.selectedExampleIndex = 0
1452        self.showPredictionsInProjection = 0
1453        self.showLegend = 1
1454        self.showAllClasses = 0
1455        self.sortProjections = 1
1456        self.showClickedProjection = 1
1457
1458        self.widget = widget
1459
1460        self.loadSettings()
1461        self.projectionCountStr = str(self.projectionCount)
1462
1463        b1 = OWGUI.widgetBox(self.controlArea, 'Projection Count')
1464        self.projectionCountEdit = OWGUI.comboBoxWithCaption(b1, self, "projectionCountStr", "Best projections to consider:   ", tooltip = "How many projections do you want to consider when computing probabilities of correct classification?", items = self.projectionCountList, callback = self.projectionCountChanged, sendSelectedValue = 1, valueType = str)
1465
1466        b2 = OWGUI.widgetBox(self.controlArea, 'Example index', orientation="horizontal")
1467        self.selectedExampleCombo = OWGUI.comboBox(b2, self, "selectedExampleIndex", tooltip = "Select the index of the example whose predictions you wish to analyse in the graph", callback = self.selectedExampleChanged, sendSelectedValue = 1, valueType = int)
1468        butt = OWGUI.button(b2, self, "Get From Projection", self.updateIndexFromGraph, tooltip = "Use the index of the example that is selected in the projections")
1469##        butt.setMaximumWidth(60)
1470
1471        b3 = OWGUI.widgetBox(self.controlArea, 'Graph settings')
1472        OWGUI.checkBox(b3, self, 'showAllClasses', 'Show probabilities for all classes', tooltip = "Show predicted probabilities for each class value", callback = self.updateGraph)
1473        OWGUI.checkBox(b3, self, 'sortProjections', 'Sort projections by decreasing probability', tooltip = "Don't show projections as they are ranked, but by decreasing probability of correct classification (this usually improves perception)", callback = self.updateGraph)
1474        OWGUI.checkBox(b3, self, 'showLegend', 'Show class legend', callback = self.updateGraph)
1475        OWGUI.checkBox(b3, self, 'showClickedProjection', 'Show selected projection', tooltip = "Show the corresponding projection by clicking its horizontal bar in the graph", callback = self.updateGraph)
1476
1477        b6 = OWGUI.widgetBox(self.controlArea, "Show predictions for all examples")
1478        self.showGraphCheck = OWGUI.checkBox(b6, self, 'showPredictionsInProjection', 'Show probabilities in the projection', tooltip = "Color the points in the projection according to the average probability of correct classification over the selected projection count", callback = self.toggleShowPredictions)
1479        self.exampleList = OWGUI.listBox(b6, self, callback = self.exampleListSelectionChanged)
1480        self.exampleList.setToolTip("Average probabilities of correct classification and indices of corresponding examples")
1481
1482        self.graph = OWGraph(self.mainArea)
1483        self.mainArea.layout().addWidget(self.graph)
1484        self.graph.showXaxisTitle = 1
1485        self.graph.showYLaxisTitle = 1
1486        self.graph.setXaxisTitle("Predicted class probabilities")
1487        self.graph.setYLaxisTitle("Projections")
1488
1489        self.connect(self.graphButton, SIGNAL("clicked()"), self.graph.saveToFile)
1490        self.graph.mouseMoveEventHandler = self.graphOnMouseMoved
1491        self.graph.mousePressEventHandler = self.graphOnMousePressed
1492        self.selectedRectangle = RectangleCurve(brush = QBrush(Qt.NoBrush))
1493        self.selectedRectangle.attach(self.graph)
1494        self.resize(600, 400)
1495
1496    # on escape
1497    def hideEvent (self, e):
1498        if self.widget:
1499            self.widget.outlierValues = None
1500            self.widget.updateGraph()
1501        self.saveSettings()
1502        OWWidget.hideEvent(self, e)
1503
1504    def setResults(self, data, results):
1505        VizRankOutliers.setResults(self, data, results)
1506
1507        # example index combo
1508        self.selectedExampleCombo.clear()
1509        if data:
1510            for i in range(len(data)):
1511                self.selectedExampleCombo.addItem(str(i))
1512
1513        self.evaluateProjections()
1514        self.selectedExampleChanged()
1515
1516    def projectionCountChanged(self):
1517        self.exampleList.clear()
1518        self.evaluatedExamples = []
1519
1520        if self.projectionCount == "Other...":
1521            (text, ok) = QInputDialog.getText('Projection Count', 'How many of the best projections do you wish to consider?')
1522            if ok and str(text).isdigit():
1523                text = str(text)
1524                if text not in self.projectionCountList:
1525                    i = 0
1526                    while i < len(self.projectionCountList)-1 and int(self.projectionCountList[i]) < int(text): i+=1
1527                    self.projectionCountList.insert(i, text)
1528                    self.projectionCountEdit.addItem(text, i)
1529                self.projectionCountStr = text
1530            else:
1531                self.projectionCountStr = "20"
1532            self.projectionCount = int(self.projectionCountStr)
1533        self.evaluateProjections()
1534        self.selectedExampleChanged()
1535
1536    # change class label to most probable and update widget with new data
1537    def changeClassToMostProbable(self):
1538        data = VizRankOutliers.changeClassToMostProbable(self)
1539        self.widget.setData(data)
1540        self.widget.handleNewSignals()
1541        return data
1542
1543    def evaluateProjections(self):
1544        if not self.results or not self.data: return
1545
1546        self.widget.progressBarInit()
1547        self.widgetStatusArea.show()
1548        self.exampleList.clear()
1549
1550        VizRankOutliers.evaluateProjections(self, qApp)
1551
1552        for i, (prob, exIndex, classPredictions) in enumerate(self.evaluatedExamples):
1553            self.exampleList.addItem("%.2f - %d" % (prob, exIndex))
1554
1555        self.widget.progressBarFinished()
1556        self.widgetStatusArea.hide()
1557
1558    def toggleShowPredictions(self):
1559        if not self.widget: return
1560        if self.showPredictionsInProjection:
1561            self.evaluateProjections()
1562
1563            self.widgetStatusArea.show()
1564            self.setStatusBarText("Computing averages...")
1565
1566            projCount = min(int(self.projectionCount), len(self.results))
1567            classCount = len(self.data.domain.classVar.values)
1568
1569            # compute the average probability of correct classification over the selected number of top projections
1570            values = [0.0 for i in range(len(self.data))]
1571            for i in range(len(self.data)):
1572                corrClass = int(self.data[i].getclass())
1573                predictions = self.matrixOfPredictions[corrClass::classCount,i]
1574                predictions = numpy.compress(predictions != -100, predictions)
1575                predictions = predictions**3
1576                if len(predictions):    # prevent division by zero!
1577                    values[i] = numpy.sum(predictions) / float(len(predictions))
1578
1579            self.widget.outlierValues = (values, "Probability of correct class value = %.2f%%")
1580            self.setStatusBarText("")
1581            #self.widgetStatusArea.hide()
1582        else:
1583            self.widget.outlierValues = None
1584
1585        self.widget.updateGraph()
1586        self.widget.showSelectedAttributes()
1587
1588
1589    def selectedExampleChanged(self):
1590        if not self.results or not self.data: return
1591
1592        projCount = min(int(self.projectionCount), len(self.results))
1593        classCount = len(self.data.domain.classVar.values)
1594        self.graphMatrix = numpy.transpose(numpy.reshape(self.matrixOfPredictions[:, self.selectedExampleIndex], (projCount, classCount)))
1595        self.updateGraph()
1596
1597        if self.dialogType == VIZRANK_POINT:
1598            valid = self.vizrank.graph.getValidList([self.vizrank.graph.attributeNameIndex[attr] for attr in self.widget.getShownAttributeList()])
1599            insideColors = numpy.zeros(len(self.data))
1600            insideColors[self.selectedExampleIndex] = 1
1601            self.widget.updateGraph(insideColors = (numpy.compress(valid, insideColors), "Focused example: %d"))
1602
1603
1604    # find which examples is selected in the graph and draw its predictions
1605    def updateIndexFromGraph(self):
1606        if self.dialogType != VIZRANK_POINT:
1607            return
1608
1609        if self.vizrank.parentName == "Polyviz":
1610            selected, unselected = self.vizrank.graph.getSelectionsAsIndices(self.widget.getShownAttributeList(), self.widget.attributeReverse)
1611        else:
1612            selected, unselected = self.vizrank.graph.getSelectionsAsIndices(self.widget.getShownAttributeList())
1613
1614        if len(selected) != 1:
1615            QMessageBox.information( None, "Outlier Identification", 'Exactly one example must be selected in the graph in order to complete this operation.', QMessageBox.Ok + QMessageBox.Default)
1616            return
1617        self.selectedExampleIndex = selected[0]
1618        self.selectedExampleChanged()
1619
1620
1621    def exampleListSelectionChanged(self):
1622        if self.exampleList.selectedItems() == []: return
1623        (val, exampleIndex, classPredictions) = self.evaluatedExamples[self.exampleList.row(self.exampleList.selectedItems()[0])]
1624        self.selectedExampleIndex = exampleIndex
1625        self.selectedExampleChanged()
1626
1627    # draw the graph of predictions for the selected example
1628    def updateGraph(self):
1629        self.graph.clear()
1630        self.graph.tips.removeAll()
1631        if not self.data or self.graphMatrix == None: return
1632
1633        classColors = ColorPaletteHSV(len(self.data.domain.classVar.values))
1634
1635        self.graph.setAxisScale(QwtPlot.yLeft, 0, len(self.graphMatrix[0]), len(self.graphMatrix[0])/5)
1636        self.graph.setAxisScale(QwtPlot.xBottom, 0, 1, 0.2)
1637
1638        valid = numpy.where(self.graphMatrix[0] != -100, 1, 0)
1639        allValid = numpy.sum(valid) == len(valid)
1640        nrOfClasses = len(self.data.domain.classVar.values)
1641
1642        if self.sortProjections:
1643            cls = int(self.data[self.selectedExampleIndex].getclass())
1644            indices = [(self.graphMatrix[cls][i], i) for i in range(len(self.graphMatrix[0]))]
1645            indices.sort()
1646            classes = range(nrOfClasses); classes.remove(cls); classes = [cls] + classes
1647        else:
1648            indices = [(i,i) for i in range(len(self.graphMatrix[0]))]
1649            classes = range(nrOfClasses)
1650
1651        self.projectionIndices = [val[1] for val in indices]
1652        classVariableValues = getVariableValuesSorted(self.data.domain.classVar)
1653        classColors = ColorPaletteHSV(len(classVariableValues))
1654
1655        for i in range(len(self.graphMatrix[0])):
1656            x = 0
1657            s = "Predicted class probabilities:<br>"
1658            invalidValue = 0
1659            for j in classes:
1660                (prob, index) = indices[i]
1661                if self.graphMatrix[j][index] < 0:
1662                    invalidValue = 1
1663                    continue
1664                s += "&nbsp; &nbsp; &nbsp; %s: %.2f%%<br>" % (classVariableValues[j], 100*self.graphMatrix[j][index])
1665                if not self.showAllClasses and int(self.data[self.selectedExampleIndex].getclass()) != j:
1666                    continue
1667                xDiff = self.graphMatrix[j][index]
1668                RectangleCurve(QPen(classColors.getColor(j)), QBrush(classColors.getColor(j)), [x, x+xDiff, x+xDiff, x], [i, i, i+1, i+1]).attach(self.graph)
1669                x += xDiff
1670            if not invalidValue:
1671                self.graph.tips.addToolTip(0, i, s[:-4], 1, 1)
1672
1673        if self.showLegend:
1674            self.graph.addCurve("<b>" + self.data.domain.classVar.name + ":</b>", QColor(0,0,0), QColor(0,0,0), 0, symbol = QwtSymbol.NoSymbol, enableLegend = 1)
1675            for i,val in enumerate(classVariableValues):
1676                self.graph.addCurve(val, classColors[i], classColors[i], 15, symbol = QwtSymbol.Rect, enableLegend = 1)
1677
1678        self.selectedRectangle = RectangleCurve(brush = QBrush(Qt.NoBrush))
1679        self.selectedRectangle.attach(self.graph)
1680
1681        self.graph.replot()
1682
1683    def graphOnMouseMoved(self, e):
1684        y = int(self.graph.invTransform(QwtPlot.yLeft, e.y()))
1685        if self.showClickedProjection and y >= 0 and y < len(self.projectionIndices):
1686            diff  = 0.005
1687            self.selectedRectangle.setData([0-diff, 1+diff, 1+diff, 0-diff], [y-diff, y-diff, y+1+diff, y+1+diff])
1688        else:
1689            self.selectedRectangle.setData([], [])
1690        self.graph.replot()
1691        return 1
1692
1693    def graphOnMousePressed(self, e):
1694        if self.showClickedProjection:
1695            y = int(self.graph.invTransform(QwtPlot.yLeft, e.y()))
1696            if y >= len(self.projectionIndices): return
1697            projIndex = self.projectionIndices[y]
1698            self.vizrank.resultList.setCurrentItem(self.vizrank.resultList.item(projIndex))
1699
1700            if self.dialogType == VIZRANK_POINT:
1701                attrs = self.vizrank.shownResults[projIndex][self.ATTR_LIST]
1702                valid = self.vizrank.graph.getValidList([self.vizrank.graph.attributeNameIndex[attr] for attr in attrs])
1703                insideColors = numpy.zeros(len(self.data))
1704                insideColors[self.selectedExampleIndex] = 1
1705                self.widget.updateGraph(attrs, setAnchors = 1, insideColors = (numpy.compress(valid, insideColors), "Focused example: %d"))
1706        return 1
1707
1708
1709def getGeneSet(geneset, gene):
1710    if len(gene) > 2 and gene[-2] == "_":
1711        gene = gene[:-2]        # remove the "_X" suffix
1712    return geneset.get(gene, [])
1713
1714
1715# load a .gmt file with gene groups
1716def loadGeneSetFile(fname):
1717    f = open(fname, "rt")
1718    geneToSet = {}
1719    setToGenes = {}
1720
1721    for i, line in enumerate(f.xreadlines()):
1722        items = line[:-1].split("\t")
1723        setName = items[0]
1724        genes = []
1725        for item in items[2:]:
1726            sub = item.split("///")
1727            itm = []
1728            for s in sub:
1729                gene = s.strip()
1730                geneToSet[gene] = geneToSet.get(gene, []) + [setName]
1731                genes.append(gene)
1732        setToGenes[setName] = (genes, len(items[2:]))
1733    return geneToSet, setToGenes
1734
1735
1736#test widget appearance
1737if __name__=="__main__":
1738    import sys
1739    a=QApplication(sys.argv)
1740    ow=OWVizRank()
1741##    ow = OWInteractionAnalysis()
1742##    ow = OWGraphAttributeHistogram()
1743    ow.show()
1744    a.exec_()
Note: See TracBrowser for help on using the repository browser.