Source code for PyMca5.PyMcaPlugins.AlignmentScanPlugin

#/*##########################################################################
# Copyright (C) 2004-2015 V.A. Sole, 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__ = "V.A. Sole - ESRF Data Analysis"
__contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import numpy

try:
    from PyMca5.PyMcaCore import Plugin1DBase    
except ImportError:
    print("WARNING:MedianFilterScanPlugin import from somewhere else")
    from . import Plugin1DBase

from PyMca5.PyMcaMath.fitting import SpecfitFuns

[docs]class AlignmentScanPlugin(Plugin1DBase.Plugin1DBase): def __init__(self, plotWindow, **kw): Plugin1DBase.Plugin1DBase.__init__(self, plotWindow, **kw) self.__randomization = True self.__methodKeys = [] self.methodDict = {} text = "FFT based alignment\n" info = text icon = None function = self.fftAlignment method = "FFT Alignment" self.methodDict[method] = [function, info, icon] self.__methodKeys.append(method) #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, ... """ if self.__randomization: return self.__methodKeys[0:1] + self.__methodKeys[2:] else: return self.__methodKeys[1:]
[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 None
[docs] def applyMethod(self, name): """ The plugin is asked to apply the method associated to name. """ return self.methodDict[name][0]()
[docs] def fftAlignment(self): curves = self.getMonotonicCurves() nCurves = len(curves) if nCurves < 2: raise ValueError("At least 2 curves needed") return # get legend of active curve try: activeCurveLegend = self.getActiveCurve()[2] if activeCurveLegend is None: activeCurveLegend = curves[0][2] for curve in curves: if curve[2] == activeCurveLegend: activeCurve = curve break except: activeCurve = curves[0] # apply between graph limits x0, y0 = activeCurve[0:2] xmin, xmax =self.getGraphXLimits() for curve in curves: xmax = float(min(xmax, curve[0][-1])) xmin = float(max(xmin, curve[0][0])) idx = numpy.nonzero((x0 >= xmin) & (x0 <= xmax))[0] x0 = numpy.take(x0, idx) y0 = numpy.take(y0, idx) #make sure values are regularly spaced xi = numpy.linspace(x0[0], x0[-1], len(idx)).reshape(-1, 1) yi = SpecfitFuns.interpol([x0], y0, xi, y0.min()) x0 = xi * 1 y0 = yi * 1 y0.shape = -1 fft0 = numpy.fft.fft(y0) y0.shape = -1, 1 x0.shape = -1, 1 nChannels = x0.shape[0] # built a couple of temporary array of spectra for handy access shiftList = [] curveList = [] i = 0 for idx in range(nCurves): x, y, legend, info = curves[idx][0:4] if x.size != x0.size: needInterpolation = True elif numpy.allclose(x, x0): # no need for interpolation needInterpolation = False else: needInterpolation = True if needInterpolation: # we have to interpolate x.shape = -1 y.shape = -1 xi = x0[:] * 1 y = SpecfitFuns.interpol([x], y, xi, y0.min()) x = xi y.shape = -1 i += 1 # now calculate the shift ffty = numpy.fft.fft(y) if numpy.allclose(fft0, ffty): shiftList.append(0.0) x.shape = -1 else: shift = numpy.fft.ifft(fft0 * ffty.conjugate()).real shift2 = numpy.zeros(shift.shape, dtype=shift.dtype) m = shift2.size//2 shift2[m:] = shift[:-m] shift2[:m] = shift[-m:] threshold = 0.80*shift2.max() #threshold = shift2.mean() idx = numpy.nonzero(shift2 > threshold)[0] #print("max indices = %d" % (m - idx)) shift = (shift2[idx] * idx/shift2[idx].sum()).sum() #print("shift = ", shift - m, "in x units = ", (shift - m) * (x[1]-x[0])) # shift the curve shift = (shift - m) * (x[1]-x[0]) x.shape = -1 y = numpy.fft.ifft(numpy.exp(-2.0*numpy.pi*numpy.sqrt(numpy.complex(-1))*\ numpy.fft.fftfreq(len(x), d=x[1]-x[0])*shift)*ffty) y = y.real y.shape = -1 curveList.append([x, y, legend + "SHIFT", False, False]) curveList[-1][-2] = True curveList[-1][-1] = False x, y, legend, replot, replace = curveList[0] self.addCurve(x, y, legend=legend, replot=True, replace=True) for i in range(1, len(curveList)): x, y, legend, replot, replace = curveList[i] self.addCurve(x, y, legend=legend, info=None, replot=replot, replace=False) return
MENU_TEXT = "Alignment Plugin"
[docs]def getPlugin1DInstance(plotWindow, **kw): ob = AlignmentScanPlugin(plotWindow) return ob
if __name__ == "__main__": import os try: from PyMca5.PyMcaGui import PyMcaQt as qt from PyMca5.PyMcaGui.plotting import PlotWindow app = qt.QApplication([]) QT = True plot = PlotWindow.PlotWindow() except: # test without graphical interface QT = False from PyMca5.PyMcaGraph import Plot plot = Plot.Plot() pluginDir = [os.path.dirname(__file__)] plot.getPlugins(method="getPlugin1DInstance", directoryList=pluginDir) i = numpy.arange(1000.) y1 = 10.0 + 5000.0 * numpy.exp(-0.01*(i-50)**2) y2 = 10.0 + 5000.0 * numpy.exp(-((i-55)/5.)**2) plot.addCurve(i, y1, "y1") plot.addCurve(i, y2, "y2") plugin = getPlugin1DInstance(plot) for method in plugin.getMethods(): print(method, ":", plugin.getMethodToolTip(method)) plugin.applyMethod(plugin.getMethods()[0]) curves = plugin.getAllCurves() #for curve in curves: # print(curve[2]) print("LIMITS = ", plugin.getGraphYLimits()) if QT: plot.show() app.exec_()