ourMELONS/matlab/graph/plotPhytree.m

687 lines
22 KiB
Mathematica
Raw Normal View History

2019-12-16 16:47:21 +01:00
function plotPhytree(tr,varargin)
%PLOTPHYTREE renders a phylogenetic tree.
%
% PLOTPHYTREE(TREE) renders a phylogenetic tree object into a MATLAB figure as a
% phylogram.
%
% plotphytree(...,'ROTATION',value) will orient the phylogenetic tree within
% the figure window. Positive angles cause counterclockwise rotation,
% otherwise clockwise rotation.
%
% plotphytree(...,'FONTSIZE',value) will set the lable font size.A value
% specifying the font size to use for text in units determined by the FontUnits
% property (1 point = 1/72 inch). The default is calculated from the data
% according to the number of nodes.
%
% plotphytree(...,'LINESTYLE',value) will set the color of the tree. The
% default color is blue.
% b blue . point - solid
% g green o circle : dotted
% r red x x-mark -. dashdot
% c cyan + plus -- dashed
% m magenta * star (none) no line
% y yellow s square
% k black d diamond
% v triangle (down)
% ^ triangle (up)
% < triangle (left)
% > triangle (right)
% p pentagram
% h hexagram
%
% plotphytree(...,'FONTCOLOR',value) will set the color of lable. It is a
% vector includes [R, G, B] components. Each with the range of 0 to 1.
% The default setting is [.2 .2 .2].
%
%
% Example:
%
% tr = phytreeread('pf00002.tree');
% plotphytree(tr,'ROTATION',-pi/2, 'FONTSIZE', 8, 'LINESTYLE', 'b', 'FONTCOLOR', [0.2 0.2 0.2]);
%
%
if numel(tr)~=1
error('plotphytree:NoMultielementArrays',...
'Phylogenetic tree must be an 1-by-1 object.');
end
% set defaults
rotation = 0;
fontsize = 1;
fontsizeset = false;
linestyle = '-b';
fontcolor = [.2 .2 .2];
if nargin>1 && islogical(varargin{1})
activeBranches = varargin{1};
argStart = 2;
else
argStart = 1;
end
if nargin - argStart > 0
if rem(nargin - argStart,2) == 1
error('plotphytree:IncorrectNumberOfArguments',...
'Incorrect number of arguments to %s.',mfilename);
end
okargs = {'rotation', 'fontsize', 'linestyle', 'fontcolor'};
for j = argStart:2:nargin-argStart
pname = varargin{j};
pval = varargin{j+1};
k = find(strncmpi(pname,okargs,numel(pname)));
if isempty(k)
error('plotphytree:UnknownParameterName',...
'Unknown parameter name: %s.',pname);
elseif length(k)>1
error('plotphytree:AmbiguousParameterName',...
'Ambiguous parameter name: %s.',pname);
else
switch(k)
case 1 % rotation
if isreal(pval(1))
rotation = double(pval(1));
else
error('plotphytree:NotValidType',...
'ROTATION must be numeric and real');
end
case 2 % fontsize
if isreal(pval(1))
fontsize = uint8(pval(1));
fontsizeset = true;
else
error('plotphytree:NotValidType',...
'fontsize must be numeric');
end
case 3 % linecolor
linestyle = pval(1);
case 4 % Fontcolor
fontcolor = [pval(1) pval(2) pval(3)];
end
end
end
end
orgtr=tr;
treeinfo = GET(tr);
%Get tree structure
tr = struct(tr);
tr.numLeaves = treeinfo.NumLeaves;
tr.numNodes = treeinfo.NumNodes;
tr.numBranches = treeinfo.NumBranches;
tr.LeafNames = treeinfo.LeafNames;
tr.BranchNames = treeinfo.BranchNames;
tr.numTree = size(tr.tree, 1);
% obtain parents for every node
tr.par(tr.tree(:)) = tr.numLeaves + [1:tr.numBranches 1:tr.numBranches];
% obtain numbers of leaves for each nodes
tr.numChildrenofNode = ChildCount(tr.par, tr.numLeaves, tr.numNodes);
tr.numChildrenofNode(tr.numChildrenofNode == 0) = 1;
% find angle of each node
unitDegree = 2 * pi / tr.numLeaves;
tr.NodeSector = tr.numChildrenofNode * unitDegree;
tr.NodeSector(tr.NodeSector == 0) = unitDegree;
tr.NodeSector(tr.numNodes) = 0;
tr.NodeAngle = zeros(tr.numNodes, 1);
tr.NodeAngle(tr.tree(tr.numTree, 2)) = tr.NodeSector(tr.tree(tr.numTree, 2)) / 2;
tr.NodeAngle(tr.tree(tr.numTree, 1)) = tr.NodeSector(tr.tree(tr.numTree, 2)) + tr.NodeSector(tr.tree(tr.numTree, 1)) / 2;
for i = tr.numTree - 1 : -1 :1
tr.NodeAngle(tr.tree(i, 2)) = tr.NodeAngle(tr.par(tr.tree(i, 2))) - tr.NodeSector(tr.par(tr.tree(i, 2))) / 2 + tr.NodeSector(tr.tree(i, 2)) / 2;
tr.NodeAngle(tr.tree(i, 1)) = tr.NodeAngle(tr.par(tr.tree(i, 1))) + tr.NodeSector(tr.par(tr.tree(i, 1))) / 2 - tr.NodeSector(tr.tree(i, 1)) / 2;
end
% Rotation
tr.NodeAngle = tr.NodeAngle + rotation;
% find (x, y) coordinates of nodes
tr.d = tr.dist;
tr.x = tr.d .* cos(tr.NodeAngle);
tr.y = tr.d .* sin(tr.NodeAngle);
for i = tr.numNodes - 1: -1 : 1
tr.x(i) = tr.x(i) + tr.x(tr.par(i));
tr.y(i) = tr.y(i) + tr.y(tr.par(i));
end
nodeIndex = 1 : tr.numNodes;
X = tr.x([nodeIndex;[tr.par(1:tr.numNodes-1) tr.numNodes]]);
Y = tr.y([nodeIndex;[tr.par(1:tr.numNodes-1) tr.numNodes]]);
tr.txtAngle = cal_textAngle(tr);
fig = gcf;
% fig = figure('Renderer','ZBuffer');
h.fig = fig;
h.axes = axes; hold on;
sepUnit = max(tr.x)*[-1/20 21/20];
set(h.axes,'XTick',[],'YTick',[]);
set(h.axes,'Position',[.05 .05 .9 .9])
dispTerminalLabels = false;
axis equal
h.BranchLines = plot(X,Y,linestyle);
% resize figure if needed
temp = 10/pi*tr.numLeaves;
correctFigureSize(fig,temp,temp);
fontRatio = max(get(fig,'Position').*[0 0 1 0])/tr.numLeaves;
set(h.axes, 'Fontsize', fontsize);
% set leaf nodes labels
leafIndex = 1 : tr.numLeaves;
X = tr.x(leafIndex);
Y = tr.y(leafIndex);
txtangle = tr.txtAngle;
% % Rotate Label
h.leafNodeLabels = zeros(1, tr.numLeaves);
for i = 1:tr.numLeaves
h.leafNodeLabels(i) = text(X(i),Y(i),tr.names(i), 'Rotation', txtangle(i));
end
set(h.leafNodeLabels,'color',fontcolor,'clipping','on')
if fontsizeset
set(h.leafNodeLabels, 'Fontsize', fontsize);
else
set(h.leafNodeLabels,'Fontsize',min(8,ceil(fontRatio*1.2)));
end
textHeight = mean(cell2mat(get(h.leafNodeLabels,'Extent')))*[0 0 0 1]';
for ind = 1:numel(h.leafNodeLabels)
if X(ind) - tr.x(tr.par(ind)) < 0
if txtangle(ind) < 90.0 - 0.001 || txtangle(ind) > 90.0 + 0.001
set(h.leafNodeLabels(ind),'horizontal','right')
set(h.leafNodeLabels(ind),'Position',get(h.leafNodeLabels(ind),'Position')+[sepUnit(1)*cos(txtangle(ind) * 2 * pi/360) sepUnit(1)*sin(txtangle(ind) * 2 * pi/360) 0])
else
if Y(ind) > 0
set(h.leafNodeLabels(ind),'Position',get(h.leafNodeLabels(ind),'Position')-[0 sepUnit(1) 0])
else
set(h.leafNodeLabels(ind),'Position',get(h.leafNodeLabels(ind),'Position')+[0 sepUnit(1) 0])
end
end
else
if txtangle(ind) < 90.0 - 0.001 || txtangle(ind) > 90.0 + 0.001
set(h.leafNodeLabels(ind),'horizontal','left')
set(h.leafNodeLabels(ind),'Position',get(h.leafNodeLabels(ind),'Position')-[sepUnit(1)*cos(txtangle(ind) * 2 * pi/360) sepUnit(1)*sin(txtangle(ind) * 2 * pi/360) 0])
else
if Y(ind) > 0
set(h.leafNodeLabels(ind),'Position',get(h.leafNodeLabels(ind),'Position')-[0 sepUnit(1) 0])
else
set(h.leafNodeLabels(ind),'Position',get(h.leafNodeLabels(ind),'Position')+[0 sepUnit(1) 0])
end
end
end
end
dispLeafLabels = 1;
% correct axis limits given the extent of labels
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
if dispTerminalLabels
set(h.terminalNodeLabels,'Fontsize',min(9,ceil(fontRatio/1.5)));
end
box off
hold off
% store handles
set(fig,'UserData',h)
if nargout
handles = h;
end
%**************************************************************
% Count number of children for each node
function numChildren = ChildCount(par, numleafs, numnodes)
n = length(par);
numChildren = zeros(1, numnodes);
NoBranchStart = numleafs + 1;
for i = 1 : numleafs
numChildren(par(i)) = numChildren(par(i)) + 1;
end
for i = NoBranchStart : n
numChildren(par(i)) = numChildren(par(i)) + numChildren(i);
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)
%*********************************************************************
%*********************************************************************
function [lefttree, righttree, thirdtree] = findsubtreeofnode(tr)
lefttree = zeros(tr.numBranches, tr.numNodes);
righttree = zeros(tr.numBranches, tr.numNodes);
thirdtree = zeros(tr.numBranches, tr.numNodes);
% thirdtree_left = zeros(tr.numBranches, tr.numNodes);
% thirdtree_right = zeros(tr.numBranches, tr.numNodes);
lefttree(1, 1) = tr.tree(1, 1);
righttree(1,1) = tr.tree(1, 2);
lefttree(1, tr.numNodes) = 1;
righttree(1, tr.numNodes) = 1;
for i = 2 : tr.numBranches
j = 0;
tmp = tr.tree(i, 1);
lefttree(i, 1) = tmp;
lefttree(i, tr.numNodes) = 1;
if tmp > tr.numLeaves
lefttrlen = lefttree(tmp - tr.numLeaves, tr.numNodes);
sub = lefttree(tmp - tr.numLeaves, 1 : lefttrlen);
lefttree(i, 2 : lefttrlen + 2 - 1) = sub;
righttrlen = righttree(tmp - tr.numLeaves, tr.numNodes);
sub = righttree(tmp - tr.numLeaves, 1 : righttrlen);
lefttree(i, lefttrlen + 3 - 1: lefttrlen + 3 - 1 + righttrlen - 1) = sub;
lefttree(i, tr.numNodes) = lefttrlen + righttrlen + lefttree(i, tr.numNodes);
end
j = 0;
tmp = tr.tree(i, 2);
righttree(i, 1) = tmp;
righttree(i, tr.numNodes) = 1;
if tmp > tr.numLeaves
lefttrlen = lefttree(tmp - tr.numLeaves, tr.numNodes);
sub = lefttree(tmp - tr.numLeaves, 1 : lefttrlen);
righttree(i, 2 : lefttrlen + 2 - 1) = sub;
righttrlen = righttree(tmp - tr.numLeaves, tr.numNodes);
sub = righttree(tmp - tr.numLeaves, 1 : righttrlen);
righttree(i, lefttrlen + 3 - 1: lefttrlen + 3 - 1 + righttrlen - 1) = sub;
righttree(i, tr.numNodes) = lefttrlen + righttrlen + righttree(i, tr.numNodes);
end
end
% Third tree
node = 1 : tr.numLeaves;
for i = 1 : tr.numBranches
tmp = [lefttree(i, 1:lefttree(i, tr.numNodes)), righttree(i, 1:righttree(i, tr.numNodes))];
tf = ismember(node, tmp);
tmp = node(find(tf == 0));
tmp = tmp(find(tmp <= tr.numLeaves));
nlength = length(tmp);
thirdtree(i, 1 : nlength) = tmp;
thirdtree(i, tr.numNodes) = nlength;
end
%*********************************************************************
function [treeangle, leftnode, rightnode] = caltreeangle(treenode, root, tr)
tmp = find(treenode <= tr.numLeaves);
leftnode = treenode(tmp(1));
rightnode = treenode(tmp(length(tmp)));
x0 = tr.x(root);
y0 = tr.y(root);
x1 = tr.x(leftnode);
y1 = tr.y(leftnode);
x2 = tr.x(rightnode);
y2 = tr.y(rightnode);
treeangle = cal_angle(x0, y0, x1, y1, x2, y2);
%*********************************************************************
function [subtree1, subtree2] = findsubtree(node, tr)
subtree1 = [];
subtree2 = [];
nodeindex = 1 : tr.numNodes;
i1 = 0;
i2 = 0;
flag1 = 0;
flag2 = 0;
while ~flag1 || ~flag2
nodetmp = find(tr.par == node);
if nodetmp(1) <= tr.numLeaves
subtree1 = [subtree1, nodetmp(1)];
i1 = i1 + 1;
flag1 = 1;
else
if i1 == 0
subtree1 = [subtree1, nodetmp(1)];
end
[subtr1, subtr2] = findsubtree(nodetmp(1), tr);
flag1 = 1;
subtree1 = [subtree1, subtr1, subtr2];
end
if nodetmp(2) <= tr.numLeaves
subtree2 = [subtree2, nodetmp(2)];
i2 = i2 + 1;
flag2 = 1;
else
if i2 == 0
subtree2 = [subtree2, nodetmp(2)];
end
[subtr1, subtr2] = findsubtree(nodetmp(2), tr);
flag2 = 1;
subtree2 = [subtree2, subtr1, subtr2];
end
end
%*********************************************************************
function leavenodes = findanothersubtree(node, tr)
nextnode = node;
cutpoint = tr.par(length(tr.par));
subtree = [];
tmpnode = nextnode;
nextnode = tr.par(nextnode);
while nextnode <= cutpoint
[subtree1, subtree2] = findsubtree(nextnode, tr);
if sum(find(subtree1 == node)) == 0
subtree = [subtree, subtree1];
else
subtree = [subtree, subtree2];
end
tmpnode = nextnode;
if nextnode < cutpoint
nextnode = tr.par(nextnode);
else
break;
end
end
leavenodes = subtree(find(subtree <= tr.numLeaves));
%*********************************************************************
function slope = cal_slope(x1, y1, x2, y2)
if x1 == x2
slope = tan(pi/2);
else
slope = (y2 - y1)/(x2 - x1);
end
%*********************************************************************
function xangle = cal_angle(x0, y0, x1, y1, x2, y2)
k1 = cal_slope(x0, y0, x1, y1);
k2 = cal_slope(x0, y0, x2, y2);
xangle = atan(abs((k2 - k1)/(1 + k1 * k2)));
%*********************************************************************
function [leftnode, rightnode, xangle] = cal_thr_angle(trnode, node, tr)
leftnode = 0;
rightnode = 0;
xangle = 0;
n = length(trnode);
if n == 1
leftnode = trnode(1);
rightnode = trnode(1);
xangle = 0;
return;
end
x0 = tr.x(node);
y0 = tr.y(node);
for i = 1 : n - 1
x1 = tr.x(trnode(i));
y1 = tr.y(trnode(i));
k1 = cal_slope(x0, y0, x1, y1);
for j = i + 1 : n
x2 = tr.x(trnode(j));
y2 = tr.y(trnode(j));
k2 = cal_slope(x0, y0, x2, y2);
theta = atan(abs((k2 - k1)/(1 + k1 * k2)));
if xangle < theta
xangle = theta;
leftnode = trnode(i);
rightnode = trnode(j);
end
end
end
%*********************************************************************
function [left, right] = leftnrightnode(subtree, tr)
lefttree = tr.tree(:, 1);
righttree = tr.tree(:, 2);
left = 0;
right = 0;
numindex = length(lefttree);
i = 1;
for i = 1 : numindex
[tf, index] = ismember(lefttree(i), subtree);
if tf == 1
left = lefttree(i);
break;
end
end
for i = 1 : numindex
[tf, index] = ismember(righttree(i), subtree);
if tf == 1
right = righttree(i);
break;
end
end
if left == 0
left = right;
end
if right == 0
right = left;
end
%*********************************************************************
function nodeangle = cal_nodeangle(y, x)
nodeangle = atan2(y, x);
if nodeangle < 0
nodeangle = 2*pi + nodeangle;
end
%*********************************************************************
function tree = adjustsubtreeangle(subtr1, subtr2, subtr3, orgnode, tr)
tr1node = subtr1(find(subtr1 <= tr.numLeaves));
tr2node = subtr2(find(subtr2 <= tr.numLeaves));
tr.x(subtr1) = tr.x(subtr1) - tr.x(orgnode);
tr.y(subtr1) = tr.y(subtr1) - tr.y(orgnode);
tr.x(subtr2) = tr.x(subtr2) - tr.x(orgnode);
tr.y(subtr2) = tr.y(subtr2) - tr.y(orgnode);
tr.x(subtr3) = tr.x(subtr3) - tr.x(orgnode);
tr.y(subtr3) = tr.y(subtr3) - tr.y(orgnode);
[tree1left, tree1right] = leftnrightnode(tr1node, tr);
[tree2left, tree2right] = leftnrightnode(tr2node, tr);
tr3node = subtr3;%leftnrightnode(subtr3, tr);
tree3left = tr3node(1);
tree3right = tr3node(2);
a1left = cal_nodeangle(tr.y(tree1left), tr.x(tree1left));
a1right = cal_nodeangle(tr.y(tree1right), tr.x(tree1right));
a2left = cal_nodeangle(tr.y(tree2left), tr.x(tree2left));
a2right = cal_nodeangle(tr.y(tree2right), tr.x(tree2right));
a3left = cal_nodeangle(tr.y(tree3left), tr.x(tree3left));
a3right = cal_nodeangle(tr.y(tree3right), tr.x(tree3right));
daylight = [a1right - a3left, a2right - a1left, a3right - a2left];
equaldaylight = sum(abs(daylight))/3;
adjust1n3 = equaldaylight - daylight(1);
adjust2n3 = daylight(3) - equaldaylight;
% Rotation --- subtr1
a = tr.x(subtr1);
b = tr.y(subtr1);
if adjust1n3 ~= 0
tr.x(subtr1) = a * cos(adjust1n3) - b * sin(adjust1n3);
tr.y(subtr1) = a * sin(adjust1n3) + b * cos(adjust1n3);
end
% Rotation --- subtr2
a = tr.x(subtr2);
b = tr.y(subtr2);
if adjust2n3 ~= 0
tr.x(subtr2) = a * cos(adjust2n3) - b * sin(adjust2n3);
tr.y(subtr2) = a * sin(adjust2n3) + b * cos(adjust2n3);
end
tr.x(subtr1) = tr.x(subtr1) + tr.x(orgnode);
tr.y(subtr1) = tr.y(subtr1) + tr.y(orgnode);
tr.x(subtr2) = tr.x(subtr2) + tr.x(orgnode);
tr.y(subtr2) = tr.y(subtr2) + tr.y(orgnode);
tr.x(subtr3) = tr.x(subtr3) + tr.x(orgnode);
tr.y(subtr3) = tr.y(subtr3) + tr.y(orgnode);
tree = tr;
%*********************************************************************
function tree = adjusttree(lefttree, righttree, thirdtree, node, tr)
tr1 = lefttree(node - tr.numLeaves, 1 : lefttree(node - tr.numLeaves, tr.numNodes));
tr2 = righttree(node - tr.numLeaves, 1 : righttree(node - tr.numLeaves, tr.numNodes));
tr3 = thirdtree(node - tr.numLeaves, 1 : thirdtree(node - tr.numLeaves, tr.numNodes));
[lefttreeangle, l_leftnode, l_rightnode] = caltreeangle(tr1, node, tr);
[righttreeangle, r_leftnode, r_rightnode] = caltreeangle(tr2, node, tr);
[thr_leftnode, thr_rightnode, xangle] = cal_thr_angle(tr3, node, tr);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
d1 = sqrt((tr.x(l_rightnode) - tr.x(thr_leftnode)) * (tr.x(l_rightnode) - tr.x(thr_leftnode)) + (tr.y(l_rightnode) -tr.y(thr_leftnode)) * (tr.y(l_rightnode) -tr.y(thr_leftnode)));
d2 = sqrt((tr.x(l_rightnode) - tr.x(thr_rightnode)) * (tr.x(l_rightnode) - tr.x(thr_rightnode)) + (tr.y(l_rightnode) -tr.y(thr_rightnode)) * (tr.y(l_rightnode) -tr.y(thr_rightnode)));
if d2 > d1
tmp = thr_leftnode;
thr_leftnode = thr_rightnode;
thr_rightnode = tmp;
end
% daylight = 2 * pi - lefttreeangle - righttreeangle - xangle;
% equaldaylight = daylight / 3;
[angle1to3, angle2to3, angle1to2] = cal_daylight(l_leftnode, l_rightnode, r_leftnode, r_rightnode, thr_leftnode, thr_rightnode, node, tr);
daylight = angle1to3 + angle2to3 + angle1to2;
equaldaylight = daylight / 3;
adjust1n3 = equaldaylight - angle1to3;
adjust2n3 = angle2to3 - equaldaylight;
tr.x(tr1) = tr.x(tr1) - tr.x(node);
tr.y(tr1) = tr.y(tr1) - tr.y(node);
tr.x(tr2) = tr.x(tr2) - tr.x(node);
tr.y(tr2) = tr.y(tr2) - tr.y(node);
% Rotation --- subtr1
a = tr.x(tr1);
b = tr.y(tr1);
if adjust1n3 ~= 0
tr.x(tr1) = a * cos(adjust1n3) - b * sin(adjust1n3);
tr.y(tr1) = a * sin(adjust1n3) + b * cos(adjust1n3);
end
% Rotation --- subtr2
a = tr.x(tr2);
b = tr.y(tr2);
if adjust2n3 ~= 0
tr.x(tr2) = a * cos(adjust2n3) - b * sin(adjust2n3);
tr.y(tr2) = a * sin(adjust2n3) + b * cos(adjust2n3);
end
tr.x(tr1) = tr.x(tr1) + tr.x(node);
tr.y(tr1) = tr.y(tr1) + tr.y(node);
tr.x(tr2) = tr.x(tr2) + tr.x(node);
tr.y(tr2) = tr.y(tr2) + tr.y(node);
tree = tr;
%*********************************************************************
function [angle1to3, angle2to3, angle1to2] = cal_daylight(l_leftnode, l_rightnode, r_leftnode, r_rightnode, thr_leftnode, thr_rightnode, node, tr)
x0 = tr.x(node);
y0 = tr.y(node);
llx = tr.x(l_leftnode);
lly = tr.y(l_leftnode);
lrx = tr.x(l_rightnode);
lry = tr.y(l_rightnode);
rlx = tr.x(r_leftnode);
rly = tr.y(r_leftnode);
rrx = tr.x(r_rightnode);
rry = tr.y(r_rightnode);
tlx = tr.x(thr_leftnode);
tly = tr.y(thr_leftnode);
trx = tr.x(thr_rightnode);
tryy = tr.y(thr_rightnode);
angle1to3 = cal_angle(x0, y0, llx, lly, trx, tryy);
angle2to3 = cal_angle(x0, y0, rrx, rry, tlx, tly);
angle1to2 = cal_angle(x0, y0, lrx, lry, rlx, rly);
%*********************************************************************
function txtAngle = cal_textAngle(tr)
nodeIndex = 1 : tr.numLeaves;
X = tr.x(nodeIndex) - tr.x(tr.par(nodeIndex));
Y = tr.y(nodeIndex) - tr.y(tr.par(nodeIndex));
txtAngle = atan(Y./X) * 360/(2*pi);