Tags:
create new tag
, view all tags

Project Network Diagrams From Tables

2008-10-26 - 02:33:52 by SeanCMorgan in Applications

Introduction

CPM/PERT diagrams (which Microsoft Project refers to by the ambiguous name of "network diagrams") are useful for planning what needs to be done in what order. Often thought of as a "one-off" project planning aid, more generally these precedence diagrams can be used for visualizing recurring procedures like the operations in a manufacturing assembly line, or even a guided procedure for business processes (like on-boarding an employee, which can include orientation, provisioning of equipment, granting security access, and of course forms to be filled out).

This application is based on Stefan Althoefer's Holiday Calendar Blog, which first showed how to generate diagrams from TWiki tables. In that respect, this blog is a sequel. Where Stefan's application requires the EasyTimelinePlugin, this one requires the DirectedGraphPlugin. In both cases, the script that generates the graph can be tedious to work with, and so tables enhance the usability.

I prefer this application's diagrams to MS Project's because they are easier to configure, maintain, and read. It is also much easier collaborate on these diagrams with TWiki than to use MS Project's collaboration environment.

Here's an example of a finished precedence diagram, based on a familiar process. (Of course everyone puts their pants on one leg at a time, but here's proof! With shading applied to completed nodes, you can see that our subject has been caught with his left leg unpanted).

Figure 1: Sample Precedence Diagram - "How To Get Dressed"
Sample.png

ALERT! the diagram in this topic is not dynamically updated because DirectedGraphPlugin and FilterPlugin are not installed at twiki.org.

How it Works

Step 1: Maintain Tables

Two data tables are used in this application:
  1. The (mandatory) set of nodes (tasks or milestones) with the following fields/columns:
    • Node (row number): is the used by the predecessor field. To maintain the referential integrity nodes should not be renumbered, e.g., by deleting rows or sorting table. %EDITTABLE{changerows="add"}% was used to prevent rows from being deleted.
    • Label: text that appears in diagram. Use \n to force a line break (e.g. to change the appearance of a node symbol.
    • Predecessors: a text field of comma-separated values. It would have been nice to use a multiple select here instead, but neither EditTablePlugin nor EditRowPlugin support multiple selects at this time. Large projects could use a separate topic for each node, and a predecessor field in a TWikiForm (since those do support multiple selects). But to avoid "topic proliferation" I would rather have the content in one place if possible.
    • Milestone flag: an indicator to overload node the default node shape
    • Completed flag: an indicator to overload node the default node shading
    • Cluster name: a named group items (see below)
    • Notes: long text that describes the task or milestone.
  2. The (optional) set of "clusters" or groups of nodes. These might be used to show sub-projects, or a set of tasks assigned to particular resource.

Table 1: Nodes (Tasks & Milestones)
Node Label Predecessors Flags Cluster name Notes
1 START\n(naked)   Milestone , Completed    
2 Ready for work 7,10 Milestone    
3 Ready for winter 2,12,14 Milestone Winter  
4 Ready for a fire alarm 9 Milestone , Completed    
5 Pants (left leg) 9   OneLegAtATime  
6 Pants (right leg) 9 Completed OneLegAtATime  
7 Shirt 1 Completed    
8 Jacket 11   Winter  
9 Underwear 1 Completed    
10 Shoes 5,6,13      
11 Sweater 7   Winter  
12 Hat 11   Winter  
13 Socks 1 Completed    
14 Gloves 8,10   Winter  

Table 2: Clusters
Name
(no spaces)
Label
(optional)
Background Color
(optional)
OneLegAtATime Everyone Does It... #f1fff1
Winter Brrrrr #ccccff

This application has "database-like" behaviour, in that the clusters defined in one table are used when maintaining the other, as shown below:

Figure 2: Table of Nodes in Edit Mode
EditTable.png

Step 2: Extract Tabular Data to Create "DOT" Code

As with the earlier blog, FilterPlugin was used for some of the trickier extractions.

<dot>
digraph Title {
   graph [rankdir=LR, ranksep=0.0, bgcolor="#eeeeff"];
   node [shape=box style=filled fillcolor=white fontsize=10]; /* Default node style */

/* Labels for all nodes (tasks+milestones) */
%SEARCH{
   "^\| [0-9]* "
   topic="%TOPIC%"
   multiple="on"
   nonoise="on"
   type="regex"
   format="  $pattern(^\| ([0-9]*) \|.*) [label=\"$pattern(^\| ([0-9]*) \|.*). $pattern(^\| [0-9]* \| (.*?) \|.*)\"]"
}%

/* Milestones (overload shape) */
%SEARCH{
   "^\| .*\|.*\|.*\|.*Milestone.*"
   topic="%TOPIC%"
   multiple="on"
   nonoise="on"
   type="regex"
   format="  $pattern(^\| ([0-9]*) \|.*) [shape=diamond]"
}%

/* Completed nodes (overload fillcolor) */
%SEARCH{
   "^\| .*\|.*\|.*\|.*Completed.*"
   topic="%TOPIC%"
   multiple="on"
   nonoise="on"
   type="regex"
   format="  $pattern(^\| ([0-9]*) \|.*) [fillcolor=grey]"
}%

/* Clusters */
%EXTRACT{topic="%TOPIC%" expand="off" skip="1"
   pattern="^ \| ([^\|]*) \| ([^\|]*) \| ([^\|]*) \|"
   format="subgraph cluster$1 {label=\"$2\" bgcolor=\"$3\" $percntSEARCH{\"\| $1 \|\" topic=\"%TOPIC%\" multiple=\"on\" nonoise=\"on\" type=\"regex\" format=\"$pattern(^\| ([0-9]*) .*)\"}$percnt}"
}%

/* Precedence */
%EXTRACT{topic="%TOPIC%" expand="off"
   pattern="^\| ([0-9]*) \| ([^\|]*) \| ([^\|]*) \| ([^\|]*) ?\| ([^\|]*) ?\| ([^\|]*) ?\|"
   format="  $percntCALC{$SUBSTITUTE($TRANSLATE($3,$comma,;),;, -> $1; )}$percnt -> $1 $n"
}%
}
</dot>

Step 3: Generate the DOT Code

The DirectedGraphPlugin stores a file with the .dot extension in /twiki/working/temp/.

digraph Title {
   graph [rankdir=LR, ranksep=0.0, bgcolor="#eeeeff"];
   node [shape=box style=filled fillcolor=white fontsize=10]; /* Default node style */

/* Labels for all nodes (tasks+milestones) */
  1 [label="1. START\n(naked)"]
  2 [label="2. Ready for work"]
  3 [label="3. Ready for winter"]
  4 [label="4. Ready for a fire alarm"]
  5 [label="5. Pants (left leg)"]
  6 [label="6. Pants (right leg)"]
  7 [label="7. Shirt"]
  8 [label="8. Jacket"]
  9 [label="9. Underwear"]
  10 [label="10. Shoes"]
  11 [label="11. Sweater"]
  12 [label="12. Hat"]
  13 [label="13. Socks"]
  14 [label="14. Gloves"]

/* Milestones (overload shape) */
  1 [shape=diamond]
  2 [shape=diamond]
  3 [shape=diamond]
  4 [shape=diamond]

/* Completed nodes (overload fillcolor) */
  1 [fillcolor=grey]
  4 [fillcolor=grey]
  6 [fillcolor=grey]
  7 [fillcolor=grey]
  9 [fillcolor=grey]
  13 [fillcolor=grey]

/* Clusters */
subgraph clusterOneLegAtATime {label="Everyone Does It..." bgcolor="#f1fff1"
  5
  6
}
subgraph clusterWinter {label="Brrrrr" bgcolor="#ccccff"
  3
  8
  11
  12
  14
}

/* Precedence */
  7-> 2; 10 -> 2 
  2-> 3; 12-> 3; 14 -> 3 
  9 -> 4 
  9 -> 5 
  9 -> 6 
  1 -> 7 
  11 -> 8 
  1 -> 9 
  5-> 10; 6-> 10; 13 -> 10 
  7 -> 11 
  11 -> 12 
  1 -> 13 
  8-> 14; 10 -> 14 
}

The original code for the cluster/subgraph section was a bit ugly because I couldn't get a newline to appear in the output of %EXTRACT%. For legibility of this article, I manually cleaned up the white space a bit (I cheated embarrassment ).

Step 4: Generate the Diagram

The DirectedGraphPlugin calls Graphviz to generate the diagram from the .dot file.

Some Implementation Details

  • A space was inserted before each line in the cluster table, to differentiate the tables during data extraction (a different regular expression works too).
  • SEARCH strings like "\| ([0-9]*) are used to find all lines in the topic that have table data except for the table header, which does not a number in the first cell.
  • The predecessor extract skips nodes without predecessors by virtue of those cells containing only one space.
  • The node numbers were prefixed to the node labels (e.g., "1. START") as an aid when maintaining the predecessor lists.
  • Precedence (this was the trickiest bit): after the FilterPlugin EXTRACTs the row number and predecessor list, the SpreadSheetPlugin is used to split the comma-separated predecessors into separate entries. But since its SUBSTITUTE can't handle commas, they first had to be TRANSLATEd into semi-colons. But in the end:
    • this: "| Node_x | Predecessor_1,Predecessor_2 |..."
    • becomes: "Predecessor_1 -> Node_x; Predecessor_2 -> Node_x"

Next Steps

  • Use the Graphviz imagemap feature to create links from nodes to the appropriate table row, for ease of maintenance. That would provide behaviour similar to clicking on a node in MS Project.
  • Fields for start dates, durations, resources... Gantt charts, and all the other stuff that MS Project has.
  • Edge labels: Graphviz has the ability to add labels to the lines (or 'edges'). Besides providing additional annotation, this could be used by those who prefer 'activity-on-the-line' diagrams to this 'activity-on-the-node' diagram.

Related Resources

Comments

Extra cool.

-- Michael Daum - 27 Oct 2008

.

Topic attachments
I Attachment History Action Size Date Who Comment
PNGpng EditTable.png r1 manage 10.5 K 2008-10-26 - 02:27 SeanCMorgan Table of nodes in edit mode
PNGpng Sample.png r1 manage 45.7 K 2008-10-26 - 02:27 SeanCMorgan Sample Precedence Diagram
Edit | Attach | Watch | Print version | History: r2 < r1 | Backlinks | Raw View | Raw edit | More topic actions
Topic revision: r2 - 2008-11-04 - SeanCMorgan
 

Twitter Delicious Facebook Digg Google Bookmarks E-mail LinkedIn Reddit StumbleUpon    
  • Help
  • Learn about TWiki  
  • Download TWiki
This site is powered by the TWiki collaboration platform Powered by Perl Hosted by OICcam.com Ideas, requests, problems regarding TWiki? Send feedback. Ask community in the support forum.
Copyright © 1999-2015 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.