Progress bars can be used to track long-running matlab programs where alternatives (e.g. displaying progress information in the console) are infeasible.
Progress bars can be group in windows, and organized independently or as a stack (for e.g. nested for-loops). Each bar displays a parameter name, the current value of that parameter out of a maximum, and an estimated remaining time for that bar.
The code is OO, so progress bar windows are created with
pr = Progress();
Organizing bars as a (FILO) stack makes it easier to add, update, and remove them:
pr.push_bar('parameter name', min, max);
where pr.set(value) sets the bar at the top of the stack. Alternatively, bars can be updated by name:
pr.set('parameter name', value);
and reset to their minimum value:
At each call to pr.set, timing data is collected, and a polynomial is fitted to the data, giving a good estimation of remaining time for processes that are of complexity O(N) or O(N^2). Higher degree polynomials can be used if a task is known not to be in these classes.
Closing a progress bar window manually (i.e. clicking on the X) produces an error - similar to ctrl-c.
The package also includes an automatic code generation tool for adding progress functionality with minimum fuss. This pre-processes an annotated matlab script and adds the necessary boilerplate code. Scripts can be annotated like this:
reptitions = 40;
for i=1:repititions %%p1
parameters_values = [1 2 3 5 10];
for j=1:numel(parameter_values) %%p2
where %%p# indicates a level of nesting, that will be reflected in the progress bar stack.
Furthermore, by including a (slightly awkward-looking) line at the top of a script:
the annotated script can be run as normal (i.e. by typing the script name) and the pre-processing will be invoked automatically - emitting the script with added boilerplate code into a temporary file, then executing this file in the base workspace, then deleting it. This makes the addition of progress bars quite transparent.
The latest addition to the functionality is that some custom code can now be executed upon request during execution. For example, when finding some results in a 100-repetition loop, we could include some code to plot the results for all of the repetitions so far. This lets us check up on the experiment whenever we like (e.g. see the results for the first 10 repetitions), without having to regularly plot graphs or wait until the entire experiment is complete. This can be easily achieved by adding this at the end of the original script:
for current_value=1:100 %%p1
results(current_value) = experiment(current_value);
%%finalise (this tag shows that all the following code should be executed when a button is pressed)
Lots of additional documentation and an example script are included.
Richard Stapenhurst (2020). Progress Bars (https://www.mathworks.com/matlabcentral/fileexchange/28179-progress-bars), MATLAB Central File Exchange. Retrieved .
Very impressed. Minimum of extra coding needed to make it work with nested for loops.
Great feature using comments. Very clever.
+1 to including within functions. If possible it would be nice to control the progress bar within nested functions using only comments too. Not sure if this is possible.
Very nice submission. One small correction that's needed is to change "pr.set" to "pr.set_val" in the example in your above description.
Thank you very much for your suggestions Jason, I have submitted an updated version.
Documentation suggestion: you give no example of creating a progress bar manually. I had to look through the methods one by one to figure out what to call.
Additionally, because the set method is typically inherited from the handle class, I completely passed over this method when exploring, causing me to miss THE most important method for using the progress bars. Had I been advising you, I would have suggested using a function name of set_bar or something else to avoid such a name conflict. Nonetheless, because of this I strongly suggest some example in the main help so we can know how to get up and running.
As the description says, the pre-processing only works for scripts. I could modify it to accommodate functions/classes, but I'd be surprised if this was regularly useful.
However, it is possible to manually add a progress bar in non-script scenarios as described in the first paragraph of the description.
I will add support for pre-processing of functions to my to-do list :)
This works great for simple scripts, but I am unable to get this to work with my GUIs or any script that has multiple functions in the same m-file.
Thanks for your feedback Donald, if you could send me your test file then I can take a closer look at it.
It's possible that there is an error in your original test.m file.
When boilerplate code is added, a new file ("test_pr.m" in this case) is created and executed. Therefore, any errors in the original file (test.m) will be reported from the modified file (test_pr.m).
Ideally, I would like to catch and modify any exception thrown in test_pr.m so that it the stack trace and line numbers refer to code in test.m; if any MATLAB wizard knows if this is possible, I would be thrilled to know how! (I would want to be able to generate an exception that looks like it came from a specific line in a specific file)
For some reason, I keep getting the following error:
??? Error: File: test_pr.m Line: 50 Column: 25
Unbalanced or unexpected parenthesis or bracket.
Error in ==> prog at 47
Error in ==> test at 1
However, it does work with other simple loop examples and is very nice!
As per Jason's suggestion, added an example (progress_example2.m) to show how to add progress bar code without annotations. Also renamed the function "Progress.set(value)" to "Progress.set_val(value)" to avoid a conflict between it and handle.set.
Added support for executing some custom code by pressing a button on the progress bars. This code can do something useful, like displaying partial results of an experiment.
Fixed some bugs that Donald Lacombe identified. Will now work for for-loops written with semicolons (for i=1:10;) and for very large loop parameters for (i=1:1000000).
Updated the example script so it no longer requires the stats toolbox
Interim progress tracking, with granular updates based on the task complexity estimation, updating the remaining time and progress twice per second, to give the illusion of progress!