Code covered by the BSD License  

Highlights from
GUI for Multivariate Image Analysis of 4-dimensional data

image thumbnail
from GUI for Multivariate Image Analysis of 4-dimensional data by Kateryna Artyushkova
Multivariate Image Analysis of 4-dimensional image sequences using 2-step two-way and three-way ...

progressbar(action, varargin)
function [varargout] = progressbar(action, varargin)
%PROGRESSBAR Display, modify, and/or update a progress indicator
%   PROGRESSBAR is a comprehensive progress indicator for long or
%   repetitive calculations.  It allows the user to display any
%   title or message, the start time, the elapsed time, and an
%   estimate of the time remaining, as well as progress - all
%   while comsuming minimal execution time.
%
%   PROGRESSBAR is a multi-function fuction, where the first
%   argument is an action string specifying what function to
%   carry out:
%
%   H = PROGRESSBAR is the same as H = PROGRESSBAR('create').
%
%   H = PROGRESSBAR('create', ['TITLE'], ['MESSAGE']) creates
%   and initializes the progress indicator.  The figure name is 
%   given 'TITLE', and 'MESSAGE' is placed in the text field
%   above the bar.  The progress bar is placed at 0, the
%   refresh rate is set to .1 seconds, and the stop signal is
%   set to 0. In addition, the status string, containing start
%   time, elapsed time, estimated time left, and percent complete
%   are all initialized (NOTE: the elapsed time is set to
%   '??:??:??' since no estimate can be made yet).
%
%   For the remaining functions (except internal ones), the
%   figure handle H must be the second arguement passed, right
%   after the action string.
%
%   PROGRESSBAR('cancelbutton', H, ['CALLBACK']) creates a cancel
%   button that changes the stop signal (defined as the STATUS
%   field '.stop' - see below) to 1, when the cancel button is
%   pressed, as well as executing 'CALLBACK' if it is specified
%   (NOTE: pushing the cancel button does not prevent further
%   execution of calls to PROGRESSBAR, it simply sets the stop
%   signal to 1.  You can check on the status of the stop signal
%   with the action string 'status' - see definition below).
%
%   PROGRESSBAR('update', H, X) first checks to see if the last
%   update was over the refresh rate seconds ago.  If it was,
%   then the bar is set to X, where X is the fractional
%   completion (NOTE: X is forced to the interval [0, 1]).  In 
%   addition, the status string is updated to reflect changes in
%   the elapsed and estimated times, as well as the percent
%   complete.
%
%   PROGRESSBAR('message', H, 'MESSAGE') replaces the current
%   message text (the text field above the bar) with 'MESSAGE'
%   (NOTE: there is enough room for three to four lines of text
%   in the message field on most screen resolutions - use
%   SPRINTF with '\n' for newline).
%
%   PROGRESSBAR('title', H, 'TITLE') replaces the current title
%   text (the figure name) with 'TITLE' (NOTE: unlike the
%   message field, there is only room for one line of text).
%
%   PROGRESSBAR('refresh', H, NEWRATE) replaces the current
%   refresh rate (in seconds) with NEWRATE.  This value controls
%   how quickly the meter and status strings can be updated.
%   Setting a low value (such as .0001) provides very detailed
%   progress information, but can slow the execution loop because
%   too much time is spent updating PROGRESSBAR.  Setting a high
%   value (such as 5) minimizes PROGRESSBAR's execution time, but
%   may be too corse a measure of progress.  The default value of
%   .1 seems to be a fairly optimal balance, but this function is
%   provided so that the rate can be arbitrarily set.
%
%   PROGRESSBAR('kill', H) closes the progress indicator.  All
%   status information is lost (NOTE: If you want this
%   information before killing the indicator, use the action
%   string 'status' - see below).
%
%   STATUS = PROGRESSBAR('status', H) returns a structure
%   containing all information pertinent to the progress
%   indicator:
%       .winscale = the scale factor used to create all UI
%       objects so that they remain fairly consistant across
%       different screen resolutions.
%
%       .X = the fractional completion (between [0, 1])
%
%       .stop = stop signal (becomes 1 when cancel button is
%       pressed)
%
%       .refresh = refresh rate (in seconds)
%
%       .h = UI graphics handles:
%           .pbar = progress indicator figure handle (H)
%           .message = message text handle
%           .status = status string text handle
%           .axes = bar axes handle
%           .line = bar line handle
%           [.cancelbutton] = cancel button handle (if called)
%
%       .time = date vectors for status string (NOTE: some
%       date vectors have 0's for the yr/mo/day spots - this
%       function doesn't care about them, meaning that these
%       times become inaccurate if the calculations take longer
%       than 99:59:59):
%           .start = start time
%           .current = current time
%           .elapsed = elapsed time = etime(.current, .start)
%           .estimated = estimated time
%           
%   DATEVEC = PROGRESSBAR('sec2time', T) is an internal function
%   that returns a date vector DATEVEC corresponding T seconds.
%
%   TIMESTR = PROGRESSBAR('time2str', DATEVEC) is an internal
%   function that returns a 'HH:MM:SS' time string corresponding
%   to DATEVEC.  It tries to correct for min/sec overflows, and
%   returns '??:??:??' if the DATEVEC = [0 0 0 0 0 0] or it
%   contains negative values or is greater than 99:59:59.
%

%   Created 2/7/2004 by:
%   Ajay Nemani
%   Center for Magnetic Resonance Research
%   University of Illinois at Chicago
%   aneman1@uic.edu
%
%   
%  %


%If no inputs given, assume create function
if nargin == 0
    action = 'create';
end

switch lower(action)
    
    
case 'create'
%Create and intialize display
%useage: h = progressbar('create', 'Title', 'Message')
    
    if nargin < 3
        varargin{2} = 'Default Message';
    end
    if nargin < 2
        varargin{1} = 'Default Title';
    end
    
    if ~ischar(varargin{1}) | ~ischar(varargin{2})
        error('2nd and/or 3rd inputs must be strings');
    end



    %Initialize UserData structure
    tmp = get(0, 'ScreenSize'); %This m-file was created on a 1600x1200 display,
    ud.winscale = tmp(3)/1600;  %so position vectors are scaled by winscale
    ud.time.start = clock;
    ud.time.current = clock;
    ud.time.elapsed = progressbar('sec2time', ...
                                  etime(ud.time.current, ud.time.start) ...
                                 );
    ud.time.estimated = [0 0 0 0 0 0];
    
    ud.X = 0;           %Fraction completed (forced to [0 1])
    ud.stop = 0;        %Stop signal
    ud.refresh = .1;    %Maximum refresh rate (in seconds)

    %Create figure
    ud.h.pbar = figure( ...
        'Tag',                  'Progress Bar', ...
        'Resize',               'off', ...
        'Color',                get(0, 'DefaultUicontrolBackgroundColor'), ...
        'DoubleBuffer',         'on', ...
        'Selected',             'off', ...
        'NumberTitle',          'off', ...
        'IntegerHandle',        'off', ...
        'MenuBar',              'none', ...
        'Units',                'pixels', ...
        'Position',             ([500 500 600 150] * ud.winscale), ...
        'Visible',              'on' ...
    );

    %Create message string
    ud.h.message = uicontrol( ...        
        'Tag',                  'Message Text', ...
        'Style',                'text', ...
        'TooltipString',        '', ...
        'Enable',               'on', ...
        'Callback',             [], ...
        'Units',                'pixels', ...
        'Position',             ([5 85 590 60] * ud.winscale), ...
        'Parent',               ud.h.pbar, ...
        'SelectionHighlight',   'off', ...
        'Selected',             'off', ...
        'FontName',             'FixedWidth', ...
        'FontSize',             get(0, 'DefaultUicontrolFontSize'), ...
        'FontUnits',            'pixels', ...
        'Visible',              'on' ...
    );

    %Create status string
    ud.h.status = uicontrol( ...        
        'Tag',                  'Status Text', ...
        'Style',                'text', ...
        'String',               [], ...
        'TooltipString',        '', ...
        'Enable',               'on', ...
        'Callback',             [], ...
        'Units',                'pixels', ...
        'Position',             ([5 5 590 50] * ud.winscale), ...
        'Parent',               ud.h.pbar, ...
        'SelectionHighlight',   'off', ...
        'Selected',             'off', ...
        'FontName',             'FixedWidth', ...
        'FontSize',             get(0, 'DefaultUicontrolFontSize'), ...
        'FontUnits',            'pixels', ...
        'Visible',              'on' ...
    );

    %Create progress bar axes
    ud.h.axes = axes( ...
        'Tag',                  'Progress Bar Axes', ...
        'Units',                'pixels', ...
        'Box',                  'on', ...
        'Color',                [1 1 1], ...
        'DrawMode',             'fast', ...
        'HitTest',              'off', ...
        'Layer',                'top', ...
        'NextPlot',             'ReplaceChildren', ...
        'Parent',               ud.h.pbar, ...
        'Position',             ([5 60 590 20] * ud.winscale), ...
        'Selected',             'off', ...
        'SelectionHighlight',   'off', ...
        'TickLength',           [.005 0], ...
        'Visible',              'on', ...
        'XLim',                 [0 1], ...
        'XTick',                [.25 .50 .75], ...
        'XTickLabel',           [], ...
        'YLim',                 [0 2], ...
        'YTick',                [], ...
        'YTickLabel',           [], ...
        'PlotBoxAspectRatio',   [1 .025 1] ...
    );

    %Create progress bar filler - thick line works fastest
    ud.h.line = line( ...
        'Tag',                  'Progress Bar Line', ...
        'Color',                [1 0 0], ...
        'EraseMode',            'normal', ...
        'HitTest',              'off', ...
        'LineStyle',            '-', ...
        'LineWidth',            1000, ...
        'Marker',               'none', ...
        'Parent',               ud.h.axes, ...
        'Selected',             'off', ...
        'SelectionHighlight',   'off', ...
        'Visible',              'on', ...
        'XData',                [0 ud.X], ...
        'YData',                [1 1] ...
    );        

    set(ud.h.pbar, 'UserData', ud);

    %Set approprate fields by making initial update
    progressbar('title', ud.h.pbar, varargin{1});
    progressbar('message', ud.h.pbar, varargin{2});
    progressbar('update', ud.h.pbar, ud.X);
        
    varargout{1} = ud.h.pbar;
    
    
case 'cancelbutton'
%Create cancel button
%usage: progressbar('cancelbutton', h)
    
    ud = get(varargin{1}, 'UserData');
    
    %Create default callback
    cancelcallback = ['set(get(gcbo, ''Parent''), ' ...
                           '''UserData'', ' ...
                           'setfield(get(get(gcbo, ''Parent''), ''UserData''), ' ...
                                     '''stop'', ' ...
                                     '1' ...
                                   ')' ...
                         '); ' ...
                     ];
    
    %Append user callback
    if nargin == 3
        cancelcallback = [cancelcallback varargin{2}];
    end
    
    %Shift all object in figure up
    tmph=get(ud.h.pbar, 'Children');
    tmppos = get(tmph, 'Position');
    for n = 1:length(tmph)
        set(tmph(n), ...
            'Position', ...
            (tmppos{n}/ud.winscale + [0 60 0 0]) * ud.winscale ...
           );
    end
    clear tmph tmppos n;
    
    %Resize figure to make room for cancel button
    set(ud.h.pbar, ...
        'Position', ...
        (get(ud.h.pbar, 'Position')/ud.winscale + [0 0 0 60]) * ud.winscale ...
       );
    
    %Create cancel button in new space
    ud.h.cancelbutton = uicontrol( ...        
        'Tag',                  'Cancel Button', ...
        'Style',                'pushbutton', ...
        'String',               'Cancel', ...
        'TooltipString',        '', ...
        'Enable',               'on', ...
        'Callback',             cancelcallback, ...
        'Units',                'pixels', ...
        'Position',             ([200 10 200 50] * ud.winscale), ...
        'Parent',               ud.h.pbar, ...
        'SelectionHighlight',   'off', ...
        'Selected',             'off', ...
        'FontName',             'FixedWidth', ...
        'FontSize',             1, ...
        'FontUnits',            'pixels', ...
        'Visible',              'on' ...
    );
    drawnow;
    
    set(ud.h.pbar, 'UserData', ud);
       
    
case 'update'
%update display (if necessary)
%usage: progressbar('update', h, X)
    
    ud = get(varargin{1}, 'UserData');
    
    %Calculate delta X and delta time
    oldX = ud.X;
    oldtime = ud.time.current;
    newX = min(max(varargin{2}, 0), 1); %Force input X to be between 0 and 1
    newtime = clock;
    difftime = etime(newtime, oldtime);
    diffX = newX - oldX;
    
    %if last update was more than refresh rate seconds ago, 
    %or if X is 100% or 0%, then update, else do nothing
    if (difftime >= ud.refresh) | (newX == 1) | (newX == 0)
        
        %Update appropriate UserData fields
        ud.time.current = newtime;
        ud.time.elapsed = progressbar('sec2time', etime(ud.time.current, ud.time.start));
        if diffX < eps  %The estimate will be too large, so set to 0's -> ??:??:??
            ud.time.estimated = [0 0 0 0 0 0];
        else %Linear estimate
            ud.time.estimated = progressbar('sec2time', (difftime/diffX)*(1-newX));
        end        
        ud.X = newX;
        set(ud.h.pbar, 'UserData', ud);
        
        %Update status string and progress bar
        statusstr = [ ...
            'Start:     ' ...
                progressbar('time2str', ud.time.start) ...
                sprintf('\t') ...
            'Elapsed:   ' ...
                progressbar('time2str', ud.time.elapsed) ...
                sprintf('\n') ...
            'Estimated: ' ...
                progressbar('time2str', ud.time.estimated) ...
                sprintf('\t') ...
            'Completed: ' ...
                sprintf(' %06.2f%%', ud.X*100) ...
        ];    
        
        set(ud.h.line, 'XData', [0 ud.X]);
        set(ud.h.status, 'String', statusstr);
        drawnow;

    end
            

case 'message'
%Change message
%usage: progressbar('message', h, 'Message')

    ud = get(varargin{1}, 'UserData');
    set(ud.h.message, 'String', varargin{2});    

    
case 'title'
%Change title
%usage: progressbar('title', h, 'Title')

    set(varargin{1}, 'Name', varargin{2});    

    
case 'refresh'
%Change refresh rate (default is .1 sec)
%useage: progressbar('refresh', h, refreshrate)

    ud = get(varargin{1}, 'UserData');
    ud.refresh = varargin{2};
    set(ud.h.pbar, 'UserData', ud);

    
case 'status'
%Get status (UserData) structure
%usage: status = progressbar('status', h)

    %Yes, this is redundant, but it is included for completeness.
    varargout{1} = get(varargin{1}, 'UserData');
    
        
case 'kill'
%Close progressbar
%usage: progressbar('kill', h)

    %Yes, this is redundant as well...
    close(varargin{1});

    
case 'sec2time'
%Convert seconds (usually from etime) to datevector
%usage: datevec = progressbar('sec2time', t)
    
    %We don't care about month/day/year, so...
    varargout{1} = [0 ...
                    0 ...
                    0 ...
                    floor(varargin{1}/3600) ...
                    mod(floor(varargin{1}/60), 60) ...
                    mod(varargin{1}, 60) ...
                   ];

               
case 'time2str'
%Convert datevector to HH:MM:SS time string
%usage: timestr = progressbar('time2str', datevec)
    
    if any(varargin{1}(5:6) > [60 60]) %Make corrections for min/sec overflow
        varargin{1} = progressbar('sec2time', sum(varargin{1}(4:6) .* [3600 60 1]));
    end
    
    %Return '??:??:??' for invalid datevectors
    if all(varargin{1}(4:6) == 0) ...
       | any(varargin{1} < 0) ...
       | any(varargin{1} > [Inf Inf Inf 99 60 60])   
        varargout{1} = ['??:??:??'];
    else %If everything is legit, return HH:MM:SS string
        varargout{1} = sprintf('%02.0f:%02.0f:%02.0f', ...
                                varargin{1}(4), ...
                                       varargin{1}(5), ...
                                              varargin{1}(6) ...
                              );
    end
    
        
otherwise
    error('Unrecognized action');
    
    
end
               
        

Contact us at files@mathworks.com