source: orange/orange/OrangeWidgets/OWkNNOptimization.py @ 7120:ebec77d14767

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