How can I make Plot show the plot while it's computing it?

Thanks to the links and tips provided by Mr.Wizard I found the answer I was looking for, with a combination of EvaluationMonitor and the undocumented Bag functionality.

Two problems with the code I found:

  1. For some reason updating the Bag object doesn't trigger the evaluation of a Dynamic expression containing it. I had to add another variable which changing value triggers the update of the plot.
  2. The code is not stable. For some reason, more often than not it crashes the Kernel. I have no idea whatsoever why it does this.

Here is an example code:

Dynamic[a;
 ListPlot[Sort@Internal`BagPart[bag, All], Joined -> True, 
  ImageSize -> Large, PlotRange -> {{0, 100}, {0, 0.2}}]
 ]

bag = Internal`Bag[]; a = False;
integral[x_] := Abs@NIntegrate[Exp[I x (t + t^2)], {t, 0, 1}];
Plot[
 integral[x],
 {x, 0, 100},
 DisplayFunction -> (Null &),
 EvaluationMonitor :> (Internal`StuffBag[bag, {x, integral[x]}]; 
   a = ! a),
 MaxRecursion -> 4
 ]

I would have liked to have it all in a nicely callable function, but I don't know (yet) how to make the Dynamic@ListPlot show before the rest of the code is executed.

Here is a short sample of how it works:

enter image description here

EDIT:

Here is a cleaner solution, inspired by the other answer (this is the function used to generate the above gif):

SetAttributes[dynamicPlot, HoldAll]
Options[dynamicPlot] = Join[Options[Plot], Options[Dynamic]];
dynamicPlot[f_, {x_Symbol, x0_, x1_}, opts : OptionsPattern[]] :=
  Module[{bag = Internal`Bag[]},
    PrintTemporary @ Dynamic[
      ListPlot[
        Sort @ Internal`BagPart[bag, All],
        Evaluate[Sequence @@ FilterRules[{opts}, Options[ListPlot]]]
      ],
      Evaluate[Sequence @@ FilterRules[{opts}, Options[Dynamic]]],
      UpdateInterval -> 0.01
    ];
    Plot[f, {x, x0, x1},
      EvaluationMonitor :> (Internal`StuffBag[bag, {x, f}]),
      Evaluate[Sequence @@ FilterRules[{opts}, Options[Plot]]]
    ]
  ];

Here is a only slightly different approach. As I think it probably isn't essential in that case to actually see every single point appearing on its own it might be much more efficient and user friendly to just update at a given period without the actual code having to wait for the update to finish. I have also added some option handling:

SetAttributes[dynamicPlot, HoldAll]

Options[dynamicPlot] = Join[Options[Plot], Options[Dynamic]];

dynamicPlot[f_, {x_Symbol, x0_Real, x1_Real}, 
  opts : OptionsPattern[]] := Module[{
   bag = Internal`Bag[]
   },
  PrintTemporary[
   Dynamic[ListPlot[Sort@Internal`BagPart[bag, All],
     Evaluate[Sequence @@ FilterRules[{opts}, Options[ListPlot]]]
     ], Evaluate[Sequence @@ FilterRules[{opts}, Options[Dynamic]]], 
    UpdateInterval -> 0.5
    ]
   ];
  Plot[f[x], {x, x0, x1},
   EvaluationMonitor :> (Internal`StuffBag[bag, {x, f[x]}]),
   Evaluate[Sequence @@ FilterRules[{opts}, Options[Plot]]]
   ]
]    

you can then call it like e.g.:

dynamicPlot[NIntegrate[Sin[t] Exp[-t] t^8, {t, 0, #}] &, {x, 0., 20.},
 MaxRecursion -> 4, PlotRange -> All, UpdateInterval -> 0.1
]  

it seems to be stable on my machine, but I don't exactly understand how it is different from your code in that respect, I use trigger variables as in your code often and that alone seems to not be a problem.

It is probably also worth noting that the bag local variable in that case is colored red by the frontend as it seems to escape the Module. It is not entirely clear to me when an expression printed with PrintTemporary will be deleted and what that means for the local bag. It seems that the last instance of that variable survives but will be cleaned by the garbage collection at the next possibility so there is never more than one of them floating around...


FWIW You can actually do this very simply with AppendTo:

a = {};
Monitor[Plot[y = Sqrt[x] Cos[1/x^(3/2)], {x, 0, 2},
  EvaluationMonitor :> (Pause[.01] ; AppendTo[a, {x, y}])], 
  ListPlot[a]]

enter image description here

I suppose if the function eval is so slow that you want to do this in the first place, you might not care about the performance hit associated with AppendTo.

I don't know if that might avoid the stability issue.

Tags:

Plotting