def interpolate(self, factor=1.): ''' Input ----- factor : float factor used to oversample existing data, use with caution. Interpolates all existing curves to an equidistant x-range using the either the active or the first curve do determine the number of data points. Use this method instead of self.getAllCurves() when performin FFT related tasks. Returns ------- interpCurves : ndarray Array containing the interpolated curves shown in the plot window. Format: [(x0, y0, legend0, info0), ...] ''' curves = self.getAllCurves() if len(curves) < 1: raise ValueError("At least 1 curve needed") if DEBUG: print('interpolate -- no curves present') return activeCurve = self.getActiveCurve() if not activeCurve: activeCurve = curves[0] else: activeLegend = activeCurve[2] idx = list.index([curve[2] for curve in curves], activeLegend) activeCurve = curves[idx] activeX, activeY, activeLegend, activeInfo = activeCurve[0:4] # Determine average spaceing between Datapoints step = numpy.average(numpy.diff(activeX)) xmin, xmax = self.getXLimits([x for (x,y,leg,info) in curves], overlap=False) num = factor * numpy.ceil((xmax-xmin)/step) # Create equidistant x-range, exclude first and last point xeq = numpy.linspace(xmin, xmax, num, endpoint=False)[:-1] # Interpolate on sections of xeq interpCurves = [] for (x,y,legend,info) in curves: idx = numpy.nonzero((x.min()<xeq) & (xeq<x.max()))[0] xi = numpy.take(xeq, idx) yi = SpecfitFuns.interpol([x], y, xi.reshape(-1,1), y.min()) yi.shape = -1 interpCurves += [(xi, yi, legend, info)] return interpCurves
def estimateXANESEdge(spectrum, energy=None, full=False): if energy is None: x = numpy.arange(len(spectrum)).astype(numpy.float) else: x = numpy.array(energy, dtype=numpy.float, copy=True) y = numpy.array(spectrum, dtype=numpy.float, copy=True) # make sure data are sorted idx = energy.argsort(kind='mergesort') x = numpy.take(energy, idx) y = numpy.take(spectrum, idx) # make sure data are strictly increasing delta = x[1:] - x[:-1] dmin = delta.min() dmax = delta.max() if delta.min() <= 1.0e-10: # force data are strictly increasing # although we do not consider last point idx = numpy.nonzero(delta>0)[0] x = numpy.take(x, idx) y = numpy.take(y, idx) delta = None sortedX = x sortedY = y # use a regularly spaced spectrum if dmax != dmin: # choose the number of points or deduce it from # the input data length? nchannels = 5 * len(spectrum) xi = numpy.linspace(x[1], x[-2], nchannels).reshape(-1, 1) x.shape = -1 y.shape = -1 y = SpecfitFuns.interpol([x], y, xi, y.min()) x = xi x.shape = -1 y.shape = -1 # take the first derivative npoints = 7 xPrime = x[npoints:-npoints] yPrime = SGModule.getSavitzkyGolay(y, npoints=npoints, degree=2, order=1) # get the index at maximum value iMax = numpy.argmax(yPrime) if full: # return intermediate information return x[iMax], sortedX, sortedY, xPrime, yPrime else: # return the corresponding x value return x[iMax]
def divideByActiveCurve(self): #all curves curves = self.getAllCurves() nCurves = len(curves) if nCurves < 2: raise ValueError("At least two curves needed") return #get active curve activeCurve = self.getActiveCurve() if activeCurve is None: raise ValueError("Please select an active curve") return x, y, legend0, info = activeCurve xmin, xmax = self.getGraphXLimits() y = y.astype(numpy.float) #get the nonzero values idx = numpy.nonzero(abs(y) != 0.0)[0] if not len(idx): raise ValueError("All divisor values are zero!") x0 = numpy.take(x, idx) y0 = numpy.take(y, idx) #sort the values idx = numpy.argsort(x0, kind='mergesort') x0 = numpy.take(x0, idx) y0 = numpy.take(y0, idx) i = 0 for curve in curves: x, y, legend, info = curve[0:4] if legend == legend0: continue #take the portion ox x between limits idx = numpy.nonzero((x>=xmin) & (x<=xmax))[0] if not len(idx): #no overlap continue x = numpy.take(x, idx) y = numpy.take(y, idx) idx = numpy.nonzero((x0>=x.min()) & (x0<=x.max()))[0] if not len(idx): #no overlap continue xi = numpy.take(x0, idx) yi = numpy.take(y0, idx) #perform interpolation xi.shape = -1, 1 yw = SpecfitFuns.interpol([x], y, xi, yi.min()) y = yw / yi if i == 0: replace = True replot = True i = 1 else: replot = False replace = False self.addCurve(x, y, legend=legend, info=info, replot=replot, replace=replace) lastCurve = [x, y, legend] self.addCurve(lastCurve[0], lastCurve[1], legend=lastCurve[2], info=info, replot=True, replace=False)
def XASNormalize(self): #all curves curves = self.getAllCurves() nCurves = len(curves) if nCurves < 1: raise ValueError("At least one curve needed") return #get active curve activeCurve = self.getActiveCurve() if activeCurve is None: raise ValueError("Please select an active curve") return x, y, legend0, info = activeCurve #sort the values idx = numpy.argsort(x, kind='mergesort') x0 = numpy.take(x, idx) y0 = numpy.take(y, idx) xmin, xmax = self.getGraphXLimits() # get calculation parameters if self.widget is None: self._createWidget(y0, x0) parameters = self.parameters if parameters['auto_edge']: edge = None else: edge = parameters['edge_energy'] energy = x pre_edge_regions = parameters['pre_edge']['regions'] post_edge_regions = parameters['post_edge']['regions'] algorithm = 'polynomial' algorithm_parameters = {} algorithm_parameters['pre_edge_order'] = parameters['pre_edge']\ ['polynomial'] algorithm_parameters['post_edge_order'] = parameters['post_edge']\ ['polynomial'] i = 0 lastCurve = None for curve in curves: x, y, legend, info = curve[0:4] #take the portion ox x between limits idx = numpy.nonzero((x >= xmin) & (x <= xmax))[0] if not len(idx): #no overlap continue x = numpy.take(x, idx) y = numpy.take(y, idx) idx = numpy.nonzero((x0 >= x.min()) & (x0 <= x.max()))[0] if not len(idx): #no overlap continue xi = numpy.take(x0, idx) yi = numpy.take(y0, idx) #perform interpolation xi.shape = -1, 1 yw = SpecfitFuns.interpol([x], y, xi, yi.min()) # try: ... except: here? yw.shape = -1 xi.shape = -1 x, y = XASNormalization.XASNormalization( yw, energy=xi, edge=edge, pre_edge_regions=pre_edge_regions, post_edge_regions=post_edge_regions, algorithm=algorithm, algorithm_parameters=algorithm_parameters)[0:2] # if i == 0: replace = True replot = True i = 1 else: replot = False replace = False newLegend = " ".join(legend.split(" ")[:-1]) if not newLegend.startswith('Norm.'): newLegend = "Norm. " + newLegend self.addCurve(x, y, legend=newLegend, info=info, replot=replot, replace=replace) lastCurve = [x, y, newLegend] self.addCurve(lastCurve[0], lastCurve[1], legend=lastCurve[2], info=info, replot=True, replace=False)
def fftAlignment(self): curves = self.getAllCurves() nCurves = len(curves) if nCurves < 2: raise ValueError("At least 2 curves needed") return # get active curve activeCurve = self.getActiveCurve() if activeCurve is None: activeCurve = curves[0] # apply between graph limits x0 = activeCurve[0][:] y0 = activeCurve[1][:] xmin, xmax = self.getGraphXLimits() idx = numpy.nonzero((x0 >= xmin) & (x0 <= xmax))[0] x0 = numpy.take(x0, idx) y0 = numpy.take(y0, idx) #sort the values idx = numpy.argsort(x0, kind='mergesort') x0 = numpy.take(x0, idx) y0 = numpy.take(y0, idx) #remove duplicates x0 = x0.ravel() idx = numpy.nonzero((x0[1:] > x0[:-1]))[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 y0 = yi 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 tmpArray = numpy.zeros((nChannels, nCurves), numpy.float) fftList = [] shiftList = [] curveList = [] i = 0 for idx in range(nCurves): x, y, legend, info = curves[idx][0:4] #sort the values x = x[:] idx = numpy.argsort(x, kind='mergesort') x = numpy.take(x, idx) y = numpy.take(y, idx) #take the portion of x between limits idx = numpy.nonzero((x >= xmin) & (x <= xmax))[0] if not len(idx): # no overlap continue x = numpy.take(x, idx) y = numpy.take(y, idx) #remove duplicates x = x.ravel() idx = numpy.nonzero((x[1:] > x[:-1]))[0] x = numpy.take(x, idx) y = numpy.take(y, idx) x.shape = -1, 1 if numpy.allclose(x, x0): # no need for interpolation pass else: # we have to interpolate x.shape = -1 y.shape = -1 xi = x0[:] y = SpecfitFuns.interpol([x], y, xi, y0.min()) y.shape = -1 tmpArray[:, i] = y i += 1 # now calculate the shift ffty = numpy.fft.fft(y) fftList.append(ffty) if 0: self.addCurve(x, y, legend="NEW Y%d" % i, info=None, replot=True, replace=False) elif numpy.allclose(fft0, ffty): shiftList.append(0.0) 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:] if 0: self.addCurve(numpy.arange(len(shift2)), shift2, legend="SHIFT", info=None, replot=True, replace=False) threshold = 0.50 * 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)*numpy.fft.fft(y)) y = y.real y.shape = -1 curveList.append([x, y, legend + "SHIFT", False, False]) tmpArray = None 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 # now get the final spectrum y = medianSpectra.sum(axis=1) / nCurves x0.shape = -1 y.shape = x0.shape legend = "%d Median from %s to %s" % (width, curves[0][2], curves[-1][2]) self.addCurve(x0, y, legend=legend, info=None, replot=True, replace=True)
def applyMedianFilter(self, width=3): curves = self.getAllCurves() nCurves = len(curves) if nCurves < width: raise ValueError("At least %d curves needed" % width) return if self.__randomization: indices = numpy.random.permutation(nCurves) else: indices = range(nCurves) # get active curve activeCurve = self.getActiveCurve() if activeCurve is None: activeCurve = curves[0] # apply between graph limits x0 = activeCurve[0][:] y0 = activeCurve[1][:] xmin, xmax =self.getGraphXLimits() idx = numpy.nonzero((x0 >= xmin) & (x0 <= xmax))[0] x0 = numpy.take(x0, idx) y0 = numpy.take(y0, idx) #sort the values idx = numpy.argsort(x0, kind='mergesort') x0 = numpy.take(x0, idx) y0 = numpy.take(y0, idx) #remove duplicates x0 = x0.ravel() idx = numpy.nonzero((x0[1:] > x0[:-1]))[0] x0 = numpy.take(x0, idx) y0 = numpy.take(y0, idx) x0.shape = -1, 1 nChannels = x0.shape[0] # built a couple of temporary array of spectra for handy access tmpArray = numpy.zeros((nChannels, nCurves), numpy.float) medianSpectra = numpy.zeros((nChannels, nCurves), numpy.float) i = 0 for idx in indices: x, y, legend, info = curves[idx][0:4] #sort the values x = x[:] idx = numpy.argsort(x, kind='mergesort') x = numpy.take(x, idx) y = numpy.take(y, idx) #take the portion of x between limits idx = numpy.nonzero((x>=xmin) & (x<=xmax))[0] if not len(idx): # no overlap continue x = numpy.take(x, idx) y = numpy.take(y, idx) #remove duplicates x = x.ravel() idx = numpy.nonzero((x[1:] > x[:-1]))[0] x = numpy.take(x, idx) y = numpy.take(y, idx) x.shape = -1, 1 if numpy.allclose(x, x0): # no need for interpolation pass else: # we have to interpolate x.shape = -1 y.shape = -1 xi = x0[:] y = SpecfitFuns.interpol([x], y, xi, y0.min()) y.shape = -1 tmpArray[:, i] = y i += 1 # now perform the median filter for i in range(nChannels): medianSpectra[i, :] = medfilt1d(tmpArray[i,:], kernel_size=width) tmpArray = None # now get the final spectrum y = medianSpectra.sum(axis=1) / nCurves x0.shape = -1 y.shape = x0.shape legend = "%d Median from %s to %s" % (width, curves[0][2], curves[-1][2]) self.addCurve(x0, y, legend=legend, info=None, replot=True, replace=True)