5
$\begingroup$

I am trying to create a multi-coloured tree plot (Mathematica 9) where each branch is coloured according to its parent node value. For example, for a tree plot with three nodes, n1, n2 and n3, coming from a single parent node (n0), the children nodes of n1 should be red & n2 and n3 should be green.

TreePlot[nodes, EdgeRenderingFunction -> ({Red, Line[#1]} &), 
 VertexRenderingFunction -> (Inset[
     Row[{If[Last[#2] > 3, Rotate[Last[#2], 90 Degree], 
        Last[#2]]}], #1, Background -> White] &)]

tree plot

I am using the EdgeRenderingFunction for this within the following expression which will render the edges of the tree plot. The problem, I think, is that the If statement is not evaluated straight away and so the compiler does not recognise the first option (contained within the If statement) as a relevant one. As you can see I'm trying to create a tree plot with red and green branches.

TreePlot[nodes, 
 EdgeRenderingFunction -> ({If[Last[#2] == 1, Red, Green], 
     Line[#1]} &), 
 VertexRenderingFunction -> (Inset[
     Row[{If[Last[#2] > 3, Rotate[Last[#2], 90 Degree], 
        Last[#2]]}], #1, Background -> White] &)]

The error message I get is:

If is not a Graphic Primitive or Directive

enter image description here

Thanks for your time in helping me with this.

$\endgroup$
  • $\begingroup$ Does your code work for the edges if you comment out the VertexRenderingFunction part? What is your goal with the vertex rendering? The second parameter passed (#2) is the vertex name, so I'm not sure what your function is trying to do with that. $\endgroup$ – aardvark2012 Sep 14 '17 at 12:30
  • $\begingroup$ For a traditional tree there is a single root node, so why aren't all your branches the same color? $\endgroup$ – David G. Stork Sep 14 '17 at 16:43
  • $\begingroup$ aardvark2012 - no, the code does not work if I comment out the VertexRenderingFunciton part. Davis G. Stork - Because each child node represents a different interrelated group. This can be done in the R programming language. $\endgroup$ – awyr_agored Sep 15 '17 at 2:30
  • 1
    $\begingroup$ "coloured according to its parent node value" <- Where and how is this "parent node value" stored? Can you provide sample data? The error is no doubt because == does not evaluate. This indicates that you may have nodes with non-numerical names. The fix may be as simple as using ===, but I can't tell for sure without seeing a complete example (with data). $\endgroup$ – Szabolcs Sep 15 '17 at 8:16
  • $\begingroup$ Szabolics - Here's a sample of the node list: {{0} -> {0, 1}, {0} -> {0, 2}, {0} -> {0, 3}, {0, 1} -> {0, 1, 4}, {0, 1} -> {0, 1, 5}, {0, 1} -> {0, 1, 6}, {0, 1} -> {0, 1, 7}, {0, 1} -> {0, 1, 8}... The code works with === or TrueQ[If...] instead of == (Thanks!) but I got an unexpected result - all edges were rendered the same colour. So either the EdgeRenderingFunction function renders the whole tree object rather than it's parts or I'll need to include the edge colour into the tree data structure (node table), or use a different way (function) to represent the tree? $\endgroup$ – awyr_agored Sep 15 '17 at 12:14
4
+50
$\begingroup$

The problem seems to be at least partially due to how you reference the arguments of EdgeRenderingFunction. We can label the edges with Last[#2] to see what we're working with:

nodes = {{0} -> {0, 1}, {0} -> {0, 2}, {0} -> {0, 3}, {0, 1} -> {0, 1, 4}, {0, 1} -> {0, 1, 5}, {0, 1} -> {0, 1, 6}, 
  {0, 1} -> {0, 1, 7}, {0, 1} -> {0, 1, 8}};
TreePlot[nodes, 
 EdgeRenderingFunction -> ({Line[#1], 
     Inset[Last[#2], Mean[#1], Automatic, Automatic, #[[1]] - #[[2]], 
      Background -> White]} &), 
 VertexRenderingFunction -> (Inset[
     Row[{If[Last[#2] > 3, Rotate[Last[#2], 90 Degree], 
        Last[#2]]}], #1, Background -> White] &)]

enter image description here

So none of these are ever going to be 1. You could, of course, use these for your colouring. You could also use the values in First[#2]:

TreePlot[nodes, 
 EdgeRenderingFunction -> ({Line[#1], 
     Inset[First[#2], Mean[#1], Automatic, Automatic, #[[1]] - #[[2]],
       Background -> White]} &), 
 VertexRenderingFunction -> (Inset[
     Row[{If[Last[#2] > 3, Rotate[Last[#2], 90 Degree], 
        Last[#2]]}], #1, Background -> White] &)]

enter image description here

You should be able to use any of these values to colour the edges however you want. For example, using #2[[1, -1]] for your condition gives:

TreePlot[nodes, 
 EdgeRenderingFunction -> ({If[#2[[1, -1]] == 1, Red, Green], 
     Line[#1]} &), 
 VertexRenderingFunction -> (Inset[
     Row[{If[Last[#2] > 3, Rotate[Last[#2], 90 Degree], 
        Last[#2]]}], #1, Background -> White] &)]

enter image description here

$\endgroup$
  • $\begingroup$ Thank you for a great explanation $\endgroup$ – awyr_agored Sep 17 '17 at 11:02
4
$\begingroup$

You code uses rules for edge styles, e.g.:

func[elist_, pn_, col_] := 
 Module[{rules = 
    MapThread[ed_[#1, x_] :> Style[ed[#1, x], #2] &, {pn, col}]},
  elist /. rules]

For example:

TreeGraph[
 func[{0 -> 1, 0 -> 2, 1 -> 3, 1 -> 4, 2 -> 5, 2 -> 6}, {0, 1, 
   2}, {Red, Green, {Purple, Thick, Dashed}}]]

enter image description here

$\endgroup$
  • $\begingroup$ Thanks ubpdqn for this example. $\endgroup$ – awyr_agored Sep 18 '17 at 11:48
2
$\begingroup$

There are simpler ways to do this. I do not have Mathematica 9 around, but I think this should work.

First, I recommend representing trees as directed graphs. This way the identity of the root vertex is already encoded. IGDirectedTree from IGraph/M is useful for this (Mathematica 10.0+ only), otherwise you can do a BreadthFirstScan.

Consider this directed tree:

tree = Graph@{1 -> 2, 2 -> 3, 1 -> 4, 1 -> 5, 1 -> 6, 2 -> 7, 2 -> 8, 
    4 -> 9, 2 -> 10, 2 -> 11, 1 -> 12, 12 -> 13, 2 -> 14, 13 -> 15, 
    2 -> 16, 2 -> 17, 9 -> 18, 4 -> 19, 11 -> 20};

Now simply use patterns to select a set of edges to colour:

Graph[tree,
 VertexShapeFunction -> "Name",
 EdgeStyle -> {1 \[DirectedEdge] _ -> Red, 2 \[DirectedEdge] _ -> Blue, 4 \[DirectedEdge] _ -> Green, 12 \[DirectedEdge] _ -> Orange}
 ]

enter image description here

Having a directed tree was useful because we could easily distinguish "down-edges" (away from the root) from "up-edges" (towards the root).

If you do not want the arrowheads displayed, add

EdgeShapeFunction -> "Line",
PerformanceGoal -> "Quality"

Like this:

Graph[tree,
 VertexShapeFunction -> "Name",
 EdgeStyle -> {Thick, (1 \[DirectedEdge] _) -> Red, 2 \[DirectedEdge] _ -> Blue, 4 \[DirectedEdge] _ -> Green, 12 \[DirectedEdge] _ -> Orange},
 EdgeShapeFunction -> "Line",
 PerformanceGoal -> "Quality"
]

enter image description here

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.