No BSD License  

Highlights from
meet the family

image thumbnail
from meet the family by nathan q
Visualisation of a family tree in the programming contest.

drawtree(parent,parent2,children,children2,t,nDesc)
function [y,te,ye] = drawtree(parent,parent2,children,children2,t,nDesc)
% Draw a family tree representation.
% Parents is a 1*n vector giving the index of the unique parent of each item (zero if no parent)
% children is a 1*n cell array containing the children of each item (empty if no children)
% t is a n*1 time vector, used as the x coordinate

t0=min(t);
t=t-t0;
n=numel(t);

% The problem is to find the y coordinate for every child to result in a
% readable layout.

% Strategy 1: every child has y > its parent. 

% Strategy 2: define a envelope that we need to stay above. 
% we want y(i) at time t(i) to be > ye(max(find(t(i)>te)))

te = [0 7];
ye = [ 0 0];

y= zeros(1,n);
y(1)=0;
done=false(1,n);
% for i=2:n
%    if done(i)
%       continue;
%    end
%    iFrontier = min(find(te > t(i)));
%    y(i) = ye(iFrontier) + 1;
%    ye = [ye(1:max(iFrontier-1,1)) y(i) ye(min(iFrontier+1,numel(ye)):end)];
%    te = [te(1:max(iFrontier-1,1)) t(i) te(min(iFrontier+1,numel(te)):end)];
%    done(i)=true;
% end

[dsort,isort] = sort(nDesc,'descend');
for i = isort
   if parent2(i)==0
      [y,te,ye] = drawtree_slave(children2, parent2, t,y, te,ye, i);
   end
end

% figure(1);
% plot(t,y,'.');
% for i=1:n;
%     if parent(i); 
%         line([t(parent(i)) t(i)],[y(parent(i)) y(i)],'color','black');
%     elseif parent2(i);
%         line([t(parent2(i)) t(i)],[y(parent2(i)) y(i)],'color','black','linestyle','--');
%     end
% end
% line(te,ye,'color','red');
% 
% figure(2);
% plot(1:n,y,'.');
% for i=1:n; if parent(i); line([parent(i) i],[y(parent(i)) y(i)],'color','black'); end; end

return





function [y,te,ye] = drawtree_slave(children, parent, t,y, te,ye, i)

maxslope = 0.01*numel(parent)/(max(t)-min(t));

%if y(i)<0
if ~parent(i)   % i has no parent
    if t(i)<min(t(y>0))
        y(i)=max(y)/2;
    else
        y(i) = interp1(te,ye,t(i))+1;
    end
else   % i is a child, and we want its parent-child link to pass above all previously plotted nodes
    % first: try simply placing it above the envelope
    y(i) = interp1(te,ye,t(i))+1;
    i1 = min(find(te>t(parent(i))));  % first envelope point to right of parent
    i2 = max(find(te<t(i)));   % last envelope point to left of node i
    % if there are no envelope points between i and parent, nothing to do. 
    % otherwise...
    if i2>=i1
        ycheck = interp1([t(parent(i)) t(i)],[y(parent(i)) y(i)],te(i1:i2));
        [dmax,imax] = max(ye(i1:i2)-ycheck);
        if dmax>0    % a envelope point is above the line joining i to its parent
            imax = i1 + imax - 1;
            slope = (ye(imax) + 1 - y(parent(i))) / (te(imax)-t(parent(i)));
            if slope>maxslope
                % retrospective change to the parent of i
                y(parent(i)) = ye(imax)+1-maxslope*(te(imax)-t(parent(i)));
                % may need to update the envelope:
                ye(te==t(parent(i))) = y(parent(i));
                slope=maxslope;
            end
%            y(i) = y(parent(i)) + slope * (t(i)-t(parent(i)));
        end
    end
 %   line([t(i) t(parent(i))],[y(i) y(parent(i))],'color','black');
end

% update the envelope
if ~isempty(children{i}) | parent(i)
    if any (te==t(i))
        i1 = find(te==t(i));
        ye(i1) = y(i);
    else
        if parent(i)
            i1 = min(find(te>t(parent(i))));  % first envelope point to right of parent
            i2 = max(find(te<t(i)));   % last envelope point to left of node i
            % if there are envelope points between i and its parent, they may need to get deleted.
            if i2>=i1
                ycheck = interp1([t(parent(i)) t(i)],[y(parent(i)) y(i)],te(i1:i2));
                ilow = find(ye(i1:i2)<ycheck) + i1 -1 ;
                te(ilow)=[]; ye(ilow)=[];
            end
        end
        % add i to the envelope list
        i1 = max(find(te<t(i)));
        ye = [ye(1:max(i1,1)) y(i) ye(min(i1+1,numel(ye)):end)];
        te = [te(1:max(i1,1)) t(i) te(min(i1+1,numel(te)):end)];
    end
end
%line(t(i),y(i),'marker','.');


% does y have children?
children1 = children{i};
while ~isempty(children1) 
   % do the first unprocessed child of i:
   [y,te,ye] = drawtree_slave(children, parent, t,y, te,ye, children1(1));
   children1(1)=[];   
end

return

Contact us at files@mathworks.com