I have a complex cell that represents a tree structure:
CellArray = {1,1,1,{1,1,1,{1,1,{1,{1 1 1 1 1 1 1 1}, 1,1}, 1,1},1,1,1},1,1,1,{1,1,1,1}};
I want to plot the representative tree from it by using treeplot(p)
, but I'm not sure how to construct the array p
for it to display correctly.
We can create a recursive function, which explores your cell array and creates a tree pointer array (as described in the docs) to each node's parent.
This function takes a cell array (like the one in your question) which contains either scalars or nested cell arrays.
treebuilder
logic:treebuilder
on that cell, returning the maximum node number which was reached (along with the generated sub-tree).function treearray = getTreeArray(cellarray)
% initialise the array construction from node 0
treearray = [0, treebuilder(cellarray, 1)];
% recursive tree building function, pass it a cell array and root node
function [out, node] = treebuilder(cellarray, rnode)
% Set up variables to be populated whilst looping
out = [];
% Start node off at root node
node = rnode;
% Loop over cell array elements, either recurse or add node
for ii = 1:numel(cellarray)
tb = []; node = node + 1;
if iscell(cellarray{ii})
[tb, node] = treebuilder(cellarray{ii}, node);
end
out = [out, rnode, tb];
end
end
end
Here is a more simple example than yours, so we can check logic works easily.
myCellArray = {1 1 {1 1 1 {1 1 1}}};
% This cell array has 3 levels:
% - 3 child nodes (2,3,4) of the root node (1)
% - Last node on the first level (4) has 4 children:
% - 4 child nodes on second level (5,6,7,8)
% - Last node on the first level (8) has 3 children:
% - 3 child nodes on third level (9,10,11)
myTreeArray = getTreeArray(myCellArray);
% Output, we see the corresponding nodes as listed above:
% [0 1 1 1 4 4 4 4 8 8 8]
treeplot(myTreeArray)
I think this works as expected, note you don't have to define the myCellArray
or myTreeArray
variables:
treeplot(getTreeArray({1,1,1,{1,1,1,{1,1,{1,{1 1 1 1 1 1 1 1}, 1,1}, 1,1},1,1,1},1,1,1,{1,1,1,1}}))
Here is the output image, showing that the algorithm can cope with the more complicated tree. Speed doesn't seem too bad either, although displaying extremely complicated trees will be fairly redundant anyway!
You can label the nodes by getting their position using treelayout
and keeping track of the values as you encounter them when building the tree array. The function should be tweaked for this "keeping track" like so:
function [treearray, nodevals] = getTreeArray(cellarray)
% initialise the array construction from node 0
[nodes, ~, nodevals] = treebuilder(cellarray, 1);
treearray = [0, nodes];
% recursive tree building function, pass it a cell array and root node
function [out, node, nodevals] = treebuilder(cellarray, rnode)
% Set up variables to be populated whilst looping
out = []; nodevals = {};
% Start node off at root node
node = rnode;
% Loop over cell array elements, either recurse or add node
for ii = 1:numel(cellarray)
node = node + 1;
if iscell(cellarray{ii})
[tb, node, nv] = treebuilder(cellarray{ii}, node);
out = [out, rnode, tb];
nodevals = [nodevals, nv];
else
out = [out, rnode];
nodevals = [nodevals, {node; cellarray{ii}}];
end
end
end
end
Note: You could use a similar adaptation to keep track of the node number instead of the node value if you wanted to number each node on the plot.
I have used a cell array here so that you could have text or numerical values on each node. If you only ever want numerical values, it may shorten the post-formatting to store nodevals
in a matrix instead.
Then to plot this you can use
% Run the tree building script above
[treearray, nodevals] = getTreeArray(myCellArray);
% Plot
treeplot(treearray);
% Get the position of each node on the plot
[x,y] = treelayout(treearray);
% Get the indices of the nodes which have values stored
nodeidx = cell2mat(nodevals(1,:));
% Get the labels (values) corresponding to those nodes. Must be strings in cell array
labels = cellfun(@num2str, nodevals(2,:), 'uniformoutput', 0);
% Add labels, with a vertical offset to the y coords so that labels don't sit on nodes
text(x(nodeidx), y(nodeidx) - 0.03, labels);
Example output for the cell myCellArray = {{17, 99.9}, 50}
, where I've chosen those numbers to make it clear they're not the actual "node number"!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With