iminuit2.py 1.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243
  1. """Fit a 3D polynomial surface to a set of noisy data using iminuit.
  2. You can rotate the scene by dragging with the left mouse button."""
  3. from iminuit import Minuit
  4. from vedo import Points, Arrows2D, show, dataurl, printc, settings
  5. def func(x, y, *pars):
  6. # the actual surface model to fit
  7. a, b, c, u, v = pars
  8. z = c - ((x + u) * a)**2 - (y + v) * b
  9. return z
  10. def cost_fcn(pars):
  11. cost = 0.0
  12. for p in pts:
  13. x, y, z = p
  14. f = func(x, y, *pars)
  15. cost += (f - z)**2 # compute the chi-square
  16. return cost / pts.size
  17. # Load a set of points from a file and fit a surface to them
  18. points = Points(dataurl + "data_points.vtk").ps(6).color("k3")
  19. pts = points.coordinates
  20. # Run the fit (minimize the cost_fcn) and print the result
  21. m = Minuit(cost_fcn, [0.01, 0.05, 200, 550, 400]) # init values
  22. m.errordef = m.LEAST_SQUARES
  23. m.migrad() # migrad is a sophisticated gradient descent algorithm
  24. printc(m, c="green7", italic=True)
  25. # Create a set of points that lie on the fitted surface
  26. fit_pts = []
  27. for x, y, _ in pts:
  28. fit_pts.append([x, y, func(x, y, *m.values)])
  29. fit_pts = Points(fit_pts).ps(9).color("r5")
  30. lines = Arrows2D(pts, fit_pts, rotation=90).color("k5", 0.25)
  31. # Show the result of the fit with the original points in grey
  32. settings.use_parallel_projection = True
  33. show(points, fit_pts, lines, __doc__,
  34. axes=1, size=(1250, 750), bg2="lavender", zoom=1.4).close()