6
$\begingroup$

Often, curve fitting is very sensitive to starting values of parameters. It would be great, if I could to find such starting values of parameters "by hand" using Manipulate.

So, I plot in Manipulate my experimental data points and theoretical curve. I can change the shape of this curve by changing all parameters in manipulate in such way that they approximate my experimental data relatively well. Now I would like to run fitting using current parameters in Manipulate as starting values. Finally I would like to insert the parameters found by fitting back into Manipulate.

Here is example code for simple function. My data is more complex.

data = Table[{x, 8 x^3 - 7 x^2 - 10 x + 1 + RandomReal[{-5, 5}]}, {x, -2, 2, 0.1}];
Manipulate[
 Show[
  Plot[a x^3 + b x^2 + c x + d, {x, -2, 2}],
  ListPlot[data]
 ],
 {a, -10, 10},
 {b, -10, 10},
 {c, -10, 10},
 {d, -10, 10}
]
$\endgroup$
3
$\begingroup$

As I understand the question a curve fitting procedure that has the following properties is sought:

  1. Manually adjust the parameters to get an approximate fit.
  2. Use these parameters as the starting values for FindFit.
  3. Propagate the solution from FindFit back to the Manipulate parameters.
  4. Subsequently enable further editing of the Manipulate parameters and repeat the cycle.

The following code satisfies this criteria by wrapping Manipulate inside a DynamicModule and the use of a Button to indicate when FindFit should be run.

data = Table[{x, 8 x^3 - 7 x^2 - 10 x + 1 + RandomReal[{-5, 5}]}, {x, -2, 2, 0.1}];

DynamicModule[
 {
  sol
  },

 Manipulate[

  If[computeFlag == True,
   sol = FindFit[data, 
     aa x^3 + bb x^2 + cc x + 
      dd, {{aa, a}, {bb, b}, {cc, c}, {dd, d}}, x];
   {a, b, c, d} = {aa, bb, cc, dd} /. sol;
   computeFlag = False;
   ];

  Column[{
    Dynamic[
     Button["Compute",
      computeFlag = True
      ]
     ],
    Show[
     Plot[a x^3 + b x^2 + c x + d, {x, -2, 2},
      PlotStyle -> Black],
     ListPlot[data, PlotStyle -> Red],
     ImageSize -> 300,
     PlotRange -> {{-2.05, 2.05}, All}
     ]
    }],

  (*Manipulate variables*)
  {{computeFlag, False}, ControlType -> None},

  {{a, 1}, -10, 10, Appearance -> "Open"},
  {{b, 1}, -10, 10, Appearance -> "Open"},
  {{c, 1}, -10, 10, Appearance -> "Open"},
  {{d, 1}, -10, 10, Appearance -> "Open"}

  ] (* end of Manipulate *)
 ] (* end of DynamicModule *)

Below is a figure where the parameters have been manually adjusted.

Mathematica graphics

After clicking the Compute button FindFit propagates the solution back to the Manipulate parameters.

Mathematica graphics

The user is free to re-edit the Manipulate parameters and repeat the cycle.

$\endgroup$
1
$\begingroup$

Initalize:

data = Table[{x, 
    8 x^3 - 7 x^2 - 10 x + 1 + RandomReal[{-5, 5}]}, {x, -2, 2, 
    0.1}];
l = {a -> 1, b -> 1, c -> 1, d -> 1}

Now run the following code, you can change the settings and then re-evaluate and it will start with the new parameters.

aa = a /. l;
bb = b /. l;
cc = c /. l;
dd = d /. l;
l = FindFit[data, 
  a x^3 + b x^2 + c x + d, {{a, aa}, {b, bb}, {c, cc}, {d, dd}}, x]
Manipulate[aa = a; bb = b; cc = c; dd = d; 
 Show[Plot[a x^3 + b x^2 + c x + d, {x, -2, 2}], 
  ListPlot[data]], {{a, aa}, -10, 10}, {{b, bb}, -10, 
  10}, {{c, cc}, -10, 10}, {{d, dd}, -10, 10}]
$\endgroup$
1
$\begingroup$
dynamicFit[data_, expr_, pars_] :=
 With[{
   n = Length[pars],
   x1 = Min[First /@ data],
   x2 = Max[First /@ data]},
  DynamicModule[{pars2, fit, fitted = Null},
   pars2 = Table[Unique[], n];
   Do[pars2[[i]] = RandomReal[{-2, 2}], {i, n}];
   Column[{
     Sequence @@ Table[
       With[{i = i},
        Labeled[
         Slider[Dynamic[pars2[[i]]], {-10, 10}, 
          Appearance -> "Labeled",
          ImageSize -> 275], pars[[i]], Left]], {i, n}],
     Dynamic@Framed@Show[
        Plot[Evaluate[{expr[x] /. Thread[pars -> pars2], fitted}],
         {x, x1, x2}],
        ListPlot[data],
        ImageSize -> 300],
     Row[{
       Button["Fit",
        fit = FindFit[data, expr[x], Transpose[{pars, pars2}], x];
        fitted = expr[x] /. fit,
        ImageSize -> Automatic],
       Button["Export",
        exported = fitted,
        ImageSize -> Automatic]
       }]
     }]
   ]
  ]

Parameters are: data, model expr (as a Function) and model parameters pars (used in the model). Your arguments can be quite general as long as the data is 2D and model a function of one variable. Clear exported before invoking the routine, adjust parameters dynamically, try a fit, adjust some more ... eventually export the fit to exported.

test = Table[{x,
    x + Sin[3 x] + RandomReal[{-.5, .5}]}, {x, -3, 3, 0.1}];

exported = Null;
dynamicFit[test, Function[x, a x + Sin[b x]], {a, b}]

enter image description here

The fit resides in exported. This is a bit clumsy, I wish I knew how to do it better.

exported

0.995803 x + Sin[3.04859 x]

$\endgroup$
  • $\begingroup$ This is a very fine piece of work. One small error was the argument of ListPlot was test and should have been data. You could add fit or fitted or the to the row with the buttons to show the values of the fitted parameters. $\endgroup$ – Jack LaVigne Jul 13 '16 at 15:36
  • $\begingroup$ @JackLaVigne Thanks, test was a residue. Many features can be readily added if one wants. Also, the question asked for Manipulate, but I didn't use it because I find it generates a very complex dynamic structures which I don't understand as well as a custom dynamic object. $\endgroup$ – BoLe Jul 13 '16 at 18:57
0
$\begingroup$

After manipulation you will have value = {a,b,c,d}. Replotting is probably best done with a separate evaluation.

data = Table[{x, 8 x^3 - 7 x^2 - 10 x + 1 + RandomReal[{-5, 5}]}, {x, -2, 2, 0.1}];
Manipulate[
 values = {a,b,c,d};
 Show[
  Plot[a x^3 + b x^2 + c x + d, {x, -2, 2}],
  ListPlot[data]
 ],
 {a, -10, 10},
 {b, -10, 10},
 {c, -10, 10},
 {d, -10, 10}
]
$\endgroup$
  • $\begingroup$ I'm not sure I will be satisfied with fit. So I will move the parameters again by hands and thus go back to Manipulate, than again to Fit and so on.. That is why I would like to fit inside the Manipulate $\endgroup$ – Филипп Цветков Jul 11 '16 at 19:49
  • 2
    $\begingroup$ FindFit[] within a dynamic function is a bad idea. $\endgroup$ – Feyre Jul 11 '16 at 19:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.