0

I came up with this fantastic reply to a question posed sometime ago about how to plot a tree. I have been trying to change the color and shape of some of the nodes based on an additional column from the data. For context, the specific code from the other question that builds up a drawing of a hierarchical tree is as follows:

Code

### tree diagram with gnuplot
reset session

#ID  Parent   Name
$Data <<EOD
   1    NaN   Ant
   2      1   Ape
   3      1   Ass
   4      2   Bat
   5      2   Bee
   6      2   Cat
   7      3   Cod
   8      3   Cow
   9      3   Dog
  10      7   Eel
  11      7   Elk
  12      7   Emu
  13      9   Fly
  14      9   Fox
  15      4   Gnu
  16      1   Hen
  17     16   Hog
  18     12   Jay
  19     12   Owl
  20     15   Pig
  21     15   Pug
  22     12   Ram
  23     14   Rat
  24     12   Sow
  25      7   Yak
EOD

# put datablock into strings
IDs = Parents = Names = ''
set table $Dummy
    plot $Data u (IDs = IDs.strcol(1).' '): \
                 (Parents = Parents.strcol(2).' '): \
                 (Names = Names.strcol(3).' ') w table
unset table

# Top node has no parent ID 'NaN'
Start(n) = int(sum [i=1:words(Parents)] (word(Parents,i) eq 'NaN' ? int(word(IDs,i)) : 0))

# get list index by ID
ItemIdx(s,n) = n == n ? (tmp=NaN, sum [i=1:words(s)] ((word(s,i)) == n ? (tmp=i,0) : 0),     tmp) : NaN

# get parent of ID n
Parent(n) = word(Parents,ItemIdx(IDs,n))

# get level of ID n, recursive function
Level(n) = n == n ? Parent(n)>0 ? Level(Parent(n))-1 : 0 : NaN

# get number of children of ID n
ChildCount(n) = int(sum [i=1:words(Parents)] (word(Parents,i)==n))

# Create child list of ID n
ChildList(n) = (Ch = ' ', sum [i=1:words(IDs)] (word(Parents,i)==n ? (Ch = Ch.word(IDs,i).' ',1) : (Ch,0) ), Ch )

# m-th child of ID n
Child(n,m) = word(ChildList(n),m)

# List of leaves, recursive function
LeafList(n) = (LL='', ChildCount(n)==0 ? LL=LL.n.' ' : sum [i=1:ChildCount(n)]     (LL=LL.LeafList(Child(n,i)), 0),LL)

# create list of all leaves
LeafAll = LeafList(Start(0))

# get x-position of ID n, recursive function
XPos(n) = ChildCount(n) == 0 ? ItemIdx(LeafAll,n) : (sum [i=1:ChildCount(n)]     (XPos(Child(n,i))))/(ChildCount(n))

# create the tree datablock for plotting
set print $Tree
    do for [j=1:words(IDs)] {
        n = int(word(IDs,j))
        print sprintf("% 3d % 7.2f % 4d % 5s", n, XPos(n), Level(n), word(Names,j))
    }
set print
print $Tree

# get x and y distance from ID n to its parent
dx(n) = XPos(Parent(int(n))) - XPos(int(n))
dy(n) = Level(Parent(int(n))) - Level(int(n))

unset border
unset tics
set offsets 0.25, 0.25, 0.25, 0.25

plot $Tree u 2:3:(dx($1)):(dy($1)) w vec nohead ls -1 not,\
        '' u 2:3 w p pt 7 ps 6 lc rgb 0xccffcc not, \
        '' u 2:3 w p pt 6 ps 6 lw 1.5 lc rgb "black" not, \
        '' u 2:3:4 w labels offset 0,0.1 center not
### end of code

The code produces the following output:

enter image description here

No suppose that the data set has a new column info

#ID  Parent   Name    Info
$Data <<EOD
   1    NaN   Ant   1
   2      1   Ape   2
   3      1   Ass   2
   4      2   Bat   1
   5      2   Bee   1
   6      2   Cat   1
   7      3   Cod   1
   8      3   Cow   1
   9      3   Dog   1
  10      7   Eel   1
  11      7   Elk   1
  12      7   Emu   1
  13      9   Fly   1
  14      9   Fox   1
  15      4   Gnu   1
  16      1   Hen   2
  17     16   Hog   1
  18     12   Jay   1
  19     12   Owl   1
  20     15   Pig   2
  21     15   Pug   4
  22     12   Ram   1
  23     14   Rat   1
  24     12   Sow   1
  25      7   Yak   1
EOD

I would like to have the nodes with info value = 1 colored yellow, = 2 colored green, = 3 shaped as a square instead of a circle. I've been wrestling with this for some time, I can get some help.

1 Answers1

2

Both the color and the shape can be encoded in arrays. The array must be as large as the largest index value you expect to have. Here I use the data you show above and two length 4 arrays that encode [circle, circle, square, square] and [yellow, green, yellow, green]

# put datablock into strings
IDs = Parents = Names = Shapes = ''
set table $Dummy
    plot $Data u (IDs = IDs.strcol(1).' '): \
                 (Parents = Parents.strcol(2).' '): \
                 (Names = Names.strcol(3).' '): \
                 (Shapes = Shapes.strcol(4).' ') w table
unset table

# Top node has no parent ID 'NaN'
Start(n) = int(sum [i=1:words(Parents)] (word(Parents,i) eq 'NaN' ? int(word(IDs,i)) : 0))

# get list index by ID
ItemIdx(s,n) = n == n ? (tmp=NaN, sum [i=1:words(s)] ((word(s,i)) == n ? (tmp=i,0) : 0),     tmp) : NaN

# get parent of ID n
Parent(n) = word(Parents,ItemIdx(IDs,n))

# get level of ID n, recursive function
Level(n) = n == n ? Parent(n)>0 ? Level(Parent(n))-1 : 0 : NaN

# get number of children of ID n
ChildCount(n) = int(sum [i=1:words(Parents)] (word(Parents,i)==n))

# Create child list of ID n
ChildList(n) = (Ch = ' ', sum [i=1:words(IDs)] (word(Parents,i)==n ? (Ch = Ch.word(IDs,i).' ',1) : (Ch,0) ), Ch )

# m-th child of ID n
Child(n,m) = word(ChildList(n),m)

# List of leaves, recursive function
LeafList(n) = (LL='', ChildCount(n)==0 ? LL=LL.n.' ' : sum [i=1:ChildCount(n)]     (LL=LL.LeafList(Child(n,i)), 0),LL)

# create list of all leaves
LeafAll = LeafList(Start(0))

# get x-position of ID n, recursive function
XPos(n) = ChildCount(n) == 0 ? ItemIdx(LeafAll,n) : (sum [i=1:ChildCount(n)]     (XPos(Child(n,i))))/(ChildCount(n))

# create the tree datablock for plotting
set print $Tree
    do for [j=1:words(IDs)] {
        n = int(word(IDs,j))
        print sprintf("% 3d % 7.2f % 4d % 5s % 2s", n, XPos(n), Level(n), word(Names,j), word(Shapes,j))
    }
set print
print $Tree

# get x and y distance from ID n to its parent
dx(n) = XPos(Parent(int(n))) - XPos(int(n))
dy(n) = Level(Parent(int(n))) - Level(int(n))

unset border
unset tics
set offsets 0.25, 0.25, 0.25, 0.25


array shape[4] = [ 6, 6, 4, 4 ]        # pointtype 6 = circle, pointtype 4 = square
array color[4] = [ 0xeeee00, 0xccffcc, 0xeeee00, 0xccffcc ]

plot $Tree u 2:3:(dx($1)):(dy($1)) w vec nohead ls -1 not,\
        '' u 2:3:(shape[$5]+1):(color[$5]) w p pt variable ps 6 lc rgb variable not, \
        '' u 2:3:(shape[$5]) w p pt variable ps 6 lw 1.5 lc rgb "black" not, \
        '' u 2:3:4 w labels offset 0,0.1 center not
### end of code

enter image description here

Ethan
  • 13,715
  • 2
  • 12
  • 21