When trying to make an optimized version of my plotRange
function I faced a problem of catching the "Preemptive"
evaluations generated by the FrontEnd from withing the main evaluation loop.
Consider the following:
ClearAll["Global`*"]
xr[r__] := (xRange = {r}; None);
yr[r__] := (yRange = {r}; None);
nb = CreateDocument[{Plot[Sin[x], {x, 0, 6 Pi}, Ticks -> {xr, yr}]}];
{xRange, yRange}
Pause[1];
{xRange, yRange}
NotebookClose[nb]
{xRange, yRange}
{{-0.392699, 19.2423}, {-1.04167, 1.04167}}
One can see that the first evaluation of {xRange, yRange}
returns undefined symbols because at the moment of its evaluation the functions xr
and yr
are still not evaluated via a "Preemptive"
link by the FrontEnd. But after waiting one second these functions are already evaluated and xRange
, yRange
are defined. Because I need these values for further evaluations I need to delay the main loop until the "Preemptive"
evaluations will be done. (An alternative solution would be to force the FrontEnd to perform its evaluations in the main loop.)
One possible way to solve the problem is to initiate a Dialog
which will wait for the Return
generated by the FrontEnd. But "Preemptive"
evaluations go past the Dialog
and do not allow the return from it (the following code freezes the kernel):
Dialog[xr[r__] := (xRange = {r}; None);
yr[r__] := (yRange = {r}; None; NotebookClose[nb];
Return[{xRange, yRange}]);
nb = CreateDocument[{Plot[Sin[x], {x, 0, 6 Pi},
Ticks -> {xr, yr}]}];]
Is it possible to catch the "Preemptive"
evaluations from the main loop in some way?
UPDATE
Here is a comparison of my original Rasterize
-based version and the new FinishDynamic
-based:
gr = Plot[Sin[x], {x, 0, 6 Pi}];
plotRange[plot : (_Graphics | _Graphics3D)] :=
Quiet@Last@
Last@Reap[
Rasterize[
Show[plot, PlotRangePadding -> None, Axes -> True,
Ticks -> (Sow[{##}] &), DisplayFunction -> Identity],
ImageResolution -> 1]]
Table[plotRange[gr], {100}]; // AbsoluteTiming
plotRange[plot : (_Graphics | _Graphics3D)] :=
Quiet@Last@
Last@Reap[(nb =
CreateDocument[{Show[plot, Axes -> True,
Ticks -> (Sow[{##}] &), PlotRangePadding -> None,
DisplayFunction -> Identity]}, ShowCellBracket -> False,
WindowFrame -> "Frameless", WindowElements -> {},
WindowSize -> 1, Antialiasing -> False, Editable -> False,
Magnification -> 1, Saveable -> False,
WindowClickSelect -> False, WindowFloating -> False,
WindowFrameElements -> {}, WindowMovable -> False,
WindowSelected -> False, WindowTitle -> ""];
FinishDynamic[]; NotebookClose[nb])]
Table[plotRange[gr], {100}]; // AbsoluteTiming
{2.828125, Null}
{8.406250, Null}
The original Rasterize
-based version is 3 times faster.
Answer
After the dynamic evaluation (in this case, your plot) has been displayed to the screen but before you wish to access the variables, evaluate:
FinishDynamic[];
Note that this function isn't selective. It will force every Dynamic
in the entire system to update before it continues.
Comments
Post a Comment