630 lines
25 KiB
Mathematica
630 lines
25 KiB
Mathematica
|
|
function handles = Plot(tr,varargin)
|
||
|
|
%PLOT renders a phylogenetic tree.
|
||
|
|
%
|
||
|
|
% PLOT(TREE) renders a phylogenetic tree object into a MATLAB figure as a
|
||
|
|
% phylogram. The significant distances between branches and nodes are in
|
||
|
|
% horizontal direction, vertical coordinates are accommodated only for
|
||
|
|
% display purposes. Handles to graph elements are stored in the
|
||
|
|
% 'UserData' figure field, such that graphic properties can be easily
|
||
|
|
% modified.
|
||
|
|
%
|
||
|
|
% PLOT(TREE,ACTIVEBRANCHES) hides the non'active branches and all their
|
||
|
|
% descendants. ACTIVEBRANCHES is a logical array of size
|
||
|
|
% [numBranches x 1] indicating the active branches.
|
||
|
|
%
|
||
|
|
% PLOT(...,'TYPE',type) selects the method to render the phylogenetic
|
||
|
|
% tree. Options are: 'square' (default), 'angular', and 'radial'.
|
||
|
|
%
|
||
|
|
% PLOT(...,'ORIENTATION',orient) will orient the phylogenetic tree within
|
||
|
|
% the figure window. Options are: 'top', 'bottom', 'left' (default), and,
|
||
|
|
% 'right'. Orientation parameter is valid only for phylograms or
|
||
|
|
% cladograms.
|
||
|
|
%
|
||
|
|
% PLOT(...,'BRANCHLABELS',value) hides/unhides branch labels. Options are
|
||
|
|
% true or false. Branch labels are placed next to the branch node.
|
||
|
|
% Defaults to false (true) when TYPE is (is not) 'radial'.
|
||
|
|
%
|
||
|
|
% PLOT(...,'LEAFLABELS',value) hides/unhides leaf labels. Options are
|
||
|
|
% true or false. Leaf labels are placed next to the leaf nodes. Defaults
|
||
|
|
% to false (true) when TYPE is (is not) 'radial'.
|
||
|
|
%
|
||
|
|
% PLOT(...,'TERMINALLABELS',value) hides/unhides terminal labels. Options
|
||
|
|
% are true (default) or false. Terminal labels are placed over the axis
|
||
|
|
% tick labels, ignored when 'radial' type is used.
|
||
|
|
%
|
||
|
|
% H = PLOT(...) returns a structure with handles to the graph elements.
|
||
|
|
%
|
||
|
|
% Example:
|
||
|
|
%
|
||
|
|
% tr = phytreeread('pf00002.tree')
|
||
|
|
% plot(tr,'type','radial')
|
||
|
|
%
|
||
|
|
% % Graph element properties can be modified as follows:
|
||
|
|
%
|
||
|
|
% h=get(gcf,'UserData')
|
||
|
|
% set(h.branchNodeLabels,'FontSize',6,'Color',[.5 .5 .5])
|
||
|
|
%
|
||
|
|
% See also PHYTREE, PHYTREE/VIEW, PHYTREEREAD, PHYTREETOOL, SEQLINKAGE.
|
||
|
|
|
||
|
|
% Copyright 2003-2006 The MathWorks, Inc.
|
||
|
|
% $Revision: 1.1.6.10 $ $Author: batserve $ $Date: 2006/06/16 20:06:45 $
|
||
|
|
|
||
|
|
if numel(tr)~=1
|
||
|
|
error('Bioinfo:phytree:plot:NoMultielementArrays',...
|
||
|
|
'Phylogenetic tree must be an 1-by-1 object.');
|
||
|
|
end
|
||
|
|
|
||
|
|
% set defaults
|
||
|
|
dispBranchLabels = NaN;
|
||
|
|
dispLeafLabels = NaN;
|
||
|
|
dispTerminalLabels = true;
|
||
|
|
renderType = 'square';
|
||
|
|
orientation = 'left';
|
||
|
|
rotation = 0;
|
||
|
|
|
||
|
|
tr = struct(tr);
|
||
|
|
tr.numBranches = size(tr.tree,1);
|
||
|
|
|
||
|
|
if nargin>1 && islogical(varargin{1})
|
||
|
|
activeBranches = varargin{1};
|
||
|
|
argStart = 2;
|
||
|
|
else
|
||
|
|
activeBranches = true(tr.numBranches,1);
|
||
|
|
argStart = 1;
|
||
|
|
end
|
||
|
|
|
||
|
|
if nargin - argStart > 0
|
||
|
|
if rem(nargin - argStart,2) == 1
|
||
|
|
error('Bioinfo:phytree:plot:IncorrectNumberOfArguments',...
|
||
|
|
'Incorrect number of arguments to %s.',mfilename);
|
||
|
|
end
|
||
|
|
okargs = {'type','orientation','rotation',...
|
||
|
|
'branchlabels','leaflabels','terminallabels'};
|
||
|
|
for j = argStart:2:nargin-argStart
|
||
|
|
pname = varargin{j};
|
||
|
|
pval = varargin{j+1};
|
||
|
|
k = find(strncmpi(pname,okargs,numel(pname)));
|
||
|
|
if isempty(k)
|
||
|
|
error('Bioinfo:phytree:plot:UnknownParameterName',...
|
||
|
|
'Unknown parameter name: %s.',pname);
|
||
|
|
elseif length(k)>1
|
||
|
|
error('Bioinfo:phytree:plot:AmbiguousParameterName',...
|
||
|
|
'Ambiguous parameter name: %s.',pname);
|
||
|
|
else
|
||
|
|
switch(k)
|
||
|
|
case 1 % type
|
||
|
|
oktypes={'square','angular','radial'};
|
||
|
|
l = strmatch(lower(pval),oktypes); %#ok
|
||
|
|
if isempty(l)
|
||
|
|
error('Bioinfo:phytree:plot:UnknownTypeName',...
|
||
|
|
'Unknown option for %s.',upper(okargs{k}));
|
||
|
|
else
|
||
|
|
if l==4
|
||
|
|
l=1;
|
||
|
|
end
|
||
|
|
renderType = oktypes{l};
|
||
|
|
end
|
||
|
|
case 2 % orientation
|
||
|
|
oktypes={'left','right','top','bottom'};
|
||
|
|
l = strmatch(lower(pval),oktypes); %#ok
|
||
|
|
if isempty(l)
|
||
|
|
error('Bioinfo:phytree:plot:UnknownOrientation',...
|
||
|
|
'Unknown option for %s.',upper(okargs{k}));
|
||
|
|
else
|
||
|
|
orientation = oktypes{l};
|
||
|
|
end
|
||
|
|
case 3 % rotation
|
||
|
|
if isreal(pval(1))
|
||
|
|
rotation = double(pval(1));
|
||
|
|
else
|
||
|
|
error('Bioinfo:phytree:plot:NotValidType',...
|
||
|
|
'ROTATION must be numeric and real');
|
||
|
|
end
|
||
|
|
case 4 % branch labels
|
||
|
|
dispBranchLabels = opttf(pval);
|
||
|
|
case 5 % leaf labels
|
||
|
|
dispLeafLabels = opttf(pval);
|
||
|
|
case 6 % terminal labels
|
||
|
|
dispTerminalLabels = opttf(pval);
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
% set dependent defaults
|
||
|
|
if isnan(dispBranchLabels)
|
||
|
|
if isequal(renderType,'radial')
|
||
|
|
dispBranchLabels = true;
|
||
|
|
else
|
||
|
|
dispBranchLabels = false;
|
||
|
|
end
|
||
|
|
end
|
||
|
|
if isnan(dispLeafLabels)
|
||
|
|
if isequal(renderType,'radial')
|
||
|
|
dispLeafLabels = true;
|
||
|
|
else
|
||
|
|
dispLeafLabels = false;
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
tr = doBasicCalculations(tr,activeBranches,renderType);
|
||
|
|
|
||
|
|
nodeIndex = 1:tr.numLabels;
|
||
|
|
leafIndex = 1:tr.numLeaves;
|
||
|
|
branchIndex = tr.numLeaves+1:tr.numLabels;
|
||
|
|
|
||
|
|
|
||
|
|
% check empty names
|
||
|
|
for ind = nodeIndex
|
||
|
|
if isempty(tr.names{ind})
|
||
|
|
if ind > tr.numLeaves
|
||
|
|
tr.names{ind} = ['Branch ' num2str(ind-tr.numLeaves)];
|
||
|
|
else
|
||
|
|
tr.names{ind} = ['Leaf ' num2str(ind)];
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
% rendering graphic objects
|
||
|
|
fig = gcf;
|
||
|
|
% fig = figure('Renderer','ZBuffer');
|
||
|
|
h.fig = fig;
|
||
|
|
h.axes = axes; hold on;
|
||
|
|
sepUnit = max(tr.x)*[-1/20 21/20];
|
||
|
|
|
||
|
|
% setting the axes
|
||
|
|
switch renderType
|
||
|
|
case {'square','angular'}
|
||
|
|
switch orientation
|
||
|
|
case 'left'
|
||
|
|
set(h.axes,'YTick',1:numel(tr.terminalNodes),'Ydir','reverse',...
|
||
|
|
'YtickLabel','','YAxisLocation','Right')
|
||
|
|
if dispTerminalLabels
|
||
|
|
set(h.axes,'Position',[.05 .10 .7 .85])
|
||
|
|
else
|
||
|
|
set(h.axes,'Position',[.05 .10 .9 .85])
|
||
|
|
end
|
||
|
|
xlim(sepUnit);
|
||
|
|
ylim([0 numel(tr.terminalNodes)+1]);
|
||
|
|
case 'right'
|
||
|
|
set(h.axes,'YTick',1:numel(tr.terminalNodes),'Xdir','reverse','Ydir','reverse',...
|
||
|
|
'YtickLabel','','YAxisLocation','Left')
|
||
|
|
if dispTerminalLabels
|
||
|
|
set(h.axes,'Position',[.25 .10 .7 .85])
|
||
|
|
else
|
||
|
|
set(h.axes,'Position',[.05 .10 .9 .85])
|
||
|
|
end
|
||
|
|
xlim(sepUnit);
|
||
|
|
ylim([0 numel(tr.terminalNodes)+1]);
|
||
|
|
case 'top'
|
||
|
|
set(h.axes,'XTick',1:numel(tr.terminalNodes),...
|
||
|
|
'XtickLabel','','XAxisLocation','Top')
|
||
|
|
if dispTerminalLabels
|
||
|
|
set(h.axes,'Position',[.10 .05 .85 .7])
|
||
|
|
else
|
||
|
|
set(h.axes,'Position',[.10 .05 .85 .9])
|
||
|
|
end
|
||
|
|
ylim(sepUnit);
|
||
|
|
xlim([0 numel(tr.terminalNodes)+1]);
|
||
|
|
case 'bottom'
|
||
|
|
set(h.axes,'XTick',1:numel(tr.terminalNodes),'Ydir','reverse',...
|
||
|
|
'XtickLabel','','XAxisLocation','Bottom')
|
||
|
|
if dispTerminalLabels
|
||
|
|
set(h.axes,'Position',[.10 .25 .85 .7])
|
||
|
|
else
|
||
|
|
set(h.axes,'Position',[.10 .05 .85 .9])
|
||
|
|
end
|
||
|
|
ylim(sepUnit);
|
||
|
|
xlim([0 numel(tr.terminalNodes)+1]);
|
||
|
|
end
|
||
|
|
case 'radial'
|
||
|
|
set(h.axes,'XTick',[],'YTick',[])
|
||
|
|
set(h.axes,'Position',[.05 .05 .9 .9])
|
||
|
|
dispTerminalLabels = false;
|
||
|
|
axis equal
|
||
|
|
end
|
||
|
|
|
||
|
|
% drawing lines
|
||
|
|
switch renderType
|
||
|
|
case 'square'
|
||
|
|
X = tr.x([nodeIndex;repmat([tr.par(1:tr.numLabels-1) tr.numLabels],2,1)]);
|
||
|
|
Y = tr.y([repmat(nodeIndex,2,1);[tr.par(1:tr.numLabels-1) tr.numLabels]]);
|
||
|
|
switch orientation
|
||
|
|
case {'left','right'}
|
||
|
|
h.BranchLines = plot(X,Y,'-k');
|
||
|
|
delete(h.BranchLines(~tr.activeNodes))
|
||
|
|
h.BranchLines = h.BranchLines(tr.activeNodes);
|
||
|
|
case {'top','bottom'}
|
||
|
|
h.BranchLines = plot(Y,X,'-k');
|
||
|
|
delete(h.BranchLines(~tr.activeNodes))
|
||
|
|
h.BranchLines = h.BranchLines(tr.activeNodes);
|
||
|
|
end
|
||
|
|
case 'angular'
|
||
|
|
X = tr.x([nodeIndex;[tr.par(1:tr.numLabels-1) tr.numLabels]]);
|
||
|
|
Y = tr.y([nodeIndex;[tr.par(1:tr.numLabels-1) tr.numLabels]]);
|
||
|
|
switch orientation
|
||
|
|
case {'left','right'}
|
||
|
|
h.BranchLines = plot(X,Y,'-k');
|
||
|
|
delete(h.BranchLines(~tr.activeNodes))
|
||
|
|
h.BranchLines = h.BranchLines(tr.activeNodes);
|
||
|
|
case {'top','bottom'}
|
||
|
|
h.BranchLines = plot(Y,X,'-k');
|
||
|
|
delete(h.BranchLines(~tr.activeNodes))
|
||
|
|
h.BranchLines = h.BranchLines(tr.activeNodes);
|
||
|
|
end
|
||
|
|
case 'radial'
|
||
|
|
R = tr.x;
|
||
|
|
A = tr.y / numel(tr.terminalNodes)*2*pi+rotation*pi/180;
|
||
|
|
tr.x = R .* sin(A);
|
||
|
|
tr.y = R .* cos(A);
|
||
|
|
X = tr.x([nodeIndex;[tr.par(1:tr.numLabels-1) tr.numLabels]]);
|
||
|
|
Y = tr.y([nodeIndex;[tr.par(1:tr.numLabels-1) tr.numLabels]]);
|
||
|
|
h.BranchLines = plot(X,Y,'-k');
|
||
|
|
delete(h.BranchLines(~tr.activeNodes))
|
||
|
|
h.BranchLines = h.BranchLines(tr.activeNodes);
|
||
|
|
end
|
||
|
|
|
||
|
|
% drawing nodes
|
||
|
|
switch renderType
|
||
|
|
case {'square','angular'}
|
||
|
|
switch orientation
|
||
|
|
case {'left','right'}
|
||
|
|
h.BranchDots = plot(tr.x(branchIndex(tr.activeNodes(branchIndex))),...
|
||
|
|
tr.y(branchIndex(tr.activeNodes(branchIndex))),'o',...
|
||
|
|
'MarkerSize',5,'MarkerEdgeColor','k',...
|
||
|
|
'MarkerFaceColor','b');
|
||
|
|
h.LeafDots = plot(tr.x(leafIndex(tr.activeNodes(leafIndex))),...
|
||
|
|
tr.y(leafIndex(tr.activeNodes(leafIndex))),'square',...
|
||
|
|
'MarkerSize',4,'MarkerEdgeColor','k',...
|
||
|
|
'MarkerFaceColor','w');
|
||
|
|
case {'top','bottom'}
|
||
|
|
h.BranchDots = plot(tr.y(branchIndex(tr.activeNodes(branchIndex))),...
|
||
|
|
tr.x(branchIndex(tr.activeNodes(branchIndex))),'o',...
|
||
|
|
'MarkerSize',5,'MarkerEdgeColor','k',...
|
||
|
|
'MarkerFaceColor','b');
|
||
|
|
h.LeafDots = plot(tr.y(leafIndex(tr.activeNodes(leafIndex))),...
|
||
|
|
tr.x(leafIndex(tr.activeNodes(leafIndex))),'square',...
|
||
|
|
'MarkerSize',4,'MarkerEdgeColor','k',...
|
||
|
|
'MarkerFaceColor','w');
|
||
|
|
end
|
||
|
|
case 'radial'
|
||
|
|
h.BranchDots = plot(tr.x(branchIndex(tr.activeNodes(branchIndex))),...
|
||
|
|
tr.y(branchIndex(tr.activeNodes(branchIndex))),'o',...
|
||
|
|
'MarkerSize',5,'MarkerEdgeColor','k',...
|
||
|
|
'MarkerFaceColor','b');
|
||
|
|
h.LeafDots = plot(tr.x(leafIndex(tr.activeNodes(leafIndex))),...
|
||
|
|
tr.y(leafIndex(tr.activeNodes(leafIndex))),'square',...
|
||
|
|
'MarkerSize',4,'MarkerEdgeColor','k',...
|
||
|
|
'MarkerFaceColor','w');
|
||
|
|
end
|
||
|
|
|
||
|
|
% resize figure if needed
|
||
|
|
switch renderType
|
||
|
|
case {'square','angular'}
|
||
|
|
switch orientation
|
||
|
|
case {'left','right'}
|
||
|
|
correctFigureSize(fig, 15 * numel(tr.terminalNodes),0);
|
||
|
|
fontRatio = max(get(fig,'Position').*[0 0 0 1])/numel(tr.terminalNodes);
|
||
|
|
case {'top','bottom'}
|
||
|
|
correctFigureSize(fig, 0, 15 * numel(tr.terminalNodes));
|
||
|
|
fontRatio = max(get(fig,'Position').*[0 0 1 0])/numel(tr.terminalNodes);
|
||
|
|
end
|
||
|
|
case 'radial'
|
||
|
|
temp = 10/pi*numel(tr.terminalNodes);
|
||
|
|
correctFigureSize(fig,temp,temp);
|
||
|
|
fontRatio = max(get(fig,'Position').*[0 0 1 0])/numel(tr.terminalNodes);
|
||
|
|
end
|
||
|
|
|
||
|
|
set(h.axes,'Fontsize',min(9,ceil(fontRatio/1.5)));
|
||
|
|
|
||
|
|
% set branch node labels
|
||
|
|
X = tr.x(branchIndex(tr.activeNodes(tr.numLeaves+1:tr.numLabels)));
|
||
|
|
Y = tr.y(branchIndex(tr.activeNodes(tr.numLeaves+1:tr.numLabels)));
|
||
|
|
switch renderType
|
||
|
|
case {'square','angular'}
|
||
|
|
switch orientation
|
||
|
|
case {'left'}
|
||
|
|
h.branchNodeLabels = text(X+sepUnit(1)/2,Y,tr.names(branchIndex(tr.activeNodes(tr.numLeaves+1:tr.numLabels))));
|
||
|
|
set(h.branchNodeLabels,'color',[0 0 .8],'clipping','on')
|
||
|
|
set(h.branchNodeLabels,'vertical','bottom')
|
||
|
|
set(h.branchNodeLabels,'horizontal','right')
|
||
|
|
set(h.branchNodeLabels,'Fontsize',min(8,ceil(fontRatio/2)));
|
||
|
|
case {'right'}
|
||
|
|
h.branchNodeLabels = text(X+sepUnit(1)/2,Y,tr.names(branchIndex(tr.activeNodes(tr.numLeaves+1:tr.numLabels))));
|
||
|
|
set(h.branchNodeLabels,'color',[0 0 .8],'clipping','on')
|
||
|
|
set(h.branchNodeLabels,'vertical','bottom')
|
||
|
|
set(h.branchNodeLabels,'Fontsize',min(8,ceil(fontRatio/2)));
|
||
|
|
case {'top'}
|
||
|
|
h.branchNodeLabels = text(Y,X-sepUnit(1)/2,tr.names(branchIndex(tr.activeNodes(tr.numLeaves+1:tr.numLabels))));
|
||
|
|
set(h.branchNodeLabels,'color',[0 0 .8],'clipping','on')
|
||
|
|
set(h.branchNodeLabels,'vertical','bottom','Rotation',30)
|
||
|
|
set(h.branchNodeLabels,'Fontsize',min(8,ceil(fontRatio/2)));
|
||
|
|
case {'bottom'}
|
||
|
|
h.branchNodeLabels = text(Y,X+sepUnit(1)/2,tr.names(branchIndex(tr.activeNodes(tr.numLeaves+1:tr.numLabels))));
|
||
|
|
set(h.branchNodeLabels,'color',[0 0 .8],'clipping','on')
|
||
|
|
set(h.branchNodeLabels,'vertical','bottom','Rotation',30)
|
||
|
|
set(h.branchNodeLabels,'Fontsize',min(8,ceil(fontRatio/2)));
|
||
|
|
end
|
||
|
|
case 'radial'
|
||
|
|
h.branchNodeLabels = text(X,Y,tr.names(branchIndex(tr.activeNodes(tr.numLeaves+1:tr.numLabels))));
|
||
|
|
set(h.branchNodeLabels,'color',[0 0 .8],'clipping','on')
|
||
|
|
set(h.branchNodeLabels,'vertical','bottom')
|
||
|
|
set(h.branchNodeLabels,'Fontsize',min(8,ceil(fontRatio*1.2)));
|
||
|
|
for ind = 1:numel(h.branchNodeLabels)
|
||
|
|
if X(ind)<0
|
||
|
|
set(h.branchNodeLabels(ind),'horizontal','right')
|
||
|
|
set(h.branchNodeLabels(ind),'Position',get(h.branchNodeLabels(ind),'Position')+[sepUnit(1)/2 0 0])
|
||
|
|
else
|
||
|
|
set(h.branchNodeLabels(ind),'horizontal','left')
|
||
|
|
set(h.branchNodeLabels(ind),'Position',get(h.branchNodeLabels(ind),'Position')-[sepUnit(1)/2 0 0])
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
% set leaf nodes labels
|
||
|
|
X = tr.x(leafIndex(tr.activeNodes(1:tr.numLeaves)));
|
||
|
|
Y = tr.y(leafIndex(tr.activeNodes(1:tr.numLeaves)));
|
||
|
|
switch renderType
|
||
|
|
case {'square','angular'}
|
||
|
|
switch orientation
|
||
|
|
case {'left'}
|
||
|
|
h.leafNodeLabels = text(X-sepUnit(1)/2,Y,tr.names(leafIndex(tr.activeNodes(1:tr.numLeaves))));
|
||
|
|
set(h.leafNodeLabels,'color',[.5 .5 .5],'clipping','on')
|
||
|
|
set(h.leafNodeLabels,'horizontal','left')
|
||
|
|
set(h.leafNodeLabels,'Fontsize',min(8,ceil(fontRatio/2)));
|
||
|
|
case {'right'}
|
||
|
|
h.leafNodeLabels = text(X-sepUnit(1)/2,Y,tr.names(leafIndex(tr.activeNodes(1:tr.numLeaves))));
|
||
|
|
set(h.leafNodeLabels,'color',[.5 .5 .5],'clipping','on')
|
||
|
|
set(h.leafNodeLabels,'horizontal','right')
|
||
|
|
set(h.leafNodeLabels,'Fontsize',min(8,ceil(fontRatio/2)));
|
||
|
|
case {'top'}
|
||
|
|
h.leafNodeLabels = text(Y,X-sepUnit(1)/2,tr.names(leafIndex(tr.activeNodes(1:tr.numLeaves))));
|
||
|
|
set(h.leafNodeLabels,'color',[.5 .5 .5],'clipping','on')
|
||
|
|
set(h.leafNodeLabels,'horizontal','left','Rotation',60)
|
||
|
|
set(h.leafNodeLabels,'Fontsize',min(8,ceil(fontRatio/2)));
|
||
|
|
case {'bottom'}
|
||
|
|
h.leafNodeLabels = text(Y,X-sepUnit(1),tr.names(leafIndex(tr.activeNodes(1:tr.numLeaves))));
|
||
|
|
set(h.leafNodeLabels,'color',[.5 .5 .5],'clipping','on')
|
||
|
|
set(h.leafNodeLabels,'horizontal','right','Rotation',60)
|
||
|
|
set(h.leafNodeLabels,'Fontsize',min(8,ceil(fontRatio/2)));
|
||
|
|
end
|
||
|
|
case 'radial'
|
||
|
|
h.leafNodeLabels = text(X,Y,tr.names(leafIndex(tr.activeNodes(1:tr.numLeaves))));
|
||
|
|
set(h.leafNodeLabels,'color',[.5 .5 .5],'clipping','on')
|
||
|
|
set(h.leafNodeLabels,'Fontsize',min(8,ceil(fontRatio*1.2)));
|
||
|
|
% textHeight = mean(cell2mat(get(h.leafNodeLabels,'Extent')))*[0 0 0 1]';
|
||
|
|
for ind = 1:numel(h.leafNodeLabels)
|
||
|
|
if X(ind)<0
|
||
|
|
set(h.leafNodeLabels(ind),'horizontal','right')
|
||
|
|
set(h.leafNodeLabels(ind),'Position',get(h.leafNodeLabels(ind),'Position')+[sepUnit(1) 0 0])
|
||
|
|
else
|
||
|
|
set(h.leafNodeLabels(ind),'horizontal','left')
|
||
|
|
set(h.leafNodeLabels(ind),'Position',get(h.leafNodeLabels(ind),'Position')-[sepUnit(1) 0 0])
|
||
|
|
end
|
||
|
|
% a=atan(Y(ind)/X(ind))*180/pi;
|
||
|
|
% if a > 0 a = max(0,a-60)/2; else
|
||
|
|
% a = min(0,a+60)/2; end
|
||
|
|
% set(h.leafNodeLabels(ind),'Rotation',a)
|
||
|
|
end
|
||
|
|
[sortedY,hsY]=sort(Y);
|
||
|
|
idx=hsY(X(hsY)>0 & sortedY>0);
|
||
|
|
if numel(idx)
|
||
|
|
extentY = get(h.leafNodeLabels(idx(1)),'Extent')*[0;0;0;1];
|
||
|
|
positionY = get(h.leafNodeLabels(idx(1)),'Position')*[0;1;0];
|
||
|
|
for i = 2:numel(idx)
|
||
|
|
position = get(h.leafNodeLabels(idx(i)),'Position');
|
||
|
|
positionY = max(positionY+extentY,position(2));
|
||
|
|
position(2) = positionY;
|
||
|
|
set(h.leafNodeLabels(idx(i)),'Position',position)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
idx=hsY(X(hsY)<0 & sortedY>0);
|
||
|
|
if numel(idx)
|
||
|
|
extentY = get(h.leafNodeLabels(idx(1)),'Extent')*[0;0;0;1];
|
||
|
|
positionY = get(h.leafNodeLabels(idx(1)),'Position')*[0;1;0];
|
||
|
|
for i = 2:numel(idx)
|
||
|
|
position = get(h.leafNodeLabels(idx(i)),'Position');
|
||
|
|
positionY = max(positionY+extentY,position(2));
|
||
|
|
position(2) = positionY;
|
||
|
|
set(h.leafNodeLabels(idx(i)),'Position',position)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
idx=flipud(hsY(X(hsY)>0 & sortedY<0));
|
||
|
|
if numel(idx)
|
||
|
|
extentY = get(h.leafNodeLabels(idx(1)),'Extent')*[0;0;0;1];
|
||
|
|
positionY = get(h.leafNodeLabels(idx(1)),'Position')*[0;1;0];
|
||
|
|
for i = 2:numel(idx)
|
||
|
|
position = get(h.leafNodeLabels(idx(i)),'Position');
|
||
|
|
positionY = min(positionY-extentY,position(2));
|
||
|
|
position(2) = positionY;
|
||
|
|
set(h.leafNodeLabels(idx(i)),'Position',position)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
idx=flipud(hsY(X(hsY)<0 & sortedY<0));
|
||
|
|
if numel(idx)
|
||
|
|
extentY = get(h.leafNodeLabels(idx(1)),'Extent')*[0;0;0;1];
|
||
|
|
positionY = get(h.leafNodeLabels(idx(1)),'Position')*[0;1;0];
|
||
|
|
for i = 2:numel(idx)
|
||
|
|
position = get(h.leafNodeLabels(idx(i)),'Position');
|
||
|
|
positionY = min(positionY-extentY,position(2));
|
||
|
|
position(2) = positionY;
|
||
|
|
set(h.leafNodeLabels(idx(i)),'Position',position)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
end
|
||
|
|
|
||
|
|
% correct axis limits given the extent of labels
|
||
|
|
if dispBranchLabels
|
||
|
|
E = cell2mat(get(h.branchNodeLabels,'Extent'));
|
||
|
|
if strcmp(get(gca,'XDir'),'reverse')
|
||
|
|
E(:,1) = E(:,1) - E(:,3);
|
||
|
|
end
|
||
|
|
if strcmp(get(gca,'YDir'),'reverse')
|
||
|
|
E(:,2) = E(:,2) - E(:,4);
|
||
|
|
end
|
||
|
|
E=[E;[xlim*[1;0] ylim*[1;0] diff(xlim) diff(ylim)]];
|
||
|
|
mins = min(E(:,[1 2]));
|
||
|
|
maxs = max([sum(E(:,[1 3]),2) sum(E(:,[2 4]),2)]);
|
||
|
|
axis([mins(1) maxs(1) mins(2) maxs(2)])
|
||
|
|
end
|
||
|
|
|
||
|
|
if dispLeafLabels
|
||
|
|
E = cell2mat(get(h.leafNodeLabels,'Extent'));
|
||
|
|
if strcmp(get(gca,'XDir'),'reverse')
|
||
|
|
E(:,1) = E(:,1) - E(:,3);
|
||
|
|
end
|
||
|
|
if strcmp(get(gca,'YDir'),'reverse')
|
||
|
|
E(:,2) = E(:,2) - E(:,4);
|
||
|
|
end
|
||
|
|
E=[E;[xlim*[1;0] ylim*[1;0] diff(xlim) diff(ylim)]];
|
||
|
|
mins = min(E(:,[1 2]));
|
||
|
|
maxs = max([sum(E(:,[1 3]),2) sum(E(:,[2 4]),2)]);
|
||
|
|
axis([mins(1) maxs(1) mins(2) maxs(2)])
|
||
|
|
end
|
||
|
|
|
||
|
|
% set terminal nodes labels
|
||
|
|
switch renderType
|
||
|
|
case {'square','angular'}
|
||
|
|
X = tr.x(tr.terminalNodes) * 0;
|
||
|
|
Y = tr.y(tr.terminalNodes);
|
||
|
|
switch orientation
|
||
|
|
case {'left'}
|
||
|
|
X = X + max(xlim) - sepUnit(1)/2;
|
||
|
|
h.terminalNodeLabels = text(X,Y,tr.names(tr.terminalNodes));
|
||
|
|
case {'right'}
|
||
|
|
X = X + max(xlim) - sepUnit(1)/2;
|
||
|
|
h.terminalNodeLabels = text(X,Y,tr.names(tr.terminalNodes));
|
||
|
|
set(h.terminalNodeLabels,'Horizontal','right')
|
||
|
|
case {'top'}
|
||
|
|
X = X + max(ylim) - sepUnit(1)/2;
|
||
|
|
h.terminalNodeLabels = text(Y,X,tr.names(tr.terminalNodes));
|
||
|
|
set(h.terminalNodeLabels,'Rotation',90)
|
||
|
|
case {'bottom'}
|
||
|
|
X = X + max(ylim) - sepUnit(1)/2;
|
||
|
|
h.terminalNodeLabels = text(Y,X,tr.names(tr.terminalNodes));
|
||
|
|
set(h.terminalNodeLabels,'Rotation',270)
|
||
|
|
end
|
||
|
|
case 'radial'
|
||
|
|
h.terminalNodeLabels = text(0,0,' ');
|
||
|
|
end
|
||
|
|
|
||
|
|
if dispTerminalLabels
|
||
|
|
set(h.terminalNodeLabels,'Fontsize',min(9,ceil(fontRatio/1.5)));
|
||
|
|
end
|
||
|
|
|
||
|
|
if ~dispBranchLabels
|
||
|
|
set(h.branchNodeLabels,'visible','off');
|
||
|
|
end
|
||
|
|
if ~dispLeafLabels
|
||
|
|
set(h.leafNodeLabels,'visible','off');
|
||
|
|
end
|
||
|
|
if ~dispTerminalLabels
|
||
|
|
set(h.terminalNodeLabels,'visible','off');
|
||
|
|
end
|
||
|
|
|
||
|
|
box on
|
||
|
|
hold off
|
||
|
|
|
||
|
|
% store handles
|
||
|
|
set(fig,'UserData',h)
|
||
|
|
if nargout
|
||
|
|
handles = h;
|
||
|
|
end
|
||
|
|
|
||
|
|
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
|
function tr = doBasicCalculations(tr,activeBranches,renderType)
|
||
|
|
|
||
|
|
% helper function to compute and find some features of the tree
|
||
|
|
tr.numLeaves = tr.numBranches + 1;
|
||
|
|
tr.numLabels = tr.numBranches + tr.numLeaves;
|
||
|
|
|
||
|
|
% remove uderscores from names
|
||
|
|
for ind = 1:tr.numLabels
|
||
|
|
tr.names{ind}(tr.names{ind}=='_')=' ';
|
||
|
|
end
|
||
|
|
|
||
|
|
% obtain parents for every node
|
||
|
|
tr.par(tr.tree(:)) = tr.numLeaves + [1:tr.numBranches 1:tr.numBranches];
|
||
|
|
|
||
|
|
% find active nodes
|
||
|
|
tr.activeNodes = true(tr.numLabels,1);
|
||
|
|
for ind =tr.numBranches:-1:1
|
||
|
|
tr.activeNodes(tr.tree(ind,:)) = tr.activeNodes(tr.numLeaves+ind) & activeBranches(ind);
|
||
|
|
end
|
||
|
|
|
||
|
|
% propagate last leaf
|
||
|
|
tr.lastleaf = 1:tr.numLabels;
|
||
|
|
for ind = tr.numBranches:-1:1
|
||
|
|
if ~tr.activeNodes(tr.tree(ind,1))
|
||
|
|
tr.lastleaf(tr.tree(ind,:))=tr.lastleaf(ind+tr.numLeaves);
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
tr.activeBranches = tr.activeNodes(tr.numLeaves+1:tr.numLabels)&activeBranches;
|
||
|
|
tr.activeLeaves = tr.activeNodes(1:tr.numLeaves);
|
||
|
|
|
||
|
|
% find x coordinates of branches
|
||
|
|
tr.x = tr.dist;
|
||
|
|
for ind = tr.numBranches:-1:1
|
||
|
|
tr.x(tr.tree(ind,:)) = tr.x(tr.tree(ind,:)) + tr.x(ind+tr.numLeaves);
|
||
|
|
end
|
||
|
|
|
||
|
|
% find y coordinates of branches
|
||
|
|
tr.terminalNodes = tr.lastleaf([true,diff(tr.lastleaf(1:tr.numLeaves))~=0]);
|
||
|
|
tr.y=zeros(tr.numLabels,1);
|
||
|
|
tr.y(tr.terminalNodes)=1:length(tr.terminalNodes);
|
||
|
|
switch renderType
|
||
|
|
case 'square'
|
||
|
|
for ind = 1:tr.numBranches
|
||
|
|
if tr.activeBranches(ind)
|
||
|
|
tr.y(ind+tr.numLeaves) = mean(tr.y(tr.tree(ind,:)));
|
||
|
|
end
|
||
|
|
end
|
||
|
|
case {'angular','radial'}
|
||
|
|
for ind = 1:tr.numBranches
|
||
|
|
if tr.activeBranches(ind)
|
||
|
|
if tr.x(tr.tree(ind,1))/tr.x(tr.tree(ind,2))>3
|
||
|
|
tr.y(ind+tr.numLeaves) = tr.y(tr.tree(ind,1));
|
||
|
|
elseif tr.x(tr.tree(ind,2))/tr.x(tr.tree(ind,1))>3
|
||
|
|
tr.y(ind+tr.numLeaves) = tr.y(tr.tree(ind,2));
|
||
|
|
else
|
||
|
|
tr.y(ind+tr.numLeaves) = mean(tr.y(tr.tree(ind,:)));
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||
|
|
function correctFigureSize(fig,recommendedHeight,recommendedWidth)
|
||
|
|
% helper function to increase initial figure size depending on the screen &
|
||
|
|
% tree sizes
|
||
|
|
screenSize = diff(reshape(get(0,'ScreenSize'),2,2),[],2)-[0;100];
|
||
|
|
% 100 gives extra space for the figure header and win toolbar
|
||
|
|
position = get(fig,'Position');
|
||
|
|
if recommendedHeight > position(4)
|
||
|
|
if recommendedHeight < sum(position([2 4]))
|
||
|
|
position(2) = sum(position([2 4])) - recommendedHeight;
|
||
|
|
position(4) = recommendedHeight;
|
||
|
|
elseif recommendedHeight < screenSize(2)
|
||
|
|
position(2) = 30;
|
||
|
|
position(4) = recommendedHeight;
|
||
|
|
else
|
||
|
|
position(2) = 30;
|
||
|
|
position(4) = screenSize(2);
|
||
|
|
end
|
||
|
|
end
|
||
|
|
if recommendedWidth > position(3)
|
||
|
|
if recommendedWidth < sum(position([1 3]))
|
||
|
|
position(1) = sum(position([1 3])) - recommendedWidth;
|
||
|
|
position(3) = recommendedWidth;
|
||
|
|
elseif recommendedWidth < screenSize(1)
|
||
|
|
position(1) = 0;
|
||
|
|
position(3) = recommendedHeight;
|
||
|
|
else
|
||
|
|
position(1) = 0;
|
||
|
|
position(3) = screenSize(1);
|
||
|
|
end
|
||
|
|
end
|
||
|
|
set(fig,'Position',position)
|