class OWMAPlot(OWWidget): settingsList = ["appendZScore", "appendRIValues"] contextHandlers = { "": DomainContextHandler("", ["selectedGroup", "zCutoff"]) } CENTER_METHODS = [("Average", obiExpression.MA_center_average), ("Lowess (fast - interpolated)", obiExpression.MA_center_lowess_fast), ("Lowess", obiExpression.MA_center_lowess)] MERGE_METHODS = [("Average", numpy.ma.average), ("Median", numpy.ma.median), ("Geometric mean", obiExpression.geometric_mean)] def __init__(self, parent=None, signalManager=None, name="Normalize Expression Array"): OWWidget.__init__(self, parent, signalManager, name, wantGraph=True) self.inputs = [("Expression array", ExampleTable, self.setData)] self.outputs = [("Normalized expression array", ExampleTable, Default), ("Filtered expression array", ExampleTable)] self.selectedGroup = 0 self.selectedCenterMethod = 0 self.selectedMergeMethod = 0 self.zCutoff = 1.96 self.appendZScore = False self.appendRIValues = False self.autoCommit = False self.loadSettings() ## GUI self.infoBox = OWGUI.widgetLabel( OWGUI.widgetBox(self.controlArea, "Info", addSpace=True), "No data on input.") box = OWGUI.widgetBox(self.controlArea, "Split by", addSpace=True) self.groupCombo = OWGUI.comboBox(box, self, "selectedGroup", callback=self.onGroupSelection) self.centerCombo = OWGUI.comboBox( self.controlArea, self, "selectedCenterMethod", box="Center Fold-change Using", items=[name for name, _ in self.CENTER_METHODS], callback=self.onCenterMethodChange, addSpace=True) self.mergeCombo = OWGUI.comboBox( self.controlArea, self, "selectedMergeMethod", box="Merge Replicates", items=[name for name, _ in self.MERGE_METHODS], tooltip="Select the method for replicate merging", callback=self.onMergeMethodChange, addSpace=True) box = OWGUI.doubleSpin(self.controlArea, self, "zCutoff", 0.0, 3.0, 0.01, box="Z-Score Cutoff", callback=[self.replotMA, self.commitIf]) OWGUI.separator(self.controlArea) box = OWGUI.widgetBox(self.controlArea, "Ouput") OWGUI.checkBox(box, self, "appendZScore", "Append Z-Scores", tooltip="Append calculated Z-Scores to output", callback=self.commitIf) OWGUI.checkBox( box, self, "appendRIValues", "Append Log Ratio and Intensity values", tooltip= "Append calculated Log Ratio and Intensity values to output data", callback=self.commitIf) cb = OWGUI.checkBox(box, self, "autoCommit", "Commit on change", tooltip="Commit data on any change", callback=self.commitIf) b = OWGUI.button(box, self, "Commit", callback=self.commit) OWGUI.setStopper(self, b, cb, "changedFlag", callback=self.commit) self.connect(self.graphButton, SIGNAL("clicked()"), self.saveGraph) OWGUI.rubber(self.controlArea) self.graph = OWGraph(self.mainArea) self.graph.setAxisTitle(QwtPlot.xBottom, "Intensity: log<sub>10</sub>(R*G)") self.graph.setAxisTitle(QwtPlot.yLeft, "Log ratio: log<sub>2</sub>(R/G)") self.graph.showFilledSymbols = True self.mainArea.layout().addWidget(self.graph) self.groups = [] self.split_data = None, None self.merged_splits = None, None self.centered = None, None self.changedFlag = False self.data = None self.resize(800, 600) def onFinished(self, status): self.setEnabled(True) def onUnhandledException(self, ex_info): self.setEnabled(True) print >> sys.stderr, "Unhandled exception in non GUI thread" ex_type, ex_val, tb = ex_info if ex_type == numpy.linalg.LinAlgError and False: self.error(0, "Linear algebra error: %s" % repr(ex_val)) else: sys.excepthook(*ex_info) def onGroupSelection(self): if self.data: self.updateInfoBox() self.splitData() self.runNormalization() def onCenterMethodChange(self): if self.data: self.runNormalization() def onMergeMethodChange(self): if self.data: self.splitData() self.runNormalization() def proposeGroups(self, data): col_labels = [ attr.attributes.items() for attr in data.domain.attributes ] col_labels = sorted(reduce(set.union, col_labels, set())) col_labels = [(key, value, 1) for key, value in col_labels] attrs = [attr for attr in data.domain.variables + data.domain.getmetas().values() \ if attr.varType == orange.VarTypes.Discrete] row_labels = [(attr.name, value, 0) for attr in attrs for value in attr.values] def filterSingleValues(labels): ret = [] for name, value, axis in labels: match = [(n, v, a) for n, v, a in labels if n == name] if len(match) > 1: ret.append((name, value, axis)) return ret col_labels = filterSingleValues(col_labels) row_labels = filterSingleValues(row_labels) return col_labels + row_labels def setData(self, data): self.closeContext("") self.data = data self.error([0, 1]) if data is not None: self.infoBox.setText("%i genes on input" % len(data)) self.groups = self.proposeGroups(data) self.groupCombo.clear() self.groupCombo.addItems( ["%s: %s" % (key, value) for key, value, axis in self.groups]) if not self.groups: self.error( 1, "Input data has no class attribute or attribute labels!") self.clear() return self.openContext("", data) self.selectedGroup = min(self.selectedGroup, len(self.groups) - 1) self.updateInfoBox() self.splitData() self.runNormalization() else: self.clear() def clear(self): self.groups = [] self.data = None self.centered = None, None self.split_data = None, None self.merged_splits = None, None self.graph.removeDrawingCurves() self.infoBox.setText("No data on input") self.send("Normalized expression array", None) self.send("Filtered expression array", None) def updateInfoBox(self): genes = self.getGeneNames() self.infoBox.setText("%i genes on input" % len(self.data)) def getSelectedGroup(self): return self.groups[self.selectedGroup] def getSelectedGroupSplit(self): key, value, axis = self.getSelectedGroup() other_values = [ v for k, v, a in self.groups if k == key and a == axis and v != value ] return [(key, value), (key, other_values)], axis def getGeneNames(self): key, value, axis = self.getSelectedGroup() if axis == 0: genes = [str(ex[key]) for ex in self.data] else: genes = [attr.name for attr in self.data.domain.attributes] return genes def splitData(self): groups, axis = self.getSelectedGroupSplit() self.split_ind = [ obiExpression.select_indices(self.data, key, value, axis) for key, value in groups ] self.split_data = obiExpression.split_data(self.data, groups, axis) def getMerged(self): split1, split2 = self.split_data (array1, _, _), (array2, _, _) = split1.toNumpyMA(), split2.toNumpyMA() _, _, axis = self.getSelectedGroup() merge_function = self.MERGE_METHODS[self.selectedMergeMethod][1] merged1 = obiExpression.merge_replicates(array1, axis, merge_function=merge_function) merged2 = obiExpression.merge_replicates(array2, axis, merge_function=merge_function) self.merged_splits = merged1, merged2 return self.merged_splits def runNormalization(self): self.progressBarInit() self.progressBarSet(0.0) G, R = self.getMerged() self.progressBarSet(5.0) center_method = self.CENTER_METHODS[self.selectedCenterMethod][1] # TODO: progess bar , lowess can take a long time if self.selectedCenterMethod in [1, 2]: #Lowess Gc, Rc = center_method(G, R, f=1. / min(500., len(G) / 100), iter=1) else: Gc, Rc = center_method(G, R) self.progressBarSet(70.0) self.centered = Gc, Rc self.z_scores = obiExpression.MA_zscore(Gc, Rc, 1. / 3.) self.progressBarSet(100.0) self.plotMA(Gc, Rc, self.z_scores, self.zCutoff) self.progressBarFinished() def runNormalizationAsync(self): """ Run MA centering and z_score estimation in a separate thread """ self.error(0) self.progressBarInit() self.progressBarSet(0.0) G, R = self.getMerged() # self.progressBarSet(5.0) center_method = self.CENTER_METHODS[self.selectedCenterMethod][1] use_lowess = self.selectedCenterMethod in [1, 2] def run(progressCallback=lambda value: None ): # the function to run in a thread # progressCallback(5.0) if use_lowess: Gc, Rc = center_method( G, R, f=2. / 3., iter=1, progressCallback=lambda val: progressCallback(val / 2)) else: Gc, Rc = center_method(G, R) progressCallback(50) z_scores = obiExpression.MA_zscore( Gc, Rc, 1. / 3., progressCallback=lambda val: progressCallback(50 + val / 2)) return Gc, Rc, z_scores self.progressDiscard = ProgressBarDiscard(self, self) async = self.asyncCall(run, name="Normalization", onResult=self.onResults, onError=self.onUnhandledException) self.connect(async, SIGNAL("progressChanged(float)"), self.progressDiscard.progressBarSet, Qt.QueuedConnection) self.setEnabled(False) async .__call__(progressCallback=async .emitProgressChanged) ## comment out this line if threading creates any problems runNormalization = runNormalizationAsync def onResults(self, (Gc, Rc, z_scores)): """ Handle the results of centering and z-scoring """ assert (QThread.currentThread() is self.thread()) self.setEnabled(True) qApp.processEvents() self.progressBarFinished() self.centered = Gc, Rc self.z_scores = z_scores self.plotMA(Gc, Rc, z_scores, self.zCutoff) self.commit()
class OWMAPlot(OWWidget): settingsList = ["appendZScore", "appendRIValues"] contextHandlers = {"": DomainContextHandler("", ["selectedGroup", "zCutoff"])} CENTER_METHODS = [("Average", obiExpression.MA_center_average), ("Lowess (fast - interpolated)", obiExpression.MA_center_lowess_fast), ("Lowess", obiExpression.MA_center_lowess)] MERGE_METHODS = [("Average", numpy.ma.average), ("Median", numpy.ma.median), ("Geometric mean", obiExpression.geometric_mean)] def __init__(self, parent=None, signalManager=None, name="Normalize Expression Array"): OWWidget.__init__(self, parent, signalManager, name, wantGraph=True) self.inputs = [("Expression array", ExampleTable, self.setData)] self.outputs = [("Normalized expression array", ExampleTable, Default), ("Filtered expression array", ExampleTable)] self.selectedGroup = 0 self.selectedCenterMethod = 0 self.selectedMergeMethod = 0 self.zCutoff = 1.96 self.appendZScore = False self.appendRIValues = False self.autoCommit = False self.loadSettings() ## GUI self.infoBox = OWGUI.widgetLabel(OWGUI.widgetBox(self.controlArea, "Info", addSpace=True), "No data on input.") box = OWGUI.widgetBox(self.controlArea, "Split by", addSpace=True) self.groupCombo = OWGUI.comboBox(box, self, "selectedGroup", callback=self.onGroupSelection ) self.centerCombo = OWGUI.comboBox(self.controlArea, self, "selectedCenterMethod", box="Center Fold-change Using", items=[name for name, _ in self.CENTER_METHODS], callback=self.onCenterMethodChange, addSpace=True ) self.mergeCombo = OWGUI.comboBox(self.controlArea, self, "selectedMergeMethod", box="Merge Replicates", items=[name for name, _ in self.MERGE_METHODS], tooltip="Select the method for replicate merging", callback=self.onMergeMethodChange, addSpace=True ) box = OWGUI.doubleSpin(self.controlArea, self, "zCutoff", 0.0, 3.0, 0.01, box="Z-Score Cutoff", callback=[self.replotMA, self.commitIf]) OWGUI.separator(self.controlArea) box = OWGUI.widgetBox(self.controlArea, "Ouput") OWGUI.checkBox(box, self, "appendZScore", "Append Z-Scores", tooltip="Append calculated Z-Scores to output", callback=self.commitIf ) OWGUI.checkBox(box, self, "appendRIValues", "Append Log Ratio and Intensity values", tooltip="Append calculated Log Ratio and Intensity values to output data", callback=self.commitIf ) cb = OWGUI.checkBox(box, self, "autoCommit", "Commit on change", tooltip="Commit data on any change", callback=self.commitIf ) b = OWGUI.button(box, self, "Commit", callback=self.commit) OWGUI.setStopper(self, b, cb, "changedFlag", callback=self.commit) self.connect(self.graphButton, SIGNAL("clicked()"), self.saveGraph) OWGUI.rubber(self.controlArea) self.graph = OWGraph(self.mainArea) self.graph.setAxisTitle(QwtPlot.xBottom, "Intensity: log<sub>10</sub>(R*G)") self.graph.setAxisTitle(QwtPlot.yLeft, "Log ratio: log<sub>2</sub>(R/G)") self.graph.showFilledSymbols = True self.mainArea.layout().addWidget(self.graph) self.groups = [] self.split_data = None, None self.merged_splits = None, None self.centered = None, None self.changedFlag = False self.data = None self.resize(800, 600) def onFinished(self, status): self.setEnabled(True) def onUnhandledException(self, ex_info): self.setEnabled(True) print >> sys.stderr, "Unhandled exception in non GUI thread" ex_type, ex_val, tb = ex_info if ex_type == numpy.linalg.LinAlgError and False: self.error(0, "Linear algebra error: %s" % repr(ex_val)) else: sys.excepthook(*ex_info) def onGroupSelection(self): if self.data: self.updateInfoBox() self.splitData() self.runNormalization() def onCenterMethodChange(self): if self.data: self.runNormalization() def onMergeMethodChange(self): if self.data: self.splitData() self.runNormalization() def proposeGroups(self, data): col_labels = [attr.attributes.items() for attr in data.domain.attributes] col_labels = sorted(reduce(set.union, col_labels, set())) col_labels = [(key, value, 1) for key, value in col_labels] attrs = [attr for attr in data.domain.variables + data.domain.getmetas().values() \ if attr.varType == orange.VarTypes.Discrete] row_labels = [(attr.name, value, 0) for attr in attrs for value in attr.values] def filterSingleValues(labels): ret = [] for name, value, axis in labels: match = [(n, v, a) for n, v, a in labels if n == name] if len(match) > 1: ret.append((name, value, axis)) return ret col_labels = filterSingleValues(col_labels) row_labels = filterSingleValues(row_labels) return col_labels + row_labels def setData(self, data): self.closeContext("") self.data = data self.error([0 ,1]) if data is not None: self.infoBox.setText("%i genes on input" % len(data)) self.groups = self.proposeGroups(data) self.groupCombo.clear() self.groupCombo.addItems(["%s: %s" % (key, value) for key, value, axis in self.groups]) if not self.groups: self.error(1, "Input data has no class attribute or attribute labels!") self.clear() return self.openContext("", data) self.selectedGroup = min(self.selectedGroup, len(self.groups) - 1) self.updateInfoBox() self.splitData() self.runNormalization() else: self.clear() def clear(self): self.groups = [] self.data = None self.centered = None, None self.split_data = None, None self.merged_splits = None, None self.graph.removeDrawingCurves() self.infoBox.setText("No data on input") self.send("Normalized expression array", None) self.send("Filtered expression array", None) def updateInfoBox(self): genes = self.getGeneNames() self.infoBox.setText("%i genes on input" % len(self.data)) def getSelectedGroup(self): return self.groups[self.selectedGroup] def getSelectedGroupSplit(self): key, value, axis = self.getSelectedGroup() other_values = [v for k, v, a in self.groups if k == key and a == axis and v != value] return [(key, value), (key, other_values)], axis def getGeneNames(self): key, value, axis = self.getSelectedGroup() if axis == 0: genes = [str(ex[key]) for ex in self.data] else: genes = [attr.name for attr in self.data.domain.attributes] return genes def splitData(self): groups, axis = self.getSelectedGroupSplit() self.split_ind = [obiExpression.select_indices(self.data, key, value, axis) for key, value in groups] self.split_data = obiExpression.split_data(self.data, groups, axis) def getMerged(self): split1, split2 = self.split_data (array1, _, _), (array2, _, _) = split1.toNumpyMA(), split2.toNumpyMA() _, _, axis = self.getSelectedGroup() merge_function = self.MERGE_METHODS[self.selectedMergeMethod][1] merged1 = obiExpression.merge_replicates(array1, axis, merge_function=merge_function) merged2 = obiExpression.merge_replicates(array2, axis, merge_function=merge_function) self.merged_splits = merged1, merged2 return self.merged_splits def runNormalization(self): self.progressBarInit() self.progressBarSet(0.0) G, R = self.getMerged() self.progressBarSet(5.0) center_method = self.CENTER_METHODS[self.selectedCenterMethod][1] # TODO: progess bar , lowess can take a long time if self.selectedCenterMethod in [1, 2]: #Lowess Gc, Rc = center_method(G, R, f = 1./min(500., len(G)/100), iter=1) else: Gc, Rc = center_method(G, R) self.progressBarSet(70.0) self.centered = Gc, Rc self.z_scores = obiExpression.MA_zscore(Gc, Rc, 1./3.) self.progressBarSet(100.0) self.plotMA(Gc, Rc, self.z_scores, self.zCutoff) self.progressBarFinished() def runNormalizationAsync(self): """ Run MA centering and z_score estimation in a separate thread """ self.error(0) self.progressBarInit() self.progressBarSet(0.0) G, R = self.getMerged() # self.progressBarSet(5.0) center_method = self.CENTER_METHODS[self.selectedCenterMethod][1] use_lowess = self.selectedCenterMethod in [1, 2] def run(progressCallback = lambda value: None): # the function to run in a thread # progressCallback(5.0) if use_lowess: Gc, Rc = center_method(G, R, f=2./3., iter=1, progressCallback=lambda val: progressCallback(val/2)) else: Gc, Rc = center_method(G, R) progressCallback(50) z_scores = obiExpression.MA_zscore(Gc, Rc, 1./3., progressCallback= lambda val: progressCallback(50 + val/2)) return Gc, Rc, z_scores self.progressDiscard = ProgressBarDiscard(self, self) async = self.asyncCall(run, name="Normalization", onResult=self.onResults, onError=self.onUnhandledException) self.connect(async, SIGNAL("progressChanged(float)"), self.progressDiscard.progressBarSet, Qt.QueuedConnection) self.setEnabled(False) async.__call__(progressCallback=async.emitProgressChanged) ## comment out this line if threading creates any problems runNormalization = runNormalizationAsync def onResults(self, (Gc, Rc, z_scores)): """ Handle the results of centering and z-scoring """ assert(QThread.currentThread() is self.thread()) self.setEnabled(True) qApp.processEvents() self.progressBarFinished() self.centered = Gc, Rc self.z_scores = z_scores self.plotMA(Gc, Rc, z_scores, self.zCutoff) self.commit()