source: orange-bioinformatics/_bioinformatics/widgets/prototypes/OWNormalize.py @ 1643:2cfa80dac3d3

Revision 1643:2cfa80dac3d3, 191.2 KB checked in by mitar, 2 years ago (diff)

Fixing some imports. Marking widgets as prototypes.

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