No BSD License  

Highlights from
Another text Waitbar

image thumbnail

Another text Waitbar

by

 

03 Sep 2007 (Updated )

A text progressbar, faster than the graphical Matlab waitbar

progress(rate,title)
function n = progress(rate,title)
%PROGRESS   Text progress bar
%   Similar to waitbar but without the figure display.
%
%   Start:
%   PROGRESS('init'); initializes the progress bar with title 'Please wait...'
%   PROGRESS('init',TITLE); initializes the progress bar with title TITLE
%   PROGRESS(RATE); sets the length of the bar to RATE (between 0 and 1)
%   PROGRESS(RATE,TITLE); sets the RATE and the TITLE
%   PROGRESS('close'); (optionnal) closes the bar
%
%   Faster version for high number of loops:
%   The function returns a integer indicating the length of the bar.
%   This can be use to speed up the computation by avoiding unnecessary
%   refresh of the display
%   N = PROGRESS('init'); or N = PROGRESS('init',TITLE);
%   N = PROGRESS(RATE,N); changes the length of the bar only if different
%   from the previous one
%   N = PROGRESS(RATE,TITLE); changes the RATE and the TITLE
%   PROGRESS('close'); (optionnal) closes the bar
%
%   The previous state could be kept in a global variable, but it is a bit
%   slower and doesn't allows nested waitbars (see examples)
%
%   Known bug: Calling progress('close') shortly afer another call of the
%   function may cause strange errors. I guess it is because of the
%   backspace char. You can add a pause(0.01) before to avoid this.
%
%   Examples:
%       progress('init');
%       for i=1:100
%           progress(i/100, sprintf('loop %d/100',i));
%
%           % computing something ...
%           pause(.1)
%       end
%       progress('close'); % optionnal
%
%
%       % Inside a script you may use:
%       n = progress('init','wait for ... whatever');
%       for i=1:100
%           n = progress(i/100,n);
%
%           % computing something ...
%           pause(.1)
%       end
%       progress('close');
%
% 
%       % Add a time estimation:
%       progress('init','Processing...');
% 		tic       % only if not already called
% 		t0 = toc; % or toc if tic has already been called
% 		tm = t0;
% 		L  = 100;
% 		for i=1:L
% 			tt = ceil((toc-t0)*(L-i)/i);
% 			progress(i/L,sprintf('Processing... (estimated time: %ds)',tt));
% 
% 			% computing something ...
% 			pause(.1)
% 		end
% 		progress('close');
% 
% 
%       % Add a faster time estimation:
% 		n  = progress('init','Processing...');
% 		tic       % only if not already called
% 		t0 = toc; % or toc if tic has already been called
% 		tm = t0;
% 		L  = 100;
% 		for i=1:L
% 			if tm+1 < toc % refresh time every 1s only
% 				tm = toc;
% 				tt = ceil((toc-t0)*(L-i)/i);
% 				n  = progress(i/L,sprintf('Processing... (estimated time: %ds)',tt));
% 			else
% 				n  = progress(i/L,n);
% 			end
% 
% 			% computing something ...
% 			pause(.1)
% 		end
% 		progress('close');
%
%       % Nested loops:
%       % One loop...
% 		n1 = progress('init','Main loop');
% 		for i=0:7
% 			n1 = progress(i/7,n1);
% 
% 			% ... and another, inside the first one.
% 			n2 = progress('init','Inside loop');
% 			for j=0:50
% 				n2 = progress(j/50,n2);
% 
% 				% computing something ...
% 				pause(.01)
% 			end
% 			progress('close');
% 		end
% 		pause(.01)
% 		progress('close');

%   31-08-2007
%   By Joseph martinot-Lagarde
%   joseph.martinot-lagarde@m4x.org

%   Adapted from:
%   MMA 31-8-2005, martinho@fis.ua.pt
%   Department of Physics
%   University of Aveiro, Portugal

%% The simplest way to bypass it...
% n = 0; return

%% Width of the bar
%If changes are made here, change also the default title
lmax=50;

%% Erasing the bar if necessary
% not needed, but one could find it prettier
if isequal(rate,'close')
	% there were 3 '\n' added plus the title and the bar itself
	fprintf(rep('\b',2*lmax+3))
	return
end

%% The init
if isequal(rate,'init') % If in init stage
	cont = 0;           % we don't continue a previous bar
	back = '\n';        % add a blank line at the begining
	rate = 0;           % start from 0
else
	cont = 1;           % we continue a previous bar
end

%% No need to update the view if not necessary
% optional, but saves a LOT of time

% length of the displayer bar in number of char
% double([0,1]) to int([0,lmax-1])
n = min(max( ceil(rate*(lmax-2)) ,0),lmax-2);

% If the 2nd arg is numeric, assumed to be the previous bar length
if nargin >=2 && isnumeric(title)
	if n == title % If no change, do nothing
		return
	else          % otherwise continue
		n_ = title;
		clear title
	end
else % draw the whole bar
	n_ = -1;
end

%% The title
% If a new title is given, display it
if exist('title','var')
	Ltitle = length(title);
	if Ltitle > lmax % If too long, cut it
		title = [title(1:lmax) '\n']
	else             % otherwise center it
		title = [rep(' ',floor((lmax-Ltitle)/2)) title rep(' ',ceil((lmax-Ltitle)/2)) '\n'];
	end
	if cont % If not in init stage, erase the '\n' and the previous title
		back = rep('\b',lmax+1);
	end
else
	if cont % If not in init stage, give a void title
		title = '';
		back  = ''; % has to be set
	else    % else set a default title
		title = '                  Please wait...                  \n';
	end
end

%% The bar
% '\f' should draw a small square (at least in Windows XP, Matlab 7.3.0 R2006b)
% If not, change to any desired single character, like '*' or '#'
if ~cont || n_ == -1 % at the begining disp the whole bar
	str = ['[' rep('\f',n) rep(' ',lmax-n-2) ']\n'];
	if cont % If not in init stage, erase the previous bar
		back = [back, rep('\b',lmax+1)];
	end
else % draw only the part that changed
	str  = [rep('\f',n-n_) rep(' ',lmax-n-2) ']\n'];
	back = [back, rep('\b',lmax-n_)];
end

%% The print
% Actually make the change
fprintf([back title str]);
return

%% Function to repeat a char n times
function cout = rep(cin,n)
if n==0
	cout = [];
	return
elseif length(cin)==1
	cout = cin(ones(1,n));
	return
else
	d    = [1; 2];
	d    = d(:,ones(1,n));
	cout = cin(reshape(d,1,2*n));
	return
end

Contact us