10
$\begingroup$

In the last 10 years (see this post) when I want to track the result of a longer calculation, I use the following pattern:

SetAttributes[progressBar,HoldFirst]
progressBar[i_,total_]:= Module[{},
    Echo@Dynamic@Row[
        {ProgressIndicator[i,{0,total}]," ",NumberForm[100.i/total,{\[Infinity],2}],"% ",i}
    ]
]

so I can monitor a function as follows, using progressBar

progressExample[data_List]:= Module[{i = 0,len = Length@data},
    progressBar[i,len];
    Scan[(i++;Pause[0.1];f[#])&,data]
]
progressExample[Range[10]]

enter image description here

The problem is that this code crashes for long runs, I think because of the use of Dynamic. Some idea for a better way to do that? Any suggestions for a more modern or native solution?

$\endgroup$
5
  • 2
    $\begingroup$ Have you reported the crash to the support? $\endgroup$ Commented Aug 13, 2022 at 3:57
  • $\begingroup$ I think almost any solution will need to use Dynamic in some way. So if you are experiencing crashes that you want to prevent, we'll need some kind of example to reproduce them. $\endgroup$
    – Lukas Lang
    Commented Aug 13, 2022 at 13:01
  • 3
    $\begingroup$ Also, have you seen ResourceFunction["MonitorProgress"]? $\endgroup$
    – Lukas Lang
    Commented Aug 13, 2022 at 13:02
  • $\begingroup$ @LukasLang, this it very interesting. Excellent tip. 🤜🏻 $\endgroup$
    – Murta
    Commented Aug 13, 2022 at 13:51
  • 1
    $\begingroup$ If the crash is reliably reproducible we'd definitely like to have an example that shows it. (I guess this is paradoxically asking for reliable unreliability.) $\endgroup$ Commented Aug 17, 2022 at 8:51

2 Answers 2

9
$\begingroup$

If you are willing to explicitly insert a call inside your computation loop to a progress updating small function, then you can do this in much simpler way without using Dynamics at all.

It is not a progress indicator, but prints the progress % only. It only uses PrintTemporary. So you have to make this explicit call anywhere in your code you want to update the progress. I would put it at the bottom of the loop for example.

Video

enter image description here

Code

CurrentValue[$FrontEnd, {"PrintAction"}] = {"PrintToNotebook"}
progressBar[currentValue_?NumericQ, maxValue_?NumericQ] := Module[{per},
      NotebookDelete[temp]; 
      per = Row[{NumberForm[100. currentValue/maxValue, {∞, 2}], "% "}];
      temp = PrintTemporary[per];
  ]


progressExample[data_List] := Module[{i = 0, len = Length@data},
      Scan[
            (i++; Pause[0.2];
              progressBar[i, len];
              f[#]) &, data
        ]
   ];

progressExample[Range[60]]

Version that uses PrintTemporary with ProgressIndicator

This version adds the actual bar, but still does not use Dynamics. Only PrintTemporary

progressBarV2[currentValue_?NumericQ, maxValue_?NumericQ] := Module[{per},
      NotebookDelete[temp]; 
      per = Row[{Spacer[5], NumberForm[100. currentValue/maxValue, {∞, 2}], "%"}];
      temp = PrintTemporary@Row[{ProgressIndicator[currentValue, {0, maxValue}], per}]
  ]

So just call the above V2 instead. This is the result

enter image description here

$\endgroup$
1
  • 1
    $\begingroup$ While this doesn't use Dynamic, it does perform notebook manipulation (printing and deleting cells). And in my experience, cell creation can be worse for performance than a suitably optimized dynamic expression. But of course, if the Dynamic expressions are actually causing the crash, this might help. (Assuming the repeated cell creation doesn't upset the front-end even more) $\endgroup$
    – Lukas Lang
    Commented Aug 13, 2022 at 13:23
3
$\begingroup$
progressBar[i_, high_] := Module[{},
  Row[{
    ProgressIndicator[i, {0, high}],
    Spacer[10], i,
    " (", NumberForm[100. i/high, {\[Infinity], 2}], "%)"
    }]
  ]

progressExample[data_List] := Module[{i = 0, len = Length@data},
  Monitor[
   Scan[(i++; Pause[0.1]; f[#]) &, data],
   progressBar[i, len]
   ]
  ]

progressExample[Range[150]]
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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