Code covered by the BSD License  

Highlights from
Multi progress bar

4.90909

4.9 | 23 ratings Rate this file 113 Downloads (last 30 days) File Size: 8.51 KB File ID: #26589
image thumbnail

Multi progress bar

by Ben Tordoff

 

04 Feb 2010 (Updated 27 Jun 2013)

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 Gpu Bench.

MATLAB release MATLAB 7.9 (R2009b)
Tags for This File  
Everyone's Tags
gui(5), progress bar, waitbar
Tags I've Applied
Add New Tags Please login to tag files.
Please login to add a comment or rating.
Comments and Ratings (41)
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

Contact us