ubuntuprocessgnuplot

Draw process tree with gnuplot


similar to this question here I want to draw process tree where a PID is given, I should be able to draw that process and its children as a tree. However, I want to preserve parent children relationship between nodes/edges. What I mean is, any two children should not have edge between. Coordinates actually do not matter. Also, I am open for other drawing tool options. I tried the accepted answer of mentioned question but it links all nodes.

Any kind of suggestion/help would make my day.

Note: I am using Ubuntu


Solution

  • You don't give too many details what you have and what you exactly want. So I assume something. Certainly, room for improvements. To learn more about plotting styles, in gnuplot console check help points, help vectors, help labels.

    Script:

    ### drawing a simple tree
    reset session
    
    $Children <<EOD
    23
    34
    45
    56
    67
    78
    EOD
    
    $Parent <<EOD
    123
    EOD
    
    unset border
    unset tics
    set offsets 0.2,0.2,0.2,0.2
    set key noautotitle
    Size = 8
    
    plot $Children u (Last=$0):(1):1 w labels, \
                '' u 0:(1):(Last/2-$0):(1) w vec nohead lc rgb "black", \
                '' u 0:(1):(Size) w p pt 7 ps var lc rgb "yellow", \
                '' u 0:(1):1 w labels, \
         $Parent u (Last/2):(2):(Size) w p pt 7 ps var lc rgb "light-grey", \
              '' u (Last/2):(2):1 w labels center
    ### end of script
    

    Result:

    enter image description here

    Addition:

    Actually, you can do a bit more complex tree diagrams with gnuplot. Fortunately, gnuplot allows for recursive functions.

    The input consists out of 5 columns without header. Each ID has only one parent, except one which is the top node. An ID can have several children.

    Prerequisites:

    Improvements are welcome.

    Script: (actually some "nonsense" tree)

    ### tree diagram with gnuplot
    reset session
    
    #ID  Parent   Name  Shape  Color
    $Data <<EOD
       1    NaN   Ant    4     0xffcccc
       2      1   Ape   14     0xccffcc
       3      1   Ass    6     0xcccccc
       4      2   Bat    6     0xffffff
       5      2   Bee    6     0xcccccc
       6      2   Cat    6     0xffffcc
       7      3   Cod    6     0xcccccc
       8      3   Cow    6     0xcccccc
       9      3   Dog   12     0xccffcc
      10      7   Eel    6     0xffffff
      11      7   Elk    6     0xffcccc
      12      7   Emu    6     0xccccff
      13      9   Fly    6     0xcccccc
      14      9   Fox    6     0xcccccc
      15      4   Gnu    4     0xffcccc
      16      1   Hen    6     0xffccff
      17     16   Hog    6     0xcccccc
      18     12   Jay    4     0xffcccc
      19     12   Owl    6     0xccffff
      20     15   Pig    6     0xffffcc
      21     15   Pug    6     0xcccccc
      22     12   Ram    4     0xcccccc
      23     14   Rat    4     0xffffff
      24     12   Sow    6     0xffffff
      25      7   Yak    6     0xcccccc
    EOD
    
    # put datablock into strings
    IDs = Parents = Names = Shapes = Colors = ''
    addToList(list, col) = sprintf("%s %s", list, strcol(col))
    stats $Data u (IDs     = addToList(IDs,1), \
                   Parents = addToList(Parents,2), \
                   Names   = addToList(Names,3), \
                   Shapes  = addToList(Shapes,4), \
                   Colors  = addToList(Colors,5)) nooutput
    
    # 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 % 4s % 10s", \
                   n, XPos(n), Level(n), word(Names,j), word(Shapes,j), word(Colors,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
    set key noautotitle
    
    plot $Tree u 2:3:(dx($1)):(dy($1)) w vec nohead ls -1,\
            '' u 2:3:($5+1):6 w p pt var ps 6 lc rgb var, \
            '' u 2:3:5 w p pt var ps 6 lw 1.5 lc rgb "black", \
            '' u 2:3:4 w labels offset 0,0.1 center
    ### end of script
    

    Result:

    enter image description here