Source code for PyMca5.PyMcaPlugins.MedianFilterScanDeglitchPlugin
#/*##########################################################################
# Copyright (C) 2004-2014 T.Rueter, European Synchrotron Radiation Facility
#
# This file is part of the PyMca X-ray Fluorescence Toolkit developed at
# the ESRF by the Software group.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
#############################################################################*/
__author__ = "T. Rueter - ESRF Data Analysis"
__contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
from PyMca5 import Plugin1DBase
from PyMca5.PyMcaMath.PyMcaSciPy.signal import medfilt1d
from PyMca5.PyMcaGui import PyMcaQt as qt
import numpy
DEBUG = 0
[docs]class MedianFilterScanDeglitchPlugin(Plugin1DBase.Plugin1DBase):
def __init__(self, plotWindow, **kw):
Plugin1DBase.Plugin1DBase.__init__(self, plotWindow, **kw)
self.methodDict = {
'Apply to active curve':
[self.removeSpikesActive,
'Apply sliding median filter to active curve',
None],
'Apply to all curves':
[self.removeSpikesAll,
'Apply sliding median filter to all curves',
None],
'Configure median filter':
[self.configureFilter,
'Set threshold and width of the filter',
None]
}
self._methodList = ['Configure median filter',
'Apply to active curve',
'Apply to all curves']
self.threshold = 0.66
self.width = 9
self._widget = None
#Methods to be implemented by the plugin
[docs] def getMethods(self, plottype=None):
"""
A list with the NAMES associated to the callable methods
that are applicable to the specified plot.
Plot type can be "SCAN", "MCA", None, ...
"""
return list(self._methodList)
[docs] def getMethodToolTip(self, name):
"""
Returns the help associated to the particular method name or None.
"""
return self.methodDict[name][1]
[docs] def getMethodPixmap(self, name):
"""
Returns the pixmap associated to the particular method name or None.
"""
return self.methodDict[name][2]
[docs] def applyMethod(self, name):
"""
The plugin is asked to apply the method associated to name.
"""
self.methodDict[name][0]()
return
[docs] def configureFilter(self):
if self._widget is None:
# construct a widget
msg = qt.QDialog()
msg.setWindowTitle("Deglitch Configuration")
msgLayout = qt.QGridLayout()
buttonLayout = qt.QHBoxLayout()
inpThreshold = qt.QDoubleSpinBox()
inpThreshold.setRange(0.,10.)
inpThreshold.setSingleStep(.1)
inpThreshold.setValue(self.threshold)
inpThreshold.setToolTip('Increase width for broad spikes')
inpWidth = qt.QSpinBox()
inpWidth.setRange(1,101)
inpWidth.setSingleStep(2)
inpWidth.setValue(self.width)
inpWidth.setToolTip('Set low threshold for multiple spikes of different markedness')
labelWidth = qt.QLabel('Width (must be odd)')
labelThreshold = qt.QLabel('Threshold (multiple of deviation)')
buttonOK = qt.QPushButton('Ok')
buttonOK.clicked.connect(msg.accept)
buttonCancel = qt.QPushButton('Cancel')
buttonCancel.clicked.connect(msg.reject)
allActiveBG = qt.QButtonGroup()
buttonAll = qt.QCheckBox('Apply to All')
buttonActive = qt.QCheckBox('Apply to Active')
allActiveBG.addButton(buttonAll, 0)
allActiveBG.addButton(buttonActive, 1)
buttonActive.setChecked(True)
buttonLayout.addWidget(qt.HorizontalSpacer())
buttonLayout.addWidget(buttonOK)
buttonLayout.addWidget(buttonCancel)
msgLayout.addWidget(labelWidth,0,0)
msgLayout.addWidget(inpWidth,0,1)
msgLayout.addWidget(labelThreshold,1,0)
msgLayout.addWidget(inpThreshold,1,1)
msgLayout.addWidget(buttonActive,2,0)
msgLayout.addWidget(buttonAll,2,1)
msgLayout.addLayout(buttonLayout,3,0,1,2)
msg.setLayout(msgLayout)
msg.inputWidth = inpWidth
msg.inputThreshold = inpThreshold
msg.applyToAll = buttonAll
self._widget = msg
if self._widget.exec_():
self.threshold = float(self._widget.inputThreshold.value())
self.width = int(self._widget.inputWidth.value())
if not (self.width%2):
self.width += 1
if buttonActive.isChecked():
if DEBUG:
print('ActiveChecked')
self.removeSpikesActive()
if buttonAll.isChecked():
if DEBUG:
print('AllChecked')
self.removeSpikesAll()
[docs] def medianThresholdFilter(self, activeOnly, threshold, length):
if activeOnly:
active = self._plotWindow.getActiveCurve()
if not active:
return
else:
x, y, legend, info = active
self.removeCurve(legend)
spectra = [active]
else:
spectra = self._plotWindow.getAllCurves()
for (idx, spec) in enumerate(spectra):
x, y, legend, info = spec
filtered = medfilt1d(y, length)
diff = filtered-y
mean = diff.mean()
sigma = (x-mean)**2
sigma = numpy.sqrt(sigma.sum()/float(len(sigma)))
ynew = numpy.where(abs(diff) > threshold * sigma, filtered, y)
legend = info.get('selectionlegend',legend) + ' SR'
if (idx==0) and (len(spectra)!=1):
self.addCurve(x,ynew,legend,info, replace=True, replot=False)
elif idx == (len(spectra)- 1):
self.addCurve(x,ynew,legend,info, replace=False, replot=True)
else:
self.addCurve(x,ynew,legend,info, replace=False, replot=False)
#self._plotWindow.replot()
MENU_TEXT = "Remove glitches from curves"
[docs]def getPlugin1DInstance(plotWindow, **kw):
ob = MedianFilterScanDeglitchPlugin(plotWindow)
return ob
if __name__ == "__main__":
from PyMca5.PyMcaGui import PlotWindow
app = qt.QApplication([])
sw = PlotWindow.PlotWindow()
x = numpy.linspace(0, 1999, 2000)
y0 = x/100. + 100.*numpy.exp(-(x-500)**2/1000.) + 50.*numpy.exp(-(x-1200)**2/5000.) + 100.*numpy.exp(-(x-1700)**2/500.) + 10 * numpy.random.random(2000)
y1 = x/100. + 100.*numpy.exp(-(x-600)**2/1000.) + 50.*numpy.exp(-(x-1000)**2/5000.) + 100.*numpy.exp(-(x-1500)**2/500.) + 10 * numpy.random.random(2000)
for idx in range(20):
y0[idx*100] = 500. * numpy.random.random(1)
y1[idx*100] = 500. * numpy.random.random(1)
sw.addCurve(x, y0, legend="Curve0")
sw.addCurve(x, y1, legend="Curve1")
plugin = getPlugin1DInstance(sw)
plugin.configureFilter()
sw.show()
app.exec_()