Code covered by the BSD License  

Highlights from
SUBFIGURE

image thumbnail
from SUBFIGURE by Matt Fig
SUBFIGURE creates figures in tiled positions.

subfigure(varargin)
function fh = subfigure(varargin)
%SUBFIGURE creates figures in tiled positions.
% H = SUBFIGURE(a,b,c) breaks the computer screen into an a-by-b matrix of 
% small figures, selects the c-th figure for the current figure, and 
% returns its handle.  The figures are counted along the top row of the 
% computer screen, then the second row, etc.  This is the same way that
% SUBPLOT tiles axes in a figure.  H is not returned if not requested.
% More than one figure can be created by calling SUBFIGURE with a cell of
% positions, or by specifying 'all' in the position argument.  If 'all' is
% called, this will be treated as if a cell {1:a*b} had been passed.  If
% more than one figure is created at a time, SUBFIGURE will create an axes
% object in each figure and H will have two columns.  Each row of H will
% contain the figure handle and corresponding axes handle.
% SUBFIGURE has a 37 pixel offset from the bottom of the screen built-in.  
% Since this is the first line of code, it is easily changed by the user 
% for their particular system if needed or desired.
%
% SUBFIGURE(a,b,'all') or SUBFIGURE(a,b,{1:a*b}) plots a*b figures
%      on screen in a a-by-b pattern.
% SUBFIGURE(a,b,C), where C is a vector, specifies a single figure position
%      that covers all the subfigure positions in C.
% SUBFIGURE(N,N,{1:N:N^2}) plots N figures on the left side of the screen.
% SUBFIGURE(N,N,1:N:N^2) plots one figure that covers the figures from the
%      previous example, in the left Nth of the screen.
% SUBFIGURE(N,N,{1:N}) plots N figures on the top of the screen.
% SUBFIGURE(N,N,1:N) plots one figure on the top Nth of the screen.
% SUBFIGURE(a,b,c,'replace') if a figure exists at position c, replaces it.
% SUBFIGURE(...,PROP1, VALUE1, PROP2, VALUE2, ...) sets the specified
% property-value pairs for the figure(s).  
% SUBFIGURE(5,5,{1:5:25},'menubar','none') plots 5 figures with no menubars
% on the left hand side of the screen, this can be useful when plotting 
% subfigures because the menubars can take up a lot of space (relatively).
%
% See also figure, subplot, close 
%
% Author:  Matt Fig
% Contact:  popkenai@yahoo.com      
% Date:  2/15/2009

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%% User editable offset from bottom of screen, in pixels.
offset = 37; % CHANGE THIS OFFSET FOR YOUR SYSTEM, IF NECESSARY OR DESIRED.
%%%%%%%%%%%%%%%%%%% User editable offset from bottom of screen, in pixels.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

if nargin<3  % Error checking.
    error('At least three input arguments are needed.  See help.')
end

pvpflag = false;  % Flag: property/value pairs passed in.
rpflag = false;   % Flag: user wanting to replace any figure in the way.
spflag = false;   % Flag: user wants no menus.
cellflag = false; % Flag: user passed in a cell for third argument.

switch nargin
    case 3
        [a,b,c] = varargin{:};  % The 'usual' case.
    case 4  % Could combine with otherwise, but this is a simpler case.
        [a,b,c,str] = varargin{:};  % User put replace, maybe.  Must check.
        
        if ischar(str) && strncmpi('replace',str,3) % User passed 'rep'*
            rpflag = true;
        else
            error('Unknown fourth option passed.  See help.')
        end
    otherwise
        pvpflag = true;  % User might have passed in property/value pairs.
        [a,b,c] = deal(varargin{1:3});   % Deal out dimensions.
        nmv = numel(varargin(4:end));
        strt = 4;
        if rem(nmv,2)  % Odd indicates user may have passed in 'replace'
            if strncmpi('replace',varargin{4},3)
              rpflag = true;
              strt = 5;
            else
                error('Unknown fourth option passed.  See help.')
            end
        end
        for ii = 1:numel(varargin(strt:end))
            if strncmpi('men',varargin{ii+strt-1},3) % Look 4 menubars off.
                if strncmpi('n',varargin{ii+strt},1) % 'menubar','none'
                    spflag = true;  % This affects the y spacing.
                    dfpos = getsp(spflag);%Y Spacing between figs: NO MENUS
                    break;
                end
            end
        end          
end

if ischar(c)
    if strcmpi(c,'all')
        c = {1:a*b};   % User wants entire grid plotted.
    else
        error('The third argument must be numeric or ''all'', See help.')
    end
end

if iscell(c)
    c = [c{:}];
    clen = length(c);
    cellflag = true;
else
    clen = 1;
end

if numel(a)>1 || numel(b)>1 || iscell(a) || iscell(b)  % Error checking.
    error('The first two arguments must be scalar.')
end

c = c(:)'; % Need a row vector.

if ~isnumeric([a,b,c]) || any([a,b,c]<1) || any(floor([a,b,c])~=[a,b,c])
   error('First 3 args must be (or contain) integers > 0.  See help.') 
end

if any(c>a*b)  % Error checking.
    error('The third arg cannot exceed the product of the first two.')
end

if ~spflag
    dfpos = getsp(spflag); % Y spacing between figs:  with MENUS.
end

rsp = dfpos(4);  % The absolute spacing between figures in row dir.
csp = dfpos(3);  % The absolute spacing between figures in col dir.
un = get(0,'units'); % Will reset at the end.
set(0,'units','pix');  % Work in common units.
scr = get(0,'screensize'); % For proper formatting.
xpwidth = (scr(3) - b * csp  - 2 )/b; % Width of figure.
ypheight = (scr(4) - a * rsp - offset + dfpos(2) )/a; % Height of figure.

if clen>1
    fh = zeros(clen,2);  % Pre-allocation.
else
    fh = zeros(clen,1);  % Pre-allocation.
end

for kk = 1:clen
    if ~cellflag  % A vector of locations.
        p = zeros(length(c),4);  % Pre-allocation.
        % We need the positions of the figures that would be here to find
        % the position of the figure that will cover the same area.
        for mm = 1:length(c)
            [ii,jj] = ind2sub([b,a],c(mm));  % Transpose: filling rows.
            xpleft = ii*csp + xpwidth*(ii-1) - (dfpos(1)-1); % Left side.
            ypbott = (a-jj)*rsp + ypheight*(a-jj) + offset; % Up by offset.
            p(mm,:) = [xpleft ypbott xpwidth ypheight]; % Position of fig.
        end
        
        [m1 i1] = min(p(:,1)); % The minimum x-value of all figures.
        [m2 i2] = min(p(:,2)); % The minimum y-value of all figures.
        [i3,i3] = max(p(:,1)); %#ok The maximum x-idx of all figures.
        [i4,i4] = max(p(:,2)); %#ok The maximum y-idx of all figures.
        posvect = [m1 m2 p(i3,1)-p(i1,1)+p(1,3) p(i4,2)-p(i2,2)+p(1,4)];
    else % A cell of locations.
        [ii,jj] = ind2sub([b,a],c(kk));  % Transpose: we are filling rows.
        xpleft = ii*csp + xpwidth*(ii-1)- (dfpos(1)-1); % Left side.
        ypbott = (a-jj)*rsp + ypheight*(a-jj) + offset; % Up by offset.
        posvect = [xpleft ypbott xpwidth ypheight]; % Position of figure.
    end

    if rpflag
        fh(kk,1) = figreplace(posvect);  % User wants to replace figure.
    else
        fh(kk,1) = figure('units','pix','pos',posvect); % Do not replace fig.
    end

    if pvpflag
        try
            set(fh(kk,1),varargin{strt:end}) % User passed property-vals.
        catch
            % Give a warning: user can still set props from command line.
            str = 'Bad Property or Value passed. Properties not assigned.';
            warning('SUBFIGURE:PropertyValueSet',str)
        end
    end
    
    if clen>1
        ax = axes;  % More than one figure is called, make an axes.
        fh(kk,2) = ax;  % Assign it to the handle matrix.
    end
end

if nargout==0
    clear fh % User doesn't want the figure handles.
end

set(0,'units',un) % Reset this guy, as promised.



function dfpos = getsp(flag)
% Subfunction gets the necessary spacing.  Includes menus or lack thereof.
% We only need to calculate this once for each type while SUBFUNCTION is 
% in memory, so we will store the results in a persistent variable.
persistent dfp1 dfp0  % dfp1 stores position format for without menubars.

if flag 
    if isempty(dfp1)
        invf = figure('units','pix','menubar','none');  % Invisible dummy.
        set(invf,'visible','off');  % We don't need to see this guy.
        op_pos = get(invf,{'outerp','pos'});  % Get the needed info.
        delete(invf);  % Delete our dummy figure.
        dfpos = abs(op_pos{1}-op_pos{2});  % Calculate the dimensions.
        dfp1 = dfpos;
    else
        dfpos = dfp1;  % Use our persistent variable.
    end
else
    if isempty(dfp0)
        invf = figure('units','pix');  % Dummy figure for formatting.
        set(invf,'visible','off');  % We don't need to see this guy.
        op_pos = get(invf,{'outerp','pos'});  % Get the needed info.
        delete(invf);  % Delete our dummy figure.
        dfpos = abs(op_pos{1}-op_pos{2});  % Calculate the dimensions.
        dfp0 = dfpos; 
    else
        dfpos = dfp0;  % Use our persistent variable.
    end
end



function fh = figreplace(posvect)
% Subfunction deals with when user calls for figure to be replaced.
fh = get(0,'children');  % Get all of the current figures.

if isempty(fh)
     fh = figure('units','pix','pos',posvect); % Nothing to replace.
     return
end

num = numel(fh);  % There are possible figures to replace.
un = get(fh,'units'); % Will reset at the end.
set(fh,'un','pix') ;  % Work in common units.                 

if num>1
    pos = cell2mat(get(fh,'pos'));  % A matrix of position vectors.
else
    pos = get(fh,'pos');  % Only one figure.
end

overlap = rectint(pos,repmat(posvect,num,1)); % Built-in to find overlap.
idx = find(overlap(:,1));  % Others have zero overlap.

if ~isempty(idx)
    delete(fh(idx));  % Delete the figures that share position.
else
    if iscell(un)
        set(fh,{'units'},un);  % Reset for user.
    else
        set(fh,'units',un);  % Reset for user.
    end
end

fh = figure('units','pixels','pos',posvect);  % Return our figure handle. 

Contact us at files@mathworks.com