tdalon
9/7/2016 - 7:58 PM

plot_depfun.m

function [opt, callstr] = plot_depfun(foo,varargin)
% PLOT_DEPFUN plots a call graph tree of the function dependencies
% SYNTAX
%     plot_depfun(foo,varargin)
%
% Ignores MATLAB function in matlabroot and any function names given in varargin.
% Uses current file in MATLAB Editor as default if no argument is passed or first argument is empty.
%
% See also depfun, mydepfun, plot_subfun (file exchange ID 46070)

% Calls: plot_graph, mydepfun, EditorGetFile

% Source: FEX http://www.mathworks.com/matlabcentral/fileexchange/46080-plot-depfun
% Modified by Thierry Dalon: calls mydepfun, EditorGetFile

% Use current file in Editor as default
if nargin==0 || isempty(foo),
    foo= EditorGetFile();
end

opt.ignore  = varargin;
opt.me      = which(foo);
if isempty(opt.me); error('this file could not be found'); end
opt.me      = sub_fileparts(opt.me);
opt         = sub_deps(opt);
opt.us      = sub_fileparts(opt.us);
opt.us.islocal = ismember(opt.us.fol,opt.me.fol);
sub_plot(opt);

if nargout==0
    clear opt;
elseif nargout>1
    callstr=sprintf('%s, ',opt.us.short{:});
    callstr=['Calls: ',callstr(1:end-2)];
    disp(callstr);
end
end

function out = sub_fileparts(foos)
if iscell(foos)
    for i=1:numel(foos)
        if ~exist(foos{i},'file')
            disp(foos{i});
            error('this file does not exist');
        end
    end
end

fols = regexprep(foos,'[^/|\\]+$','');

%short name of each function, and the folder it occurs
short = regexp(foos,'[^/|\\]+$','match','once');
short = regexprep(short,'\..+','');

out.full  = foos;
out.fol   = fols;
out.short = short;
end

function opt = sub_deps(opt)
%find dependencies of opt.me
%uses recursive calls to depfun with -toponly
%calls builtin functions for speed

names = {opt.me.full}; %list of all files found (will grow)
done = false;          %which files have been examined
from = [];             %dependency - parent
to   = [];             %dependency - child
t = now;
while any(~done)
    for i=find(~done)
        new=mydepfun(names{i});
        keep = true(size(new));
        %catch any strange return sizes from other os/versions
        if size(new,1)>1; new = new'; end
        %remove self
        keep(ismember(new,names{i})) = false;
        %remove ignored : full filename
        keep(ismember(new,opt.ignore)) = false;
        %remove ignored : short filename
        short = regexp(new,'[^/|\\]+$','match','once');
        keep(ismember(short,opt.ignore)) = false;
        %remove ignored : short filename no extension
        short = regexprep(short,'\..+','');
        keep(ismember(short,opt.ignore)) = false;
        %reduce the set of new
        new = new(keep);
                
        %add to list of names any new that are not already in it
        [I,I,I] = setxor(names,new);
        names = [names new(I)]; %#ok<AGROW>
        %rearrange I because apparently mac and pc do things differently
        if size(I,1)>1; I = I'; end
        
        %add to list of done
        done = [done false(size(I))]; %#ok<AGROW>
        done(i) = true;
        
        %new dependencies
        [newkid,newkid] = ismember(new,names);
        newdad = repmat(i,size(newkid));
        from = [from newdad]; %#ok<AGROW>
        to   = [to   newkid]; %#ok<AGROW>

        %report every 10 seconds
        if now-t>10;
            t = now;
            fprintf(1,'%d dependencies found so far',numel(names));
        end
    end
end

%sort names
[names,order] = sort(names);

%sort from/to references to match new names order
[rev,rev] = sort(order);
from = rev(from);
to   = rev(to);

%export results
opt.us = names;
opt.from = from;
opt.to   = to;
end

function sub_plot(opt)
if isempty(opt.from); disp('this function has no dependencies'); return; end
cols = repmat('b',size(opt.us.short));
cols(~opt.us.islocal) = 'r';
plot_graph(opt.us.short,opt.from,opt.to,'-colour',cols);
end

%% DEVNOTES
%140329 added handling of functions with no dependencies
%150311 bugfix : was not ignoring function calls correctly if they didn't
%                have an extension.