def testStep(self): """Test fit manager on a step function with a more complex estimate function than the gaussian (convolution filter)""" for theory_name, theory_fun in (('Step Down', sum_stepdown), ('Step Up', sum_stepup)): # Create synthetic data with a sum of gaussian functions x = numpy.arange(1000).astype(numpy.float64) # ('Height', 'Position', 'FWHM') p = [1000, 439, 250] constantbg = 13 y = theory_fun(x, *p) + constantbg # Fitting fit = fitmanager.FitManager() fit.setdata(x=x, y=y) fit.loadtheories(fittheories) fit.settheory(theory_name) fit.setbackground('Constant') fit.estimate() params, sigmas, infodict = fit.runfit() # first parameter is the constant background self.assertAlmostEqual(params[0], 13, places=5) for i, param in enumerate(params[1:]): self.assertAlmostEqual(param, p[i], places=5) self.assertAlmostEqual( _order_of_magnitude(fit.fit_results[i + 1]["estimation"]), _order_of_magnitude(p[i]))
def testFitManager(self): """Test fit manager on synthetic data using a gaussian function and a linear background""" # Create synthetic data with a sum of gaussian functions x = numpy.arange(1000).astype(numpy.float64) p = [1000, 100., 250, 255, 650., 45, 1500, 800.5, 95] linear_bg = 2.65 * x + 13 y = linear_bg + sum_gauss(x, *p) y_with_nans = numpy.array(y) y_with_nans[::10] = numpy.nan x_with_nans = numpy.array(x) x_with_nans[5::15] = numpy.nan tests = { 'all finite': (x, y), 'y with NaNs': (x, y_with_nans), 'x with NaNs': (x_with_nans, y), } for name, (xdata, ydata) in tests.items(): with self.subTest(name=name): # Fitting fit = fitmanager.FitManager() fit.setdata(x=xdata, y=ydata) fit.loadtheories(fittheories) # Use one of the default fit functions fit.settheory('Gaussians') fit.setbackground('Linear') fit.estimate() fit.runfit() # fit.fit_results[] # first 2 parameters are related to the linear background self.assertEqual(fit.fit_results[0]["name"], "Constant") self.assertAlmostEqual(fit.fit_results[0]["fitresult"], 13) self.assertEqual(fit.fit_results[1]["name"], "Slope") self.assertAlmostEqual(fit.fit_results[1]["fitresult"], 2.65) for i, param in enumerate(fit.fit_results[2:]): param_number = i // 3 + 1 if i % 3 == 0: self.assertEqual(param["name"], "Height%d" % param_number) elif i % 3 == 1: self.assertEqual(param["name"], "Position%d" % param_number) elif i % 3 == 2: self.assertEqual(param["name"], "FWHM%d" % param_number) self.assertAlmostEqual(param["fitresult"], p[i]) self.assertAlmostEqual(_order_of_magnitude(param["estimation"]), _order_of_magnitude(p[i]))
def test(): from silx.math.fit import fittheories from silx.math.fit import fitmanager from silx.math.fit import functions from silx.gui.plot.PlotWindow import PlotWindow import numpy a = qt.QApplication([]) x = numpy.arange(1000) y1 = functions.sum_gauss(x, 100, 400, 100) fit = fitmanager.FitManager(x=x, y=y1) fitfuns = fittheories.FitTheories() fit.addtheory(name="Gaussian", function=functions.sum_gauss, parameters=("height", "peak center", "fwhm"), estimate=fitfuns.estimate_height_position_fwhm) fit.settheory('Gaussian') fit.configure( PositiveFwhmFlag=True, PositiveHeightAreaFlag=True, AutoFwhm=True, ) # Fit fit.estimate() fit.runfit() w = ParametersTab() w.show() w.fillFromFit(fit.fit_results, view='Gaussians') y2 = functions.sum_splitgauss(x, 100, 400, 100, 40, 10, 600, 50, 500, 80, 850, 10, 50) fit.setdata(x=x, y=y2) # Define new theory fit.addtheory(name="Asymetric gaussian", function=functions.sum_splitgauss, parameters=("height", "peak center", "left fwhm", "right fwhm"), estimate=fitfuns.estimate_splitgauss) fit.settheory('Asymetric gaussian') # Fit fit.estimate() fit.runfit() w.fillFromFit(fit.fit_results, view='Asymetric gaussians') # Plot pw = PlotWindow(control=True) pw.addCurve(x, y1, "Gaussians") pw.addCurve(x, y2, "Asymetric gaussians") pw.show() a.exec_()
def _testPoly(self, poly_params, theory, places=5): p = numpy.poly1d(poly_params) y = p(self.x) fm = fitmanager.FitManager(self.x, y) fm.loadbgtheories(bgtheories) fm.loadtheories(fittheories) fm.settheory(theory) esti_params = fm.estimate() fit_params = fm.runfit()[0] for p, pfit in zip(poly_params, fit_params): self.assertAlmostEqual(p, pfit, places=places)
def testQuarticcBg(self): gaussian_params = [10000, 69, 25] poly_params = [5e-10, 0.0005, 0.005, 2, 4] p = numpy.poly1d(poly_params) y = p(self.x) + sum_gauss(self.x, *gaussian_params) fm = fitmanager.FitManager(self.x, y) fm.loadtheories(fittheories) fm.settheory("Gaussians") fm.setbackground("Degree 4 Polynomial") esti_params = fm.estimate() fit_params = fm.runfit()[0] for p, pfit in zip(poly_params + gaussian_params, fit_params): self.assertAlmostEqual(p, pfit, places=5)
def testCubicBg(self): gaussian_params = [1000, 45, 8] poly_params = [0.0005, -0.05, 3, -4] p = numpy.poly1d(poly_params) y = p(self.x) + sum_gauss(self.x, *gaussian_params) fm = fitmanager.FitManager(self.x, y) fm.loadtheories(fittheories) fm.settheory("Gaussians") fm.setbackground("Degree 3 Polynomial") esti_params = fm.estimate() fit_params = fm.runfit()[0] for p, pfit in zip(poly_params + gaussian_params, fit_params): self.assertAlmostEqual(p, pfit)
def testLoadCustomFitFunction(self): """Test FitManager using a custom fit function defined in an external file and imported with FitManager.loadtheories""" # Create synthetic data with a sum of gaussian functions x = numpy.arange(100).astype(numpy.float64) # a, b, c are the fit parameters # d is a known scaling parameter that is set using configure() a, b, c, d = 1.5, 2.5, 3.5, 4.5 y = (a * x**2 + b * x + c) / d # Fitting fit = fitmanager.FitManager() fit.setdata(x=x, y=y) # Create a temporary function definition file, and import it with temp_dir() as tmpDir: tmpfile = os.path.join(tmpDir, 'customfun.py') # custom_function_definition fd = open(tmpfile, "w") fd.write(custom_function_definition) fd.close() fit.loadtheories(tmpfile) tmpfile_pyc = os.path.join(tmpDir, 'customfun.pyc') if os.path.exists(tmpfile_pyc): os.unlink(tmpfile_pyc) os.unlink(tmpfile) fit.settheory('my fit theory') # Test configure fit.configure(d=4.5) fit.estimate() fit.runfit() self.assertEqual(fit.fit_results[0]["name"], "A1") self.assertAlmostEqual(fit.fit_results[0]["fitresult"], 1.5) self.assertEqual(fit.fit_results[1]["name"], "B1") self.assertAlmostEqual(fit.fit_results[1]["fitresult"], 2.5) self.assertEqual(fit.fit_results[2]["name"], "C1") self.assertAlmostEqual(fit.fit_results[2]["fitresult"], 3.5)
def _setFitManager(self, fitinstance): """Initialize a :class:`FitManager` instance, to be assigned to :attr:`fitmanager`, or use a custom FitManager instance. :param fitinstance: Existing instance of FitManager, possibly customized by the user, or None to load a default instance.""" if isinstance(fitinstance, fitmanager.FitManager): # customized fitmngr = fitinstance else: # initialize default instance fitmngr = fitmanager.FitManager() # initialize the default fitting functions in case # none is present if not len(fitmngr.theories): fitmngr.loadtheories(fittheories) return fitmngr
def main(args): from silx.math.fit import fittheories from silx.math.fit import fitmanager try: from PyMca5 import PyMcaDataDir except ImportError: raise ImportError("This demo requires PyMca data. Install PyMca5.") import numpy import os app = qt.QApplication(args) tab = Parameters(paramlist=['Height', 'Position', 'FWHM']) tab.showGrid() tab.configureLine(name='Height', estimation='1234', group=0) tab.configureLine(name='Position', code='FIXED', group=1) tab.configureLine(name='FWHM', group=1) y = numpy.loadtxt( os.path.join(PyMcaDataDir.PYMCA_DATA_DIR, "XRFSpectrum.mca")) # FIXME x = numpy.arange(len(y)) * 0.0502883 - 0.492773 fit = fitmanager.FitManager() fit.setdata(x=x, y=y, xmin=20, xmax=150) fit.loadtheories(fittheories) fit.settheory('ahypermet') fit.configure(Yscaling=1., PositiveFwhmFlag=True, PositiveHeightAreaFlag=True, FwhmPoints=16, QuotedPositionFlag=1, HypermetTails=1) fit.setbackground('Linear') fit.estimate() fit.runfit() tab.fillFromFit(fit.fit_results) tab.show() app.exec_()
def testAddTheory(self, estimate=True): """Test FitManager using a custom fit function imported with FitManager.addtheory""" # Create synthetic data with a sum of gaussian functions x = numpy.arange(100).astype(numpy.float64) # a, b, c are the fit parameters # d is a known scaling parameter that is set using configure() a, b, c, d = -3.14, 1234.5, 10000, 4.5 y = (a * x**2 + b * x + c) / d # Fitting fit = fitmanager.FitManager() fit.setdata(x=x, y=y) # Define and add the fit theory CONFIG = {'d': 1.} def myfun(x_, a_, b_, c_): """"Model function""" return (a_ * x_**2 + b_ * x_ + c_) / CONFIG['d'] def myesti(x_, y_): """"Initial parameters for iterative fit: (a, b, c) = (1, 1, 1) Constraints all set to 0 (FREE)""" return (1., 1., 1.), ((0, 0, 0), (0, 0, 0), (0, 0, 0)) def myconfig(d_=1., **kw): """This function can modify CONFIG""" CONFIG["d"] = d_ return CONFIG def myderiv(x_, parameters, index): """Custom derivative""" pars_plus = numpy.array(parameters, copy=True) pars_plus[index] *= 1.001 pars_minus = numpy.array(parameters, copy=True) pars_minus[index] *= 0.999 delta_fun = myfun(x_, *pars_plus) - myfun(x_, *pars_minus) delta_par = parameters[index] * 0.001 * 2 return delta_fun / delta_par fit.addtheory( "polynomial", FitTheory(function=myfun, parameters=["A", "B", "C"], estimate=myesti if estimate else None, configure=myconfig, derivative=myderiv)) fit.settheory('polynomial') fit.configure(d_=4.5) fit.estimate() params1, sigmas, infodict = fit.runfit() self.assertEqual(fit.fit_results[0]["name"], "A1") self.assertAlmostEqual(fit.fit_results[0]["fitresult"], -3.14) self.assertEqual(fit.fit_results[1]["name"], "B1") # params1[1] is the same as fit.fit_results[1]["fitresult"] self.assertAlmostEqual(params1[1], 1234.5) self.assertEqual(fit.fit_results[2]["name"], "C1") self.assertAlmostEqual(params1[2], 10000) # change configuration scaling factor and check that the fit returns # different values fit.configure(d_=5.) fit.estimate() params2, sigmas, infodict = fit.runfit() for p1, p2 in zip(params1, params2): self.assertFalse( numpy.array_equal(p1, p2), "Fit parameters are equal even though the " + "configuration has been changed")