Combining graphviz with a timeline for events with a time dimension

I use graphviz a lot and love it for network / graph visualization. But this time I am visualizing a network of events with a time stamp (think years not secs).

So I was looking for something that allows me a combination of timelines plus a digraph. Based on some Stackexchange snippets I am currently working with something like this. But it seems a bit of a hack and leads to pretty unweildy code.

Any ideas about how I could do this better?

digraph shells {
size="7,8";
node [fontsize=24, shape = plaintext];

1972 -> 1976;
1976 -> 1978;
1978 -> 1980;
1980 -> 1982;
1982 -> 1984;
1984 -> 1986;
1986 -> 1988;
1988 -> 1990;
1990 -> future;

node [fontsize=20, shape = box];
{ rank=same;  1976 Mashey Bourne; }
{ rank=same;  1978 Formshell csh; }
{ rank=same;  1980 esh vsh; }
{ rank=same;  1982 ksh "System-V"; }
{ rank=same;  1984 v9sh tcsh; }
{ rank=same;  1986 "ksh-i"; }
{ rank=same;  1988 KornShell Perl rc; }
{ rank=same;  1990 tcl Bash; }
{ rank=same;  "future" POSIX "ksh-POSIX"; }

Thompson -> Mashey;
Thompson -> Bourne;
Thompson -> csh;
csh -> tcsh;
Bourne -> ksh;
Bourne -> esh;
Bourne -> vsh;
Bourne -> "System-V";
Bourne -> v9sh;
v9sh -> rc;
Bourne -> Bash;
"ksh-i" -> Bash;
KornShell -> Bash;
esh -> ksh;
vsh -> ksh;
Formshell -> ksh;
csh -> ksh;
KornShell -> POSIX;
"System-V" -> POSIX;
ksh -> "ksh-i";
"ksh-i" -> KornShell;
KornShell -> "ksh-POSIX";
Bourne -> Formshell;

edge [style=invis];
1984 -> v9sh -> tcsh ;
1988 -> rc -> KornShell;
Formshell -> csh;
KornShell -> Perl;

}

The short answer is that your current input is about the minimum you need to get what you want without a lot of extra analysis.

Long answer: Your current input is just about minimal in specifying what needs to be determined. You clearly need the chain of years; you clearly need the graph specifying the relations among the shells. That only leaves the “rank=same” subgraphs and the invisible edges at the bottom.

You could avoid the former if shell nodes corresponded to the least possible year allowed by the edge constraints. For example, if vsh and esh corresponded to 1978. Since this is not the case, there needs to be some constraint to force them to correspond to 1980. You could use indirect constraints such as setting minlen=2 in the edge Bourne->vsh, but this would require a lot of analysis, such as making sure Thompson->Bourne has exactly length 1. The cleanest way is doing what you are doing with the rank=same constraints. (Again, you don’t need all of these, but to determine which ones you can remove, you would again have to analyze the expected layout.)

That just leaves the invisible edges. The year constraints are not necessary as they would be the default. The other constraints are only needed if you want them. Why, for example, do you want the rc node to the left of the KornShell node?