Skip to content

Instantly share code, notes, and snippets.

@tdalon
Last active September 8, 2016 07:20
Show Gist options
  • Save tdalon/28c27eed23630cf474d3f7834e703616 to your computer and use it in GitHub Desktop.
Save tdalon/28c27eed23630cf474d3f7834e703616 to your computer and use it in GitHub Desktop.
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment