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.
{{-0.392699, 19.2423}, {-1.04167, 1.04167}}from both of the two evaluations. My system: v9 on win7 64bit. – Silvia Jan 24 '13 at 00:17Dynamicevaluations. Those orderings are specifically not guaranteed by Mathematica. – John Fultz Jan 24 '13 at 11:21Reap[Rasterize[Show[plot, Ticks -> (Sow[{##}] &)]]][[2, 1]]do not guarantee that the ordering of ranges will always be standard:{xRange, yRange}and sometimes one can get{yRange, xRange}? – Alexey Popkov Jan 25 '13 at 13:29Ticksfunction, which is acting like aDynamicin this case (even though noDynamicwas specified, it's resolved in a similar fashion), might be evaluated at any time relative to the ordering of the Shift+Enter evaluations. It might happen before theCreateDocumenthas finished evaluation, or shortly thereafter, or a very long time thereafter. That's why it behaves differently on different machines...because there is no guarantee...it's just evaluating when it can. – John Fultz Jan 31 '13 at 08:31