Code covered by the BSD License  

Highlights from
multiWaitbar( label, varargin )

4.86111

4.9 | 38 ratings Rate this file 80 Downloads (last 30 days) File Size: 27.6 KB File ID: #26589
image thumbnail

multiWaitbar( label, varargin )

by

 

04 Feb 2010 (Updated )

A new "shiny" progress-bar with multiple bars in a single window, time-estimates and more.

| Watch this File

File Information
Description

This function provides a new progress-bar (waitbar in MATLAB-speak) with the following features:
 * Multiple bars in one window
 * Robust to the window being closed
 * Time-estimates for long-running tasks
 * Completion percentage for long-running tasks
 * Control of the color for each bar
 * Textured bars (pointless, but nice)
 * No need to keep/manage window handles
 * Cancel tasks using a return flag or callback function
 * "Busy mode" where a bar bounces back and forth
Note that this incurs roughly the same computational overhead as the built-in WAITBAR for low numbers of iterations and usually less overhead for high numbers of iterations.

Requires MATLAB R2009a or above.

Acknowledgements

This file inspired Waitbar Time Remaining.

MATLAB release MATLAB 7.9 (R2009b)
MATLAB Search Path
/
Tags for This File   Please login to tag files.
Please login to add a comment or rating.
Comments and Ratings (61)
13 Nov 2014 Jonas Asprion

The command "flip" was introduced in R2013b as a more efficient version of "flipdim". I suggest to include a try-catch construction which first tries "flip" and in case of an error uses "flipdim" (or "fliplr", in the case of flip(M,2) as it is used here).

[The more 'clean' way of using "verLessThan" is extremely slow (~5.000x slower than try-catch).]

06 Nov 2014 Timo Dörsam

I had an error with call of flip() r2012a - "Undefined function" and replaced that line.

06 Nov 2014 Timo Dörsam  
03 Oct 2014 Andrei Veldman

Excellent utility! There is a bug however with 'ResetCancel' (noticed already by Bryant Svedin in 2013). In order for it to work as intended, I'd suggest adding at line 196 "needs_update = true;"; otherwise, the new value of entries(idx).Cancel is not saved in AppData.

12 Aug 2014 Luis Camilo

Hi Ben, you have a new version so that you can integrate your code in a GUI?

07 Jul 2014 Ben

The speed-up compared to the built-in waitbar is great, thank you!

18 Jun 2014 Adam Wyatt

Excellent!

I observed the same bug (or similar) as David - 04/11/13 to do with not updating the % correctly.

A couple of additions would be nice:
1) Option to return the figure handle - useful in some circumstances (e.g. to force the window to the front / edit some properties.
2) To be able to embed the multiWaitbar inside a different parent object (e.g. user defined figure / panel).

06 Jan 2014 Echidna

I like this tool a lot and managed to get it to work very easily. However, I wanted three different processes to run simultaneous (as now one function has to terminate before the next starts calculation so there is always only one waitbar progressing) so I am using the parallel computing toolbox and run three functions in batch. Now the progress on the multiwaitbar is not updated anymore so there is no means to check how far the process has progressed. Because it takes a long time, this is really required for my application so I was wondering if it was possible to make the multiwaitbar to work when using batch to run the function where it is called. If this is inherently impossible, please let me know so that I do not spend any more time on it. Any suggestion would be welcome to tackle this problem in a different way.

29 Dec 2013 Nikolay S.

Very nice visually, and easy to use. The time measurement, is not very exact. For fast iteration counting (percentage) and time estimation start a bit late...

09 Dec 2013 Amir Pasha  
09 Dec 2013 Amir Pasha

Great Job!!!

04 Nov 2013 David

Very useful, thank you... but there might be a bug in the current version:
In some cases, when I change the value, the bar changes, but the percent-value does not...

many thanks,
David

try this as an example:

multiWaitbar( 'Task 1', 'Value', 0);
pause(1.5); multiWaitbar( 'Task 1', 'Value', 0.15); % Task 1 still at (0%)
pause(1.5); multiWaitbar( 'Task 1', 'Value', 0.3); % Task 1 still at (0%)
pause(1.5); multiWaitbar( 'Task 2', 0.5, 'Color', 'b' ); % Task 1 gets (30%)
pause(1.5); multiWaitbar( 'Task 1', 'Value', 0.45 ); % Task 1 gets (45%)
pause(1.5); multiWaitbar( 'Task 1', 'Value', 0.6 ); % Task 1 gets (60%)
pause(1.5); multiWaitbar( 'Task 2', 'Value', 0.75 );
pause(1.5); multiWaitbar( 'Task 1', 'Reset'); % Task 1 still at (60%)
pause(1.5); multiWaitbar( 'Task 1', 'Value', 0.2); % Task 1 still at (60%)
pause(1.5); multiWaitbar( 'Task 2', 'Close' ); % Task 1 gets (20%)
pause(1.5); multiWaitbar( 'Task 1', 'Close' );

31 Oct 2013 Brian Katz

Very useful, especially the time estimator. Well done, and well supported.

25 Oct 2013 Katja

Very nice and useful progress bar!
Good point there Marc G. I would also like to change the label of each progress bar. I wanted to display the elapsed time.
Looking forward to your update!
Katja

24 Oct 2013 Ben Tordoff

I've submitted an update that fixes the interp issue, centres the window and adds a 'relabel' command. It should appear here within the next few days.

Ben

23 Oct 2013 Marc G

Thanks! Very useful and easy to use.

I would love to be able to update the label of a given entry (for example to be able to give more information like "Simulation in progress... [Current year: 2012 / Current month: 10]") without destroying it and recreating it.

I am thinking to a command like "UpdateLabel".

I understand that it would not be a straightforward change to the code, given that it seems that the Label is used to define the entry. But if I find enough time later I may try to dig into the code and decorrelate the label text from the entry in order to make it updateable.

Thanks again!

22 Oct 2013 Igor

Hm,since R2013b Matlab complains about interpolation method:

>> multiWaitbar('aaa',1)
Warning: INTERP1(...,'CUBIC') will change in a future release. Use INTERP1(...,'PCHIP') instead.
> In interp1>sanitycheckmethod at 283
In interp1>parseinputs at 420
In interp1 at 81
In multiWaitbar>iMakeColors at 389
In multiWaitbar>iAddEntry at 413
In multiWaitbar at 128

It looks like this file needs another update...

03 Aug 2013 Mohammed Diab

It is great!, but, why the progress bar is not centered in the screen?, I think it is better if you add the following few lines at beginning of the figure creation and in the function iCreateFig

FigSize = [300 800]; % figure size
ScreenSize = get(0,'ScreenSize');
xpos = ceil((ScreenSize(3)-FigSize(2))/2); % center the figure on the screen horizontally
ypos = ceil((ScreenSize(4)-FigSize(1))/2); % center the figure on the screen vertically
fobj.Position = [xpos, ypos, sz(2), sz(1)];

26 Jul 2013 Paolo  
18 Jul 2013 Right Grievous

Really nice piece of code. I was wondering though - is there a way to reposition the bar window? On my screen it pops up right over the command line so it hides any output from the running script, I can move it but I would like to make it automatic. Thanks.

20 Jun 2013 Bryant Svedin

I love this, but I am having trouble with the cancel function. I can't get the 'ResetCancel' to work. Example

multiWaitbar( 'Task 1', 0, 'CanCancel', 'on' );
for ii=1:15
abort = multiWaitbar('Task 1', ii/15);
if abort
yesno = questdlg('Are you sure you want to cancel?', ...
'Cancel', ...
'Yes','No','No');
if strcmp(yesno,'Yes'), break;
else
pause( 1 )
multiWaitbar('Task 1', ii/15, 'ResetCancel');
end
else
pause( 1 )
end
end
multiWaitbar( 'Task 1', 'Close' );

It gives the following error when this code is run and no is selected after trying to cancel.

??? Error using ==> multiWaitbar>iParseInputs at 276
Additional properties must be supplied as property-value pairs

Error in ==> multiWaitbar at 145
[params,values] = iParseInputs( varargin{:} );

15 May 2013 Alexandre Willame

Perfect

05 May 2013 Suraj Kamya

Awesome

21 Mar 2013 Joel

This waitbar is great!
To make the window always appear in the center of the screen, I modified the 'Resize' section as shown below since I couldn't figure out a way to get the figure handle of the waitbar. Is there any simpler way to do this? I'm new to MatLab, so I'm suspecting that I might have over complicated things.

% Resize
fobj = handle( f );
screenSize = get(0, 'ScreenSize');
xCord = screenSize(3)/2 - 180;
yCord = screenSize(4)/2 - 21;
fobj.Position(1:4) = [xCord yCord 360 42];
setappdata( fobj, 'ProgressEntries', [] );

21 Mar 2013 Joel  
22 Feb 2013 Ben Tordoff

Good spot Dan, I'll add that in the next update - thanks!

21 Feb 2013 Dan K

Very nice, albeit with one bug. If one has defaultWindowStyle set to docked, you get some very interesting effects... I would suggest adding:

'WindowStyle','normal',...

At line 293

08 Jan 2013 Ben Tordoff

Hi Jerome, that's a good suggestion. Ideally it should update the labels whenever they change (which may be more often than the bar updating) but it seems that the computation of the remaining time is itself worth avoiding. Avoiding updating the labels when the bar hasn't moved is a reasonable compromise. I'll add it.

07 Jan 2013 Jerome Lecoq

Fantastic tool!
I think it could be improved further by limiting the call to remaining time calculation.

Adding 'if updated' between the remaining time block in iUpdateEntry makes thing much faster when using this in a large loop.

14 Aug 2012 Sebastian Holmqvist

Excellent! It was just what I needed and the example included sets it right up!

09 Jul 2012 Timo_Eberle  
28 Jun 2012 Kevin Claytor

Fantastic and easy to use.

07 Jun 2012 Paul

Works great!!! Thanks.

07 Jun 2012 Ben Tordoff

Hi Paul, this is going to take a bit of explaining, but to cut to the chase, try this:

function testme
multiWaitbar('CloseAll');
multiWaitbar('One', 0, 'CanCancel', 'on', 'CancelFcn', @callback );
multiWaitbar('Two', 0, 'CanCancel', 'on', 'CancelFcn', @callback );

drawnow()
cleanupFigObj = onCleanup(@() multiWaitbar('CloseAll'));
pause
end

function callback(a,~)
disp( ['Cancel ',a] )
end

The main problem you were hitting is that the anonymous functions you use in the callbacks (i.e. the @(a,b)) cause the "cleanup" object to be held in-scope (i.e. it never gets deleted and therefore never "cleans-up"). If you use internal or external functions for your callbacks rather than nested or anonymous ones (i.e. functions defined outside of the function you're working in) then this doesn't happen.

That's probably clear as mud, but try the code and let me know. Hopefully this restriction won't be too onerous.

Cheers. Ben

06 Jun 2012 Paul

Ben, thanks for the file, I really like your implemntation of the progress bar. I'm currently using it for a 2-part progress bar, however I'm having difficulty implementing the cleanup function. Is it possible to use a variant of

cleanupFigObj = onCleanup(multiwaitbar('CloseAll'));

to close the multiwaitbar upon function exit? I was able to close one (and only one) of my two progress bars using a function handle to multiwaitbar such as:

fh = @multiWaitbar;
fh('CloseAll');
fh('One', 0, 'Color', [1.0 0.4 0.0], 'CancelFcn', @(a,b) disp( ['Cancel ',a] ));
fh('Two, 0, 'Color', [0.1 0.5 0.8], 'CancelFcn', @(a,b) disp( ['Cancel ',a] ));
cleanupFigObj = onCleanup(fh('CloseAll'));

Do you have any suggestions? Thanks.

02 May 2012 NDC  
13 Dec 2011 Ben Tordoff

The simple answer would be:

multiWaitbar('Progress',0);
for uio=1:480
...
multiWaitbar('Progress',uio/480);
end
multiWaitbar('Progress','close');

I wouldn't worry too much about calling it lots of times - it doesn't update unless the progress bar would visibly change. If you find it is taking a measurable amount of time then surround the inner call with something like

if mod(uio,10)==0
multiWaitbar('Progress',uio/480);
end

That will make it update every tenth iteration of your outer loop.

Cheers. Ben

13 Dec 2011 karan

So I played around with it and i ran it in the command window a couple of times.
I have another question.How can i use it within a for-loop
For eg:
My for loop structure is shown below.Now since there are 480 times this loop is going to be run.How can i add your multiwaitbar showing an increment of 10% after 'uio' computes the loop every 48 times.

To elaborate more.
when uio = 96 (finished) multiwaitbar should show 20%
when uio = 192 (finished) multiwaitbar should show 40%
....etc

for uio = 1:480
for i = 1:uio
for j = 1:num_periods
if time(i,1)>= ((time_per).*(j-1)) && time(i,1) < (time_per*(j))
travel_column(uio)= j;

end
j=j+1;
end

i=i+1;
end
uio=uio+1;
end

Many thanks for your assistance.

13 Dec 2011 karan

Hi Ben, I am just trying to use it for its main purpose i.e
to show it while something is running.

Now lets say I have 10 blocks(parts) of code which more importantly are not in a for-loop structure and after every part i want to popup the multiwaitbar such that it shows the progress by an increment of 0.1 or 10%.

How can I achieve this in my GUI Window??

13 Dec 2011 Ben Tordoff

Hi Karan, when you say "integrate" what do you mean? Are you just trying to show it/hide it whilst something is running or are you trying to embed the bars themselves into your GUI window? (the latter isn't possible in any sane way right now). If you can explain a bit more I (or someone else here) can probably give you some guidance.

12 Dec 2011 karan

Hi I am making my first GUI and I would like to add this in my GUI, however the code in this tool is way beyond my knowledge in matlab.
It would be really appreciated if somebody can give me some tips on how to integrate/use it successfully with my GUI

07 Dec 2011 Rossella Blatt Vital

A very well done function! Very simple to use, yet with many options and really looking good!
Great job!

20 Nov 2011 DBS

Great!

18 Nov 2011 DBS

Great.

04 Nov 2011 Igor

Well, I think I got it.

One need to add getappdata(..) to the very end of iAddEntry(..)
=======================================
if strcmpi( get( parent, 'Visible' ), 'on' )
iRedraw( parent, [] );
else
set( parent, 'Visible', 'on' );
end
entries = getappdata( parent, 'ProgressEntries' ); % added to keep background
end % iAddEntry
======================================

04 Nov 2011 Igor

Jeroen van Nugteren,

Nice hint, but it seem to result in loss of bar background (for me at least).

Screenshot:
http://img37.imageshack.us/img37/3816/capture2fef.png

had you solved this?

11 Sep 2011 Andrey Babkin

Nice, stable and simple.

28 Jul 2011 Jeroen van Nugteren

Awesome waitbar.

To prevent the waitbar from jumping back to its original position (in matlab 2011a and maybe other editions) I added drawnow to the first few lines of the iRedraw function.

fobj = handle( fig );
drawnow;
p = fobj.Position;

18 Jul 2011 Ashvin  
23 Jun 2011 Sherif

Fantastic work. Thank you.

18 Jun 2011 Jorrit  
23 Aug 2010 Ben Tordoff

Hi Igor, thanks for the comments. I've just submitted a new version that fixes the focus-grabbing - that was a bug, sorry. This should appear here within the next day or two. Cheers. Ben

22 Aug 2010 Igor

Great job!
yet lastest (Updated 29 Jul 2010) version steals focus where previous one didn't... so I prefer to use previous one...
also, as a suggestion... To reduce overlap in loops like
===============================
for ....
multiWaitbar( label, varargin )
....
for ...
multiWaitbar( label2, varargin2 )
....
end
end
===========================

inner multiWaitbar(...) may be replaed with something like

===============================================
function multiWaitbarT( varargin )

persistent multiWaitbarT_tic
min_refresh_t=0.1;

res=cellfun(@isscalar,varargin);

if (~any(res)) ||...
isempty(multiWaitbarT_tic) ||...
toc(multiWaitbarT_tic)>=min_refresh_t

multiWaitbar(varargin{:});
multiWaitbarT_tic=tic();
end

end
================================================
this seem to reduce overlap up to ~20x, and can be useful if execution time varies strongly in test/release runs....

multiWaitbar(varargin{:});
multiWaitbarT_tic=tic();
end

end

For example, this code:
====================================================

N=10^2;

%% strict
t=tic();

for i=1:N
multiWaitbar('l1',i/N,'Color', [0.2 0.9 0.3]);
for j=1:N
multiWaitbar('l2',j/N,'Color', [0.2 0.9 0.3]);
end
end
multiWaitbarT('l1','Close');
multiWaitbarT('l2','Close');
disp(['strict:' num2str(toc(t))]);

%% T
t=tic();

for i=1:N
multiWaitbar('l1',i/N,'Color', [0.2 0.9 0.3]);
for j=1:N
multiWaitbarT('l2',j/N,'Color', [0.2 0.9 0.3]);
end
end
multiWaitbarT('l1','Close');
multiWaitbarT('l2','Close');
disp(['T:' num2str(toc(t))]);
====================================================
results in:

strict:38.4253
T:1.1701

====================================================
Thanks for great tool!

29 Jul 2010 Ben Tordoff

Hi Sander, you're right. I forgot to turn off integer handles, so even though the figure handle is not visible it can still be clobbered. This is fixed in the update I'm about to submit. Should be with you within the next day or two.

Cheers
Ben

28 Jul 2010 Sander van Delden

Hi Ben,

Look great, works great but.....
I think there is a small bug.
When a figure in a loop is called h = figure(1) then the progress bar disappears (were h is whatever handle). Naming a figure: h = figure(10) prevents this bug from happening.

then (ofcourse) looping a figure: h = figure(j) has this problem also

it maybe your choice but "close all" also closes the progress bar. I would let your build in LABEL comment close do this and not the general close all. But that is a choice...I think the previous is a bug?

cheers,
Sander

26 Jul 2010 Bryant Svedin

Works Perfect. Thank you

25 Jun 2010 Ben Tordoff

Hi Gordon,

There are two ways to set the value and I think your code mixes the two - you are incrementing by ever larger factors! Because you increment by 'k/1000' rather than '1/1000' your total value by the end will be over 500, rather than 1. Here are the two ways the multiWaitbar should be used:

% Set value directly
for k=1:1000
multiWaitbar( 'Task 1', k/1000 )
end

% Set by increment
for k=1:1000
multiWaitbar( 'Task 2', 'Increment', 1/1000 )
end

Let me know if you have problems with either of these, or I have missed some subtlety in the problem you're having.

Cheers.
Ben

25 Jun 2010 Gordon

Looks good, but It doesn't seem to work well with small increments, unless I am missing something.
For the code below, the progress bar finishes much earlier than the main loop.

multiWaitbar( 'Task 1',0);
for k=1:1000
multiWaitbar( 'Task 1','Increment',k/1000 );
pause(0.01)
fprintf('%d / %d <%1.4f>\n',k,1000,k/1000);
drawnow
end

22 Jun 2010 Jim Crozier  
13 Jun 2010 John de Leon  
28 Apr 2010 Joseph Kirk

This is *exactly* what I was looking for! I wanted a waitbar that could get called by various functions (so that I could have an "overall progress" bar along with progress updates for various subroutines) without having to pass handles around everywhere. This does all that and more... I'm really impressed (and glad I checked the File Exchange before attempting my own version). Rate it a 6!

Updates
12 May 2010

2010-05-12: Significant (~20%) speed improvement

18 Jun 2010

Fix highlight markers at 10% intervals (were wrong way round)
Shade background

29 Jul 2010

* Add ability to cancel using return flag or callback function
* Don't lose bar properties if the window gets closed
* Prevent the window being accidentally clobbered

23 Aug 2010

* Don't grab focus unless currently hidden

26 Jun 2012

This update should hopefully fix some of the long-standing graphical glitches when moving or resizing the window. Thanks to Igor for testing this!

21 Dec 2012

* Add ability to set a bar into "busy" mode where it bounces back and forth

08 Jan 2013

* Don't update text labels if bar didn't move. This gives around a 20% speed-up in some cases.

27 Jun 2013

* Fix updating of percentage indication
* Fix ResetCancel command

29 Oct 2013

* Allow labels to be changed ('relabel')
* Use 'pchip' interpolation instead of 'cubic'

06 Oct 2014

* Fix bug with ResetCancel
* Improve compatibility with MATLAB R2014b

Contact us