source: orange-bioinformatics/_bioinformatics/widgets/prototypes/OWNormalize.py @ 1636:10d234fdadb9

Revision 1636:10d234fdadb9, 191.2 KB checked in by mitar, 2 years ago (diff)

Restructuring because we will not be using namespaces.

Line 
1## Automatically adapted for numpy.oldnumeric Oct 04, 2007 by
2
3"""
4<name>Normalize Expression Array Data</name>
5<description>Normalization of expression array data.</description>
6<icon>icons/Normalize.png</icon>
7<priority>1150</priority>
8<author>Peter Juvan (peter.juvan@fri.uni-lj.si)</author>
9"""
10
11"""
12TODO: settingsList
13"""
14
15from __future__ import absolute_import
16
17import string, math
18import types
19
20import numpy.oldnumeric as Numeric, numpy.oldnumeric.ma as MA
21import numpy.oldnumeric.mlab as MLab
22import numpy.oldnumeric.linear_algebra as LinearAlgebra
23import numpyExtn
24
25import orange
26from Orange.OrangeWidgets import ColorPalette             # ColorButton
27from Orange.OrangeWidgets import OWGUI, OWToolbars
28from Orange.OrangeWidgets.OWGraph import *
29from Orange.OrangeWidgets.OWGraphTools import *      # color palletes, user defined curves, ...
30from Orange.OrangeWidgets.OWWidget import *
31
32from .. import chipstat
33
34# global debugging variables
35D1 = False
36D2 = False
37D3 = False
38D4 = False
39D5 = False
40D6 = False # Probes
41
42class OWNormalize(OWWidget):
43
44    settingsList = ["varNameA", "varNameB", "varNameSignalSmpl", "varNameSignalRef", "varNameBGSmpl", "varNameBGRef", "varNameBGSmplSD", "varNameBGRefSD",
45                    "defNameA", "defNameB", "defNameSmpl1", "defNameSmpl2", "defNameRef1", "defNameRef2", "defNameForeground", "defNameBackground", "defNameMean", "defNameSD",
46                    "displayVarAAliases", "commitOnChange"]
47    # constants
48    stylesIndices = zip(["<none>","Circle","Rect","Diamond","Triangle","DTriangle","UTriangle","LTriangle","RTriangle","Cross","XCross"], range(11))
49    sizeButtonColor = 18
50    # self.tblControls column indices
51    tcPKey = 0      # hidden column for probe keys
52    tcMarker = 1
53    tcRatio = 2
54    tcNPAll = 3         # number of all probes
55    tcNPAccepted = 4    # number of non-filtered probes
56    tcVarA = 5
57    tcVarAAlias = 6      # hidden if not self.displayVarAAliases
58    tcVarB = 7          # hidden if probe varB is <none>
59    # merge level
60    MergeLevelNone = 0
61    MergeLevelPerVarsAB = 1
62    MergeLevelPerVarA = 2
63    # mergeOtherTypes
64    MergeOtherTypeMean = 0
65    MergeOtherTypeMedian = 1
66    MergeOtherTypeConc = 2
67    # normalization curve styles
68    normCurveStyles = {0: "normal", 1: "fitted"}
69    # approximation function
70    AppxFuncMed = 0
71    AppxFuncLR = 1
72    AppxFuncLoess = 2
73
74
75    def __init__(self, parent = None, signalManager = None, name = "Normalize Microarray Data"):
76        if D1 or D6: print "OWNormalize.__init__"
77        OWWidget.__init__(self, parent, signalManager, name, wantGraph=True, wantStatusBar=False)  #initialize base class
78        # store original caption title for extending it with expression and probe data file names
79        self.captionTitleBase = self.captionTitle
80
81        # set channels
82        self.inputs = [("Expression Data", ExampleTable, self.onDataInput), ("Probe Data", ExampleTable, self.onProbesInput)]
83        self.outputs = [("Expression Data", ExampleTable), ("Probe Data", ExampleTable)]
84
85        # defaults: filters
86        self._def_subtrBG = 0
87        self._def_useCV = True
88        self._def_maxCV = 0.5
89        self._def_useMinIntensity = True
90        self._def_minIntensityRatio = 1.5
91        self._def_useMaxFGIntensity = True
92        self._def_maxFGIntensity = 60000
93        self._def_useMaxBGIntensity = False
94        self._def_maxBGIntensity = 400
95        # defaults: normalization
96        self._def_normRange = 2  # 0: global, 1: local, per var B values, 2: combined
97        self._def_minNumControlProbes = 2
98        self._def_approxFunction = OWNormalize.AppxFuncLoess
99        self._def_loessWindow = 60
100        self._def_loessNumIter = 3
101        self._def_includeNonControl = False
102        self._def_loessWeight = 0.01
103
104        # general settings
105        self.controlName = ""
106        self.ratioStr = ""
107        self.probeSymbolIdx = 0    # index of selected cmbProbeSymbol item
108        self.probeColor = ProbeSet.NoColor
109        # general settings: filters
110        self.subtrBG = self._def_subtrBG
111        self.useCV = self._def_useCV
112        self.maxCV = self._def_maxCV
113        self.useMinIntensity = self._def_useMinIntensity
114        self.minIntensityRatio = self._def_minIntensityRatio
115        self.useMaxFGIntensity = self._def_useMaxFGIntensity
116        self.maxFGIntensity = self._def_maxFGIntensity
117        self.useMaxBGIntensity = self._def_useMaxBGIntensity
118        self.maxBGIntensity = self._def_maxBGIntensity
119        # general settings: normalization
120        self.normRange = self._def_normRange
121        self.minNumControlProbes = self._def_minNumControlProbes
122        self.approxFunction = self._def_approxFunction
123        self.loessWindow = self._def_loessWindow
124        self.loessNumIter = self._def_loessNumIter
125        self.includeNonControl = self._def_includeNonControl
126        self.loessWeight = self._def_loessWeight
127
128        # settings
129        self.logAxisY = True
130        self.markerSize = 9
131        self.mergeReplGraph = False
132##        self.showLegend = False
133        self.tracking = True
134        self.normCurveStyleIdx = 0
135        self.displayVarAAliases = True
136##        self.recomputeNormCurveOnChange = True
137        self.commitOnChange = True
138
139        # output
140        self.mergeLevel = OWNormalize.MergeLevelPerVarA             #0: none, 1: per vars A & B (ID & Type), 2: per var A (ID)
141        self.mergeIntensitiesType = 1   #0: mean, 1: median
142        self.mergeOtherType = OWNormalize.MergeOtherTypeMedian        # Mean, Median, Concatenate
143        self.mergeOtherRemoveDupl = False                           # whether or not to remove duplicates from comma separated list of values
144       
145        self.outVarAAliases = True
146        self.outNumProbes = True
147        self.outNetSignal = True
148        self.outA = True
149        self.outMRaw = True
150        self.outMCentered = True
151        self.autoSendSelection = 1
152
153        # context-specific settings
154        self.data = None
155        self.dataProbes = None
156        self.varsAll = {}
157        self.varsFloat = {}
158        self.varsEnumStr = {}
159        # variable indices selected within combos
160        self.varNameA = None
161        self.varNameB = "<none>"
162        self.varNameSignalSmpl = None
163        self.varNameSignalRef = None
164        self.varNameBGSmpl = None
165        self.varNameBGRef = None
166        self.varNameBGSmplSD = "<none>"
167        self.varNameBGRefSD = "<none>"
168        # default var names
169        self.defNameA = "id"
170        self.defNameB = ""
171        self.defNameSmpl1 = "smpl"
172        self.defNameSmpl2 = ""
173        self.defNameRef1 = "ref"
174        self.defNameRef2 = ""
175        self.defNameForeground = "raw"
176        self.defNameBackground = "background"
177        self.defNameMean = "med"
178        self.defNameSD = "st.dev"
179        # names of selected vars from listBox
180        self.varsOtherSelected = {}
181
182        # load previous settings
183        self.loadSettings()
184
185        # GUI
186        self.controlArea.setFixedWidth(265)
187        self.controlArea.setFixedWidth(275)
188        # main area: two tabs: non-normalized and normalized MA plots
189#        boxMainArea = OWGUI.widgetBox(self.mainArea)
190#        layoutMainArea = QVBoxLayout(self.mainArea)
191#        layoutMainArea.addWidget(boxMainArea)
192       
193        # main area: tabs
194#        self.tabsMain = QTabWidget(boxMainArea)
195        self.tabsMain = OWGUI.tabWidget(self.mainArea) #QTabWidget()
196#        self.mainArea.layout().addWidget(self.tabsMain)
197        self.connect(self.tabsMain, SIGNAL("currentChanged(QWidget*)"), self.onTabMainCurrentChange)
198#        self.boxMAnonNorm = QGroupBox(self)
199        self.boxMAnonNorm = OWGUI.createTabPage(self.tabsMain, "MA non-normalized")
200#        self.tabsMain.addTab(self.boxMAnonNorm, "MA non-normalized")
201#        self.boxMAnorm = QGroupBox(self)
202        self.boxMAnorm = OWGUI.createTabPage(self.tabsMain, "MA normalized")
203#        self.tabsMain.addTab(self.boxMAnorm, "MA normalized")
204
205        # reference to currently active MA graph (automatically set by onTabMainCurrentChange)
206        self.graphMAcurrent = None
207        # main area: graph MA non-normalized
208        self.graphMAnonNorm = OWGraphMA(self.boxMAnonNorm)
209        self.graphMAnonNorm.setAutoReplot(False)
210        self.boxMAnonNorm.layout().addWidget(self.graphMAnonNorm)
211       
212##        self.connect(self.graphMAnonNorm, SIGNAL("legendClicked(long)"), self.onLegendClickedMAnonNorm)
213##        self.graphMAnonNorm.enableGraphLegend(self.showLegend)
214        # main area: graph MA normalized
215        self.graphMAnorm = OWGraphMA(self.boxMAnorm)
216        self.graphMAnorm.setAutoReplot(False)
217        self.boxMAnorm.layout().addWidget(self.graphMAnorm)
218       
219        self.setGraphAxes(axes=[0,2])
220##        self.connect(self.graphMAnorm, SIGNAL("legendClicked(long)"), self.onLegendClickedMAnorm)
221##        self.graphMAnorm.enableGraphLegend(self.showLegend)
222        # for both MA graphs
223        self.setGraphAxes(axes=[0,2])
224        self.settingsProbeTrackingChange() # connect events mouseOnClick & mouseOnMove to self.graphMAnonNorm & self.graphMAnorm
225       
226        # control area: tabs
227        self.tabsCtrl = OWGUI.tabWidget(self.controlArea) #QTabWidget(self.controlArea)
228#        self.controlArea.layout().addWidget(self.tabsCtrl)
229        # tab 1: vars
230#        boxVars = QGroupBox(self)
231        boxVars = OWGUI.createTabPage(self.tabsCtrl, "Var")
232#        self.tabsCtrl.addTab(boxVars, "Var")
233#        boxGroupBy = QGroupBox('Group probes by', boxVars)
234
235        boxGroupBy = OWGUI.widgetBox(boxVars, "Group probes by")
236        self.cmbVarA = OWGUI.comboBox(boxGroupBy, self, "varNameA", label="ID", labelWidth=33, orientation="horizontal", callback=self.varABChange, sendSelectedValue=1, valueType=str)
237        ### Var B, Type, Other, Additional, Optional, Opt.var, Extra, Alternative var, Alt.var
238        self.cmbVarB = OWGUI.comboBox(boxGroupBy, self, "varNameB", label="Alt.var", labelWidth=33, orientation="horizontal", callback=self.varABChange, sendSelectedValue=1, valueType=str)
239       
240#        boxFGI = QGroupBox('Average foreground intensity', boxVars)
241        boxFGI = OWGUI.widgetBox(boxVars, "Average foreground intensity")
242        self.cmbVarSignalSmpl = OWGUI.comboBox(boxFGI, self, "varNameSignalSmpl", label="Smpl", labelWidth=33, orientation="horizontal", callback=self.varFBChange, sendSelectedValue=1, valueType=str)
243        self.cmbVarSignalRef = OWGUI.comboBox(boxFGI, self, "varNameSignalRef", label="Ref", labelWidth=33, orientation="horizontal", callback=self.varFBChange, sendSelectedValue=1, valueType=str)
244       
245#        boxBGI = QGroupBox('Average background intensity', boxVars)
246        boxBGI = OWGUI.widgetBox(boxVars, "Average background intensity")
247        self.cmbVarBGSmpl = OWGUI.comboBox(boxBGI, self, "varNameBGSmpl", label="Smpl", labelWidth=33, orientation="horizontal", callback=self.varFBChange, sendSelectedValue=1, valueType=str)
248        self.cmbVarBGRef = OWGUI.comboBox(boxBGI, self, "varNameBGRef", label="Ref", labelWidth=33, orientation="horizontal", callback=self.varFBChange, sendSelectedValue=1, valueType=str)
249       
250#        boxBGSD = QGroupBox('Background std. deviation', boxVars)
251        boxBGSD = OWGUI.widgetBox(boxVars, "Background std. deviation")
252        self.cmbVarBGSmplSD = OWGUI.comboBox(boxBGSD, self, "varNameBGSmplSD", label="Smpl", labelWidth=33, orientation="horizontal", callback=self.varFBChange, sendSelectedValue=1, valueType=str)
253        self.cmbVarBGRefSD = OWGUI.comboBox(boxBGSD, self, "varNameBGRefSD", label="Ref", labelWidth=33, orientation="horizontal", callback=self.varFBChange, sendSelectedValue=1, valueType=str)
254        # tab 1: default var names
255       
256#        boxDefaultNames = QGroupBox('Default variable names', boxVars)
257        boxDefaultNames = OWGUI.widgetBox(boxVars, "Default variable names")
258        OWGUI.lineEdit(boxDefaultNames, self, "defNameA", label="ID", labelWidth=70, orientation='horizontal', box=None, tooltip=None)
259        OWGUI.lineEdit(boxDefaultNames, self, "defNameB", label="Alt.var", labelWidth=70, orientation='horizontal', box=None, tooltip=None)
260        OWGUI.lineEdit(boxDefaultNames, self, "defNameSmpl1", label="Smpl 1", labelWidth=70, orientation='horizontal', box=None, tooltip=None)
261        OWGUI.lineEdit(boxDefaultNames, self, "defNameSmpl2", label="Smpl 2", labelWidth=70, orientation='horizontal', box=None, tooltip=None)
262        OWGUI.lineEdit(boxDefaultNames, self, "defNameRef1", label="Ref 1", labelWidth=70, orientation='horizontal', box=None, tooltip=None)
263        OWGUI.lineEdit(boxDefaultNames, self, "defNameRef2", label="Ref 2", labelWidth=70, orientation='horizontal', box=None, tooltip=None)
264        OWGUI.lineEdit(boxDefaultNames, self, "defNameForeground", label="Foreground", labelWidth=70, orientation='horizontal', box=None, tooltip=None)
265        OWGUI.lineEdit(boxDefaultNames, self, "defNameBackground", label="Background", labelWidth=70, orientation='horizontal', box=None, tooltip=None)
266        OWGUI.lineEdit(boxDefaultNames, self, "defNameMean", label="Average", labelWidth=70, orientation='horizontal', box=None, tooltip=None)
267        OWGUI.lineEdit(boxDefaultNames, self, "defNameSD", label="Std. deviation", labelWidth=70, orientation='horizontal', box=None, tooltip=None)
268        OWGUI.button(boxDefaultNames, self, "Search for Default Variables", callback=self.defaultVarAssignmentClick)
269
270        # tab 2: normalization
271#        boxNorm = QGroupBox(self)
272#        self.tabsCtrl.addTab(boxNorm, "Norm")
273        boxNorm = OWGUI.createTabPage(self.tabsCtrl, "Norm")
274        # tab 2: normalization: range, type
275        self.boxNormRange = OWGUI.radioButtonsInBox(boxNorm, self, value="normRange", box='Normalization range', btnLabels=["Global, entire microarray", "Per type of probe", "Combined (w.r.t. num. of control probes)"], callback=self.settingsNormalizationChange)
276        self.boxMinNumControlProbes = OWGUI.widgetBox(self.boxNormRange, orientation="horizontal")
277        self.boxMinNumControlProbes.setEnabled(self.normRange==2)
278        sldMinNumControlProbes = OWGUI.qwtHSlider(self.boxMinNumControlProbes, self, "minNumControlProbes", box="Min. number of control probes", minValue=2, maxValue=300, step=1, precision=0, callback=None, logarithmic=0, ticks=0, maxWidth=110)
279        self.connect(sldMinNumControlProbes, SIGNAL("sliderReleased()"), self.settingsNormalizationChange)
280        # tab 2: normalization type: loess settings
281        boxApproxFunction = OWGUI.radioButtonsInBox(boxNorm, self, value="approxFunction", box='Approximation function', btnLabels=["Median (intensity independent)", "Linear regression", "Loess"], callback=self.settingsNormalizationChange)
282
283        self.boxLoessWindow = OWGUI.widgetBox(boxApproxFunction, orientation="horizontal")
284        self.boxLoessWindow.setEnabled(self.approxFunction==OWNormalize.AppxFuncLoess)
285        sldLoessWindow = OWGUI.qwtHSlider(self.boxLoessWindow, self, "loessWindow", box="Window size (% of points)", minValue=1, maxValue=99, step=1, precision=0, logarithmic=0, ticks=0, maxWidth=110)
286        self.connect(sldLoessWindow, SIGNAL("sliderReleased()"), self.settingsNormalizationChange)
287
288        self.boxLoessNumIter =  OWGUI.widgetBox(boxApproxFunction, orientation="horizontal")
289        self.boxLoessNumIter.setEnabled(self.approxFunction==OWNormalize.AppxFuncLoess)
290        sldLoessNumIter = OWGUI.qwtHSlider(self.boxLoessNumIter, self, "loessNumIter", box="Number of robustifying iterations", minValue=1, maxValue=10, step=1, precision=0, logarithmic=0, ticks=0, maxWidth=110)
291        self.connect(sldLoessNumIter, SIGNAL("sliderReleased()"), self.settingsNormalizationChange)
292
293        OWGUI.checkBox(boxApproxFunction, self, "includeNonControl", "Include non-control probes", callback=self.settingsNormalizationChange)
294
295        self.boxSldLoessWeight = OWGUI.widgetBox(boxApproxFunction, orientation="horizontal")
296        self.boxSldLoessWeight.setEnabled(self.includeNonControl and self.approxFunction!=OWNormalize.AppxFuncMed)
297        sldLoessWeight = OWGUI.qwtHSlider(self.boxSldLoessWeight, self, "loessWeight", box="Weight of non-control probes [0,1]", minValue=0, maxValue=1, step=0.01, precision=2, logarithmic=0, ticks=0, maxWidth=110)
298        self.connect(sldLoessWeight, SIGNAL("sliderReleased()"), self.settingsNormalizationChange)
299        # tab 2: default button
300        OWGUI.button(boxNorm, self, "Set &Default Values", callback=self.normalizationAllChange)
301
302        # tab 3: filters
303#        boxFilters = QGroupBox(self)
304#        self.tabsCtrl.addTab(boxFilters, "Filter")
305        boxFilters = OWGUI.createTabPage(self.tabsCtrl, "Filter")
306        # tab 3: filters: subtract BG
307        self.cbSubtrBG = OWGUI.checkBox(boxFilters, self, "subtrBG", "Subtract background", callback=self.settingsSubstrBGChange)
308       
309        # tab 3: filters: CV
310#        self.boxMaxCV = QGroupBox('Max. coeff. of variation (CV)', boxFilters)
311        self.boxMaxCV = OWGUI.widgetBox(boxFilters, "Max. coeff. of variation (CV)")
312        OWGUI.checkBox(self.boxMaxCV, self, "useCV", "Enabled", callback=self.settingsFilterMaxCVChange)
313        sldMaxCV = OWGUI.qwtHSlider(self.boxMaxCV, self, "maxCV", minValue=0, maxValue=2, step=0.01, precision=2, callback=None, logarithmic=0, ticks=0, maxWidth=110)
314        self.connect(sldMaxCV, SIGNAL("sliderReleased()"), self.settingsFilterMaxCVChange)
315#        self.lblInfoFilterMaxCV = QLabel("\n", self.boxMaxCV)
316        self.lblInfoFilterMaxCV = OWGUI.widgetLabel(self.boxMaxCV, "\n")
317       
318        # tab 3: filters: minIntensityRatio
319#        boxMinIntRatio = QGroupBox('Min. signal to background ratio', boxFilters)
320        boxMinIntRatio = OWGUI.widgetBox(boxFilters, "Min. signal to background ratio")
321        OWGUI.checkBox(boxMinIntRatio, self, "useMinIntensity", "Enabled", callback=self.settingsFilterMinIntRatioChange)
322        sldMinInt = OWGUI.qwtHSlider(boxMinIntRatio, self, "minIntensityRatio", minValue=0, maxValue=5, step=0.01, precision=2, callback=None, logarithmic=0, ticks=0, maxWidth=110)
323        self.connect(sldMinInt, SIGNAL("sliderReleased()"), self.settingsFilterMinIntRatioChange)
324#        self.lblInfoFilterMinIntRatio = QLabel("\n", boxMinIntRatio)
325        self.lblInfoFilterMinIntRatio = OWGUI.widgetLabel(boxMinIntRatio, "\n")
326       
327        # tab 3: filters: maxFGIntensity
328#        boxMaxFGIntensity = QGroupBox('Max. foreground intensity', boxFilters)
329        boxMaxFGIntensity = OWGUI.widgetBox(boxFilters, "Max. foreground intensity")
330        OWGUI.checkBox(boxMaxFGIntensity, self, "useMaxFGIntensity", "Enabled", callback=self.settingsFilterMaxFGIntChange)
331        sldMaxFGInt = OWGUI.qwtHSlider(boxMaxFGIntensity, self, "maxFGIntensity", minValue=0, maxValue=65536, step=100, precision=0, callback=None, logarithmic=0, ticks=0, maxWidth=110)
332        self.connect(sldMaxFGInt, SIGNAL("sliderReleased()"), self.settingsFilterMaxFGIntChange)
333#        self.lblInfoFilterMaxFGInt = QLabel("\n", boxMaxFGIntensity)
334        self.lblInfoFilterMaxFGInt = OWGUI.widgetLabel(boxMaxFGIntensity,"\n")
335       
336        # tab 3: filters: maxBGIntensity
337#        boxMaxBGIntensity = QGroupBox('Max. background intensity', boxFilters)
338        boxMaxBGIntensity = OWGUI.widgetBox(boxFilters, "Max. background intensity")
339        OWGUI.checkBox(boxMaxBGIntensity, self, "useMaxBGIntensity", "Enabled", callback=self.settingsFilterMaxBGIntChange)
340        sldMaxBGInt = OWGUI.qwtHSlider(boxMaxBGIntensity, self, "maxBGIntensity", minValue=0, maxValue=4096, step=1, precision=0, callback=None, logarithmic=0, ticks=0, maxWidth=110)
341        self.connect(sldMaxBGInt, SIGNAL("sliderReleased()"), self.settingsFilterMaxBGIntChange)
342#        self.lblInfoFilterMaxBGInt = QLabel("\n", boxMaxBGIntensity)
343        self.lblInfoFilterMaxBGInt = OWGUI.widgetLabel(boxMaxBGIntensity,"\n")
344        # tab 3: default button
345        OWGUI.button(boxFilters, self, "Set &Default Values", callback=self.filtersAllChange)
346
347        # tab 4: table probe/ratio/marker
348        """
349        boxProbes = QGroupBox(boxVars)
350        self.tabsCtrl.addTab(boxProbes, "Probe")
351        self.tblControls = QTable(boxProbes)
352        self.tblControls.setNumCols(8)
353        self.tblControls.setColumnWidth(OWNormalize.tcMarker, 20)
354        self.tblControls.setColumnWidth(OWNormalize.tcRatio, 15)
355        self.tblControls.setColumnWidth(OWNormalize.tcNPAll, 10)
356        self.tblControls.setColumnWidth(OWNormalize.tcNPAccepted, 10)
357        self.tblControls.setColumnWidth(OWNormalize.tcVarA, 15)
358        self.tblControls.setColumnWidth(OWNormalize.tcVarAAlias, 0)
359        self.tblControls.setColumnWidth(OWNormalize.tcVarB, 0)
360        self.connect(self.tblControls, SIGNAL("valueChanged(int,int)"), self.tblControlsValueChange)
361        self.connect(self.tblControls, SIGNAL("currentChanged(int, int)"), self.tblControlsCurrentChanged)
362        self.connect(self.tblControls , SIGNAL('selectionChanged()'), self.tblControlsSelectionChanged)
363        self.connect(self.tblControls, SIGNAL("doubleClicked(int, int, int, const QPoint &)"), self.tblControlsDoubleClicked)
364        hheader=self.tblControls.horizontalHeader()
365        self.connect(hheader,SIGNAL("clicked(int)"), self.tblControlsHHeaderClicked)
366        self.sortby = 0
367        hheader.setLabel(OWNormalize.tcMarker, "")
368        hheader.setLabel(OWNormalize.tcRatio, "Ratio")
369        hheader.setLabel(OWNormalize.tcNPAll, "##")
370        hheader.setLabel(OWNormalize.tcNPAccepted, "#")
371        hheader.setLabel(OWNormalize.tcVarA, "ID")
372        hheader.setLabel(OWNormalize.tcVarAAlias, "Alias")
373        hheader.setLabel(OWNormalize.tcVarB, "Alt.var")
374        hheader.setMovingEnabled(False)
375        # hide vertical header and columns pKey, name
376        self.tblControls.setLeftMargin(0)
377        self.tblControls.verticalHeader().hide()
378        self.tblControls.hideColumn(OWNormalize.tcPKey)
379        self.tblControls.hideColumn(OWNormalize.tcVarAAlias)
380        self.tblControls.hideColumn(OWNormalize.tcVarB)
381        # tab 4: buttons
382        boxBtns0 = QGroupBox("Select probes where ID contains", boxProbes)
383        boxBtns00 = OWGUI.widgetBox(boxBtns0, orientation="horizontal")
384        OWGUI.lineEdit(boxBtns00, self, "controlName")
385        OWGUI.button(boxBtns00, self, "Select", callback=self.btnSelectControlsClick)
386        boxBtns01 = OWGUI.widgetBox(boxBtns0, orientation="horizontal")
387        OWGUI.button(boxBtns01, self, "Select all", callback=self.btnSelectControlsAllClick)
388        OWGUI.button(boxBtns01, self, "Unselect all", callback=self.btnUnselectControlsAllClick)
389        boxBtns1 = QGroupBox("Set marker and ratio for selected probes", boxProbes)
390        boxBtns11 = OWGUI.widgetBox(boxBtns1, orientation="horizontal")
391        pxm = QPixmap(OWNormalize.sizeButtonColor,OWNormalize.sizeButtonColor)
392        pxm.fill(self.probeColor)
393        self.cmbProbeSymbol = OWGUI.comboBox(boxBtns11, self, "probeSymbolIdx")#, callback=self.cmbProbeSymbolActivated)
394        for styleName, styleIdx in OWNormalize.stylesIndices:
395            symbol = QwtSymbol(styleIdx, QBrush(QColor(255,255,255), QBrush.SolidPattern), QPen(QColor(0,0,0),1), QSize(self.markerSize,self.markerSize))
396            pixmap = QPixmap(14,14)
397            pixmap.fill(QColor(255,255,255))
398            painter = QPainter(pixmap)
399            symbol.draw(painter, QPoint(7,7))
400            painter.end()
401            self.cmbProbeSymbol.insertItem(pixmap, styleName)
402        self.btnProbeColor = OWGUI.button(boxBtns11, self, "", callback=self.probeColorClick)
403        self.btnProbeColor.setPixmap(pxm)
404        leRatio = OWGUI.lineEdit(boxBtns11, self, "ratioStr", tooltip="Enter a positive number for normalization controls, a minus for negative controls, leave empty for others.")
405        self.connect(leRatio, SIGNAL("returnPressed()"), self.leRatioReturnPressed)
406        boxBtns12 =  OWGUI.widgetBox(boxBtns1, orientation="horizontal")
407        OWGUI.button(boxBtns12, self, "Set", callback=self.btnSetProbesClick)
408        OWGUI.button(boxBtns12, self, "Clear", callback=self.btnClearProbesClick)
409        """
410
411        # tab 5: output
412#        boxOutput = QGroupBox(self)
413#        self.tabsCtrl.addTab(boxOutput, "Out")
414        boxOutput = OWGUI.createTabPage(self.tabsCtrl, "Out")
415       
416        # tab 5: output: merge replicas
417#        boxMerge = QGroupBox('Merge replicas', boxOutput)
418        boxMerge = OWGUI.widgetBox(boxOutput, "Merge replicas")
419        OWGUI.radioButtonsInBox(boxMerge, self, value="mergeLevel", btnLabels=["None", "ID &  Alt.var", "ID"], box="Group probes by matching variable(s)", callback=self.settingsOutputReplicasChange)
420        self.rbgMergeIntensitiesType = OWGUI.radioButtonsInBox(boxMerge, self, value="mergeIntensitiesType", btnLabels=["Mean", "Median"], box="Average calculation", callback=self.settingsOutputReplicasChange)
421        # tab 5: output: additional info
422#        boxAdditional = QGroupBox('Additional info', boxOutput)
423        boxAdditional = OWGUI.widgetBox(boxOutput, "Additional info")
424        self.cbOutVarAAliases = OWGUI.checkBox(boxAdditional, self, "outVarAAliases", "ID alias", callback=self.settingsOutputChange)
425        self.cbOutNumProbes = OWGUI.checkBox(boxAdditional, self, "outNumProbes", "Number of probes", callback=self.settingsOutputChange)
426        OWGUI.checkBox(boxAdditional, self, "outNetSignal", "Net intensities", callback=self.settingsOutputChange)
427        OWGUI.checkBox(boxAdditional, self, "outA", "A (log2 average intensity)", callback=self.settingsOutputChange)
428        OWGUI.checkBox(boxAdditional, self, "outMRaw", "M raw", callback=self.settingsOutputChange)
429        OWGUI.checkBox(boxAdditional, self, "outMCentered", "M centered", callback=self.settingsOutputChange)
430        # tab 5: output: other variables
431#        boxOtherVars = QGroupBox('Other variables', boxOutput)
432        boxOtherVars = OWGUI.widgetBox(boxOutput, "Other variables")
433        self.lbVarOthers = OWGUI.listBox(boxOtherVars, self)
434        self.lbVarOthers.setSelectionMode(QListWidget.MultiSelection)
435        self.connect(self.lbVarOthers , SIGNAL('selectionChanged()'), self.varOthersChange)
436#        self.boxMergeOtherType = QGroupBox("Merge", boxOutput)
437        self.boxMergeOtherType = OWGUI.widgetBox(boxOutput, "Merge")
438        self.boxMergeOtherType.setEnabled(self.mergeLevel and len(self.varsOtherSelected) > 0)
439        rbgMergeOtherType = OWGUI.radioButtonsInBox(self.boxMergeOtherType, self, value="mergeOtherType", btnLabels=["Mean", "Median", "Concatenate values"], box="Continuous variables", callback=self.settingsOutputOtherChange)
440#        boxMergeOtherTypeD = QGroupBox('Non-continuous variables', self.boxMergeOtherType)
441        boxMergeOtherTypeD = OWGUI.widgetBox(self.boxMergeOtherType, "Non-continuous variables")
442#        QLabel("Values are concatenated by default.", boxMergeOtherTypeD)
443        OWGUI.widgetLabel(boxMergeOtherTypeD, "Values are concatenated by default.")
444        self.cbMergeOtherRemoveDupl = OWGUI.checkBox(boxMergeOtherTypeD, self, "mergeOtherRemoveDupl", "Remove duplicate values", callback=self.settingsOutputOtherChange)
445
446        # tab 6: settings
447#        boxSettings = QGroupBox(self)
448#        self.tabsCtrl.addTab(boxSettings, "Settings")
449        boxSettings = OWGUI.createTabPage(self.tabsCtrl, "Settings")
450       
451        # tab 6: settings: graph
452#        boxGraph = QGroupBox('Graph', boxSettings)
453        boxGraph = OWGUI.widgetBox(boxSettings, "Graph")
454##        OWGUI.checkBox(boxGraph, self, "recomputeNormCurveOnChange", "Update normalization curve(s) on change", callback=self.settingsRecomputeNormCurveChange)
455        boxMSize = OWGUI.widgetBox(boxGraph, orientation="horizontal")
456#        QLabel("Marker size", boxMSize)
457        OWGUI.widgetLabel(boxMSize, "Marker size")
458        cmbMarkerSize = OWGUI.comboBox(boxMSize, self, "markerSize", callback=self.settingsGraphChange, sendSelectedValue=1, valueType=int)
459        for itemIdx, size in enumerate(range(3,16)):
460            cmbMarkerSize.addItem(str(size))
461            if self.markerSize == size:
462                pass
463                #cmbMarkerSize.setCurrentItem(itemIdx) TODO PORTING
464        OWGUI.checkBox(boxGraph, self, "logAxisY", "Logarithmic Y axis", callback=lambda ax=0: self.settingsGraphAxisChange(ax))
465        cbMergeReplicas = OWGUI.checkBox(boxGraph, self, value="mergeReplGraph", label="Merge replicas", callback=self.settingsGraphChange)
466        cbMergeReplicas.setEnabled(False)
467##        OWGUI.checkBox(boxGraph, self, value="showLegend", label="Show legend", callback=self.settingsShowLegendChange)
468        OWGUI.checkBox(boxGraph, self, value="tracking", label="Tracking", callback=self.settingsProbeTrackingChange)
469        boxNormCurveStyle = OWGUI.radioButtonsInBox(boxGraph, self, box='Curve style', value="normCurveStyleIdx", btnLabels=["Line", "Spline"], callback=self.settingsGraphChange)
470        # ZoomSelectToolbar currently not used; should be connected to both MA graphs
471        #self.zoomSelectToolbar = OWToolbars.ZoomSelectToolbar(self, boxGraph, self.graphMAnonNorm, self.autoSendSelection)
472        # tab 6: settings: Probes
473#        boxProbes = QGroupBox("Probes", boxSettings)
474        boxProbes = OWGUI.widgetBox(boxSettings, "Probes")
475        OWGUI.checkBox(boxProbes, self, 'displayVarAAliases', 'Display ID aliases', callback=self.adjustProbeTableColumns)
476        # tab 6: settings: commit
477#        boxCommit = QGroupBox("Output", boxSettings)
478        boxCommit = OWGUI.widgetBox(boxSettings, "Output")
479        OWGUI.checkBox(boxCommit, self, 'commitOnChange', 'Commit data on change', callback=self.commitChange)
480       
481        # control area: commit
482        self.btnCommit = OWGUI.button(self.controlArea, self, "&Commit", callback=self.commitClicked, disabled=self.commitOnChange)
483##        self.btnRecomputeNormCurve = OWGUI.button(self.controlArea, self, "&Update Normalization Curve(s)", callback=self.recomputeNormCurveClick)       
484        # control area: info
485#        boxProbeInfo = QGroupBox("Info", self.controlArea)
486        boxProbeInfo = OWGUI.widgetBox(self.controlArea, "Info")
487#        self.lblProbeInfo = QLabel("\n\n", boxProbeInfo)
488        self.lblProbeInfo = OWGUI.widgetLabel(boxProbeInfo, "\n\n")
489
490        self.resize(1000, 752)
491
492        # INITIALIZATION: controls/ratios, probe info, filters, filter info
493        self.probes = Probes(self.graphMAnonNorm, self.graphMAnorm, self.subtrBG, self.logAxisY, self.markerSize, OWNormalize.normCurveStyles[self.normCurveStyleIdx])
494        self.setInfoProbes()
495        self.setProbeFilters()
496        self.setInfoFilterMaxCV()
497        self.setInfoFilterMinRatio()
498        self.setInfoFilterMaxFGInt()
499        self.setInfoFilterMaxBGInt()
500        self.probes.setNormalizationParameters(self.normRange, self.minNumControlProbes, self.approxFunction, self.loessWindow, self.loessNumIter, self.includeNonControl, self.loessWeight)
501
502
503    def updateCaptionTitle(self):
504        """updates caption title accorting to the expression and probe data filenames
505        """
506        ct = self.captionTitleBase
507        ctMid = ""
508        ctEnd = ""
509        exprDataName = ""
510        if self.data:
511            exprDataName = self.data.name
512        probeDataName = ""
513        if self.dataProbes:
514            probeDataName = self.dataProbes.name
515        if exprDataName or probeDataName:
516            ct += " ["
517            ctEnd = "]"
518        if exprDataName and probeDataName:
519            ctMid = ", "
520        if exprDataName:
521            ct += "E: " + exprDataName
522        ct += ctMid
523        if probeDataName:
524            ct += "P: " + probeDataName
525#        self.setCaptionTitle(ct + ctEnd)
526        self.setWindowTitle(ct + ctEnd)
527       
528
529
530
531    ###################################################################################
532    ## EXPRESSION DATA IN / OUT, SEARCH DEFAULT VARS CLICK
533    ###################################################################################
534
535    def onDataInput(self, data):
536        """Handles input of new data:
537            - put metas among variables
538            - fill combos, select default variables
539            - initialize self.probes
540        """
541        if D1 or D2: print "OWNormalize.onDataInput"
542        # qApp.restoreOverrideCursor()  #TODO PORTING
543        # qApp.setOverrideCursor(QWidget.waitCursor)  #TODO PORTING
544        self.progressBarInit()
545        # move metas among normal variables, remove string variables and variables with duplicate names, store to self.data
546        self.varsAll = {}
547        self.varsFloat = {}
548        self.varsEnumStr = {}
549        self.data = None
550        if data is not None:
551            # remove string variables and variables with duplicate names
552            newVarList = []
553            for var in data.domain.variables + data.domain.getmetas().values():
554                if self.varsAll.has_key(var.name):
555                    print "Warning: domain contains two variables with the same name: %s; the first one will be used"  % var.name
556                    continue
557                self.varsAll[var.name] = var
558                if var.varType == orange.VarTypes.Continuous:
559                    self.varsFloat[var.name] = var
560                else:
561                    self.varsEnumStr[var.name] = var
562                newVarList.append(var)
563            domNoMeta = orange.Domain(newVarList, None)
564            self.data = orange.ExampleTable(domNoMeta, data)
565            self.data.name = data.name
566        # update caption title
567        self.updateCaptionTitle()
568        # fill combos and listBox with variables
569        self.fillCmbVars()
570        self.fillLbVarOthers()
571        self.updateVarAssignment()
572        pbPortion = 1./(1+int(self.commitOnChange))
573        print "S: onDataInput: pbPortion %f" % pbPortion
574        self.initProbes(pbPortion)
575        self.sendProbes()
576        # send data
577        if self.commitOnChange:
578            self.sendData(pbPortion)
579        print "F: onDataInput"
580        self.progressBarFinished()
581        #qApp.restoreOverrideCursor()  #TODO PORTING
582
583
584    def defaultVarAssignmentClick(self):
585        """Select default variables in combos based on their names.
586        """
587        if D1: print "OWNormalize.defaultVarAssignmentClick"
588        if self.data:
589            #qApp.restoreOverrideCursor()  #TODO PORTING
590            #qApp.setOverrideCursor(QWidget.waitCursor)  #TODO PORTING
591            self.progressBarInit()
592            self.setDefaultVarAssignment()
593            pbPortion = 1./(1+int(self.commitOnChange))
594            self.initProbes(pbPortion)
595            self.sendProbes()
596            # send data
597            if self.commitOnChange:
598                self.sendData(pbPortion)
599            self.progressBarFinished()
600            # qApp.restoreOverrideCursor()  #TODO PORTING
601           
602       
603    def fillCmbVars(self):
604        """ Fills combos with variables; add "<none>":None for 2nd Probe combo.
605        """
606        if D1: print "OWNormalize.fillCmbVars"
607        cmbNamesAllVars = ["cmbVarA", "cmbVarB"]
608        cmbNamesFloatVars = ["cmbVarSignalSmpl", "cmbVarSignalRef", "cmbVarBGSmpl", "cmbVarBGRef", "cmbVarBGSmplSD", "cmbVarBGRefSD"]
609        if self.data:
610            varNamesAllVars = zip(map(lambda x: x.lower(), self.varsAll.keys()), self.varsAll.keys())
611            varNamesAllVars.sort()
612            varNamesFloatVars = zip(map(lambda x: x.lower(), self.varsFloat.keys()), self.varsFloat.keys())
613            varNamesFloatVars.sort()
614            # fill VarA & VarB combos
615            for cmbName in cmbNamesAllVars:
616                self.__dict__[cmbName].clear()
617                self.__dict__[cmbName].addItems(map(lambda x: x[1], varNamesAllVars))
618            # fill intensity combos
619            for cmbName in cmbNamesFloatVars:
620                self.__dict__[cmbName].clear()
621                self.__dict__[cmbName].addItems(map(lambda x: x[1], varNamesFloatVars))
622        else:
623            for cmbName in cmbNamesAllVars + cmbNamesFloatVars:
624                self.__dict__[cmbName].clear()           
625        # add "<none>"
626        if self.varsAll.has_key("<none>"):
627            print "Warning: doman consists of discrete variable named '<none>'; this name is reserved and should not be used"
628        self.cmbVarB.insertItem(0, "<none>")
629        self.cmbVarBGSmplSD.insertItem(0, "<none>")
630        self.cmbVarBGRefSD.insertItem(0, "<none>")
631
632
633    def updateVarAssignment(self):
634        """check that the current var names are present in the data
635        if not, set to the first variable;
636        othervise rewrite the value of the member variable so that the right item in the combo is shown
637        """
638        if D1 or D2: print "OWNormalize.updateVarAssignment"
639        if self.data and len(self.varsAll) > 0:
640            varsAllNames = self.varsAll.keys()
641            varsAllNames.sort()
642            varsEnumStrNames = self.varsEnumStr.keys()
643            varsEnumStrNames.sort()
644            varsFloatNames = self.varsFloat.keys()
645            varsFloatNames.sort()
646
647            # test variable names if exist in the data; rewrite if exist, reset if not
648            if not self.varNameA in varsAllNames:
649                self._setDefaultVarAssignment_varA(varsEnumStrNames + varsFloatNames)
650            else:
651                self.varNameA = self.varNameA
652            if not self.varNameSignalSmpl in varsAllNames:
653                self._setDefaultVarAssignment_varSignalSmpl(varsFloatNames)
654            else:
655                self.varNameSignalSmpl = self.varNameSignalSmpl
656            if not self.varNameSignalRef in varsAllNames:
657                self._setDefaultVarAssignment_varSignalRef(varsFloatNames)
658            else:
659                self.varNameSignalRef = self.varNameSignalRef
660            if not self.varNameBGSmpl in varsAllNames:
661                self._setDefaultVarAssignment_varBGSmpl(varsFloatNames)
662            else:
663                self.varNameBGSmpl = self.varNameBGSmpl
664            if not self.varNameBGRef in varsAllNames:
665                self._setDefaultVarAssignment_varBGRef(varsFloatNames)
666            else:
667                self.varNameBGRef = self.varNameBGRef
668            if not self.varNameB in varsAllNames:
669                self._setDefaultVarAssignment_varB(varsEnumStrNames + varsFloatNames)
670            else:
671                self.varNameB = self.varNameB
672            if not self.varNameBGSmplSD in varsAllNames:
673                self._setDefaultVarAssignment_varBGSmplSD(varsFloatNames)
674            else:
675                self.varNameBGSmplSD = self.varNameBGSmplSD
676            if not self.varNameBGRefSD in varsAllNames:
677                self._setDefaultVarAssignment_varBGRefSD(varsFloatNames)
678            else:
679                self.varNameBGRefSD = self.varNameBGRefSD
680       
681
682    def setDefaultVarAssignment(self):
683        """Select default variables in combos based on their names.
684        """
685        if D1 or D2: print "OWNormalize.setDefaultVarAssignment"
686        if self.data and len(self.varsAll) > 0:
687            varsAllNames = self.varsAll.keys()
688            varsAllNames.sort()
689            varsEnumStrNames = self.varsEnumStr.keys()
690            varsEnumStrNames.sort()
691            varsFloatNames = self.varsFloat.keys()
692            varsFloatNames.sort()
693            self._setDefaultVarAssignment_varA(varsEnumStrNames + varsFloatNames)
694            self._setDefaultVarAssignment_varB(varsEnumStrNames + varsFloatNames)
695            self._setDefaultVarAssignment_varSignalSmpl(varsFloatNames)
696            self._setDefaultVarAssignment_varSignalRef(varsFloatNames)
697            self._setDefaultVarAssignment_varBGSmpl(varsFloatNames)
698            self._setDefaultVarAssignment_varBGRef(varsFloatNames)
699            self._setDefaultVarAssignment_varBGSmplSD(varsFloatNames)
700            self._setDefaultVarAssignment_varBGRefSD(varsFloatNames)
701
702
703    def _setDefaultVarAssignment_varA(self, dataVarNames):
704        self.varNameA = None
705        if self.data and len(dataVarNames) > 0:
706            # first search variables with equal name, then by substrings, then all variables
707            if self.defNameA:
708                for name in dataVarNames:
709                    if self.defNameA == name:
710                        self.varNameA = name
711                        break
712                if self.varNameA == None:
713                    candVarsLenName = []    # list of tuples (len, varName)
714                    for name in dataVarNames:
715                        if self.defNameA in name:
716                            candVarsLenName.append((len(name),name))
717                    if len(candVarsLenName) > 0:
718                        candVarsLenName.sort()
719                        self.varNameA = candVarsLenName[0][1]
720            if self.varNameA == None:
721                self.varNameA = dataVarNames[0]
722
723
724    def _setDefaultVarAssignment_varB(self, dataVarNames):
725        self.varNameB = "<none>"
726        if self.data and len(dataVarNames) > 0:
727            # first search variables with equal name, then by substrings, then all variables
728            if self.defNameB:
729                for name in dataVarNames:
730                    if self.defNameB == name:
731                        self.varNameB = name
732                        break
733                if self.varNameB == "<none>":
734                    candVarsLenName = []    # list of tuples (len, varName)
735                    for name in dataVarNames:
736                        if self.defNameB in name:
737                            candVarsLenName.append((len(name),name))
738                    if len(candVarsLenName) > 0:
739                        candVarsLenName.sort()
740                        self.varNameB = candVarsLenName[0][1]
741            if self.varNameB != "<none>":
742                # select self.varNameB among the other variables (tab Output)
743                self.disconnect(self.lbVarOthers , SIGNAL('selectionChanged()'), self.varOthersChange)
744                for idx in range(self.lbVarOthers.count()):
745                    if self.varNameB == self.lbVarOthers.item(idx).text():
746                        self.lbVarOthers.item(idx).setSelected(True)
747                self.fillVarsOtherSelected()
748                self.connect(self.lbVarOthers , SIGNAL('selectionChanged()'), self.varOthersChange)
749            # enable/disable self.boxMergeOtherType
750            self.boxMergeOtherType.setEnabled(self.mergeLevel and len(self.varsOtherSelected) > 0)
751       
752
753    def _setDefaultVarAssignment_varSignalSmpl(self, dataVarNames):
754        self.varNameSignalSmpl = None
755        if self.data and len(dataVarNames) > 0:
756            candVarsLenName = []    # list of tuples (len, varName)
757            for vName in dataVarNames:
758                if vName and self.defNameSmpl1 in vName and self.defNameSmpl2 in vName and self.defNameForeground in vName and self.defNameMean in vName:
759                    candVarsLenName.append((len(vName),vName))
760            if len(candVarsLenName) > 0:
761                candVarsLenName.sort()
762                self.varNameSignalSmpl = candVarsLenName[0][1]
763            else:
764                self.varNameSignalSmpl = dataVarNames[0]
765
766    def _setDefaultVarAssignment_varSignalRef(self, dataVarNames):
767        self.varNameSignalRef = None
768        if self.data and len(dataVarNames) > 0:
769            candVarsLenName = []    # list of tuples (len, varName)
770            for vName in dataVarNames:
771                if vName and self.defNameRef1 in vName and self.defNameRef2 in vName and self.defNameForeground in vName and self.defNameMean in vName:
772                    candVarsLenName.append((len(vName),vName))
773            if len(candVarsLenName) > 0:
774                candVarsLenName.sort()
775                self.varNameSignalRef = candVarsLenName[0][1]
776            else:
777                self.varNameSignalRef = dataVarNames[0]
778
779    def _setDefaultVarAssignment_varBGSmpl(self, dataVarNames):
780        self.varNameBGSmpl = None
781        if self.data and len(dataVarNames) > 0:
782            candVarsLenName = []    # list of tuples (len, varName)
783            for vName in dataVarNames:
784                if vName and self.defNameSmpl1 in vName and self.defNameSmpl2 in vName and self.defNameBackground in vName and self.defNameMean in vName:
785                    candVarsLenName.append((len(vName),vName))
786            if len(candVarsLenName) > 0:
787                candVarsLenName.sort()
788                self.varNameBGSmpl = candVarsLenName[0][1]
789            else:
790                self.varNameBGSmpl = dataVarNames[0]
791
792    def _setDefaultVarAssignment_varBGRef(self, dataVarNames):
793        self.varNameBGRef = None
794        if self.data and len(dataVarNames) > 0:
795            candVarsLenName = []    # list of tuples (len, varName)
796            for vName in dataVarNames:
797                if vName and self.defNameRef1 in vName and self.defNameRef2 in vName and self.defNameBackground in vName and self.defNameMean in vName:
798                    candVarsLenName.append((len(vName),vName))
799            if len(candVarsLenName) > 0:
800                candVarsLenName.sort()
801                self.varNameBGRef = candVarsLenName[0][1]
802            else:
803                self.varNameBGRef = dataVarNames[0]
804
805    def _setDefaultVarAssignment_varBGSmplSD(self, dataVarNames):
806        self.varNameBGSmplSD = "<none>"
807        if self.data and len(dataVarNames) > 0:
808            candVarsLenName = []    # list of tuples (len, varName)
809            for vName in dataVarNames:
810##                if vName and self.defNameSmpl1 in vName and self.defNameSmpl2 in vName and self.defNameBackground in vName and self.defNameSD in vName and self.defNameSmpl and self.defNameBackground and self.defNameSD:
811                if vName and self.defNameSmpl1 in vName and self.defNameSmpl2 in vName and self.defNameBackground in vName and self.defNameSD in vName:
812                    candVarsLenName.append((len(vName),vName))
813            if len(candVarsLenName) > 0:
814                candVarsLenName.sort()
815                self.varNameBGSmplSD = candVarsLenName[0][1]
816        # enable/disable Max. CV slider
817        self.boxMaxCV.setEnabled(self.varNameBGSmplSD != "<none>" and self.varNameBGRefSD != "<none>")
818
819    def _setDefaultVarAssignment_varBGRefSD(self, dataVarNames):
820        self.varNameBGRefSD = "<none>"
821        if self.data and len(dataVarNames) > 0:
822            candVarsLenName = []    # list of tuples (len, varName)
823            for vName in dataVarNames:
824##                if vName and self.defNameRef1 in vName and self.defNameRef2 in vName and self.defNameBackground in vName and self.defNameSD in vName and self.defNameRef and self.defNameBackground and self.defNameSD:
825                if vName and self.defNameRef1 in vName and self.defNameRef2 in vName and self.defNameBackground in vName and self.defNameSD in vName:
826                    candVarsLenName.append((len(vName),vName))
827            if len(candVarsLenName) > 0:
828                candVarsLenName.sort()
829                self.varNameBGRefSD = candVarsLenName[0][1]
830        # enable/disable Max. CV slider
831        self.boxMaxCV.setEnabled(self.varNameBGSmplSD != "<none>" and self.varNameBGRefSD != "<none>")
832                   
833
834    def fillLbVarOthers(self):
835        """Fills listBox with variables not selected by combos
836        """
837        if D1: print "OWNormalize.fillLbVarOthers"
838        self.lbVarOthers.clear()
839        if self.data:
840            varNamesAllVars = zip(map(lambda x: x.lower(), self.varsAll.keys()), self.varsAll.keys())
841            varNamesAllVars.sort()
842            self.lbVarOthers.addItems(map(lambda x: x[1], varNamesAllVars))
843            # select items (self.lbVarOthers <- self.varsOtherSelected)
844            self.disconnect(self.lbVarOthers , SIGNAL('selectionChanged()'), self.varOthersChange)
845            for idx in range(self.lbVarOthers.count()):
846                self.lbVarOthers.item(idx).setSelected(self.lbVarOthers.item(idx).text() in self.varsOtherSelected.keys())
847            self.connect(self.lbVarOthers , SIGNAL('selectionChanged()'), self.varOthersChange)
848
849
850    def initProbes(self, pbPortion):
851        """Init self.probes:
852            - reload probe data
853            - fill self.tblControls
854            - update self.graphMAnonNorm and self.graphMAnorm
855            - update infos
856        """
857        if D1 or D2 or D6: print "OWNormalize.initProbes"
858        if self.data:
859            if self.dataProbes: pbPortion /= 3.
860            self.probes.initProbes(self.data, self.varNameA, self.varNameB, self.varNameSignalSmpl, self.varNameSignalRef, self.varNameBGSmpl, self.varNameBGRef,
861                                   self.varNameBGSmplSD, self.varNameBGRefSD, callback=lambda: self.progressBarAdvance(100./len(self.data)*pbPortion))
862        else:
863            if self.dataProbes: pbPortion /= 2.
864            self.probes.clear(False)
865        # process external probe data
866        if self.dataProbes:
867            self.processDataProbes(lambda: self.progressBarAdvance(100./len(self.dataProbes)*pbPortion))
868            # fill / update probe table & probe info
869            self.fillProbeTable(callback=lambda: self.progressBarAdvance(100./len(self.probes)*pbPortion))
870        self.setInfoProbes()
871        # filter info
872        self.setInfoFilterMaxCV()
873        self.setInfoFilterMinRatio()
874        self.setInfoFilterMaxFGInt()
875        self.setInfoFilterMaxBGInt()
876
877
878    def sendData(self, pbPortion=1.0):
879        """Compute norm. factors, plot them, normalize data and send out normalized data.
880        """
881        if D1 or D2 or D6: print "OWNormalize.sendData"
882        if self.data:
883##            pbPortion /= (int(not self.probes.isNormCurveUpToDate)*len(self.probes._valB2ind)+3+
884##                          int(self.outNumProbes)+int(self.outNetSignal)+int(self.outA)+int(self.outMRaw)+int(self.outMRaw and self.outMCentered)+int(self.outMCentered))
885##            pbPortion /= (int(not self.probes.isNormCurveUpToDate)+3+
886##                          int(self.outNumProbes)+int(self.outNetSignal)+int(self.outA)+int(self.outMRaw)+int(self.outMRaw and self.outMCentered)+int(self.outMCentered))
887            pbStep = 100.*pbPortion
888            if not self.probes.isNormCurveUpToDate:
889                if self.approxFunction == OWNormalize.AppxFuncMed:
890                    self.probes.calcReplotNormCurves(forceRecompute=True, callback=lambda: self.progressBarAdvance(pbStep/len(self.probes._ncdd)))
891                elif self.approxFunction == OWNormalize.AppxFuncLR:
892                    self.probes.calcReplotNormCurves(forceRecompute=True, callback=lambda: self.progressBarAdvance(pbStep/len(self.probes._ncdd)/8))
893                elif self.approxFunction == OWNormalize.AppxFuncLoess:
894                    self.probes.calcReplotNormCurves(forceRecompute=True, callback=lambda: self.progressBarAdvance(pbStep/len(self.probes._ncdd)/self.loessNumIter))
895            else:
896                self.progressBarAdvance(pbStep)
897            # etNum, varListNum: normalized log2 ratios, num. probes, net intensities, A, non-norm M;
898            varListNum = [orange.FloatVariable("M normalized")]
899            l2r = self.probes.getLog2Ratio_norm_masked(self.mergeLevel, self.mergeIntensitiesType, False)
900##            self.progressBarAdvance(pbStep)
901            maData = MA.reshape(l2r, (l2r.shape[0], 1))
902            # control ratios
903            varListNum.append(orange.FloatVariable("Control ratio"))
904            maData = MA.concatenate([maData, MA.reshape(self.probes.getControlRatios(self.mergeLevel, self.mergeIntensitiesType), (maData.shape[0], 1))], 1)
905##            self.progressBarAdvance(pbStep)
906            # control weights
907            varListNum.append(orange.FloatVariable("Control weight"))
908            maData = MA.concatenate([maData, MA.reshape(self.probes.getControlWeights(self.mergeLevel, self.mergeIntensitiesType), (maData.shape[0], 1))], 1)
909##            self.progressBarAdvance(pbStep)
910            if self.outNumProbes:
911                varListNum += [orange.FloatVariable("Num. probes"), orange.FloatVariable("Num. accepted probes")]
912                maData = MA.concatenate([maData, self.probes.getNumReplicas_nonFiltered(self.mergeLevel)], 1)
913    ##            self.progressBarAdvance(pbStep)
914            if self.outNetSignal:
915                varListNum += [orange.FloatVariable("Net intensity (Smpl)"), orange.FloatVariable("Net intensity (Ref)")]
916                maData = MA.concatenate([maData, self.probes.getNetIntensity_smpl_ref(self.mergeLevel, self.mergeIntensitiesType)], 1)
917    ##            self.progressBarAdvance(pbStep)
918            if self.outA:
919                varListNum.append(orange.FloatVariable("A"))
920                maData = MA.concatenate([maData, MA.reshape(self.probes.getA_masked(self.mergeLevel, self.mergeIntensitiesType), (maData.shape[0], 1))], 1)
921    ##            self.progressBarAdvance(pbStep)
922            if self.outMRaw:
923                varListNum.append(orange.FloatVariable("M raw"))
924                maData = MA.concatenate([maData, MA.reshape(self.probes.getLog2Ratio_raw_masked(self.mergeLevel, self.mergeIntensitiesType, False), (maData.shape[0], 1))], 1)
925    ##            self.progressBarAdvance(pbStep)
926            if self.outMRaw and self.outMCentered:
927                varListNum.append(orange.FloatVariable("M raw centered"))
928                maData = MA.concatenate([maData, MA.reshape(self.probes.getLog2Ratio_raw_masked(self.mergeLevel, self.mergeIntensitiesType, True), (maData.shape[0], 1))], 1)
929    ##            self.progressBarAdvance(pbStep)
930            if self.outMCentered:
931                varListNum.append(orange.FloatVariable("M normalized centered"))
932                maData = MA.concatenate([maData, MA.reshape(self.probes.getLog2Ratio_norm_masked(self.mergeLevel, self.mergeIntensitiesType, True), (maData.shape[0], 1))], 1)
933    ##            self.progressBarAdvance(pbStep)
934            etNum = chipstat.ma2orng(maData, orange.Domain(varListNum, None))
935
936            # valListList_byAttr: list of lists of values of individual attributes from varListNames + varListOtherCSV; needs to be transposed before converted to ExampleTable
937            # varListNames: data table with varA (cloned and renamed to "ID"), varA aliases ("ID alias") and varB
938            varAclone = self.data.domain[self.varNameA].clone()
939            varAclone.name = "ID"
940            varAclone.getValueFrom = lambda e,r: e[self.varNameA]
941            varListNames = [varAclone]
942            valListList_byAttr = [self.probes.getValsA(self.mergeLevel)]
943            if self.outVarAAliases:
944                varListNames.append(orange.StringVariable("ID alias"))
945                valListList_byAttr.append(self.probes.getValsAAlias(self.mergeLevel))
946            if self.varNameB != "<none>" and self.mergeLevel != OWNormalize.MergeLevelPerVarA:
947                # cannot get unique varB values if self.mergeLevel == OWNormalize.MergeLevelPerVarA
948                varListNames.append(self.data.domain[self.varNameB])
949                valListList_byAttr.append(self.probes.getValsB(self.mergeLevel))
950
951            # varListOtherCSV: subset of examples/attributes from self.data where non-continuous vars are replaced by String vars named as var.name + " list"
952            varListOtherCSV = []
953            if len(self.varsOtherSelected) > 0:
954                domainOtherVars = orange.Domain(self.varsOtherSelected.values(), None)
955                lstLstOtherVars = list(orange.ExampleTable(domainOtherVars, self.data))
956                for varIdx, var in enumerate(domainOtherVars):
957                    vals = map(lambda x: x[varIdx].native(), lstLstOtherVars)
958                    if var.varType == orange.VarTypes.Continuous and self.mergeOtherType != OWNormalize.MergeOtherTypeConc:
959                        valListList_byAttr.append(self.probes._mergeFunc[self.mergeLevel](MA.asarray(vals, Numeric.Float), Probes.mergeTypes[self.mergeOtherType], lambda x: None))
960                        varListOtherCSV.append(var)
961                        var.numberOfDecimals = 3    # by default it is set to zero because usually all values are integers; after merging we need higher precision (3 is the default value)
962                    else:
963                        valListList_byAttr.append(self.probes._concatFunc[self.mergeLevel](vals, removeDupl=self.mergeOtherRemoveDupl))
964                        varListOtherCSV.append(orange.StringVariable(var.name + " list"))
965
966            # etNamesOtherCSV: ExampleTable with variables from varListNames + varListOtherCSV, data from valListList_byAttr
967            etNamesOtherCSV = orange.ExampleTable(orange.Domain(varListNames+varListOtherCSV, None), Numeric.transpose(Numeric.asarray(valListList_byAttr, Numeric.PyObject)).tolist())
968
969            # final example table: Log2 ratio first, then metas with names, then CSV of other selected attributes
970            domOut = orange.Domain([varListNum[0]], None)
971            for var in varListNames + varListNum[1:] + varListOtherCSV:
972                domOut.addmeta(orange.newmetaid(), var)
973            etOut = orange.ExampleTable(domOut, orange.ExampleTable([etNum, etNamesOtherCSV]))
974            etOut.name = (self.data.name + " normalized").strip()
975
976        else:
977            etOut = None
978            self.progressBarAdvance(100./pbPortion)
979            self.send("Expression Data", etOut)
980
981
982    ###################################################################################
983    ## PROBE DATA IN / OUT
984    ###################################################################################
985
986    def onProbesInput(self, dataProbes):
987        """Handles input of probes data.
988        """
989        if D1 or D2: print "OWNormalize.onProbesInput"
990        #qApp.restoreOverrideCursor()  #TODO PORTING
991        #qApp.setOverrideCursor(QWidget.waitCursor)  #TODO PORTING
992        self.progressBarInit()
993        self.dataProbes = dataProbes
994        # update caption title
995        self.updateCaptionTitle()
996        # process external probe data
997        pbPortion = 1./(2+int(self.commitOnChange))
998        self.processDataProbes(lambda: self.progressBarAdvance(100./len(self.dataProbes)*pbPortion))
999        self.sendProbes()
1000        # fill / update probe table & info
1001        self.fillProbeTable(callback=lambda: self.progressBarAdvance(100./len(self.probes)*pbPortion))
1002        self.setInfoProbes()
1003        # filters info
1004        self.setInfoFilterMaxCV()
1005        self.setInfoFilterMinRatio()
1006        self.setInfoFilterMaxFGInt()
1007        self.setInfoFilterMaxBGInt()
1008        # send data
1009        if self.commitOnChange:
1010            self.sendData(pbPortion)
1011        self.progressBarFinished()
1012        #qApp.restoreOverrideCursor()  #TODO PORTING
1013
1014
1015    def processDataProbes(self, callback):
1016        """Copy data from orange.ExampleTable to self.probes.
1017        """
1018        if D1 or D2 or D6: print "OWNormalize.processDataProbes"
1019        if self.dataProbes:
1020            varNames = map(lambda var: var.name, self.dataProbes.domain.variables)
1021            if "Var A" in varNames and "ColorRGB" in varNames and "Ratio" in varNames and "Symbol" in varNames:
1022                # list of probe keys
1023                if self.varNameB != "<none>" and "Var B" in varNames:
1024                    pKeysIDsNames = map(lambda e: (str(e["Var A"].native()) + str(e["Var B"].native()), str(e["Var A"].native()), str(e["Var B"].native())), self.dataProbes)
1025                else:
1026                    pKeysIDsNames = map(lambda e: (str(e["Var A"].native()), str(e["Var A"].native()), ""), self.dataProbes)
1027                # get color, symbol and ratio of probes
1028                for e, (pKey, pID, pName) in zip(self.dataProbes, pKeysIDsNames):
1029                    c = str(e["ColorRGB"])
1030                    try:
1031                        color = QColor(int(c[0:2],16), int(c[2:4],16), int(c[4:6],16), QColor.Rgb)
1032                    except ValueError:
1033                        # this test is here because Excel changes "000000" to "0"
1034                        if c=="0":
1035                            color = QColor(0,0,0)
1036                        else:
1037                            color = ProbeSet.NoColor
1038                    try:
1039                        symbol = int(e["Symbol"].native())
1040                    except TypeError:
1041                        symbol = QwtSymbol.NoSymbol
1042                    ratio = str(e["Ratio"])
1043                    # read optional name for varA and varB values
1044                    try:
1045                        valAAlias = str(e["Var A alias"].native())
1046                    except TypeError:
1047                        valAAlias = None
1048                    ###########################################################
1049                    # if pKey exists
1050                    probe = self.probes.get(pKey)
1051                    if probe:
1052                        self.probes.setMarker(probe, symbol, color, refresh=False)
1053                        self.probes.setRatioWeight(probe, ratio, recalc=False, refresh=False)
1054                        if valAAlias:
1055                            probe.valAAlias = valAAlias
1056                    # if pKey does not exist
1057                    else:
1058                        for pk in self.probes.getKeysFromValAValB(pID, pName):
1059                            probe = self.probes.get(pk)
1060                            self.probes.setMarker(probe, symbol, color, refresh=False)
1061                            self.probes.setRatioWeight(probe, ratio, recalc=False, refresh=False)
1062                            if valAAlias:
1063                                probe.valAAlias = valAAlias
1064                    if callback: callback()
1065                if len(self.dataProbes) > 0:
1066                    self.probes.calcReplotAllCurves(refresh=True)
1067            else:
1068                print "Warning: probe data must consist of attributes 'Var A', 'Ratio', 'ColorRGB' and 'Symbol'; optional attributes: 'Var B' and 'Var A alias'"
1069
1070
1071    def sendProbes(self):
1072        """Sends out example table with currently used probes.
1073        """
1074        if D1 or D2 or D6: print "OWNormalize.sendProbes"
1075        if self.data:
1076            vals = []
1077            pKeys = self.probes.keys()
1078            pKeys.sort()
1079            for pKey in pKeys:
1080                probe = self.probes[pKey]
1081                vals.append([probe.valA, probe.valAAlias, probe.valB, probe.ratioExpr, probe.getColorRgbStr(), probe.symbol])
1082            # create domain, clone and rename variables to "Var A" and "Var B"
1083            if self.varNameB != "<none>":
1084                varB = self.varsAll[self.varNameB].clone()
1085                varB.name = "Var B"
1086            else:
1087                varB = orange.StringVariable("Var B")
1088            varAAlias = orange.StringVariable("Var A alias")
1089            domain = orange.Domain([self.varsAll[self.varNameA].clone(), varAAlias, varB, orange.StringVariable("Ratio"), orange.StringVariable("ColorRGB"), orange.FloatVariable("Symbol")], None)
1090            domain[0].name = "Var A"
1091            # copy values into example table
1092            et = orange.ExampleTable(domain, vals)
1093            # remove 'Var B' if selv.varNameB == "<none>"
1094            if self.varNameB == "<none>":
1095                et = orange.ExampleTable(orange.Domain(et.domain[0:2] + et.domain[3:], None), et)
1096            if self.dataProbes:
1097                et.name = self.dataProbes.name
1098            else:
1099                et.name = "Probe Data"
1100            self.send("Probe Data", et)
1101        else:
1102            self.send("Probe Data", None)
1103
1104
1105    ###################################################################################
1106    ## SELECTION OF VARIABLES
1107    ###################################################################################
1108
1109    def varABChange(self):
1110        """Refresh listbox containing other variables and refill self.tblControls.
1111        """
1112        if D1: print "OWNormalize.varABChange"
1113        #qApp.restoreOverrideCursor()  #TODO PORTING
1114        #qApp.setOverrideCursor(QWidget.waitCursor)  #TODO PORTING
1115        self.progressBarInit()
1116        pbPortion = 1./(1+int(self.commitOnChange))
1117        self.initProbes(pbPortion)
1118        self.sendProbes()
1119        # send data
1120        if self.commitOnChange:
1121            self.sendData(pbPortion)
1122        self.progressBarFinished()
1123        #qApp.restoreOverrideCursor()  #TODO PORTING
1124
1125
1126    def varFBChange(self):
1127        """Refresh listbox containing other variables (tab Out);
1128        enables/disables Max. CV slider (tab Filter).
1129        """
1130        if D1 or D6: print "OWNormalize.varFBChange"
1131        #qApp.restoreOverrideCursor()  #TODO PORTING
1132        #qApp.setOverrideCursor(QWidget.waitCursor)  #TODO PORTING
1133        # enable/disable Max. CV slider
1134        self.boxMaxCV.setEnabled(self.varNameBGSmplSD != "<none>" and self.varNameBGRefSD != "<none>")
1135        # update data
1136        self.probes.updateProbeData(self.data, self.varNameSignalSmpl, self.varNameSignalRef, self.varNameBGSmpl, self.varNameBGRef, self.varNameBGSmplSD, self.varNameBGRefSD)
1137        # update info
1138        self.setInfoProbes()
1139        self.setInfoFilterMaxCV()
1140        self.setInfoFilterMinRatio()
1141        self.setInfoFilterMaxFGInt()
1142        self.setInfoFilterMaxBGInt()
1143        if self.commitOnChange:
1144            self.progressBarInit()
1145            self.sendData()
1146            self.progressBarFinished()
1147        #qApp.restoreOverrideCursor()  #TODO PORTING
1148
1149
1150    def varOthersChange(self):
1151        """Updates list of selected other vars (lbVarOthers -> self.varsOtherSelected);
1152        enables merge options for other variables.
1153        """
1154        #qApp.restoreOverrideCursor()  #TODO PORTING
1155        #qApp.setOverrideCursor(QWidget.waitCursor)  #TODO PORTING
1156        self.fillVarsOtherSelected()
1157        self.boxMergeOtherType.setEnabled(self.mergeLevel and len(self.varsOtherSelected) > 0)
1158        if self.commitOnChange:
1159            self.progressBarInit()
1160            self.sendData()
1161            self.progressBarFinished()
1162        #qApp.restoreOverrideCursor()  #TODO PORTING
1163
1164
1165    def fillVarsOtherSelected(self):       
1166        if D1: print "OWNormalize.varOtherChange"
1167        self.varsOtherSelected = {}
1168        if self.data:
1169            for i in range(0, self.lbVarOthers.count()):
1170                if self.lbVarOthers.isSelected(i):
1171                    varName = str(self.lbVarOthers.item(i).text())
1172                    self.varsOtherSelected[varName] = self.data.domain[varName]
1173
1174
1175    ###################################################################################
1176    ## PROBE TABLE (self.tblControls)
1177    ###################################################################################
1178
1179    def fillProbeTable(self, callback):
1180        # init self.tblControls
1181        if D1 or D2 or D6: print "OWNormalize.fillProbeTable"
1182        if self.probes:
1183            # table row items and their number, header labels, len of sorting keys where spaces are added in front
1184            allProbes = self.probes.values()
1185            numProbes = len(allProbes)
1186            self.tblControls.setNumRows(numProbes)
1187            self.tblControls.horizontalHeader().setLabel(OWNormalize.tcVarA, "ID")
1188            sortKeyLen = int(math.log(numProbes, 10))+1
1189            # generate sorting keys: varA, varAAlias
1190            valAIdx = zip(map(lambda pr: (pr.valA, pr.valAAlias, pr.valB), allProbes), range(numProbes))
1191            valAIdx.sort()
1192            valARank = dict(zip([x[1] for x in valAIdx], range(numProbes)))
1193            valAAliasIdx = zip(map(lambda pr: (pr.valAAlias, pr.valA, pr.valB), allProbes), range(numProbes))
1194            valAAliasIdx.sort()
1195            valAAliasRank = dict(zip([x[1] for x in valAAliasIdx], range(numProbes)))
1196            if self.varNameB != "<none>":
1197                # generate sorting keys: varB)
1198                valBIdx = zip(map(lambda pr: (pr.valB, pr.valA, pr.valAAlias), allProbes), range(numProbes))
1199                valBIdx.sort()
1200                valBRank = dict(zip([x[1] for x in valBIdx], range(numProbes)))
1201                # fill rows
1202                for row, (key,pr) in enumerate(self.probes.items()):
1203                    # store the table row index of the probe
1204                    pr.tblRowIdx = row
1205                    numProbesAll = pr.getNumProbes()
1206                    numProbesAcc = self.probes.getNumProbes_nonFiltered(pr)
1207                    OWGUI.tableItem(self.tblControls, row, OWNormalize.tcNPAll, str(numProbesAll), editType=QTableItem.Never, sortingKey="%05d%05d"%(numProbesAll,numProbesAcc))#, background=QColor(160,160,160))
1208                    OWGUI.tableItem(self.tblControls, row, OWNormalize.tcNPAccepted, str(numProbesAcc), editType=QTableItem.Never, sortingKey="%05d%05d"%(numProbesAcc,numProbesAll))#, background=QColor(160,160,160))
1209                    OWGUI.tableItem(self.tblControls, row, OWNormalize.tcVarA, str(pr.valA), editType=QTableItem.Never, sortingKey=self.sortingKey(valARank[row], 20))#, background=QColor(160,160,160))
1210                    OWGUI.tableItem(self.tblControls, row, OWNormalize.tcVarAAlias, str(pr.valAAlias), editType=QTableItem.OnTyping, sortingKey=self.sortingKey(valAAliasRank[row], 20))#, background=QColor(160,160,160))
1211                    OWGUI.tableItem(self.tblControls, row, OWNormalize.tcVarB, str(pr.valB), editType=QTableItem.Never, sortingKey=self.sortingKey(valBRank[row], 20))#, background=QColor(160,160,160))
1212                    OWGUI.tableItem(self.tblControls, row, OWNormalize.tcPKey, key)
1213                    self.fillProbeTableItemMarkerRatio(row, pr)
1214                    if callback: callback()
1215                self.tblControls.horizontalHeader().setLabel(OWNormalize.tcVarB, self.varNameB)
1216            else:
1217                # fill rows
1218                for row, (key,pr) in enumerate(self.probes.items()):
1219                    # store the table row index of the probe
1220                    pr.tblRowIdx = row
1221                    numProbesAll = pr.getNumProbes()
1222                    numProbesAcc = self.probes.getNumProbes_nonFiltered(pr)
1223                    OWGUI.tableItem(self.tblControls, row, OWNormalize.tcNPAll, str(numProbesAll), editType=QTableItem.Never, sortingKey="%05d%05d"%(numProbesAll,numProbesAcc))#, background=QColor(160,160,160))
1224                    OWGUI.tableItem(self.tblControls, row, OWNormalize.tcNPAccepted, str(numProbesAcc), editType=QTableItem.Never, sortingKey="%05d%05d"%(numProbesAcc,numProbesAll))#, background=QColor(160,160,160))
1225                    OWGUI.tableItem(self.tblControls, row, OWNormalize.tcVarA, str(pr.valA), editType=QTableItem.Never, sortingKey=self.sortingKey(valARank[row], 20))#, background=QColor(160,160,160))
1226                    OWGUI.tableItem(self.tblControls, row, OWNormalize.tcVarAAlias, str(pr.valAAlias), editType=QTableItem.OnTyping, sortingKey=self.sortingKey(valAAliasRank[row], 20))#, background=QColor(160,160,160))
1227                    OWGUI.tableItem(self.tblControls, row, OWNormalize.tcPKey, key)
1228                    self.fillProbeTableItemMarkerRatio(row, pr)
1229                    if callback: callback()
1230        else:
1231            self.tblControls.horizontalHeader().setLabel(OWNormalize.tcVarA, "ID")
1232            self.tblControls.horizontalHeader().setLabel(OWNormalize.tcVarB, "Alt.var")
1233            self.tblControls.setNumRows(0)
1234        self.adjustProbeTableColumns()
1235
1236
1237    def adjustProbeTableColumns(self):
1238        """shows/hides appropriate columns, adjusts their widths
1239        """
1240        # show/hide columns with aliases and varB values and adjust their widths
1241        lastColumn = OWNormalize.tcVarA
1242        if self.displayVarAAliases:
1243            self.tblControls.showColumn(OWNormalize.tcVarAAlias)
1244            self.tblControls.adjustColumn(OWNormalize.tcVarAAlias)
1245            lastColumn = OWNormalize.tcVarAAlias
1246        else:
1247            self.tblControls.hideColumn(OWNormalize.tcVarAAlias)
1248            self.tblControls.setColumnWidth(OWNormalize.tcVarAAlias, 0)
1249
1250        if self.varNameB != "<none>":
1251            self.tblControls.showColumn(OWNormalize.tcVarB)
1252            self.tblControls.adjustColumn(OWNormalize.tcVarB)
1253            lastColumn = OWNormalize.tcVarB
1254        else:
1255            self.tblControls.hideColumn(OWNormalize.tcVarB)
1256            self.tblControls.setColumnWidth(OWNormalize.tcVarB, 0)
1257        # adjust other columns' width
1258        self.tblControls.adjustColumn(OWNormalize.tcRatio)
1259        self.tblControls.adjustColumn(OWNormalize.tcNPAll)
1260        self.tblControls.adjustColumn(OWNormalize.tcNPAccepted)
1261        self.tblControls.adjustColumn(OWNormalize.tcVarA)
1262        # calculate the width of the last column
1263        colWidthSum = self.tblControls.columnWidth(OWNormalize.tcMarker) + self.tblControls.columnWidth(OWNormalize.tcRatio) + self.tblControls.columnWidth(OWNormalize.tcNPAll) + self.tblControls.columnWidth(OWNormalize.tcNPAccepted) + self.tblControls.columnWidth(OWNormalize.tcVarA) + self.tblControls.columnWidth(OWNormalize.tcVarAAlias) + self.tblControls.columnWidth(OWNormalize.tcVarB)
1264        lastColWidth = max(self.tblControls.columnWidth(lastColumn), self.tblControls.visibleWidth() - colWidthSum + self.tblControls.columnWidth(lastColumn))
1265        self.tblControls.setColumnWidth(lastColumn, lastColWidth)
1266
1267
1268    def fillProbeTableItemMarkerRatio(self, row, probe):
1269        """Updates a given row of self.tblControls: marker & ratio.
1270        """
1271        pxm = self.probes.getSymbolPixmap(probe, self.tblControls.cellGeometry(row, OWNormalize.tcMarker))
1272        ratioSortKey = self.probes.getRatioSortingKey(probe)
1273        markerSortKey = probe.getMarkerSortKey()
1274        OWGUI.tableItem(self.tblControls, row, OWNormalize.tcRatio, self.probes.getRatioStr(probe), editType=QTableItem.OnTyping, sortingKey=ratioSortKey+markerSortKey) #, background=QColor(160,160,160))
1275        OWGUI.tableItem(self.tblControls, row, OWNormalize.tcMarker, "", editType=QTableItem.Never, sortingKey=markerSortKey+ratioSortKey, pixmap=pxm)#, background=QColor(160,160,160))
1276
1277
1278    def sortingKey(self, val, len):
1279        """Returns a string with leading spaces followed by str(val), whose length is at least len.
1280        """
1281        s = "%" + str(int(len)) + "." + str(int(len/2)) + "f"
1282        return s % val
1283
1284
1285    def updateProbeTableNumAcceptedProbes(self):
1286        # updates column tcNPAccepted after filters change
1287        if D1 or D2 or D6: print "OWNormalize.updateProbeTableNumAcceptedProbes"
1288        if self.probes:
1289            # table row items and their number, header labels, len of sorting keys where spaces are added in front
1290            for row in range(self.tblControls.numRows()):
1291                pr = self.probes.get(str(self.tblControls.text(row, OWNormalize.tcPKey)))
1292                numProbesAll = pr.getNumProbes()
1293                numProbesAcc = self.probes.getNumProbes_nonFiltered(pr)
1294                OWGUI.tableItem(self.tblControls, row, OWNormalize.tcNPAccepted, str(numProbesAcc), editType=QTableItem.Never, sortingKey="%05d%05d"%(numProbesAcc,numProbesAll))
1295 
1296
1297    def tblControlsHHeaderClicked(self, col):
1298        """Sorts the table by column col; sets probe.tblRowIdx accordingly
1299        """
1300        if D1: print "OWNormalize.tblControlsSort"
1301        #qApp.restoreOverrideCursor()  #TODO PORTING
1302        #qApp.setOverrideCursor(QWidget.waitCursor)  #TODO PORTING
1303        if col == self.sortby-1:
1304            self.sortby = - self.sortby
1305        else:
1306            self.sortby = col+1
1307        self.tblControls.sortColumn(col, self.sortby>=0, TRUE)
1308        self.tblControls.horizontalHeader().setSortIndicator(col, self.sortby<0)
1309        # update probe.tblRowIdx
1310        for row in range(self.tblControls.numRows()):
1311            pKey = str(self.tblControls.item(row, OWNormalize.tcPKey).text())
1312            self.probes[pKey].tblRowIdx = row
1313        #qApp.restoreOverrideCursor()  #TODO PORTING
1314
1315
1316    def tblControlsValueChange(self, row, col):
1317        """Handles direct changes to self.tblControls;
1318        if col == tcRatio: updates self.internContRatios and sends out expression and probe data;
1319        if col == tcVarAAlias: updates probe.valAAlias and sends out probe data;
1320        """
1321        if D1 or D3: print "OWNormalize.tblControlsValueChange"
1322        #qApp.restoreOverrideCursor()  #TODO PORTING
1323        #qApp.setOverrideCursor(QWidget.waitCursor)  #TODO PORTING
1324        if col == OWNormalize.tcRatio:
1325            pKey = str(self.tblControls.item(row, OWNormalize.tcPKey).text())
1326            ratio = str(self.tblControls.item(row, OWNormalize.tcRatio).text())
1327            if ratio != self.probes[pKey].ratioExpr:
1328                # set ratio
1329                probe = self.probes[pKey]
1330                newRatio = self.probes.setRatioWeight(probe, ratio, recalc=True)
1331                self.sendProbes()
1332                # update table & info
1333                self.fillProbeTableItemMarkerRatio(row, probe)
1334                self.setInfoProbes()
1335                self.setInfoFilterMaxCV()
1336                self.setInfoFilterMinRatio()
1337                self.setInfoFilterMaxFGInt()
1338                self.setInfoFilterMaxBGInt()
1339                if self.commitOnChange:
1340                    self.progressBarInit()
1341                    self.sendData()
1342                    self.progressBarFinished()
1343        if col == OWNormalize.tcVarAAlias:
1344            pKey = str(self.tblControls.item(row, OWNormalize.tcPKey).text())
1345            alias = str(self.tblControls.item(row, OWNormalize.tcVarAAlias).text())
1346            if alias != self.probes[pKey].valAAlias:
1347                self.probes[pKey].valAAlias = alias
1348                self.sendProbes()
1349                if self.commitOnChange and self.outVarAAliases:
1350                    self.progressBarInit()
1351                    self.sendData()
1352                    self.progressBarFinished()
1353        #qApp.restoreOverrideCursor()  #TODO PORTING
1354               
1355               
1356
1357
1358    def tblControlsCurrentChanged(self, row, col):
1359        """Handles changes of currently selected cell in self.tblControls;
1360        activate the current probe.
1361        """
1362        if D1: print "OWNormalize.tblControlsCurrentChanged"
1363        if row >= 0 and col >= 0:
1364            pKey = str(self.tblControls.item(row, OWNormalize.tcPKey).text())
1365            self.probes.setCurveActive(pKey, True, refresh=True)
1366
1367
1368    def tblControlsSelectionChanged(self):
1369        if D1: print "OWNormalize.tblControlsSelectionChanged"
1370        self.activateSelectedProbes()
1371
1372
1373    def tblControlsDoubleClicked(self, row, col, button, mousePos):
1374        """Adjust values of self.ratioStr, self.btnProbeColor and self.cmbProbeSymbol.
1375        """
1376        if D1: print "OWNormalize.tblControlsSelectionChanged"
1377        if row>=0 and col>=0:
1378            pKey = str(self.tblControls.item(row, OWNormalize.tcPKey).text())
1379            probe = self.probes[pKey]
1380            # update GUI: ratio lineEdit, probeSymbol, probeColor
1381            self.probeSymbolIdx = probe.symbol
1382            self.ratioStr = probe.ratioExpr
1383            if probe.color != ProbeSet.NoColor:
1384                self.probeColor = probe.color
1385                # update color of button
1386                self.btnProbeColor.pixmap().fill(self.probeColor)
1387                self.btnProbeColor.repaint()
1388
1389
1390    ###################################################################################
1391    ## ASSIGNMENT OF RATIOS / COLORS / SYMBOLS
1392    ###################################################################################
1393
1394    def btnSelectControlsClick(self):
1395        """Select probes where ID contains self.controlName.
1396        """
1397        if D1: print "OWNormalize.btnSelectControlsClick"
1398        #qApp.restoreOverrideCursor()  #TODO PORTING
1399        #qApp.setOverrideCursor(QWidget.waitCursor)  #TODO PORTING
1400        self.tblControls.setCurrentCell(-1,-1)
1401        numSelectionsOld = self.tblControls.numSelections()
1402        for idx in range(self.tblControls.numRows()):
1403            if string.lower(self.controlName) in string.lower(self.tblControls.item(idx, OWNormalize.tcVarA).text()):
1404                sel = QTableSelection()
1405                sel.init(idx,OWNormalize.tcVarA)
1406                sel.expandTo(idx,OWNormalize.tcVarA)
1407                self.tblControls.addSelection(sel)
1408        if self.tblControls.numSelections() != numSelectionsOld:
1409            self.activateSelectedProbes()
1410        #qApp.restoreOverrideCursor()  #TODO PORTING
1411
1412
1413    def btnSelectControlsAllClick(self):
1414        """Clears all selections and selects all probes.
1415        """
1416        if D1: print "OWNormalize.btnSelectControlsAllClick"
1417        #qApp.restoreOverrideCursor()  #TODO PORTING
1418        #qApp.setOverrideCursor(QWidget.waitCursor)  #TODO PORTING
1419        self.tblControls.clearSelection(False)
1420        sel = QTableSelection()
1421        sel.init(0,OWNormalize.tcMarker)
1422        sel.expandTo(self.tblControls.numRows()-1,OWNormalize.tcVarB)
1423        self.tblControls.addSelection(sel)
1424        self.activateSelectedProbes()
1425        #qApp.restoreOverrideCursor()  #TODO PORTING
1426
1427
1428    def btnUnselectControlsAllClick(self):
1429        """Clears all selections and selects all probes.
1430        """
1431        if D1: print "OWNormalize.btnUnselectControlsAllClick"
1432        #qApp.restoreOverrideCursor()  #TODO PORTING
1433        #qApp.setOverrideCursor(QWidget.waitCursor)  #TODO PORTING
1434        self.tblControls.setCurrentCell(-1,-1)
1435        self.tblControls.clearSelection(True)
1436        #qApp.restoreOverrideCursor()  #TODO PORTING
1437
1438
1439    def leRatioReturnPressed(self):
1440        """If new ratio is entered and return pressed, selected controls get updated.
1441        """
1442        if D1: print "OWNormalize.leRatioReturnPressed"
1443        #qApp.restoreOverrideCursor()  #TODO PORTING
1444        #qApp.setOverrideCursor(QWidget.waitCursor)  #TODO PORTING
1445        self.progressBarInit()
1446        self.updateSelectedProbes(self.ratioStr, self.probeColor, self.probeSymbolIdx, True, False, False)
1447        self.sendProbes()
1448        self.setInfoProbes()
1449        self.setInfoFilterMaxCV()
1450        self.setInfoFilterMinRatio()
1451        self.setInfoFilterMaxFGInt()
1452        self.setInfoFilterMaxBGInt()
1453        if self.commitOnChange:
1454            self.sendData()
1455        self.progressBarFinished()
1456        #qApp.restoreOverrideCursor()  #TODO PORTING
1457
1458
1459    def probeColorClick(self):
1460        """Show color-selection window, update button color and color of the symbols of the selected probes.
1461        """
1462        if D1: print "OWNormalize.probeColorCick"
1463        probeColor = QColorDialog.getColor(self.probeColor, self)
1464        if probeColor.isValid():
1465            self.probeColor = probeColor
1466        self.btnProbeColor.pixmap().fill(self.probeColor)
1467        self.btnProbeColor.repaint()
1468
1469       
1470    def btnSetProbesClick(self):
1471        """Sets ratio, color and symbol for the selected controls.
1472        """
1473        if D1: print "OWNormalize.btnSetProbesClick"
1474        # qApp.restoreOverrideCursor()  #TODO PORTING
1475        # qApp.setOverrideCursor(QWidget.waitCursor)  #TODO PORTING
1476        self.progressBarInit()
1477        self.updateSelectedProbes(self.ratioStr, self.probeColor, self.probeSymbolIdx, True, True, True)
1478        self.sendProbes()
1479        self.setInfoProbes()
1480        self.setInfoFilterMaxCV()
1481        self.setInfoFilterMinRatio()
1482        self.setInfoFilterMaxFGInt()
1483        self.setInfoFilterMaxBGInt()
1484        if self.commitOnChange:
1485            self.sendData()
1486        self.progressBarFinished()
1487        # qApp.restoreOverrideCursor()  #TODO PORTING
1488
1489
1490    def btnClearProbesClick(self):
1491        """Clears ratios for the selected controls
1492        """
1493        if D1: print "OWNormalize.btnClearProbesClick"
1494        # qApp.restoreOverrideCursor()  #TODO PORTING
1495        #qApp.setOverrideCursor(QWidget.waitCursor)  #TODO PORTING
1496        self.progressBarInit()
1497        self.updateSelectedProbes("", ProbeSet.NoColor, QwtSymbol.NoSymbol, True, True, True)
1498        self.sendProbes()
1499        self.setInfoProbes()
1500        self.setInfoFilterMaxCV()
1501        self.setInfoFilterMinRatio()
1502        self.setInfoFilterMaxFGInt()
1503        self.setInfoFilterMaxBGInt()
1504        if self.commitOnChange:
1505            self.sendData()
1506        self.progressBarFinished()
1507        # qApp.restoreOverrideCursor()  #TODO PORTING
1508
1509
1510    def updateSelectedProbes(self, ratioStr, color, symbol, updateRatio, updateColor, updateSymbol):
1511        """Updates selected probes with a given ratio string, color and symbol;
1512        updates only those values where the correcponding update value == True;
1513        calls fillProbeTableItemMarkerRatio(row, probe), replots/removes curves.
1514        """
1515        if D1 or D2: print "OWNormalize.updateSelectedProbes"
1516        numSelections = self.tblControls.numSelections()
1517        for selNum in range(self.tblControls.numSelections()):
1518            sel = self.tblControls.selection(selNum)
1519            for row in range(sel.topRow(), sel.bottomRow()+1):
1520                # update probe
1521                pKey = str(self.tblControls.item(row, OWNormalize.tcPKey).text())
1522                probe = self.probes[pKey]
1523                if updateRatio:
1524                    self.probes.setRatioWeight(probe, ratioStr, recalc=False, refresh=False)
1525                if updateColor or updateSymbol:
1526                    if updateColor:
1527                        newColor = color
1528                    else:
1529                        newColor = probe.color
1530                    if updateSymbol:
1531                        newSymbol = symbol
1532                    else:
1533                        newSymbol = probe.symbol
1534                    self.probes.setMarker(probe, newSymbol, newColor, refresh=False)
1535                # update table
1536                self.fillProbeTableItemMarkerRatio(row, probe)
1537        if self.tblControls.numSelections() > 0:
1538            self.probes.calcReplotAllCurves(refresh=True)
1539
1540
1541    def activateSelectedProbes(self):
1542        """Activate currently selected probes;
1543        """
1544        if D1 or D2 or D6: print "OWNormalize.activateSelectedProbes"
1545        activePKeys = {}    # dict pKey:pKey (to remove duplicates)
1546        for selNum in range(self.tblControls.numSelections()):
1547            sel = self.tblControls.selection(selNum)
1548            for row in range(sel.topRow(), sel.bottomRow()+1):
1549                item = self.tblControls.item(row, OWNormalize.tcPKey)
1550                if item:
1551                    aPKey = str(item.text())
1552                    activePKeys[aPKey] = aPKey
1553        self.probes.setCurveActiveList(activePKeys.keys(), refresh=True)
1554
1555
1556    def setInfoProbes(self):
1557        if D4: print "OWNormalize.setInfoProbes"
1558        if self.probes:
1559            self.lblProbeInfo.setText("Probes in total:\t%5d norm, %5d neg, %5d other.\nAccepted:\t%5d norm, %5d neg, %5d other.\nPlotted:\t\t%5d norm, %5d neg, %5d other." %
1560                                      (self.probes.getNumProbesCtrlNorm(), self.probes.getNumProbesCtrlNeg(), self.probes.getNumProbesOthers(),
1561                                       self.probes.getNumProbesCtrlNorm_nonFiltered(), self.probes.getNumProbesCtrlNeg_nonFiltered(), self.probes.getNumProbesOthers_nonFiltered(),
1562                                       self.probes.getNumProbesCtrlNorm_nonFiltered_plotted(), self.probes.getNumProbesCtrlNeg_nonFiltered_plotted(), self.probes.getNumProbesOthers_nonFiltered_plotted()))
1563        else:
1564            self.lblProbeInfo.setText("No data on input.\n\n")
1565
1566
1567    ###################################################################################
1568    ## GRAPH
1569    ###################################################################################
1570
1571    def onTabMainCurrentChange(self, currWidget):
1572        """change the reference self.graphMAcurrent to either self.graphMAnonNorm or self.graphMAnorm;
1573        connect "Save Graph" button to the current graph (disconnect the graph in background).
1574        note: first called automatically from __init__
1575        """
1576        if D1: print "onTabMainCurrentChange"
1577        if currWidget == self.boxMAnonNorm:
1578            self.graphMAcurrent = self.graphMAnonNorm
1579            if self.getConnectionMethod(self.graphButton, SIGNAL("clicked()")) is not None:
1580                self.disconnect(self.graphButton, SIGNAL("clicked()"))
1581            self.connect(self.graphButton, SIGNAL("clicked()"), self.graphMAnonNorm.saveToFile)
1582        elif currWidget == self.boxMAnorm:
1583            self.graphMAcurrent = self.graphMAnorm
1584            if self.getConnectionMethod(self.graphButton, SIGNAL("clicked()")) is not None:
1585                self.disconnect(self.graphButton, SIGNAL("clicked()"))
1586            self.connect(self.graphButton, SIGNAL("clicked()"), self.graphMAnorm.saveToFile)
1587       
1588
1589    def setGraphAxes(self, axes=None):
1590        """According to selected scaling sets up axis labels and scales;
1591        axis: 0: vertical left, 1: vertical right, 2: horizontal bottom, 3: horizontal top
1592        """
1593        if D1: print "OWNormalize.setGraphAxes"
1594        titles = {False: ["Centered ratio"]*2 + ["Average intensity"]*2, True: ["M: centered log2 ratio"]*2 + ["A: log2 average intensity"]*2}
1595        useLog = [self.logAxisY]*2 + [True]*2
1596        if axes==None: axes = [0,2]
1597        for axis in axes:
1598            self.graphMAnonNorm.setAxisTitle(axis, titles[useLog[axis]][axis])
1599            self.graphMAnorm.setAxisTitle(axis, titles[useLog[axis]][axis])
1600   
1601
1602##    def onLegendClickedMAnonNorm(self, key):
1603##        """Change active probe curve
1604##        """
1605##        if D1: print "OWNormalize.onLegendClickedMAnonNorm"
1606##        qApp.restoreOverrideCursor()
1607##        qApp.setOverrideCursor(QWidget.waitCursor)
1608##        pKey = self.graphMAnonNorm.curve(key).key
1609##        if pKey <> None:
1610##            self.probes.switchCurveActive(pKey, refresh=True)
1611##        qApp.restoreOverrideCursor()
1612##
1613##
1614##    def onLegendClickedMAnorm(self, key):
1615##        """Change active probe curve
1616##        """
1617##        if D1: print "OWNormalize.onLegendClickedMAnorm"
1618##        qApp.restoreOverrideCursor()
1619##        qApp.setOverrideCursor(QWidget.waitCursor)
1620##        pKey = self.graphMAnorm.curve(key).key
1621##        if pKey <> None:
1622##            self.probes.switchCurveActive(pKey, refresh=True)
1623##        qApp.restoreOverrideCursor()
1624
1625
1626    def onMouseMovedGraphMA(self, e):
1627        """Find closest curve (if close enough), activate corresponding probe, print tooltip.
1628        """
1629        if D1 or D6: print "OWNormalize.onMouseMovedGraphMA"
1630        (curveKey, distPoints, x, y, pointKey) = self.graphMAcurrent.closestCurve(e.x(), e.y())
1631        curve = self.graphMAcurrent.curve(curveKey)
1632        # if we have a curve and the curve has a "key" (member variable specific for our curves)
1633        if curve and curve.__dict__.has_key("key"):
1634            # if we are close enough to the curve
1635            if distPoints<=self.markerSize/2:
1636                # activata probe and/or normalization curve (if not already active)
1637                self.probes.setCurveActiveList([curve.key], refresh=True)
1638                # show tooltip
1639                self.probes.showDataTooltip(curve.key, x, y, self.graphMAcurrent)
1640            else:
1641                # deactivate all curves
1642                self.probes.setCurveActiveList([], refresh=True)
1643
1644
1645    def onMousePressedGraphMA(self, e):
1646        """If left button is pressed, the active control is made current in self.tblControls;
1647        first, OWGraph.onMousePressed(e) is executed (by default), followed by this code.
1648        """
1649        if D1: print "OWNormalize.onMousePressedGraphMA"
1650        actCrvKeys = self.probes.getActiveCurveKeys()
1651        if e.button() == Qt.LeftButton and len(actCrvKeys) > 0:
1652            # clear selections from tblControls (without fireing events)
1653            self.disconnect(self.tblControls , SIGNAL('selectionChanged()'), self.tblControlsSelectionChanged)
1654            self.tblControls.clearSelection(True)
1655            selectedRows = []
1656            for crvKey in actCrvKeys:
1657                probe = self.probes.get(crvKey)
1658                if probe:
1659                    selectedRows.append(probe.tblRowIdx)
1660                    # select appropriate table cells
1661                    sel = QTableSelection()
1662                    sel.init(probe.tblRowIdx,OWNormalize.tcVarA)
1663                    sel.expandTo(probe.tblRowIdx,OWNormalize.tcVarA)
1664                    self.tblControls.addSelection(sel)
1665            # set current cell
1666            selectedRows.sort()
1667            if selectedRows:
1668                self.tblControls.setCurrentCell(selectedRows[0], OWNormalize.tcMarker)
1669            self.connect(self.tblControls , SIGNAL('selectionChanged()'), self.tblControlsSelectionChanged)
1670
1671    ###################################################################################
1672    ## SETTINGS
1673    ###################################################################################
1674
1675    def settingsSubstrBGChange(self):
1676        if D1: print "OWNormalize.settingsSubstrBGChange"
1677        # qApp.restoreOverrideCursor()  #TODO PORTING
1678        # qApp.setOverrideCursor(QWidget.waitCursor)  #TODO PORTING
1679        self.probes.setSubtrBG(self.subtrBG)
1680        self.setInfoProbes()
1681        self.setInfoFilterMaxCV()
1682        self.setInfoFilterMinRatio()
1683        self.setInfoFilterMaxFGInt()
1684        self.setInfoFilterMaxBGInt()
1685        if self.commitOnChange:
1686            self.progressBarInit()
1687            self.sendData()
1688            self.progressBarFinished()
1689        # qApp.restoreOverrideCursor()  #TODO PORTING
1690
1691
1692    def settingsFilterMaxCVChange(self):
1693        """Handles changes of filter settings, which affects graph curves and ouput data.
1694        """
1695        if D1: print "OWNormalize.settingsFiltersChange"
1696        # qApp.restoreOverrideCursor()  #TODO PORTING
1697        # qApp.setOverrideCursor(QWidget.waitCursor)  #TODO PORTING
1698        self.setProbeFilters()
1699        self.setInfoProbes()
1700        self.setInfoFilterMaxCV()
1701        self.updateProbeTableNumAcceptedProbes()
1702        if self.commitOnChange:
1703            self.progressBarInit()
1704            self.sendData()
1705            self.progressBarFinished()
1706        #qApp.restoreOverrideCursor()  #TODO PORTING
1707
1708
1709    def settingsFilterMinIntRatioChange(self):
1710        """Handles changes of filter settings, which affects graph curves and ouput data.
1711        """
1712        if D1: print "OWNormalize.settingsFiltersChange"
1713        # qApp.restoreOverrideCursor()  #TODO PORTING
1714        # qApp.setOverrideCursor(QWidget.waitCursor)  #TODO PORTING
1715        self.setProbeFilters()
1716        self.setInfoProbes()
1717        self.setInfoFilterMinRatio()
1718        self.updateProbeTableNumAcceptedProbes()
1719        if self.commitOnChange:
1720            self.progressBarInit()
1721            self.sendData()
1722            self.progressBarFinished()
1723        # qApp.restoreOverrideCursor()  #TODO PORTING
1724
1725
1726    def settingsFilterMaxFGIntChange(self):
1727        """Handles changes of filter settings, which affects graph curves and ouput data.
1728        """
1729        if D1: print "OWNormalize.settingsFilterMaxFGIntChange"
1730        #qApp.restoreOverrideCursor()  #TODO PORTING
1731        #qApp.setOverrideCursor(QWidget.waitCursor)  #TODO PORTING
1732        self.setProbeFilters()
1733        self.setInfoProbes()
1734        self.setInfoFilterMaxFGInt()
1735        self.updateProbeTableNumAcceptedProbes()
1736        if self.commitOnChange:
1737            self.progressBarInit()
1738            self.sendData()
1739            self.progressBarFinished()
1740        # qApp.restoreOverrideCursor()  #TODO PORTING
1741
1742
1743    def settingsFilterMaxBGIntChange(self):
1744        """Handles changes of filter settings, which affects graph curves and ouput data.
1745        """
1746        if D1: print "OWNormalize.settingsFilterMaxBGIntChange"
1747        # qApp.restoreOverrideCursor()  #TODO PORTING
1748        # qApp.setOverrideCursor(QWidget.waitCursor)  #TODO PORTING
1749        self.setProbeFilters()
1750        self.setInfoProbes()
1751        self.setInfoFilterMaxBGInt()
1752        self.updateProbeTableNumAcceptedProbes()
1753        if self.commitOnChange:
1754            self.progressBarInit()
1755            self.sendData()
1756            self.progressBarFinished()
1757        # qApp.restoreOverrideCursor()  #TODO PORTING
1758
1759
1760    def setProbeFilters(self):     
1761        if D1: print "OWNormalize.setProbeFilters"
1762        if self.useCV:
1763            maxCV = self.maxCV
1764        else:
1765            maxCV = Probes.bigVal
1766        if self.useMinIntensity: 
1767            minIntensityRatio = self.minIntensityRatio
1768        else:
1769            minIntensityRatio = 0
1770        if self.useMaxFGIntensity:
1771            maxFGIntensity = self.maxFGIntensity
1772        else:
1773            maxFGIntensity = Probes.bigVal
1774        if self.useMaxBGIntensity:
1775            maxBGIntensity = self.maxBGIntensity
1776        else:
1777            maxBGIntensity = Probes.bigVal
1778        self.probes.setFilterParameters(maxCV, minIntensityRatio, maxFGIntensity, maxBGIntensity)
1779
1780
1781    def setInfoFilterMaxCV(self):
1782        if D4: print "OWNormalize.setInfoFilterMaxCV"
1783        if self.probes:
1784            if self.probes.getNumProbesCtrlNorm() > 0:
1785                ratioNorm = 100. * self.probes.getNumFilteredProbesCtrlNorm_MaxCV() / self.probes.getNumProbesCtrlNorm()
1786            else:
1787                ratioNorm = 0
1788            if self.probes.getNumProbesCtrlNeg() > 0:
1789                ratioNeg = 100. * self.probes.getNumFilteredProbesCtrlNeg_MaxCV() / self.probes.getNumProbesCtrlNeg()
1790            else:
1791                ratioNeg = 0
1792            if self.probes.getNumProbesOthers() > 0:
1793                ratioOthers = 100. * self.probes.getNumFilteredProbesOther_MaxCV() / self.probes.getNumProbesOthers()
1794            else:
1795                ratioOthers = 0
1796            self.lblInfoFilterMaxCV.setText("Number (percentage) of probes removed:\n%d (%2.2f%s) normalization\n%d (%2.2f%s) negative\n%d (%2.2f%s) other" %
1797                                            (self.probes.getNumFilteredProbesCtrlNorm_MaxCV(), ratioNorm, "%", self.probes.getNumFilteredProbesCtrlNeg_MaxCV(), ratioNeg, "%", self.probes.getNumFilteredProbesOther_MaxCV(), ratioOthers, "%"))
1798        else:
1799            self.lblInfoFilterMaxCV.setText("No data on input.\n")
1800
1801
1802    def setInfoFilterMinRatio(self):
1803        if D4: print "OWNormalize.setInfoFilterMinIntRatio"
1804        if self.probes:
1805            if self.probes.getNumProbesCtrlNorm() > 0:
1806                ratioNorm = 100. * self.probes.getNumFilteredProbesCtrlNorm_MinRatio() / self.probes.getNumProbesCtrlNorm()
1807            else:
1808                ratioNorm = 0
1809            if self.probes.getNumProbesCtrlNeg() > 0:
1810                ratioNeg = 100. * self.probes.getNumFilteredProbesCtrlNeg_MinRatio() / self.probes.getNumProbesCtrlNeg()
1811            else:
1812                ratioNeg = 0
1813            if self.probes.getNumProbesOthers() > 0:
1814                ratioOthers = 100. * self.probes.getNumFilteredProbesOther_MinRatio() / self.probes.getNumProbesOthers()
1815            else:
1816                ratioOthers = 0
1817            self.lblInfoFilterMinIntRatio.setText("Number (percentage) of probes removed:\n%d (%2.2f%s) normalization\n%d (%2.2f%s) negative\n%d (%2.2f%s) other" %
1818                                                  (self.probes.getNumFilteredProbesCtrlNorm_MinRatio(), ratioNorm, "%", self.probes.getNumFilteredProbesCtrlNeg_MinRatio(), ratioNeg, "%", self.probes.getNumFilteredProbesOther_MinRatio(), ratioOthers, "%"))
1819        else:
1820            self.lblInfoFilterMinIntRatio.setText("No data on input.\n")
1821
1822
1823    def setInfoFilterMaxFGInt(self):
1824        if D4: print "OWNormalize.setInfoFilterMaxFGInt"
1825        if self.probes:
1826            if self.probes.getNumProbesCtrlNorm() > 0:
1827                ratioNorm = 100. * self.probes.getNumFilteredProbesCtrlNorm_MaxFGInt() / self.probes.getNumProbesCtrlNorm()
1828            else:
1829                ratioNorm = 0
1830            if self.probes.getNumProbesCtrlNeg() > 0:
1831                ratioNeg = 100. * self.probes.getNumFilteredProbesCtrlNeg_MaxFGInt() / self.probes.getNumProbesCtrlNeg()
1832            else:
1833                ratioNeg = 0
1834            if self.probes.getNumProbesOthers() > 0:
1835                ratioOthers = 100. * self.probes.getNumFilteredProbesOther_MaxFGInt() / self.probes.getNumProbesOthers()
1836            else:
1837                ratioOthers = 0
1838            self.lblInfoFilterMaxFGInt.setText("Number (percentage) of probes removed:\n%d (%2.2f%s) normalization\n%d (%2.2f%s) negative\n%d (%2.2f%s) other" %
1839                                               (self.probes.getNumFilteredProbesCtrlNorm_MaxFGInt(), ratioNorm, "%", self.probes.getNumFilteredProbesCtrlNeg_MaxFGInt(), ratioNeg, "%", self.probes.getNumFilteredProbesOther_MaxFGInt(), ratioOthers, "%"))
1840        else:
1841            self.lblInfoFilterMaxFGInt.setText("No data on input.\n")
1842
1843
1844    def setInfoFilterMaxBGInt(self):
1845        if D4: print "OWNormalize.setInfoFilterMaxBGInt"
1846        if self.probes:
1847            if self.probes.getNumProbesCtrlNorm() > 0:
1848                ratioNorm = 100. * self.probes.getNumFilteredProbesCtrlNorm_MaxBGInt() / self.probes.getNumProbesCtrlNorm()
1849            else:
1850                ratioNorm = 0
1851            if self.probes.getNumProbesCtrlNeg() > 0:
1852                ratioNeg = 100. * self.probes.getNumFilteredProbesCtrlNeg_MaxBGInt() / self.probes.getNumProbesCtrlNeg()
1853            else:
1854                ratioNeg = 0
1855            if self.probes.getNumProbesOthers() > 0:
1856                ratioOthers = 100. * self.probes.getNumFilteredProbesOther_MaxBGInt() / self.probes.getNumProbesOthers()
1857            else:
1858                ratioOthers = 0
1859            self.lblInfoFilterMaxBGInt.setText("Number (percentage) of probes removed:\n%d (%2.2f%s) normalization\n%d (%2.2f%s) negative\n%d (%2.2f%s) other" %
1860                                               (self.probes.getNumFilteredProbesCtrlNorm_MaxBGInt(), ratioNorm, "%", self.probes.getNumFilteredProbesCtrlNeg_MaxBGInt(), ratioNeg, "%", self.probes.getNumFilteredProbesOther_MaxBGInt(), ratioOthers, "%"))
1861        else:
1862            self.lblInfoFilterMaxBGInt.setText("No data on input.\n")
1863
1864
1865    def settingsNormalizationChange(self):
1866        """Handles changes of normalization type, which affects normalization curve and output data.
1867        """
1868        if D1: print "OWNormalize.settingsNormalizationChange"
1869        #qApp.restoreOverrideCursor()  #TODO PORTING
1870        #qApp.setOverrideCursor(QWidget.waitCursor)  #TODO PORTING
1871        self.boxMinNumControlProbes.setEnabled(self.normRange==2)
1872        self.boxLoessWindow.setEnabled(self.approxFunction==OWNormalize.AppxFuncLoess)
1873        self.boxLoessNumIter.setEnabled(self.approxFunction==OWNormalize.AppxFuncLoess)
1874        self.boxSldLoessWeight.setEnabled(self.includeNonControl and self.approxFunction!=OWNormalize.AppxFuncMed)
1875        self.probes.setNormalizationParameters(self.normRange, self.minNumControlProbes, self.approxFunction, self.loessWindow, self.loessNumIter, self.includeNonControl, self.loessWeight)
1876        if self.commitOnChange:
1877            self.progressBarInit()
1878            self.sendData()
1879            self.progressBarFinished()
1880        # qApp.restoreOverrideCursor()  #TODO PORTING
1881
1882
1883    def filtersAllChange(self):
1884        """handles changes caused by Set Default Values button"""
1885        # qApp.restoreOverrideCursor()  #TODO PORTING
1886        # qApp.setOverrideCursor(QWidget.waitCursor)  #TODO PORTING
1887        chngF = False
1888        # subtract background
1889        if self.subtrBG != self._def_subtrBG:
1890            self.subtrBG = self._def_subtrBG
1891            self.probes.setSubtrBG(self.subtrBG)
1892            chngF = True
1893        # CV           
1894        if self.useCV != self._def_useCV:
1895            self.useCV = self._def_useCV
1896            chngF = True
1897        if self.maxCV != self._def_maxCV:
1898            self.maxCV = self._def_maxCV
1899            chngF = True
1900        # min. intensity ratio
1901        if self.useMinIntensity != self._def_useMinIntensity:
1902            self.useMinIntensity = self._def_useMinIntensity
1903            chngF = True
1904        if self.minIntensityRatio != self._def_minIntensityRatio:
1905            self.minIntensityRatio = self._def_minIntensityRatio
1906            chngF = True
1907        # max FG intensity
1908        if self.useMaxFGIntensity != self._def_useMaxFGIntensity:
1909            self.useMaxFGIntensity = self._def_useMaxFGIntensity
1910            chngF = True
1911        if self.maxFGIntensity != self._def_maxFGIntensity:
1912            self.maxFGIntensity = self._def_maxFGIntensity
1913            chngF = True
1914        # max BG intensity
1915        if self.useMaxBGIntensity != self._def_useMaxBGIntensity:
1916            self.useMaxBGIntensity = self._def_useMaxBGIntensity
1917            chngF = True
1918        if self.maxBGIntensity != self._def_maxBGIntensity:
1919            self.maxBGIntensity = self._def_maxBGIntensity
1920            chngF = True
1921        # refresh
1922        if chngF:
1923            self.setProbeFilters()
1924            self.setInfoProbes()
1925            self.setInfoFilterMaxCV()
1926            self.setInfoFilterMinRatio()
1927            self.setInfoFilterMaxFGInt()
1928            self.setInfoFilterMaxBGInt()
1929            if self.commitOnChange:
1930                self.progressBarInit()
1931                self.sendData()
1932                self.progressBarFinished()
1933        #qApp.restoreOverrideCursor()  #TODO PORTING
1934
1935
1936    def normalizationAllChange(self):
1937        """handles changes caused by Set Default Values button"""
1938        #qApp.restoreOverrideCursor()  #TODO PORTING
1939        #qApp.setOverrideCursor(QWidget.waitCursor)  #TODO PORTING
1940        chngN = False
1941        if self.normRange != self._def_normRange:
1942            self.normRange = self._def_normRange
1943            chngN = True
1944        if self.minNumControlProbes != self._def_minNumControlProbes:
1945            self.minNumControlProbes = self._def_minNumControlProbes
1946            chngN = True
1947        if self.approxFunction != self._def_approxFunction:
1948            self.approxFunction = self._def_approxFunction
1949            chngN = True
1950        if self.loessWindow != self._def_loessWindow:
1951            self.loessWindow = self._def_loessWindow
1952            chngN = True
1953        if self.loessNumIter != self._def_loessNumIter:
1954            self.loessNumIter = self._def_loessNumIter
1955            chngN = True
1956        if self.includeNonControl != self._def_includeNonControl:
1957            self.includeNonControl = self._def_includeNonControl
1958            chngN = True
1959        if self.loessWeight != self._def_loessWeight:
1960            self.loessWeight = self._def_loessWeight
1961            chngN = True
1962        # refresh
1963        if chngN:
1964            self.probes.setNormalizationParameters(self.normRange, self.minNumControlProbes, self.approxFunction, self.loessWindow, self.loessNumIter, self.includeNonControl, self.loessWeight)
1965            if self.commitOnChange:
1966                self.progressBarInit()
1967                self.sendData()
1968                self.progressBarFinished()
1969        #qApp.restoreOverrideCursor()  #TODO PORTING
1970
1971
1972    ###################################################################################
1973    ## OUTPUT SETTINGS
1974    ###################################################################################
1975
1976
1977    def settingsOutputReplicasChange(self):
1978        """Handles changes of replicas settings, which affect output data;
1979        enables / disables some output options.
1980        """
1981        if D1: print "OWNormalize.settingsOutputReplicasChange"
1982        #qApp.restoreOverrideCursor() # TODO PORTING
1983        #qApp.setOverrideCursor(QWidget.waitCursor) #TODO PORTING
1984        self.rbgMergeIntensitiesType.setEnabled(self.mergeLevel)
1985        self.boxMergeOtherType.setEnabled(self.mergeLevel and len(self.varsOtherSelected) > 0)
1986        if self.commitOnChange:
1987            self.progressBarInit()
1988            self.sendData()
1989            self.progressBarFinished()
1990        #qApp.restoreOverrideCursor() #TODO PORTING
1991
1992
1993    def settingsOutputOtherChange(self):       
1994        """Handles changes of output settings, which affect output data only if other variables are selected.
1995        """
1996        if D1: print "OWNormalize.settingsOutputChange"
1997        if len(self.varsOtherSelected) > 0:
1998            #qApp.restoreOverrideCursor()  #TODO PORTING
1999            #qApp.setOverrideCursor(QWidget.waitCursor)  #TODO PORTING
2000            if self.commitOnChange:
2001                self.progressBarInit()
2002                self.sendData()
2003                self.progressBarFinished()
2004            #qApp.restoreOverrideCursor()  #TODO PORTING
2005
2006
2007    def settingsOutputChange(self): 
2008        """Handles changes of output settings; send out data.
2009        """
2010        if D1: print "OWNormalize.settingsOutputChange"
2011        #qApp.restoreOverrideCursor()  #TODO PORTING
2012        #qApp.setOverrideCursor(QWidget.waitCursor)  #TODO PORTING
2013        if self.commitOnChange:
2014            self.progressBarInit()
2015            self.sendData()
2016            self.progressBarFinished()
2017        #qApp.restoreOverrideCursor()  #TODO PORTING
2018       
2019    def settingsGraphAxisChange(self, axis):
2020        """Handles changes of graph axis settings; replot axes and curves.
2021        """
2022        if D1: print "OWNormalize.settingsGraphAxisChange"
2023        #qApp.restoreOverrideCursor()  #TODO PORTING
2024        #qApp.setOverrideCursor(QWidget.waitCursor)  #TODO PORTING
2025        self.probes.setPlotParameters(self.logAxisY, self.markerSize, OWNormalize.normCurveStyles[self.normCurveStyleIdx], refresh=True)
2026        self.setGraphAxes([axis])
2027        #qApp.restoreOverrideCursor()  #TODO PORTING
2028
2029
2030    def settingsGraphChange(self):
2031        """Handles changes of graph settings; replot curves.
2032        """
2033        if D1: print "OWNormalize.settingsGraphChange"
2034        #qApp.restoreOverrideCursor()  #TODO PORTING
2035        #qApp.setOverrideCursor(QWidget.waitCursor)  #TODO PORTING
2036        self.probes.setPlotParameters(self.logAxisY, self.markerSize, OWNormalize.normCurveStyles[self.normCurveStyleIdx], refresh=True)
2037        #qApp.restoreOverrideCursor()  #TODO PORTING
2038
2039
2040##    def settingsShowLegendChange(self):
2041##        """Enables/disables legend.
2042##        """
2043##        if D1: print "OWNormalize.settingsShowLegendChange"
2044##        qApp.restoreOverrideCursor()
2045##        qApp.setOverrideCursor(QWidget.waitCursor)
2046##        self.graphMAnonNorm.enableGraphLegend(self.showLegend)
2047##        self.graphMAnorm.enableGraphLegend(self.showLegend)
2048##        qApp.restoreOverrideCursor()
2049
2050
2051    def settingsProbeTrackingChange(self):
2052        if D1: print "OWNormalize.settingsProbeTrackingChange"
2053        signal1 = SIGNAL("plotMouseMoved(const QMouseEvent &)")
2054        signal2 = SIGNAL('plotMousePressed(const QMouseEvent&)')
2055        if self.tracking:
2056            self.connect(self.graphMAnonNorm, signal1, self.onMouseMovedGraphMA)
2057            self.connect(self.graphMAnonNorm, signal2, self.onMousePressedGraphMA)
2058            self.connect(self.graphMAnorm, signal1, self.onMouseMovedGraphMA)
2059            self.connect(self.graphMAnorm, signal2, self.onMousePressedGraphMA)
2060        else:
2061            self.disconnect(self.graphMAnonNorm, signal1, self.onMouseMovedGraphMA)
2062            self.disconnect(self.graphMAnonNorm, signal2, self.onMousePressedGraphMA)
2063            self.disconnect(self.graphMAnorm, signal1, self.onMouseMovedGraphMA)
2064            self.disconnect(self.graphMAnorm, signal2, self.onMousePressedGraphMA)
2065           
2066
2067    def commitChange(self):
2068        self.btnCommit.setEnabled(not self.commitOnChange)
2069        self.probes.recomputeNormCurveOnChange = self.commitOnChange
2070        if self.commitOnChange:
2071            self.commitClicked()
2072
2073
2074    def commitClicked(self):
2075        """Handles Commit click, sends out examples and probes.
2076        """
2077        if D1: print "OWNormalize.commitClicked"
2078        #qApp.restoreOverrideCursor()  #TODO PORTING
2079        #qApp.setOverrideCursor(QWidget.waitCursor)  #TODO PORTING
2080        self.progressBarInit()
2081        self.sendData()
2082##        self.sendProbes()
2083        self.progressBarFinished()
2084        #qApp.restoreOverrideCursor()  #TODO PORTING
2085
2086
2087##    ###################################################################
2088##    ## Recompute normalization curve on change (2008-06-23)
2089##    ###################################################################
2090##
2091##    def settingsRecomputeNormCurveChange(self):
2092##        """handles "Recompute norm. curve on change" checkbox click
2093##        """
2094##        if self.recomputeNormCurveOnChange:
2095##            qApp.restoreOverrideCursor()
2096##            qApp.setOverrideCursor(QWidget.waitCursor)
2097##            self.probes.recomputeNormCurveOnChange = self.recomputeNormCurveOnChange
2098##            self.probes.calcReplotNormCurves()
2099##            qApp.restoreOverrideCursor()
2100##
2101##    def recomputeNormCurveClick(self):
2102##        """handles "Update Norm Curve" click
2103##        """
2104##        qApp.restoreOverrideCursor()
2105##        qApp.setOverrideCursor(QWidget.waitCursor)
2106##        self.probes.calcReplotNormCurves(forceRecompute=True)
2107##        qApp.restoreOverrideCursor()
2108##
2109
2110
2111class QwtPlotKeyCurve(QwtPlotCurve):
2112    """QwtPlotCurve with additional member variable: key.
2113    """
2114
2115    def __init__(self, parent, name, key):
2116        self.key = key
2117        QwtPlotCurve.__init__(self, parent, name)
2118
2119
2120
2121class OWGraphMA(OWGraph):
2122    """OWGraph for MA plot with curves of type QwtPlotKeyCurve;
2123    additionally handles zooming and mouse clicks.
2124    """
2125
2126    def insertCurve(self, title, key, xAxis=QwtPlot.xBottom, yAxis=QwtPlot.yLeft):
2127        curve = QwtPlotKeyCurve(self, title, key)
2128        curve.setAxis(xAxis, yAxis)
2129        print "Curve", title
2130        return OWGraph.insertCurve(self, curve)
2131
2132   
2133    def zoomOut(self):
2134        """Overridden in order to fix for autoscaling when there is no zoom.
2135        """
2136        if len(self.zoomStack):
2137            (xmin, xmax, ymin, ymax) = self.zoomStack.pop()
2138            if len(self.zoomStack):
2139                self.setAxisScale(QwtPlot.xBottom, xmin, xmax)
2140                self.setAxisScale(QwtPlot.yLeft, ymin, ymax)
2141            else:
2142                self.setAxisAutoScale(QwtPlot.xBottom)
2143                self.setAxisAutoScale(QwtPlot.xTop)
2144                self.setAxisAutoScale(QwtPlot.yLeft)
2145                self.setAxisAutoScale(QwtPlot.yRight)
2146            self.replot()
2147            return 1
2148        return 0
2149
2150
2151    def onMousePressed(self, e):
2152        self.mouseCurrentlyPressed = 1
2153        self.mouseCurrentButton = e.button()
2154        self.xpos = e.x()
2155        self.ypos = e.y()
2156
2157        # ####
2158        # ZOOM
2159        if e.button() == Qt.LeftButton and self.state == ZOOMING:
2160            self.tempSelectionCurve = SelectionCurve(self, pen = Qt.DashLine)
2161            self.zoomKey = OWGraph.insertCurve(self, self.tempSelectionCurve)
2162
2163        # ####
2164        # SELECT RECTANGLE
2165        elif e.button() == Qt.LeftButton and self.state == SELECT_RECTANGLE:
2166            self.tempSelectionCurve = SelectionCurve(self)
2167            key = OWGraph.insertCurve(self, self.tempSelectionCurve)
2168            self.selectionCurveKeyList.append(key)
2169
2170        # ####
2171        # SELECT POLYGON
2172        elif e.button() == Qt.LeftButton and self.state == SELECT_POLYGON:
2173            if self.tempSelectionCurve == None:
2174                self.tempSelectionCurve = SelectionCurve(self)
2175                key = OWGraph.insertCurve(self, self.tempSelectionCurve)
2176                self.selectionCurveKeyList.append(key)
2177                self.tempSelectionCurve.addPoint(self.invTransform(QwtPlot.xBottom, self.xpos), self.invTransform(QwtPlot.yLeft, self.ypos))
2178            self.tempSelectionCurve.addPoint(self.invTransform(QwtPlot.xBottom, self.xpos), self.invTransform(QwtPlot.yLeft, self.ypos))
2179
2180            if self.tempSelectionCurve.closed():    # did we intersect an existing line. if yes then close the curve and finish appending lines
2181                self.tempSelectionCurve = None
2182                self.replot()
2183                if self.autoSendSelectionCallback: self.autoSendSelectionCallback() # do we want to send new selection
2184        self.event(e)
2185
2186
2187class NormCurveDataDict(dict):
2188    """Dictionary of NormCurveData objects.
2189    """
2190    class NormCurveData:
2191        """Class for storing data about normalization curve.
2192        """
2193        def __init__(self, key, computInd, adjustInd, probeList):
2194            self._key = key                     # a key for NormCurveDataDict, equal to QwtPlotKeyCurve.key
2195            self.computInd = computInd          # data indices for computing the normalization curve
2196            self.adjustInd = adjustInd              # data indices that get adjusted by this curve and for plotting tick marks - they indicate the probes which get adjusted by this curve
2197            self.probeList = probeList          # list of ProbeSet
2198            self.curveList = []                 # list of long key returned by OWGraphMA.insertCurve, i.e. QwtPlot.insertCurve
2199
2200        def getKey(self):
2201            return self._key
2202
2203        def extendComputInd(self, computInd):
2204            tmpDict = dict(zip(self.computInd, self.computInd))
2205            tmpDict.update(dict(zip(computInd, computInd)))
2206            self.computInd = tmpDict.keys()
2207
2208        def extendAdjustInd(self, adjustInd):
2209            tmpDict = dict(zip(self.adjustInd, self.adjustInd))
2210            tmpDict.update(dict(zip(adjustInd, adjustInd)))
2211            self.adjustInd = tmpDict.keys()
2212
2213        def extendProbeList(self, probeList):
2214            tmpDict = dict(zip(self.probeList, self.probeList))
2215            tmpDict.update(dict(zip(probeList, probeList)))
2216            self.probeList = tmpDict.keys()
2217
2218
2219    def __setitem__(self, key, ncd):
2220        if ncd.__class__.__name__ != "NormCurveData":
2221            raise ValueError, "instance of class NormCurveData expected, got %s" % ncd.__class__.__name__
2222        if ncd.getKey() != key:
2223            raise ValueError, "key (%s) and ncd.key (%s) do not match" % (str(key), str(ncd.getKey()))
2224        dict.__setitem__(self, key, ncd)
2225
2226    def add(self, key, computInd, adjustInd, probeList):
2227        if self.has_key(key):
2228            self.__getitem__(key).extendComputInd(computInd)
2229            self.__getitem__(key).extendAdjustInd(adjustInd)
2230            self.__getitem__(key).extendProbeList(probeList)
2231        else:
2232            self.__setitem__(key, NormCurveDataDict.NormCurveData(key, computInd, adjustInd, probeList))
2233
2234
2235class ProbeSet:
2236    """A set of equivalent probes, their intensities, and their expected ratio, display symbol & color;
2237    curve represents normalization factors where color and symbol is used to plot the curve on the graph.
2238    """
2239    PenWidthActiveProbe = 3
2240    PenWidthActiveCurve = 3
2241    PenWidthInactiveProbe = 1
2242    PenWidthInactiveCurve = 1
2243    PenWidths = {False:PenWidthInactiveCurve,
2244                 True: PenWidthActiveCurve}
2245    NoColor = QColor(0,0,0)
2246   
2247    def __init__(self, valA, valB, pKey):
2248        if D1: print "ProbeSet.__init__"
2249        self.valA = valA            # string
2250        self.valAAlias = valA       # string that is shown in the probe table
2251        self.valB = valB            # string
2252        self.pKey = pKey            # ID / ID+name
2253        # ratio
2254        self.ratioExpr = ""         # string from which ratio is evaluated
2255        # marker
2256        self.color = ProbeSet.NoColor       # QColor
2257        self.symbol = QwtSymbol.NoSymbol        # int (QwtSymbol.Style)
2258        # table, gaph
2259        self.tblRowIdx = None       # row index in OWNormalize.tblControls
2260        self.curveMAnonNorm = None           # curve in OWNormalize.graphMAnonNorm
2261        self.curveMAnorm = None           # curve in OWNormalize.graphMAnorm
2262        # data indices
2263        self._dataIndices = []
2264
2265
2266    ############################################
2267    # DATA
2268    ############################################
2269
2270    def getDataIndices(self):
2271        if D1: print "ProbeSet.getDataIndices"
2272        return self._dataIndices
2273
2274
2275    def addProbeIdx(self, dataIdx):
2276        if D1: print "ProbeSet.addProbeIdx"
2277        self._dataIndices.append(dataIdx)
2278
2279
2280    def getNumProbes(self):
2281        return len(self._dataIndices)
2282
2283
2284    ############################################
2285    # TABLE
2286    ############################################
2287
2288    def generateSymbolPixmap(self, rect):
2289        """Input: QRect instance; output: QPixmap instance.
2290        """
2291        if D1: print "ProbeSet.generateSymbolPixmap"
2292        # init pixmap for table item
2293        symbolPixmap = QPixmap(rect.width(),rect.height())
2294        symbolPixmap.fill(QColor(255,255,255))
2295        if self.symbol != QwtSymbol.NoSymbol:
2296            painter = QPainter(symbolPixmap)
2297            symbol = QwtSymbol(self.symbol, QBrush(self.color, QBrush.SolidPattern), QPen(QColor(0,0,0),1), QSize(8,8))
2298            symbol.draw(painter, QPoint(rect.width()/2,rect.height()/2))
2299            painter.end()
2300        return symbolPixmap
2301
2302
2303    def getColorRgbStr(self):
2304        """returns hexadecimal color string, e.g. "00ff10
2305        """
2306        return string.replace("%2s%2s%2s" % (hex(self.color.red())[2:], hex(self.color.green())[2:], hex(self.color.blue())[2:]), " ", "0")
2307
2308
2309    def getMarkerSortKey(self):
2310        """string for sorting merkers and storing pixmaps to dict
2311        """
2312        ch = self.color.hsv()
2313        return "%02d%03d%03d%03d" % (self.symbol, ch[0], ch[1], ch[2])
2314
2315
2316
2317class Probes(dict):
2318    """Dictionary of ProbeSet items; key: pKey (probe varA + optionally probe varB, item: ProbeSet
2319    WARNING: Normalization curve is always calculated on (log2A,log2ratio) data.
2320    Technical issues:
2321        recalc: recalculate l2r-s
2322        refresh: self.graphMAnonNorm.replot() & self.graphMAnorm.replot()
2323    Careful:
2324        within this class:
2325            - M refers to either ratio or log2ratio (depending on logAxisY)
2326            - log2ratio refers to log2ratio
2327        on the output of this widget M refers to log2ratio
2328    TODO:
2329        - setFilterParameters: divide into three functions, one for each parameter
2330    """
2331
2332    mergeTypes = {0:MA.average, 1:numpyExtn.medianMA}
2333    bigVal = 1e20
2334    midVal = 1e10
2335
2336    NormRangeGlobal = 0
2337    NormRangeLocal = 1
2338    NormRangeCombined = 2
2339
2340    # global normalization curve key
2341    # local norm. curve names equal varB values
2342    NormCurveNameGlobal = "NormCurveNameGlobal"
2343
2344    def __init__(self, graphMAnonNorm, graphMAnorm, subtrBG, logAxisY, markerSize, normCurveStyle):
2345        if D1 or D2 or D6: print "Probes.__init__"
2346        self._active = {}   # currently active probeSet and normalization curves; key & value: curve.key
2347        self.graphMAnonNorm = graphMAnonNorm
2348        self.graphMAnorm = graphMAnorm
2349        # plot parameters
2350        self.subtrBG = subtrBG
2351        self.logAxisY = logAxisY
2352        self.markerSize = markerSize
2353        self.normCurveStyle = normCurveStyle
2354        # var names
2355        self.varNameA = None
2356        self.varNameB = "<none>"
2357        # var A values, var A aliases, var B values
2358        self._valAList = []         # consecutive list of varA values (replicated)
2359        self._valBList = []         # consecutive list of varB values (replicated)
2360        # data: Numeric arrays
2361        self.__sigSmpl = MA.zeros((0,), Numeric.Float)
2362        self.__sigRef = MA.zeros((0,), Numeric.Float)
2363        self.__bgSmpl = MA.zeros((0,), Numeric.Float)
2364        self.__bgRef = MA.zeros((0,), Numeric.Float)
2365        self.__bgSmplSD = MA.zeros((0,), Numeric.Float)
2366        self.__bgRefSD = MA.zeros((0,), Numeric.Float)
2367        # net intensity function dict (indexed by self.subtrBG)
2368        self.__netSmpl_masked_func = {0: lambda cond: self._sigSmpl_masked(cond), 1: lambda cond: self._sigSmpl_masked(cond) - self._bgSmpl_masked(cond)}
2369        self.__netRef_masked_func =  {0: lambda cond: self._sigRef_masked(cond),  1: lambda cond: self._sigRef_masked(cond) -  self._bgRef_masked(cond) }
2370        # weights of data points; MA.masked values denote negative controls
2371        self.__weights = MA.zeros((0,), Numeric.Float)
2372        # ratios; MA.masked values denote non-normalization probes
2373        self.__ratio = None     # MA array with control ratios and masked non-normalization controls
2374        # Numeric array: 0: OK, 1: filtered out
2375        self.__filterMaxCV = None
2376        self.__filterMinRatio = None
2377        self.__filterMaxFGInt = None
2378        self.__filterMaxBGInt = None
2379        self.__plotted = Numeric.zeros((0,), Numeric.Int)
2380        # normalization functions
2381        self._approxFunctionDict = {OWNormalize.AppxFuncMed:   self._getNormCurveMedian,
2382                                    OWNormalize.AppxFuncLR:    self._getNormCurveLinReg,
2383                                    OWNormalize.AppxFuncLoess: self._getNormCurveLoess}
2384        self._approxFunction = self._approxFunctionDict[OWNormalize.AppxFuncLoess]
2385        # normalization curves
2386        self._ncdd = NormCurveDataDict()
2387        # default parameters
2388        self._normRange = None  # 0: NormRangeGlobal, 1: NormRangeLocal (per var B values); 2: NormRangeCombined
2389        self._minNumControlProbes = 0
2390        self.maxCV = Probes.bigVal
2391        self.minIntensityRatio = 0
2392        self.maxFGIntensity = Probes.bigVal
2393        self.maxBGIntensity = Probes.bigVal
2394        self.loessWindow = 60
2395        self.loessNumIter = 3
2396        self.includeNonControl = False
2397        self.loessWeight = 0.01
2398        # for normalization per varB values
2399        self._valB2ind = {}     # {valB1:[indices1], valB2:[indices2]}; key: probe valB; value: list of data indices
2400        self._valB2probes = {}  # {valB1:[probes1],  valB2:[probes2]};  key: probe valB; value: list of ProbeSets
2401        self._valA2ind = {}       # {valA1:[indices1], valA2:[indices2]}; key: probe valA; value: list of data indices
2402        # normalized log2 ratio
2403        self._Mnorm = MA.zeros((0,), Numeric.Float) # ratio or lo2ratio (depending on logAxisY)
2404        # different levels of merging
2405        self._mergeFunc = {OWNormalize.MergeLevelNone:self.__mergeReplicasNone,
2406                           OWNormalize.MergeLevelPerVarsAB:self.__mergeReplicasPerVarsAB,
2407                           OWNormalize.MergeLevelPerVarA:self.__mergeReplicasPerVarA}
2408        self._concatFunc = {OWNormalize.MergeLevelNone:self.__concatReplicasNone,
2409                            OWNormalize.MergeLevelPerVarsAB:self.__concatReplicasPerVarsAB,
2410                            OWNormalize.MergeLevelPerVarA:self.__concatReplicasPerVarA}
2411        # dictionary of marker pixmaps
2412        self.__markerPixmapDict = {}    # key: ProbeSet.getMarkerSortKey(), item: pixmap
2413        # is normalization curve up-to-date?
2414        self.isNormCurveUpToDate = False
2415        self.recomputeNormCurveOnChange = False
2416
2417
2418    def clear(self, refresh=True):
2419        if D1 or D2 or D6: print "Probes.clear"
2420        self._clearNormCurves(False)
2421        self._removeAllProbeCurves(refresh)
2422        self._removeAllProbeCurvesNorm(refresh)
2423        dict.clear(self)
2424        self._active = {}
2425        self._valAList = []
2426        self._valBList = []
2427        self.__sigSmpl = MA.zeros((0,), Numeric.Float)
2428        self.__sigRef = MA.zeros((0,), Numeric.Float)
2429        self.__bgSmpl = MA.zeros((0,), Numeric.Float)
2430        self.__bgRef = MA.zeros((0,), Numeric.Float)
2431        self.__bgSmplSD = MA.zeros((0,), Numeric.Float)
2432        self.__bgRefSD = MA.zeros((0,), Numeric.Float)
2433        # weights of data points
2434        self.__weights = MA.zeros((0,), Numeric.Float)
2435        # ratio
2436        self.__ratio = None
2437        # Numeric array: 0: OK, 1: filtered out
2438        self.__filterMaxCV = None
2439        self.__filterMinRatio = None
2440        self.__filterMaxFGInt = None
2441        self.__filterMaxBGInt = None
2442        self.__plotted = Numeric.zeros((0,), Numeric.Int)
2443        # for normalization per varB values
2444        self._valB2ind = {}
2445        self._valB2probes = {}
2446        self._valA2ind = {}
2447        # normalized log2 ratio
2448        self._Mnorm = MA.zeros((0,), Numeric.Float)
2449        # dictionary of marker pixmaps
2450        self.__markerPixmapDict = {}
2451        # is normalization curve up-to-date?
2452        self.isNormCurveUpToDate = False
2453        self.recomputeNormCurveOnChange = False
2454
2455
2456    def setFilterParameters(self, maxCV, minIntensityRatio, maxFGIntensity, maxBGIntensity):
2457        if D1 or D2 or D6: print "Probes.setFilterParameters"
2458        if maxCV != self.maxCV or minIntensityRatio != self.minIntensityRatio or maxFGIntensity != self.maxFGIntensity or maxBGIntensity != self.maxBGIntensity:
2459            self.maxCV = maxCV                       
2460            self.minIntensityRatio = minIntensityRatio
2461            self.maxFGIntensity = maxFGIntensity
2462            self.maxBGIntensity = maxBGIntensity
2463            self.__filterMaxCV = None
2464            self.__filterMinRatio = None
2465            self.__filterMaxFGInt = None
2466            self.__filterMaxBGInt = None
2467            self.isNormCurveUpToDate = False
2468##            self.calcReplotAllCurves(True) # 1. removes old norm. curves; 2. replots probe curves
2469            self._clearNormCurves(False)
2470            self.replotProbeCurves(True)
2471            self.replotProbeCurvesNorm(True)
2472
2473
2474    def setNormalizationParameters(self, normRange, minNumControlProbes, approxFunction, loessWindow, loessNumIter, includeNonControl, loessWeight):
2475        """approxFunction: 0: median, 1: LR, 2: LOESS
2476        """
2477        if D1 or D2 or D6: print "Probes.setNormalizationParameters"
2478        change = False
2479        if self._minNumControlProbes != minNumControlProbes or normRange != self._normRange:
2480            self._normRange = normRange
2481            self._minNumControlProbes = minNumControlProbes
2482            change = True
2483        if self._approxFunctionDict[approxFunction] != self._approxFunction or loessWindow != self.loessWindow or loessNumIter != self.loessNumIter or includeNonControl != self.includeNonControl or loessWeight != self.loessWeight:
2484            self._normRange = normRange
2485            self._approxFunction = self._approxFunctionDict[approxFunction]
2486            self.loessWindow = loessWindow
2487            self.loessNumIter = loessNumIter
2488            self.includeNonControl = includeNonControl
2489            self.loessWeight = loessWeight
2490            # 2008-06-02: adjust weights
2491            # indirect: numpy.put(self.__weights, numpy.where(numpy.ma.getmaskarray(self.__ratio)<>True), loessWeight)
2492            if self.includeNonControl:
2493                weightToSet = loessWeight
2494            else:
2495                weightToSet = 0
2496            self.__weights = MA.where(self._isProbeOtherArr(), weightToSet, self.__weights)
2497            change = True
2498        if change:
2499            self.isNormCurveUpToDate = False
2500            self._clearNormCurves(True)
2501            self.replotProbeCurvesNorm(True)
2502            # refresh=True is needed in order to avoid error upon moving a mouse over an old curve while self._ncdd is being updated after changing normRange
2503##            self.calcReplotNormCurves(refresh=True) # keep it here to remove old normalization curves
2504##            self.calcReplotAllCurves(True)
2505
2506
2507    def setSubtrBG(self, subtrBG):
2508        if D1 or D2 or D6: print "Probes.setSubtrBG"
2509        if self.subtrBG != subtrBG:
2510            self.subtrBG = subtrBG
2511            self.isNormCurveUpToDate = False
2512            self._clearNormCurves(False)
2513            self.replotProbeCurves(True)
2514            self.replotProbeCurvesNorm(True)
2515##            self.calcReplotAllCurves(True, callback)
2516       
2517
2518    def setPlotParameters(self, logAxisY, markerSize, normCurveStyle, refresh=True):
2519        if D1 or D2 or D6: print "Probes.setPlotParameters"
2520        if self.logAxisY != logAxisY or self.markerSize != markerSize or self.normCurveStyle != normCurveStyle:
2521            self.logAxisY = logAxisY
2522            self.markerSize = markerSize
2523            self.normCurveStyle = normCurveStyle
2524            self.calcReplotAllCurves(refresh)
2525
2526
2527    def initProbes(self, data, varNameA, varNameB, varNameSignalSmpl, varNameSignalRef, varNameBGSmpl, varNameBGRef, varNameBGSmplSD, varNameBGRefSD, callback):
2528        """Input: orange.ExampleTable, orange.Variable.names;
2529        stores self.varNameA and self.varNameB.
2530        """
2531        if D1 or D2 or D6: print "Probes.initProbes"
2532        self.clear(refresh=True)
2533        self.varNameA = varNameA
2534        self.varNameB = varNameB
2535        self.__plotted = Numeric.zeros((len(data),), Numeric.Int)
2536        self.__ratio = MA.ones((len(data),), Numeric.Float) * MA.masked
2537        # 2008-06-02: set weights
2538        self.__weights = MA.zeros((len(data),), Numeric.Float)
2539        # update data and probe data indices
2540        self.updateProbeData(data, varNameSignalSmpl, varNameSignalRef, varNameBGSmpl, varNameBGRef, varNameBGSmplSD, varNameBGRefSD)
2541        # set varPKey and add varNameB (if necessary)
2542        domainNew = orange.Domain(data.domain)
2543        # add var 'pKey(varNameAvarNameB)' with string values from varNameA (+ varNameB)
2544        varPKey = orange.StringVariable("pKey(" + self.varNameA + self.varNameB + ")")
2545        domainNew.addmeta(orange.newmetaid(), varPKey)
2546        if self.varNameB != "<none>":
2547            varPKey.getValueFrom = lambda example, returnWhat: orange.Value(varPKey, str(example[self.varNameA].native()) + str(example[self.varNameB].native()))
2548        else:
2549            varPKey.getValueFrom = lambda example, returnWhat: orange.Value(varPKey, str(example[self.varNameA].native()))
2550            # add varNameB with unknown values
2551            domainNew.addmeta(orange.newmetaid(), orange.StringVariable("<none>"))
2552        data = orange.ExampleTable(domainNew, data)
2553        # create / update ProbeSets, update self._valAList, self._valBList, self._valB2ind, self._valB2probes, self._valA2ind
2554        for eIdx, e in enumerate(data):
2555            pKey = e[varPKey].native()
2556            valA = e[varNameA].native()
2557            valB = e[varNameB].native()
2558            # update self._valAList, self._valBList
2559            self._valAList.append(valA)
2560            self._valBList.append(valB)
2561            # add/update ProbeSet
2562            if dict.has_key(self, pKey):
2563                ps = dict.get(self, pKey)
2564            else:
2565                ps = ProbeSet(valA, valB, pKey)
2566                dict.__setitem__(self, pKey, ps)
2567            ps.addProbeIdx(eIdx)
2568            # store probes/data indices for normalization per valB values
2569            if self._valB2ind.has_key(valB):
2570                self._valB2ind[valB].append(eIdx)
2571                self._valB2probes[valB].append(ps)
2572            else:
2573                self._valB2ind[valB] = [eIdx]
2574                self._valB2probes[valB] = [ps]
2575            if self._valA2ind.has_key(valA):
2576                self._valA2ind[valA].append(eIdx)
2577            else:
2578                self._valA2ind[valA] = [eIdx]
2579            # progressbar callback
2580            if callback: callback()
2581##        self.calcReplotAllCurves(True)
2582       
2583
2584    def updateProbeData(self, data, varNameSignalSmpl, varNameSignalRef, varNameBGSmpl, varNameBGRef, varNameBGSmplSD, varNameBGRefSD):
2585        """Update signal and background of the selected probes, construct new filter.
2586        """
2587        if D1 or D2 or D6: print "Probes.updateProbeData"
2588        if data:
2589            # keep only the variables that you need
2590            domVarList = [data.domain[varNameSignalSmpl], data.domain[varNameSignalRef], data.domain[varNameBGSmpl], data.domain[varNameBGRef]]
2591            if varNameBGSmplSD != "<none>":
2592                domVarList.append(data.domain[varNameBGSmplSD])
2593            if varNameBGRefSD != "<none>":
2594                domVarList.append(data.domain[varNameBGRefSD])
2595            dom = orange.Domain(domVarList, None)
2596            data = orange.ExampleTable(dom, data)
2597            # convert to MA
2598            dataMA = data.toNumpyMA("a")[0]
2599            self.__sigSmpl = dataMA[:,data.domain.index(varNameSignalSmpl)]
2600            self.__sigRef = dataMA[:,data.domain.index(varNameSignalRef)]
2601            self.__bgSmpl = dataMA[:,data.domain.index(varNameBGSmpl)]
2602            self.__bgRef = dataMA[:,data.domain.index(varNameBGRef)]
2603            if varNameBGSmplSD != "<none>":
2604                self.__bgSmplSD = dataMA[:,data.domain.index(varNameBGSmplSD)]
2605            else:
2606                self.__bgSmplSD = None
2607            if varNameBGRefSD != "<none>":
2608                self.__bgRefSD = dataMA[:,data.domain.index(varNameBGRefSD)]
2609            else:
2610                self.__bgRefSD = None
2611            self.__filterMaxCV = None
2612            self.__filterMinRatio = None
2613            self.__filterMaxFGInt = None
2614            self.__filterMaxBGInt = None
2615##            if recalc:
2616            self.isNormCurveUpToDate = False
2617            self._clearNormCurves(False)
2618            self.replotProbeCurves(True)
2619            self.replotProbeCurvesNorm(True)
2620##                self.calcReplotAllCurves(True)
2621
2622    ###########################################################################################################
2623
2624    def getSymbolPixmap(self, probe, rect):
2625        markerSortKey = probe.getMarkerSortKey()
2626        pxm = self.__markerPixmapDict.get(markerSortKey)
2627        if not pxm:
2628            pxm = probe.generateSymbolPixmap(rect)
2629            self.__markerPixmapDict[markerSortKey] = pxm
2630        return pxm
2631
2632
2633
2634    def getKeysFromValAValB(self, valASub, valBSub):
2635        """Return a list of probe keys which contain a given part of valA and valB (optionally);
2636        """
2637        if D1: print "Probes.getKeysFromValAValB"
2638        probesValAValB = {}   # probes where both valA and valB matches
2639        probesValA = {}       # probes where only valA matches
2640        valASub = str(valASub)
2641        valBSub = str(valBSub)
2642        for pKey, probe in self.items():
2643            if valASub and (valASub in str(probe.valA)):
2644                probesValA[pKey] = probe
2645                if valBSub and (valBSub in str(probe.valB)):
2646                    probesValAValB[pKey] = probe
2647        if len(probesValAValB) > 0:
2648            return probesValAValB.keys()
2649        else:
2650            return probesValA.keys()
2651
2652
2653    ############################################
2654    # NUMBER OF PROBES
2655    ############################################
2656
2657    def _isProbeCtrlNormArr(self):
2658        """returns array of len(data) where 1 for normalization controls and 0 for others
2659        """
2660        return Numeric.asarray(Numeric.logical_not(MA.getmaskarray(self.__ratio)), Numeric.Int)
2661
2662    def _isProbeCtrlNegArr(self):
2663        """returns array of len(data) where 1 for negative controls and 0 for others
2664        negative controls are denoted by MA.masked values in self.__weights
2665        """
2666        return Numeric.asarray(MA.getmaskarray(self.__weights), Numeric.Int)
2667
2668    def _isProbeOtherArr(self):
2669        """returns array of len(data) where 0 for normalization and negative controls and 1 for others
2670        """
2671        return Numeric.asarray(MA.logical_and(MA.getmaskarray(self.__ratio), MA.logical_not(MA.getmaskarray(self.__weights))), Numeric.Int)
2672
2673
2674    def getNumReplicas_nonFiltered(self, mergeLevel):
2675        """Returns (..., 2) Numeric array where rows represent different probes and columns:
2676            0: number of all probes
2677            1: number of non-filtered probes
2678        """
2679        na = Numeric.transpose(Numeric.asarray([Numeric.ones(self.getFilter().shape), Numeric.logical_not(self.getFilter())]))
2680        return self._mergeFunc[mergeLevel](na, Numeric.add.reduce)
2681
2682
2683    def getNumFilteredProbesCtrlNorm_MaxCV(self):
2684        if type(self.__filterMaxCV) == types.NoneType:
2685            self._setFilterMaxCV()
2686        return Numeric.add.reduce(Numeric.logical_and(self.__filterMaxCV, self._isProbeCtrlNormArr()))
2687
2688    def getNumFilteredProbesCtrlNeg_MaxCV(self):
2689        if type(self.__filterMaxCV) == types.NoneType:
2690            self._setFilterMaxCV()
2691        return Numeric.add.reduce(Numeric.logical_and(self.__filterMaxCV, self._isProbeCtrlNegArr()))
2692
2693    def getNumFilteredProbesOther_MaxCV(self):
2694        if type(self.__filterMaxCV) == types.NoneType:
2695            self._setFilterMaxCV()
2696        return Numeric.add.reduce(Numeric.logical_and(self.__filterMaxCV, self._isProbeOtherArr()))
2697
2698
2699    def getNumFilteredProbesCtrlNorm_MinRatio(self):
2700        if type(self.__filterMinRatio) == types.NoneType:
2701            self._setFilterMinRatio()
2702        return Numeric.add.reduce(Numeric.logical_and(self.__filterMinRatio, self._isProbeCtrlNormArr()))
2703
2704    def getNumFilteredProbesCtrlNeg_MinRatio(self):
2705        if type(self.__filterMinRatio) == types.NoneType:
2706            self._setFilterMinRatio()
2707        return Numeric.add.reduce(Numeric.logical_and(self.__filterMinRatio, self._isProbeCtrlNegArr()))
2708
2709    def getNumFilteredProbesOther_MinRatio(self):
2710        if type(self.__filterMinRatio) == types.NoneType:
2711            self._setFilterMinRatio()
2712        return Numeric.add.reduce(Numeric.logical_and(self.__filterMinRatio, self._isProbeOtherArr()))
2713
2714
2715    def getNumFilteredProbesCtrlNorm_MaxFGInt(self):
2716        if type(self.__filterMaxFGInt) == types.NoneType:
2717            self._setFilterMaxFGInt()
2718        return Numeric.add.reduce(Numeric.logical_and(self.__filterMaxFGInt, self._isProbeCtrlNormArr()))
2719   
2720    def getNumFilteredProbesCtrlNeg_MaxFGInt(self):
2721        if type(self.__filterMaxFGInt) == types.NoneType:
2722            self._setFilterMaxFGInt()
2723        return Numeric.add.reduce(Numeric.logical_and(self.__filterMaxFGInt, self._isProbeCtrlNegArr()))
2724
2725    def getNumFilteredProbesOther_MaxFGInt(self):
2726        if type(self.__filterMaxFGInt) == types.NoneType:
2727            self._setFilterMaxFGInt()
2728        return Numeric.add.reduce(Numeric.logical_and(self.__filterMaxFGInt, self._isProbeOtherArr()))
2729
2730
2731    def getNumFilteredProbesCtrlNorm_MaxBGInt(self):
2732        if type(self.__filterMaxBGInt) == types.NoneType:
2733            self._setFilterMaxBGInt()
2734        return Numeric.add.reduce(Numeric.logical_and(self.__filterMaxBGInt, self._isProbeCtrlNormArr()))
2735   
2736    def getNumFilteredProbesCtrlNeg_MaxBGInt(self):
2737        if type(self.__filterMaxBGInt) == types.NoneType:
2738            self._setFilterMaxBGInt()
2739        return Numeric.add.reduce(Numeric.logical_and(self.__filterMaxBGInt, self._isProbeCtrlNegArr()))
2740
2741    def getNumFilteredProbesOther_MaxBGInt(self):
2742        if type(self.__filterMaxBGInt) == types.NoneType:
2743            self._setFilterMaxBGInt()
2744        return Numeric.add.reduce(Numeric.logical_and(self.__filterMaxBGInt, self._isProbeOtherArr()))
2745
2746
2747    def getNumProbes(self):
2748        return self.__ratio.shape[0]
2749
2750    def getNumProbesCtrlNorm(self):
2751        return Numeric.add.reduce(Numeric.greater(self._isProbeCtrlNormArr(), 0))
2752
2753    def getNumProbesCtrlNeg(self):
2754        return Numeric.add.reduce(Numeric.greater(self._isProbeCtrlNegArr(), 0))
2755
2756    def getNumProbesOthers(self):
2757        return Numeric.add.reduce(self._isProbeOtherArr())
2758
2759
2760    def getNumProbesCtrlNorm_nonFiltered(self):
2761        return Numeric.add.reduce(Numeric.logical_and(self._isProbeCtrlNormArr(), Numeric.logical_not(self.getFilter())))
2762
2763    def getNumProbesCtrlNeg_nonFiltered(self):
2764        return Numeric.add.reduce(Numeric.logical_and(self._isProbeCtrlNegArr(), Numeric.logical_not(self.getFilter())))
2765
2766    def getNumProbesOthers_nonFiltered(self):
2767        return Numeric.add.reduce(Numeric.logical_and(self._isProbeOtherArr(), Numeric.logical_not(self.getFilter())))
2768
2769
2770    def getNumProbes_nonFiltered(self, probe):
2771        return Numeric.add.reduce(Numeric.take(Numeric.logical_not(self.getFilter()), probe.getDataIndices(), 0))   # added 2008-01-22
2772
2773    def getNumProbes_nonFiltered_plotted(self):
2774        return Numeric.add.reduce(Numeric.logical_and(self.__plotted, Numeric.logical_not(self.getFilter())))
2775
2776
2777    def getNumProbesCtrlNorm_nonFiltered_plotted(self):
2778        return Numeric.add.reduce(Numeric.logical_and(self._isProbeCtrlNormArr(), Numeric.logical_and(self.__plotted, Numeric.logical_not(self.getFilter()))))
2779
2780    def getNumProbesCtrlNeg_nonFiltered_plotted(self):
2781        return Numeric.add.reduce(Numeric.logical_and(self._isProbeCtrlNegArr(), Numeric.logical_and(self.__plotted, Numeric.logical_not(self.getFilter()))))
2782
2783    def getNumProbesOthers_nonFiltered_plotted(self):
2784        return Numeric.add.reduce(Numeric.logical_and(self._isProbeOtherArr(), Numeric.logical_and(self.__plotted, Numeric.logical_not(self.getFilter()))))
2785
2786
2787    def getNumProbesCtrlNorm_indexed(self, indices):
2788        return Numeric.add.reduce(Numeric.logical_and(self._isProbeCtrlNormArr(), numpyExtn.indices2condition(indices, self.__sigSmpl.shape[0])))
2789
2790    def getNumProbesCtrlNeg_indexed(self, indices):
2791        return Numeric.add.reduce(Numeric.logical_and(self._isProbeCtrlNegArr(), numpyExtn.indices2condition(indices, self.__sigSmpl.shape[0])))
2792
2793    def getNumProbesOthers_indexed(self, indices):
2794        return Numeric.add.reduce(Numeric.logical_and(self._isProbeOtherArr(), numpyExtn.indices2condition(indices, self.__sigSmpl.shape[0])))
2795
2796
2797    def getNumProbesCtrlNorm_nonFiltered_indexed(self, indices):
2798        if D6: print "getNumProbesCtrlNorm_nonFiltered_indexed", Numeric.add.reduce(self._isProbeCtrlNormArr()), Numeric.add.reduce(self.getFilter())
2799        return Numeric.add.reduce(Numeric.logical_and(self._isProbeCtrlNormArr(), Numeric.logical_and(numpyExtn.indices2condition(indices, self.__sigSmpl.shape[0]), Numeric.logical_not(self.getFilter()))))
2800
2801    def getNumProbesCtrlNeg_nonFiltered_indexed(self, indices):
2802        return Numeric.add.reduce(Numeric.logical_and(self._isProbeCtrlNegArr(), Numeric.logical_and(numpyExtn.indices2condition(indices, self.__sigSmpl.shape[0]), Numeric.logical_not(self.getFilter()))))
2803
2804    def getNumProbesOthers_nonFiltered_indexed(self, indices):
2805        return Numeric.add.reduce(Numeric.logical_and(self._isProbeOtherArr(), Numeric.logical_and(numpyExtn.indices2condition(indices, self.__sigSmpl.shape[0]), Numeric.logical_not(self.getFilter()))))
2806
2807
2808    ############################################
2809    # MARKER, RATIO & WEIGHT
2810    ############################################
2811
2812    def setMarker(self, probe, symbol, color, refresh=True):
2813        """Set symbol or color to None to remove probe set from the graph;
2814        """
2815        if D1 or D2 or D3: print "Probes.setMarker"
2816        probe.symbol = symbol
2817        probe.color = color
2818        self._replotProbeCurve(probe, refresh)
2819        self._replotProbeCurveNorm(probe, refresh)
2820
2821
2822    def setRatioWeight(self, probe, ratioExpr, recalc, refresh=True):
2823        """Sets self.__ratio, dict[pKey].ratioExpr and self.__weights
2824        ratioExpr should be None in order not to use probeSet as a control.
2825        """
2826        if D1 or D2 or D3: print "Probes.setRatioWeight"
2827        try:
2828            ratio = float(eval(ratioExpr))
2829            if ratio <= 0:
2830                ratio = MA.masked
2831                newRatioExpr = ""
2832            else:
2833                newRatioExpr = ratioExpr
2834        except:
2835            if string.strip(ratioExpr) == "-":
2836                newRatioExpr = "-"
2837            else:
2838                newRatioExpr = ""
2839            ratio = MA.masked
2840        # if self.__ratio different from ratio
2841        if probe.ratioExpr != newRatioExpr:
2842            probe.ratioExpr = newRatioExpr
2843            self.__ratio[probe.getDataIndices()] = ratio
2844            # 2008-06-02: update weights
2845            if newRatioExpr == "":
2846                # other probe
2847                if self.includeNonControl:
2848                    self.__weights[probe.getDataIndices()] = self.loessWeight
2849                else:
2850                    self.__weights[probe.getDataIndices()] = 0
2851            elif newRatioExpr == "-":
2852                # negative probe
2853                self.__weights[probe.getDataIndices()] = MA.masked
2854            else:
2855                # normalization probe
2856                self.__weights[probe.getDataIndices()] = 1
2857            self._replotProbeCurve(probe, refresh and not recalc)
2858            self._replotProbeCurveNorm(probe, refresh and not recalc)
2859            # recalc and replot norm. curves
2860            if recalc:                   
2861                self.calcReplotAllCurves(refresh)
2862        return ratio
2863
2864
2865    def getRatioStr(self, probe):
2866        if D1: print "Probes.getRatioStr"
2867        if len(probe.getDataIndices())>0:
2868            return probe.ratioExpr
2869
2870
2871    def getRatioSortingKey(self, probe):
2872        """Returns a string with leading spaces followed by str(val), whose length is at least len."""
2873        if probe.ratioExpr and len(probe.getDataIndices())>0:
2874            return "%15.7f" % self.__ratio.filled(-1)[probe.getDataIndices()[0]]
2875        else:
2876            return ""
2877
2878
2879    def getActiveCurveKeys(self):
2880        if D1: print "Probes.getActiveCurveKeys"
2881        return self._active.keys()
2882
2883
2884    ############################################
2885    # ALL (PROBE + NORMALIZATION) CURVES
2886    ############################################
2887
2888    def calcReplotAllCurves(self, refresh=True, callback=None):
2889        self.calcReplotNormCurves(refresh=False, callback=callback)
2890        self.replotProbeCurves(refresh=refresh)
2891        self.replotProbeCurvesNorm(refresh=refresh)
2892
2893       
2894    ############################################
2895    # PROBE CURVES
2896    ############################################
2897
2898    def _removeProbeCurve(self, probe, refresh=True):
2899        if D1 or D2 or D3: print "Probes._removeProbeCurve"
2900        if probe and probe.curveMAnonNorm:
2901            Numeric.put(self.__plotted, probe.getDataIndices(), 0)
2902            self.graphMAnonNorm.removeCurve(probe.curveMAnonNorm)
2903            probe.curveMAnonNorm = None
2904        if refresh:
2905            self.graphMAnonNorm.replot()
2906
2907    def _removeProbeCurveNorm(self, probe, refresh=True):
2908        if D1 or D2 or D3: print "Probes._removeProbeCurveNorm"
2909        if probe and probe.curveMAnorm:
2910            self.graphMAnorm.removeCurve(probe.curveMAnorm)
2911            probe.curveMAnorm = None
2912        if refresh:
2913            self.graphMAnorm.replot()
2914
2915
2916    def _removeAllProbeCurves(self, refresh=True):
2917        if D1 or D2 or D6: print "Probes._removeAllProbeCurves"
2918        for probe in self.values():
2919            if probe.curveMAnonNorm:
2920                self.graphMAnonNorm.removeCurve(probe.curveMAnonNorm)
2921                probe.curveMAnonNorm = None
2922        self.__plotted *= 0
2923        if refresh and len(self)>0:
2924            self.graphMAnonNorm.replot()
2925
2926    def _removeAllProbeCurvesNorm(self, refresh=True):
2927        if D1 or D2 or D6: print "Probes._removeAllProbeCurvesNorm"
2928        for probe in self.values():
2929            if probe.curveMAnorm:
2930                self.graphMAnorm.removeCurve(probe.curveMAnorm)
2931                probe.curveMAnorm = None
2932        if refresh and len(self)>0:
2933            self.graphMAnorm.replot()
2934
2935
2936    def _replotProbeCurve(self, probe, refresh=True):
2937        if D1 or D2 or D3: print "Probes._replotProbeCurve"
2938        change = False
2939        if probe.curveMAnonNorm:
2940            self._removeProbeCurve(probe, False)
2941            change = True
2942        if probe.symbol != QwtSymbol.NoSymbol:
2943            probe.curveMAnonNorm = self.graphMAnonNorm.insertCurve(probe.valA, probe.pKey)
2944            Numeric.put(self.__plotted, probe.getDataIndices(), 1)
2945            M,A = self.getMA(probe.pKey, True)
2946            # 2007-10-06 Numeric->numpy: PyQwt supports only Numeric, not numpy, therefore list() is used
2947            self.graphMAnonNorm.setCurveData(probe.curveMAnonNorm, list(A), list(M))
2948            self.graphMAnonNorm.setCurveStyle(probe.curveMAnonNorm, QwtPlotCurve.NoCurve)
2949            self._setProbeCurveSymbol(probe, False)
2950            change = True
2951        if change and refresh:
2952            self.graphMAnonNorm.replot()
2953
2954
2955    def _replotProbeCurveNorm(self, probe, refresh=True):
2956        if D1 or D2 or D3: print "Probes._replotProbeCurveNorm"
2957        change = False
2958        if probe.curveMAnorm:
2959            self._removeProbeCurveNorm(probe, False)
2960            change = True
2961        if probe.symbol != QwtSymbol.NoSymbol:
2962            probe.curveMAnorm = self.graphMAnorm.insertCurve(probe.valA, probe.pKey)
2963            M,A = self.getMA(probe.pKey, True)
2964            # 2007-10-06 Numeric->numpy: PyQwt supports only Numeric, not numpy, therefore list() is used
2965            normM = self.getNormM(probe.pKey, True)
2966            # in second MA graph, plot normM instead of M
2967            self.graphMAnorm.setCurveData(probe.curveMAnorm, list(A), list(normM))             
2968            self.graphMAnorm.setCurveStyle(probe.curveMAnorm, QwtPlotCurve.NoCurve)
2969            self._setProbeCurveSymbolNorm(probe, False)
2970            change = True
2971        if change and refresh:
2972            self.graphMAnorm.replot()
2973
2974
2975    def _setProbeCurveSymbol(self, probe, refresh=True):
2976        """sets graph marker symbol
2977        """
2978        if probe.curveMAnonNorm:
2979            if self._active.has_key(probe.pKey):
2980                pen = QPen(QColor(0,0,0),ProbeSet.PenWidthActiveProbe)
2981            else:
2982                pen = QPen(QColor(0,0,0),ProbeSet.PenWidthInactiveProbe)
2983            qSymbol = QwtSymbol(probe.symbol, QBrush(probe.color, QBrush.SolidPattern), pen, QSize(self.markerSize,self.markerSize))
2984            self.graphMAnonNorm.setCurveSymbol(probe.curveMAnonNorm, qSymbol)
2985            if refresh:
2986                self.graphMAnonNorm.replot()
2987
2988    def _setProbeCurveSymbolNorm(self, probe, refresh=True):
2989        """sets graph marker symbol
2990        """
2991        if probe.curveMAnorm:
2992            if self._active.has_key(probe.pKey):
2993                pen = QPen(QColor(0,0,0),ProbeSet.PenWidthActiveProbe)
2994            else:
2995                pen = QPen(QColor(0,0,0),ProbeSet.PenWidthInactiveProbe)
2996            qSymbol = QwtSymbol(probe.symbol, QBrush(probe.color, QBrush.SolidPattern), pen, QSize(self.markerSize,self.markerSize))
2997            self.graphMAnorm.setCurveSymbol(probe.curveMAnorm, qSymbol)
2998            if refresh:
2999                self.graphMAnorm.replot()
3000
3001
3002    def replotProbeCurves(self, refresh=True):
3003        """iterate all probes, remove their curves (if exist) and replot them (if symbol <> None)
3004        """
3005        if D1 or D2 or D6: print "Probes.replotProbeCurves"
3006        for probe in self.values():
3007            self._replotProbeCurve(probe, False)
3008        if refresh:
3009            self.graphMAnonNorm.replot()
3010
3011
3012    def replotProbeCurvesNorm(self, refresh=True):
3013        """iterate all probes, remove their curves (if exist) and replot them (if symbol <> None)
3014        """
3015        if D1 or D2 or D6: print "Probes.replotProbeCurvesNorm"
3016        if self.isNormCurveUpToDate:
3017            for probe in self.values():
3018                self._replotProbeCurveNorm(probe, False)
3019            if refresh:
3020                self.graphMAnorm.replot()
3021        else:
3022            print "replotProbeCurvesNorm: self._removeAllProbeCurvesNorm(refresh=refresh)"
3023            self._removeAllProbeCurvesNorm(refresh=refresh)
3024
3025
3026    ############################################
3027    # GRAPH: NORM. CURVES; NORMALIZED LOG2 RATIOS
3028    ############################################
3029
3030    def calcReplotNormCurves(self, refresh=True, forceRecompute=False, callback=None):
3031        """updates self._Mnorm and replots norm curves
3032        """
3033        if D1 or D2 or D6: print "Probes.calcReplotNormCurves"
3034        self._clearNormCurves(False)
3035        if self.recomputeNormCurveOnChange or forceRecompute:
3036            self._Mnorm = MA.zeros(self.__sigSmpl.shape, Numeric.Float) * MA.masked
3037            if self.__sigSmpl.any():
3038                condColors = [QColor(0,0,0), QColor(0,0,255), QColor(0,255,0)]
3039                # fill self._ncdd (NormCurveDataDict)
3040                if self._normRange == Probes.NormRangeGlobal:
3041                    self._ncdd.add(Probes.NormCurveNameGlobal, range(len(self.__sigSmpl)), range(len(self.__sigSmpl)), self.values())
3042                elif self._normRange == Probes.NormRangeLocal:
3043                    for valB, ind in self._valB2ind.items():
3044                        self._ncdd.add(valB, ind, ind, self._valB2probes[valB])
3045                elif self._normRange == Probes.NormRangeCombined:
3046                    for valB, ind in self._valB2ind.items():
3047                        if self.getNumProbesCtrlNorm_nonFiltered_indexed(ind) < self._minNumControlProbes:
3048                            self._ncdd.add(Probes.NormCurveNameGlobal, range(len(self.__sigSmpl)), ind, self._valB2probes[valB])
3049                        else:
3050                            self._ncdd.add(valB, ind, ind, self._valB2probes[valB])
3051                else:
3052                    raise ValueError, "Unknown Probes._normRange: %s" % str(self._normRange)
3053                # cycle all norm curve data, normalize and plot norm. curves
3054                for ncKey, ncData in self._ncdd.items():
3055                    Ac, Mc, An_masked, Mn_masked = self.__getNormCurveMasked_Actrl_Mctrl_A_M(ncData.computInd, callback)
3056                    # condition for plotting ticks
3057                    condTicks = numpyExtn.indices2condition(ncData.adjustInd, An_masked.shape[0])
3058                    if len(Ac) <= 0:
3059                        continue
3060                    minAc = min(Ac)
3061                    maxAc = max(Ac)
3062                    # plot norm. curve
3063                    notMask_AnMn = MA.logical_not(MA.getmaskarray(An_masked+Mn_masked))
3064                    # condList: [interpolated part, extrapolated lower part, extrapolated upper part of norm. curve]
3065                    condList =  [MA.logical_and(MA.logical_and(MA.greater_equal(An_masked, minAc), MA.less_equal(An_masked, maxAc)), notMask_AnMn),
3066                                 MA.logical_and(MA.less_equal(An_masked, minAc), notMask_AnMn),
3067                                 MA.logical_and(MA.greater_equal(An_masked, maxAc), notMask_AnMn)]
3068                    # add curveLists to self._ncdd items
3069                    for condIdx, cond in enumerate(condList):
3070                        if MA.add.reduce(MA.asarray(cond, Numeric.Float)) > 1:
3071                            # plot normalization curve
3072                            normCurve = self.graphMAnonNorm.insertCurve("Norm. curve %i: %s" % (condIdx, str(ncKey)), ncKey)
3073                            ncData.curveList.append(normCurve)
3074                            Aplot = Numeric.asarray(MA.compress(cond, An_masked))
3075                            Aargsort = Numeric.argsort(Aplot)
3076                            Mplot = Numeric.asarray(MA.compress(cond, Mn_masked))
3077                            # 2007-10-06 Numeric->numpy: PyQwt supports only Numeric, not numpy, therefore list() is used
3078                            self.graphMAnonNorm.setCurveData(normCurve, list(Numeric.take(Aplot, Aargsort, 0)), list(Numeric.take(Mplot, Aargsort, 0)))    # added 2008-01-22
3079                            pen = QPen(condColors[condIdx],ProbeSet.PenWidthInactiveCurve)
3080                            self.graphMAnonNorm.setCurvePen(normCurve, pen)
3081                            self.graphMAnonNorm.setCurveStyle(normCurve, QwtPlotCurve.Lines)
3082                            if self.normCurveStyle == "fitted":
3083                                self.graphMAnonNorm.setCurveAttribute(QwtPlotCurve.Fitted)
3084
3085                            # plot a normalization curve consisting only of ticks corresponding to the "right" probes
3086                            normCurveTicks = self.graphMAnonNorm.insertCurve("Norm. curve ticks %i: %s" % (condIdx, str(ncKey)), ncKey)
3087                            ncData.curveList.append(normCurveTicks)
3088                            cond_condTicks = MA.logical_and(cond, condTicks)
3089                            Aplot = Numeric.asarray(MA.compress(cond_condTicks, An_masked))
3090                            Aargsort = Numeric.argsort(Aplot)
3091                            Mplot = Numeric.asarray(MA.compress(cond_condTicks, Mn_masked))
3092                            ## 2007-10-06 Numeric->numpy: PyQwt supports only Numeric, not numpy, therefore list() is used
3093                            self.graphMAnonNorm.setCurveData(normCurveTicks, list(Numeric.take(Aplot, Aargsort, 0)), list(Numeric.take(Mplot, Aargsort, 0)))    # added 2008-01-22
3094                            print "Curve data", list(Numeric.take(Aplot, Aargsort, 0)), list(Numeric.take(Mplot, Aargsort, 0))
3095                            pen = QPen(condColors[condIdx],ProbeSet.PenWidthInactiveCurve)
3096                            self.graphMAnonNorm.setCurvePen(normCurveTicks, pen)
3097                            self.graphMAnonNorm.setCurveStyle(normCurveTicks, QwtPlotCurve.NoCurve)
3098                            # add markers: 5x5 circles
3099                            qSymbol = QwtSymbol(1, QBrush(QColor(255,255,255), QBrush.SolidPattern), pen, QSize(5,5))
3100                            self.graphMAnonNorm.setCurveSymbol(normCurveTicks, qSymbol)
3101
3102                    # compute normalized log2 ratio for indices ncData.adjustInd
3103                    Mdata, Adata = self._getMA_masked_indexed(ncData.adjustInd, False)
3104                    if self.logAxisY:
3105                        Mdata -= Mn_masked
3106                    else:
3107                        Mdata /= Mn_masked
3108                    # store self._Mnorm
3109                    self._Mnorm = MA.where(numpyExtn.indices2condition(ncData.adjustInd, self._Mnorm.shape[0]), Mdata, self._Mnorm)
3110            self.isNormCurveUpToDate = True
3111        else:
3112            self.isNormCurveUpToDate = False
3113        if refresh:
3114            self.graphMAnonNorm.replot()
3115        self.replotProbeCurvesNorm(refresh=refresh)
3116
3117
3118    def _clearNormCurves(self, refresh=True):
3119        if D1 or D2 or D6: print "Probes._clearNormCurves"
3120        changed = False
3121        for ncData in self._ncdd.values():
3122            for curve in ncData.curveList:
3123                # remove curve from self._active list
3124                plotCurve = self.graphMAnonNorm.curve(curve)
3125                if self._active.has_key(plotCurve.key):
3126                    self._active.pop(plotCurve.key)
3127                # remove curve from graph
3128                self.graphMAnonNorm.removeCurve(curve)
3129                changed = True
3130            ncData.curveList = []
3131        self._ncdd = NormCurveDataDict()
3132        if refresh and changed:
3133            self.graphMAnonNorm.replot()
3134            self.graphMAnorm.replot()
3135
3136
3137    ############################################
3138    # GRAPH: ACTIVATE PROBE & NORM. CURVES
3139    ############################################
3140
3141    def switchCurveActive(self, curveKey, refresh=True):
3142        if D1 or D3 or D6: print "Probes.switchCurveActive"
3143        self.setCurveActive(curveKey, not(self._active.has_key(curveKey)), refresh)
3144
3145
3146    def setCurveActiveList(self, curveKeyList, refresh=True):
3147        """Deactivetes currently active, activates those from the given list;
3148        curveKeyList : [curveKey1, curveKey2,...] | None
3149        """
3150        if D1 or D3 or D6: print "Probes.setCurveActiveList", curveKeyList
3151        if curveKeyList:
3152            for curveKey in self._active.keys():
3153                if curveKey not in curveKeyList:
3154                    self.setCurveActive(curveKey, False, False)
3155            for curveKey in curveKeyList:
3156                self.setCurveActive(curveKey, True, False)                   
3157        else:
3158            for curveKey in self._active.keys():
3159                self.setCurveActive(curveKey, False, False)
3160        if refresh:
3161            self.graphMAnonNorm.replot()
3162            self.graphMAnorm.replot()
3163
3164
3165    def setCurveActive(self, curveKey, active, refresh=True):
3166        """activate either probeSet or normalization curve
3167        """
3168        if D1 or D3 or D6: print "Probes.setCurveActive"
3169        # if curveKey represents a normalization curve
3170        if self._ncdd.has_key(curveKey):
3171            # activate probe curves that match with the normalization curve
3172            for probe in self._ncdd[curveKey].probeList:
3173                self._setProbeCurveActive(probe, active, False)
3174            # activate the normalization curve
3175            self._setNormCurveActive(curveKey, active, refresh)
3176        # if curveKey represents a ProbeSet
3177        elif self.has_key(curveKey):
3178            # activate corresponding norm. curve (if exists)
3179            if self._ncdd.has_key(curveKey):
3180                self._setNormCurveActive(curveKey, active, False)
3181            elif self._ncdd.has_key(Probes.NormCurveNameGlobal):
3182                self._setNormCurveActive(Probes.NormCurveNameGlobal, active, False)
3183            # activate probe
3184            self._setProbeCurveActive(self[curveKey], active, refresh)
3185        else:
3186            # do not raise error, this can occur on mouseOver when self._ncdd is being updated
3187            print "Warning: unknown curveKey: %s, known %s" % (str(curveKey), str(self._ncdd.keys()))
3188
3189
3190    def _setProbeCurveActive(self, probe, active, refresh=True):
3191        if D1 or D3: print "Probes._setProbeCurveActive"
3192        if probe.curveMAnonNorm is not None and active != self._active.has_key(probe.pKey):
3193            if active:
3194                self._active[probe.pKey] = probe.pKey
3195            else:
3196                self._active.pop(probe.pKey)
3197            self._setProbeCurveSymbol(probe, refresh)
3198            self._setProbeCurveSymbolNorm(probe, refresh)
3199
3200
3201    def _setNormCurveActive(self, curveKey, active, refresh=True):
3202        if D1: print "Probes._setNormCurveActive"
3203        if self._ncdd.has_key(curveKey) and self._ncdd[curveKey].curveList and active != self._active.has_key(curveKey):
3204            for curve in self._ncdd[curveKey].curveList:
3205                pen = self.graphMAnonNorm.curve(curve).pen() # curve is actually a long curve key
3206                pen.setWidth(ProbeSet.PenWidths[active])
3207                self.graphMAnonNorm.setCurvePen(curve, pen)
3208                symbol = self.graphMAnonNorm.curveSymbol(curve)
3209                symbol.setPen(pen)
3210                self.graphMAnonNorm.setCurveSymbol(curve, symbol)
3211            if active:
3212                self._active[curveKey] = curveKey
3213            else:
3214                self._active.pop(curveKey)
3215            if refresh and len(self._ncdd[curveKey].curveList) > 0:
3216                self.graphMAnonNorm.replot()
3217                self.graphMAnorm.replot()
3218               
3219
3220    ############################################
3221    # FILTER
3222    ############################################
3223
3224    def getFilter(self):
3225        if D1: print "Probes.getFilter"
3226        if type(self.__filterMaxCV) == types.NoneType:
3227            self._setFilterMaxCV()
3228        if type(self.__filterMinRatio) == types.NoneType:
3229            self._setFilterMinRatio()
3230        if type(self.__filterMaxFGInt) == types.NoneType:
3231            self._setFilterMaxFGInt()
3232        if type(self.__filterMaxBGInt) == types.NoneType:
3233            self._setFilterMaxBGInt()
3234        return Numeric.logical_or(Numeric.logical_or(Numeric.logical_or(self.__filterMaxCV, self.__filterMinRatio), self.__filterMaxFGInt), self.__filterMaxBGInt)
3235
3236
3237    def _setFilterMaxCV(self):
3238        if D1 or D2 or D4: print "Probes._setFilterMaxCV"
3239        if self.__sigSmpl.any():
3240            # maxCV: bgSD / sig <= self.maxCV
3241            if self.__bgSmplSD is not None and self.__bgRefSD is not None:
3242                self.__filterMaxCV = MA.asarray(self.__bgSmplSD / self.__sigSmpl).filled(Probes.midVal) > self.maxCV
3243                self.__filterMaxCV += MA.asarray(self.__bgRefSD / self.__sigRef).filled(Probes.midVal) > self.maxCV
3244                # convert to 0/1
3245                self.__filterMaxCV = self.__filterMaxCV > 0
3246            else:
3247                self.__filterMaxCV = Numeric.zeros(self.__sigSmpl.shape, Numeric.Int)
3248
3249    def _setFilterMinRatio(self):
3250        if D1 or D2 or D4: print "Probes._setFilterMinRatio"
3251        if self.__sigSmpl.any():
3252            # minIntRatio: sig / bg >= self.max
3253            self.__filterMinRatio = MA.asarray(self.__sigSmpl < self.minIntensityRatio * self.__bgSmpl).filled(1)
3254            self.__filterMinRatio += MA.asarray(self.__sigRef < self.minIntensityRatio * self.__bgRef).filled(1)
3255            # convert to 0/1
3256            self.__filterMinRatio = self.__filterMinRatio > 0
3257
3258    def _setFilterMaxFGInt(self):
3259        if D1 or D2 or D4: print "Probes._setFilterMaxFGInt"
3260        if self.__sigSmpl.any():
3261            # maxFGIntensity: sig <= maxFGIntensity
3262            self.__filterMaxFGInt = MA.asarray(self.__sigSmpl > self.maxFGIntensity).filled(1)
3263            self.__filterMaxFGInt += MA.asarray(self.__sigRef > self.maxFGIntensity).filled(1)
3264            # convert to 0/1
3265            self.__filterMaxFGInt = self.__filterMaxFGInt > 0
3266
3267    def _setFilterMaxBGInt(self):
3268        if D1 or D2 or D4: print "Probes._setFilterMaxBGInt"
3269        if self.__bgSmpl.any():
3270            # maxBGIntensity: bg <= maxBGIntensity
3271            self.__filterMaxBGInt = MA.asarray(self.__bgSmpl > self.maxBGIntensity).filled(1)
3272            self.__filterMaxBGInt += MA.asarray(self.__bgRef > self.maxBGIntensity).filled(1)
3273            # convert to 0/1
3274            self.__filterMaxBGInt = self.__filterMaxBGInt > 0
3275
3276
3277    ##############################################
3278    # DATA (accounts for filters)
3279    # _get..._masked(): returns MA array
3280    # _get...(): returns compressed Numeric array
3281    ##############################################
3282
3283    def _sigSmpl_masked(self, condition):
3284        return MA.masked_where(Numeric.logical_or(Numeric.logical_not(condition), self.getFilter()), self.__sigSmpl)
3285
3286    def _sigRef_masked(self, condition):
3287        return MA.masked_where(Numeric.logical_or(Numeric.logical_not(condition), self.getFilter()), self.__sigRef)
3288
3289    def _bgSmpl_masked(self, condition):
3290        return MA.masked_where(Numeric.logical_or(Numeric.logical_not(condition), self.getFilter()), self.__bgSmpl)
3291
3292    def _bgRef_masked(self, condition):
3293        return MA.masked_where(Numeric.logical_or(Numeric.logical_not(condition), self.getFilter()), self.__bgRef)
3294
3295    def _ratio_masked(self, condition):
3296        return MA.masked_where(Numeric.logical_or(Numeric.logical_not(condition), self.getFilter()), self.__ratio.filled(1))
3297
3298    def _weights_masked(self, condition):   
3299        #2008-06-02
3300        return MA.masked_where(Numeric.logical_or(Numeric.logical_not(condition), self.getFilter()), self.__weights)
3301
3302
3303    def _netSmpl_masked(self, condition):
3304        return self.__netSmpl_masked_func[self.subtrBG](condition)
3305   
3306    def _netRef_masked(self, condition):
3307        return self.__netRef_masked_func[self.subtrBG](condition)
3308   
3309
3310    def _sigSmpl(self, condition):
3311        return Numeric.asarray(self._sigSmpl_masked(condition).compressed())
3312
3313    def _sigRef(self, condition):
3314        return Numeric.asarray(self._sigRef_masked(condition).compressed())
3315
3316    def _bgSmpl(self, condition):
3317        return Numeric.asarray(self._bgSmpl_masked(condition).compressed())
3318
3319    def _bgRef(self, condition):
3320        return Numeric.asarray(self._bgRef_masked(condition).compressed())
3321
3322    def _ratio(self, condition):
3323        return Numeric.asarray(self._ratio_masked(condition).compressed())
3324
3325
3326    def sigSmpl(self, pKey):
3327        cond = numpyExtn.indices2condition(dict.__getitem__(self, pKey).getDataIndices(), self.__sigSmpl.shape[0])
3328        return self._sigSmpl(cond)
3329
3330    def sigRef(self, pKey):
3331        cond = numpyExtn.indices2condition(dict.__getitem__(self, pKey).getDataIndices(), self.__sigRef.shape[0])
3332        return self._sigRef(cond)
3333
3334    def bgSmpl(self, pKey):
3335        cond = numpyExtn.indices2condition(dict.__getitem__(self, pKey).getDataIndices(), self.__bgSmpl.shape[0])
3336        return self._bgSmpl(cond)
3337
3338    def bgRef(self, pKey):
3339        cond = numpyExtn.indices2condition(dict.__getitem__(self, pKey).getDataIndices(), self.__bgRef.shape[0])
3340        return self._bgRef(cond)
3341
3342    def ratio(self, pKey):
3343        cond = numpyExtn.indices2condition(dict.__getitem__(self, pKey).getDataIndices(), self.__ratio.shape[0])
3344        return self._ratio(cond)
3345
3346
3347    def __compM_masked(self, netSmpl, netRef, ratios):
3348        M = netSmpl / netRef / ratios
3349        if self.logAxisY:
3350            M = MA.log(M) / math.log(2)
3351        return M
3352
3353    def __compA_masked(self, netSmpl, netRef):
3354        return MA.log(MA.sqrt(netSmpl*netRef)) / math.log(2)
3355
3356    def _getA_masked(self, condition):
3357        netSmpl = self._netSmpl_masked(condition)
3358        netRef = self._netRef_masked(condition)
3359        return self.__compA_masked(netSmpl, netRef)
3360
3361
3362    def _getMA_masked(self, condition, center):
3363        """Returns MA arrays: M/ratio, A (masked by filter and condition);
3364        if center: center M by ratios.
3365        """
3366        if D1 or D2: print "Probes._getMA_masked"
3367        netSmpl = self._netSmpl_masked(condition)
3368        netRef = self._netRef_masked(condition)
3369        if center:
3370            ratios = self._ratio_masked(condition)
3371        else:
3372            ratios = Numeric.ones(condition.shape)
3373        return self.__compM_masked(netSmpl, netRef, ratios), self.__compA_masked(netSmpl, netRef)
3374
3375    def _getMA_masked_indexed(self, indices, center):
3376        return self._getMA_masked(numpyExtn.indices2condition(indices, self.__sigSmpl.shape[0]), center)
3377
3378    def _getMA_compressed(self, condition, center):
3379        """Returns Numeric arrays: M/ratio and A (compressed by filter, mask and condition).
3380        added 2008-06-20 for plotting MA plot (includes negative controls for which __weight==MA.masked and ratio==1)
3381        """
3382        M,A = self._getMA_masked(condition, center)
3383        noMask = Numeric.logical_not(Numeric.logical_or(MA.getmaskarray(A), MA.getmaskarray(M)))
3384        return Numeric.asarray(MA.compress(noMask, M)), Numeric.asarray(MA.compress(noMask, A))
3385
3386    def _getMAW_compressed(self, condition, center):
3387        """Returns Numeric arrays: M/ratio, A, weights (all compressed by filter, mask and condition).
3388        used for calculation of normalization curve; negative controls (__weight==MA.masked) are discarded
3389        """
3390        M,A = self._getMA_masked(condition, center)
3391        W = self._weights_masked(condition)
3392        noMask = Numeric.logical_not(Numeric.logical_or(MA.getmaskarray(A), Numeric.logical_or(MA.getmaskarray(M), MA.getmaskarray(W))))
3393        return Numeric.asarray(MA.compress(noMask, M)), Numeric.asarray(MA.compress(noMask, A)), Numeric.asarray(MA.compress(noMask, W))
3394
3395    def getMA(self, pKey, center):
3396        """Returns Numeric arrays: M/ratio, A (compressed by filter, condition and mask)
3397        """
3398        if D1 or D2: print "Probes.getMA"
3399        cond = numpyExtn.indices2condition(dict.__getitem__(self, pKey).getDataIndices(), self.__sigSmpl.shape[0])
3400        return self._getMA_compressed(cond, center)
3401
3402
3403    def getNormM(self, pKey, center):
3404        """Returns Numeric arrays: normalized M/ratio (compressed by filter, condition and mask);
3405        added for plotting of normalized MA graph.
3406        """
3407        if D1 or D2: print "Probes.getNormM"
3408        if MA.allequal(self._Mnorm, 0):
3409            return Numeric.asarray([])
3410       
3411        condition = numpyExtn.indices2condition(dict.__getitem__(self, pKey).getDataIndices(), self.__sigSmpl.shape[0])
3412        if self.logAxisY:
3413            normMcenteredAll = self._Mnorm - MA.log(self.__ratio.filled(1))/math.log(2)
3414        else:
3415            normMcenteredAll = self._Mnorm / self.__ratio.filled(1)
3416        normM = MA.masked_where(Numeric.logical_or(Numeric.logical_not(condition), self.getFilter()), normMcenteredAll)
3417        noMask = Numeric.logical_not(MA.getmaskarray(normM))
3418        return Numeric.asarray(MA.compress(noMask, normM))
3419
3420
3421    ############################################
3422    # TOOLTIP
3423    ############################################
3424
3425    def showDataTooltip(self, curveKey, x, y, graphMA):
3426        if D1: print "Probes.showDataTooltip"
3427        if D4: print "# self.__plotted and self.getFilter(): ", Numeric.add.reduce(self.__plotted == self.getFilter())
3428        out = ""
3429        # curve represents a probeSet, curveKey corresponds to probe.pKey
3430        if self.has_key(curveKey):
3431            probe = self.get(curveKey)
3432            out = "%s (%s)" % (str(probe.valA), str(probe.valAAlias))
3433            if self.varNameB != "<none>":
3434                out += ", " + str(probe.valB)
3435            out += "\nSmpl (signal - bg = net) / Ref (signal - bg = net)\n"
3436            for ss,sr,bs,br in zip(self.sigSmpl(curveKey), self.sigRef(curveKey), self.bgSmpl(curveKey), self.bgRef(curveKey)):
3437                out += "%5.f - %5.f = %5.f  /  %5.f - %5.f = %5.f\n" % (ss,bs,ss-bs, sr,br,sr-br)
3438        # curve represents one of the normalization curves, curveKey corresponds to curve.key
3439        elif self._ncdd.has_key(curveKey):
3440            indices = self._ncdd[curveKey].adjustInd
3441            out = "%s: %s\nProbes in total:\t%d norm,\t%d neg,\t%d other.\nAccepted:\t%d norm,\t%d neg,\t%d other.\nAdjusted:\t%d norm,\t%d neg,\t%d other." % \
3442                  (self.varNameB, curveKey,
3443                   self.getNumProbesCtrlNorm_indexed(self._ncdd[curveKey].computInd), self.getNumProbesCtrlNeg_indexed(self._ncdd[curveKey].computInd), self.getNumProbesOthers_indexed(self._ncdd[curveKey].computInd),
3444                   self.getNumProbesCtrlNorm_nonFiltered_indexed(self._ncdd[curveKey].computInd), self.getNumProbesCtrlNeg_nonFiltered_indexed(self._ncdd[curveKey].computInd), self.getNumProbesOthers_nonFiltered_indexed(self._ncdd[curveKey].computInd),
3445                   self.getNumProbesCtrlNorm_nonFiltered_indexed(self._ncdd[curveKey].adjustInd), self.getNumProbesCtrlNeg_nonFiltered_indexed(self._ncdd[curveKey].adjustInd), self.getNumProbesOthers_nonFiltered_indexed(self._ncdd[curveKey].adjustInd))
3446        else:
3447            raise ValueError, "Unknown curveKey: %s" % str(curveKey)
3448        if out:
3449            out = out[:-1]
3450            xPoints = graphMA.transform(QwtPlot.xBottom, x)
3451            yPoints = graphMA.transform(QwtPlot.yLeft, y)
3452            rect = QRect(xPoints+graphMA.canvas().frameGeometry().x()-self.markerSize/2, yPoints+graphMA.canvas().frameGeometry().y()-self.markerSize/2, self.markerSize, self.markerSize)
3453            MyQToolTip.setRect(graphMA.tooltip, rect, out)
3454
3455
3456    ############################################
3457    # NORMALIZED DATA for plotting curves
3458    ############################################
3459
3460    def __getNormCurveMasked_Actrl_Mctrl_A_M(self, computInd, callback):
3461        """calculates normalization curve from A & L2R data for given computational indices (computInd) containing both controls and data points;
3462        WARNING: normalization curve is always fitted to log2ratio and log2Average data (independently of self.logAxisY parameter) !!!
3463        returns compressed A,M values of normalization controls and A,M of normalization curve calculated in the given computation indices (computInd);
3464        returns (Ac,Mc, An_msk, Mn_msk) where:
3465            - Ac, Mc: (compressed) values of normalization controls
3466            - An_msk, Mn_msk: (masked) values of normalization curve calculated in data indices computInd;
3467        """
3468        if  D6: print "Probes.__getNormCurveMasked_Actrl_Mctrl_A_M"
3469        condName = numpyExtn.indices2condition(computInd, self.__sigSmpl.shape[0])
3470        # 2008-06-02: Ac & Mc comprise of all data points given by computInd
3471        if self.includeNonControl:
3472            condControlName = condName
3473        else:
3474            condControlName = Numeric.logical_and(self._isProbeCtrlNormArr(), condName)
3475        Mc,Ac,Wc = self._getMAW_compressed(condControlName, True)
3476        if self.logAxisY:
3477            L2Rc = Mc
3478        else:
3479            L2Rc = Numeric.log(Mc) / math.log(2)
3480        A = self._getA_masked(condName)
3481        M = MA.zeros(A.shape, Numeric.Float) * MA.masked
3482        # calc normalization curve on l2r data
3483        # proceed if we have at least one control probe (we account for _minNumControlProbes in _getNormCurveName2Ind())
3484        if L2Rc.shape[0] >= 1:
3485            L2RnormCurve = self._approxFunction(A.compressed(), L2Rc, Ac, Wc, callback)
3486            if L2RnormCurve is not None:
3487                if self.logAxisY:
3488                    MnormCurve = L2RnormCurve
3489                else:
3490                    MnormCurve = Numeric.power(2.0, L2RnormCurve)
3491                MA.put(M, numpyExtn.condition2indices(Numeric.logical_not(MA.getmaskarray(A))), MnormCurve)
3492        return  Ac, Mc, A, M
3493
3494
3495    def _getNormCurveLoess(self, A, L2Rc, Ac, weights, callback):
3496        return numpyExtn.lowessW(Ac, L2Rc, A, f=self.loessWindow/100., iter=self.loessNumIter, dWeights=weights, callback=callback)
3497
3498
3499    def _getNormCurveLinReg(self, A, L2Rc, Ac, weights, callback):
3500        # 2008-06-17
3501        # see http://en.wikipedia.org/wiki/Weighted_least_squares#weighted_least_squares
3502        # XT.W.X.b=XT.W.y === wXT.wX.b=wXT.wy
3503        # where w = sqrt(W)
3504        w = Numeric.diag(Numeric.sqrt(Numeric.asarray(weights)))            # 2008-06-17
3505        if callback: callback()
3506        wy = Numeric.dot(w, Numeric.asarray(L2Rc))                          # 2008-06-17
3507        if callback: callback()
3508        wX = Numeric.reshape(Numeric.asarray(Ac), (len(Ac),1))
3509        if callback: callback()
3510        wX = Numeric.concatenate((Numeric.ones((wX.shape[0],1), Numeric.Float), wX), 1)
3511        if callback: callback()
3512        wX = Numeric.dot(w,wX)                                              # 2008-06-17
3513        if callback: callback()
3514        wXT = Numeric.transpose(wX)
3515        if callback: callback()
3516        try:
3517            wXTwXinv = LinearAlgebra.inverse(Numeric.dot(wXT,wX))
3518        except LinearAlgebra.LinAlgError:
3519            print "Warning: singular matrix, using generalized_inverse"
3520            wXTwX = Numeric.dot(wXT,wX)   # store the singuar matrix
3521            wXTwXinv = LinearAlgebra.generalized_inverse(wXTwX)
3522        if callback: callback()
3523        b = Numeric.dot(Numeric.dot(wXTwXinv, wXT), wy)
3524        if callback: callback()
3525        return b[0] + b[1]*A
3526
3527
3528    def _getNormCurveMedian(self, A, L2Rc, Ac, weights, callback):
3529        if D4 or D5: print "Probes._getNormCurveMedian, value:", numpyExtn.median(L2Rc)
3530        if callback: callback()
3531        return Numeric.resize(numpyExtn.median(L2Rc), A.shape)
3532       
3533
3534    #################################################
3535    # MERGE REPLICAS, CONCATENATE LISTS OF STRINGS
3536    #################################################
3537
3538    def __mergeReplicasNone(self, ma, mergeFunction, callback):
3539        return ma
3540
3541    def __concatReplicasNone(self, lst, removeDupl):
3542        return lst
3543
3544
3545    def __mergeReplicasPerVarsAB(self, ma, mergeFunction):
3546        """merge by pKey (varA and varB)
3547        """
3548        if D1: print "Probes.__mergeReplicasPerVarsAB"
3549        shp = list(ma.shape)
3550        shp[0] = len(self.values())
3551        maMerged = MA.zeros(shp, ma.dtype.char)
3552        try:
3553            for idx, probe in enumerate(self.values()):
3554                maMerged[idx] = mergeFunction(ma.take(probe.getDataIndices(), 0))    # FIXED 2008-01-22
3555        except:
3556                print "ma.take(probe.getDataIndices(), 0)"
3557                print ma.take(probe.getDataIndices(), 0)
3558                print mergeFunction
3559                raise mergeFunction(ma.take(probe.getDataIndices(), 0))
3560        return maMerged
3561
3562    def __concatReplicasPerVarsAB(self, lst, removeDupl):
3563        """concatenate list of strings by pKey (var A and var B)
3564        """
3565        if D1: print "Probes.__concatReplicasPerVarsAB"
3566        lstMerged = [""]*len(self.values())
3567        for idx, probe in enumerate(self.values()):
3568            # remove duplicates, sort, merge as CSV
3569            subLst = Numeric.take(Numeric.asarray(lst, Numeric.PyObject), probe.getDataIndices(), 0).tolist()   # added 2008-01-22
3570            if removeDupl:
3571                subLst = dict(zip(subLst,subLst)).keys()
3572            subLst.sort()
3573            lstMerged[idx] = reduce(lambda a,b: "%s, %s" % (a,b), subLst, "")[2:]
3574        return lstMerged
3575
3576
3577    def __mergeReplicasPerVarA(self, ma, mergeFunction):
3578        """merge by var A
3579        """
3580        if D1: print "Probes.__mergeReplicasPerVarA"
3581        shp = list(ma.shape)
3582        shp[0] = len(self._valA2ind)
3583        maMerged = MA.zeros(shp, ma.dtype.char)
3584        for idx, dataInd in enumerate(self._valA2ind.values()):
3585            maMerged[idx] = mergeFunction(ma.take(dataInd, 0))          # FIXED 2008-01-22
3586        return maMerged
3587
3588    def __concatReplicasPerVarA(self, lst, removeDupl):
3589        """concatenate list of strings by var A
3590        """
3591        if D1: print "Probes.__concatReplicasPerVarA"
3592        lstMerged = [""]*len(self._valA2ind)
3593        for idx, dataInd in enumerate(self._valA2ind.values()):
3594            # remove duplicates, sort, merge as CSV
3595            subLst = Numeric.take(Numeric.asarray(lst, Numeric.PyObject), dataInd, 0).tolist()   # added 2008-01-22
3596            if removeDupl:
3597                subLst = dict(zip(subLst,subLst)).keys()
3598            subLst.sort()
3599            lstMerged[idx] = reduce(lambda a,b: "%s, %s" % (a,b), subLst, "")[2:]
3600        return lstMerged
3601
3602
3603    ############################################
3604    # NORMALIZED DATA for output
3605    ############################################   
3606
3607    def getLog2Ratio_norm_masked(self, mergeLevel, mergeType, center):
3608        """Returns masked array of normalized log2ratio of individual probes;
3609        accounts for filters, but NOT for ratios;
3610        mergeType: 0:None, 1:mean, 2:median
3611        """
3612        if D6: print "Probes.getLog2Ratio_norm_masked"
3613        if self.logAxisY:
3614            l2rNorm = self._Mnorm
3615        else:
3616            l2rNorm = MA.log(self._Mnorm) / math.log(2)
3617        if center:
3618            l2rNorm = l2rNorm - MA.log(self.__ratio.filled(1))/math.log(2)
3619        return self._mergeFunc[mergeLevel](l2rNorm, Probes.mergeTypes[mergeType])
3620
3621
3622    def getNetIntensity_smpl_ref(self, mergeLevel, mergeType):
3623        """For output, return MA array (#probes, 2) where columns correspond to sample & reference signals.
3624        """
3625        if D6: print "Probes.getNetIntensity_smpl_ref"
3626        netS = self._netSmpl_masked(1)
3627        netR = self._netRef_masked(1)
3628        iSR = MA.concatenate([MA.reshape(netS, (netS.shape[0], 1)), MA.reshape(netR, (netR.shape[0], 1))], 1)
3629        # merge and return
3630        return self._mergeFunc[mergeLevel](iSR, Probes.mergeTypes[mergeType])
3631   
3632
3633    def getLog2Ratio_raw_masked(self, mergeLevel, mergeType, center):
3634        """returns non-normalized log2 ratio, accounts for filters
3635        """
3636        if D6: print "Probes.getLog2Ratio_raw_masked"
3637        if center:
3638            l2r = MA.log(self._netSmpl_masked(1) / self._netRef_masked(1) / self._ratio_masked(1)) / math.log(2)
3639        else:
3640            l2r = MA.log(self._netSmpl_masked(1) / self._netRef_masked(1)) / math.log(2)
3641        # merge and return
3642        return self._mergeFunc[mergeLevel](l2r, Probes.mergeTypes[mergeType])
3643
3644
3645    def getA_masked(self, mergeLevel, mergeType):
3646        """returns log2 average (net) intensity, accounts for filters
3647        """
3648        if D6: print "Probes.getA_masked"
3649        A = MA.log(MA.sqrt(self._netSmpl_masked(1)*self._netRef_masked(1))) / math.log(2)
3650        # merge and return
3651        return self._mergeFunc[mergeLevel](A, Probes.mergeTypes[mergeType])
3652
3653
3654    def getControlRatios(self, mergeLevel, mergeType):
3655        """returns ratios of controls, DK for others; does not account for filters
3656        """
3657        return self._mergeFunc[mergeLevel](self.__ratio, Probes.mergeTypes[mergeType])
3658##        """returns ratios of controls, DK for others; does not account for filters
3659##        2008-06-23: negative controls get ratio -1
3660##        """
3661##        return self._mergeFunc[mergeLevel](MA.where(MA.getmaskarray(self.__weights), -1, self.__ratio), Probes.mergeTypes[mergeType], callback)
3662       
3663    def getControlWeights(self, mergeLevel, mergeType):
3664        """returns weights of normalization controls, DK for negative controls; does not account for filters (2008-06-23)
3665        """
3666        return self._mergeFunc[mergeLevel](self.__weights, Probes.mergeTypes[mergeType])
3667
3668
3669    ############################################
3670    # valsA, valsB
3671    ############################################
3672
3673    def getValsA(self, mergeLevel):
3674        if D1: print "Probes.getValsA"
3675        if mergeLevel == OWNormalize.MergeLevelNone:
3676            return self._valAList
3677        elif mergeLevel == OWNormalize.MergeLevelPerVarsAB:
3678            return map(lambda x: x.valA, self.values())
3679        elif mergeLevel == OWNormalize.MergeLevelPerVarA:
3680            return self._valA2ind.keys()
3681        else:
3682            raise AttributeError, "unknown merge level: %s" % str(mergeLevel)
3683
3684
3685    def getValsAAlias(self, mergeLevel):
3686        if D1: print "Probes.getValsAAlias"
3687        aliasList = list(self._valAList)
3688        for pr in self.values():
3689            for idx in pr.getDataIndices():
3690                aliasList[idx] = pr.valAAlias
3691        return self._concatFunc[mergeLevel](aliasList, removeDupl=True)
3692
3693
3694    def getValsB(self, mergeLevel):
3695        if mergeLevel == OWNormalize.MergeLevelNone:
3696            return self._valBList
3697        elif mergeLevel == OWNormalize.MergeLevelPerVarsAB:
3698            return map(lambda x: x.valB, self.values())
3699        elif mergeLevel ==OWNormalize.MergeLevelPerVarA:
3700            raise ValueError, "cannot return probe vals B if mergeLevel == %i" % OWNormalize.MergeLevelPerVarA
3701        else:
3702            raise AttributeError, "unknown merge level: %s" % str(mergeLevel)
3703
3704
3705
3706
3707if __name__=="__main__":
3708
3709    def test_minNumControlProbes(numC):
3710        import numpy.oldnumeric as Numeric, numpy.oldnumeric.linear_algebra as LinearAlgebra, statc
3711        A = [-1,0,0.5,1,1.5, 3]
3712        Mc = Numeric.arange(0,numC,1.)
3713        Ac = Numeric.arange(0,numC,1.)
3714        X = Numeric.reshape(Numeric.asarray(Ac), (len(Ac),1))
3715        y = Numeric.asarray(Mc)
3716        X = Numeric.concatenate((Numeric.ones((X.shape[0],1), Numeric.Float), X), 1)
3717        XT = Numeric.transpose(X)
3718        try:
3719            XTXinv = LinearAlgebra.inverse(Numeric.dot(XT,X))
3720        except LinearAlgebra.LinAlgError:
3721            print "Warning: singular matrix, using generalized_inverse"
3722            XTX = Numeric.dot(XT,X)   # store the singuar matrix
3723            XTXinv = LinearAlgebra.generalized_inverse(XTX)
3724        b = Numeric.dot(Numeric.dot(XTXinv, XT), y)
3725        print "linReg: ", b[0] + b[1]*Numeric.asarray(A)
3726        print "loess:  ", Numeric.asarray(statc.loess(zip(Ac, Mc), Numeric.asarray(A).tolist(), 0.5))[:,1]
3727
3728
3729    def test_widget():       
3730        from Orange.orng import orngSignalManager
3731        from Orange.OrangeWidgets.Data import OWDataTable
3732        signalManager = orngSignalManager.SignalManager(0)
3733        a=QApplication(sys.argv)
3734        ow=OWNormalize(signalManager = signalManager)
3735        #a.setMainWidget(ow)
3736        ow.show()
3737
3738        # settings   
3739##        ow.outNonNormLogRatio = True
3740##        ow.normRange = Probes.NormRangeLocal
3741##        ow.approxFunction = 0
3742
3743        # variables for steroltalk array
3744        ow.defNameA = "ID"
3745        ow.defNameB = ""
3746        ow.defNameSmpl1 = "Smpl"
3747        ow.defNameSmpl2 = ""
3748        ow.defNameRef1 = "Ref"
3749        ow.defNameRef2 = ""
3750        ow.defNameForeground = "Raw intensity"
3751        ow.defNameBackground = "Background"
3752        ow.defNameMean = "(med)"
3753        ow.defNameSD = "(st.dev.)"
3754        ow.mergeLevel = OWNormalize.MergeLevelPerVarsAB
3755##        ow.mergeLevel = OWNormalize.MergeLevelPerVarA
3756        ow.settingsOutputReplicasChange()
3757        ow.approxFunction = OWNormalize.AppxFuncMed
3758        ow.settingsNormalizationChange()
3759        ow.commitOnChange = False
3760        ow.commitChange()
3761
3762
3763
3764
3765        # DATA 1: horizontal line in the middle of the slide
3766        ow.defNameB = "yPos"
3767        ow.defaultVarAssignmentClick()
3768        #TODO PORT ow.onDataInput(orange.ExampleTable(r"C:\Documents and Settings\peterjuv\My Documents\STEROLTALK\Sterolgene v.0 mouse\PB, cholesterol\Tadeja 2nd image analysis\10vs10mg original data\0449yPos.txt", DC="<NO DATA>"))
3769        #TODO PORT ow.onProbesInput(orange.ExampleTable(r"c:\Documents and Settings\peterjuv\My Documents\STEROLTALK\Sterolgene v.0 mouse\Sterolgene v0 mouse probeRatios (ID v0).tab"))
3770
3771##        # DATA 2: extremely low signal (only few genes pass the filters)
3772##        ow.onDataInput(orange.ExampleTable(r"c:\Documents and Settings\peterjuv\My Documents\STEROLTALK\Sterolgene v.0 mouse\PB, cholesterol\Tadeja drago\05vs10mg\chol.diet\2537.txt"))
3773##        ow.onProbesInput(orange.ExampleTable(r"c:\Documents and Settings\peterjuv\My Documents\STEROLTALK\Sterolgene v.0 mouse\sterolgene v.0 mouse controlGeneRatios 2.tab"))
3774##
3775##        # DATA 3: high noise
3776##        ow.onDataInput(orange.ExampleTable(r"c:\Documents and Settings\peterjuv\My Documents\STEROLTALK\Sterolgene v.0 mouse\PB, cholesterol\Tadeja drago\05vs10mg\control\6033.txt"))
3777##        ow.onProbesInput(orange.ExampleTable(r"c:\Documents and Settings\peterjuv\My Documents\STEROLTALK\Sterolgene v.0 mouse\sterolgene v.0 mouse controlGeneRatios 2.tab"))
3778##
3779##        # DATA 4: krizstina
3780##        ow.onDataInput(orange.ExampleTable(r"c:\Documents and Settings\peterjuv\My Documents\STEROLTALK\Sterolgene v.1 human\Krisztina\13217291-A01.txt", DC="<NO DATA>", noClass=1, noCodedDiscrete=1))
3781##        ow.onProbesInput(orange.ExampleTable(r"c:\Documents and Settings\peterjuv\My Documents\STEROLTALK\Sterolgene v.1 human\Sterolgene v1 ControlGeneRatios REVERSED 2.tab"))
3782##
3783##        # DATA 5: patologija, predzadnje spotiranje (redcene kontrole)
3784##        ow.onDataInput(orange.ExampleTable(r"c:\Documents and Settings\peterjuv\My Documents\MF other\Patologija\2005-11-21\136926 results.txt", DC="<NO DATA>"))
3785##        ow.onProbesInput(orange.ExampleTable(r"c:\Documents and Settings\peterjuv\My Documents\MF other\Patologija\2005-11-21\gasper controlRatios genes 2.tab"))
3786##
3787##        # DATA 6: patologija, zadnje spotiranje
3788##        ow.onDataInput(orange.ExampleTable(r"c:\Documents and Settings\peterjuv\My Documents\MF other\Patologija\2006-01-18\2006-01-18-rezultati.txt", DC="<NO DATA>"))
3789##        ow.onProbesInput(orange.ExampleTable(r"c:\Documents and Settings\peterjuv\My Documents\MF other\Patologija\2005-11-21\gasper controlRatios genes 2.tab"))
3790
3791##        # DATA 7: Agilent
3792##        ow.onDataInput(orange.ExampleTable(r"c:\Documents and Settings\peterjuv\My Documents\STEROLTALK\Sterolgene v.0 mouse\TNF, starved\Agilent\6135_A01.txt"))
3793
3794##        # DATA 8: Krisztina, June 2006
3795##        ow.onDataInput(orange.ExampleTable(r"C:\Documents and Settings\peterjuv\My Documents\STEROLTALK\Sterolgene v.1 human\Krisztina\2006-06-09\Analysis\13217311-top.txt"))
3796##        ow.onDataInput(orange.ExampleTable(r"C:\Documents and Settings\peterjuv\My Documents\STEROLTALK\Sterolgene v.1 human\Krisztina\2006-06-09\Analysis\13217311-bottom.txt"))
3797##        ow.onProbesInput(orange.ExampleTable(r"c:\Documents and Settings\peterjuv\My Documents\STEROLTALK\Sterolgene v.1 human\Sterolgene v1 ControlGeneRatios 2.tab"))
3798
3799##        # DATA 9: Jana, 28.6.2006
3800##        ow.onDataInput(orange.ExampleTable(r"C:\Documents and Settings\peterjuv\My Documents\STEROLTALK\Sterolgene v.1 mouse\Jana\2006-07-11 data\PMEA\13221205bottom.txt"))
3801##        ow.onProbesInput(orange.ExampleTable(r"c:\Documents and Settings\peterjuv\My Documents\STEROLTALK\Sterolgene v.1 mouse\Sterolgene v1 mouse probeRatios (ID).tab"))
3802
3803##        # DATA 10: Viola, 2006-07-27
3804##        ow.defNameA = "SteroltalkID"
3805##        ow.defNameB = ""
3806##        ow.defNameSmpl1 = "635"
3807##        ow.defNameSmpl2 = ""
3808##        ow.defNameRef1 = "532"
3809##        ow.defNameRef2 = ""
3810##        ow.defNameForeground = "F"
3811##        ow.defNameBackground = "B"
3812##        ow.defNameMean = "Median"
3813##        ow.defNameSD = "SD"
3814##        ow.onDataInput(orange.ExampleTable(r"C:\Documents and Settings\peterjuv\My Documents\STEROLTALK\Sterolgene v.1 mouse\2006-07-26 Viola Tamasi\2007-03 data from Viola\PB CAR- 01.tab", DK="Error"))
3815##        ow.onProbesInput(orange.ExampleTable(r"c:\Documents and Settings\peterjuv\My Documents\STEROLTALK\Sterolgene v.1 mouse\ST1m probeRatios Lucidea Luty1,2.tab"))
3816
3817        # OWDataTable
3818        dt = OWDataTable.OWDataTable(signalManager = signalManager)
3819        signalManager.addWidget(ow)
3820        signalManager.addWidget(dt)
3821        signalManager.setFreeze(1)
3822        signalManager.addLink(ow, dt, "Probe Data", "Examples", 1)
3823        signalManager.addLink(ow, dt, "Expression Data", "Examples", 1)
3824        signalManager.setFreeze(0)
3825        dt.show()
3826
3827##        # save
3828##        orange.saveTabDelimited(r"c:\Documents and Settings\peterjuv\My Documents\Orange\OWNormalize\test comp 2\output.tab", dt.data.values()[0])
3829
3830        # exec, save settings
3831        a.exec_()
3832        ow.saveSettings()
3833
3834
3835##############################################################
3836##    test_minNumControlProbes(2)
3837    test_widget()
Note: See TracBrowser for help on using the repository browser.