progress indicator without dynamic
Here is one approach, based on @b3m2a1's excellent answer here:
Attributes[StaticMonitor] = {HoldAll};
UpdateMonitor[] := Null;
StaticMonitor[expr_, mon_] :=
Block[
{UpdateMonitor, boxID = ToString@Unique[]},
PrintTemporary[RawBoxes@TagBox[ToBoxes@mon, boxID, BoxID -> boxID]];
UpdateMonitor[] := FrontEndExecute@FrontEnd`BoxReferenceReplace[
FE`BoxReference[
FE`Evaluate@FrontEnd`EvaluationNotebook[],
{{boxID}},
FE`BoxOffset -> {FE`BoxChild[1]}
],
ToBoxes@mon
];
expr
]
Since we can't rely on Dynamic
to automatically trigger updates, we need to call UpdateMonitor[]
to force the update. The actual updating is done by replacing the contents on the cell created by PrintTemporary
using the BoxReference*
utilities explained in this answer. One could also replace the entire cell created by PrintTempoary
, but that leads to undesirable flashing of the scrollbar.
Here is how it looks like in action:
StaticMonitor[
Table[
[email protected];
UpdateMonitor[];
i,
{i, 10}
],
ProgressIndicator[i, {0, 10}]
]
The folllowing solution is based on some functionalities of https://github.com/Ludwiggle/JWLS_2
In particular, we borrow the webListenerF
function, the refresh
function and the refresh.wl
file from the JWLS_2 project.
refresh.wl
is a StringTemplate
that the refresh
function uses to create a dynamic HTML page; such HTML page will serve as our monitor/progress indicator.
What you need:
- Download the template from https://github.com/Ludwiggle/JWLS_2/blob/master/JWLS_2_kernel/refresh.wl and put it in your working directory.
- Copy the
webListenerF
function definition from line 55 to line 77 of https://github.com/Ludwiggle/JWLS_2/blob/master/JWLS_2.sh - Copy the
refresh
function definition from line 139 to 144 of the sameJWLS_2.sh
script above
Usage Example
Let's say you have some computation in a loop and you want to monitor the value of a variable g
:
First of all, activate the socket with SocketListen[5859, webListenerF]
.
Then create and open the HTML page that monitors the value of g
with refresh[HoldForm @ g] // SystemOpen
.
Now you can start your loop process where g
gets updated, something like
Clear[g,k]
k = {RandomReal[]};
While[True,
AppendTo[k, RandomReal[]];
g = ListLinePlot[k, PlotMarkers -> {Automatic, 10}];
[email protected]]
Check your browser and enjoy.
Cons: It works outside the notebook interface.
Pros: It works without the notebook interface.
Notes:
The refresh
function takes the page refresh interval in milliseconds as a second argument.
For smoother animations, modify the webListenerF
to export rasters instead of vector graphics. Then add the proper HTML tags in the template.
For maximum efficiency and smoothness, define the whole computation inside refresh
, so that the kernel executes your code while synchronously serving the javascript client.
If something goes wrong try to close and reopen the socket.