50 votes

Mise en page de l'arbre généalogique avec Dot/GraphViz

J'essaie de dessiner un arbre généalogique avec Dot et GraphViz.

Voici ce que j'ai actuellement :

# just graph set-up
digraph simpsons {
ratio = "auto"
mincross = 2.0

# draw some nodes
"Abraham"   [shape=box, regular=1, color="blue"] ;
"Mona"      [shape=box, regular=1, color="pink"] ;
"Clancy"    [shape=box, regular=1, color="blue"] ;
"Jackeline" [shape=box, regular=1, color="pink"] ;
"Herb"      [shape=box, regular=1, color="blue"] ;
"Homer"     [shape=box, regular=1, color="blue"] ;
"Marge"     [shape=box, regular=1, color="pink"] ;
"Patty"     [shape=box, regular=1, color="pink"] ;
"Selma"     [shape=box, regular=1, color="pink"] ;
"Bart"      [shape=box, regular=1, color="blue"] ;
"Lisa"      [shape=box, regular=1, color="pink"] ;
"Maggie"    [shape=box, regular=1, color="pink"] ;
"Ling"      [shape=box, regular=1, color="blue"] ;
# creating tiny nodes w/ no label, no color
"ParentsHomer" [shape=diamond,style=filled,label="",height=.1,width=.1] ;
"ParentsMarge" [shape=diamond,style=filled,label="",height=.1,width=.1] ;
"ParentsBart"  [shape=diamond,style=filled,label="",height=.1,width=.1] ;

# draw the edges
"Abraham"      -> "ParentsHomer" [dir=none, weight=1] ;
"Mona"         -> "ParentsHomer" [dir=none, weight=1] ;
"ParentsHomer" -> "Homer"        [dir=none, weight=2] ;
"ParentsHomer" -> "Herb"         [dir=none, weight=2] ;
"Clancy"       -> "ParentsMarge" [dir=none, weight=1] ;
"Jackeline"    -> "ParentsMarge" [dir=none, weight=1] ;
"ParentsMarge" -> "Marge"        [dir=none, weight=2] ;
"ParentsMarge" -> "Patty"        [dir=none, weight=2] ;
"ParentsMarge" -> "Selma"        [dir=none, weight=2] ;
"Homer"        -> "ParentsBart"  [dir=none, weight=1] ;
"Marge"        -> "ParentsBart"  [dir=none, weight=1] ;
"ParentsBart"  -> "Bart"         [dir=none, weight=2] ;
"ParentsBart"  -> "Lisa"         [dir=none, weight=2] ;
"ParentsBart"  -> "Maggie"       [dir=none, weight=2] ;
"Selma"        -> "Ling"         [dir=none, weight=2] ;
}

Si je fais passer cela par dot ( dot simpsons.dot -Tsvg > simpsons.svg ), J'obtiens la mise en page suivante : Original, made by dot/graphviz

Cependant, j'aimerais que les bords ressemblent davantage à un "arbre généalogique" : une jonction en T entre deux personnes mariées, la ligne verticale du T se ramifiant à nouveau en une jonction en T inversé avec de petites subdivisions pour chacun des enfants, comme cette maquette, réalisée avec KolourPaint :

what I would like to achieve

Quelle est la syntaxe du point que je dois utiliser pour y parvenir ?

17 votes

Vous avez oublié Hugo entre Bart et Lisa

23voto

greg Points 479

Essayez ce qui suit :

digraph simpsons {  
  subgraph Generation0 {
    rank = same
    Abraham [shape = box, color = blue]
    Mona [shape = box, color = pink]
    AbrahamAndMona [shape = point]
    Abraham -> AbrahamAndMona [dir = none]
    AbrahamAndMona -> Mona [dir = none]

    Clancy [shape = box, color = blue]
    Jackeline [shape = box, color = pink]
    ClancyAndJackeline [shape = point]
    Clancy -> ClancyAndJackeline [dir = none]
    ClancyAndJackeline -> Jackeline [dir = none]
  }

  subgraph Generation0Sons {
    rank = same
    AbrahamAndMonaSons [shape = point]
    HerbSon [shape = point]
    HomerSon [shape = point]
    HerbSon -> AbrahamAndMonaSons [dir = none]
    HomerSon -> AbrahamAndMonaSons [dir = none]

    MargeSon [shape = point]
    PattySon [shape = point]
    SelmaSon [shape = point]
    MargeSon -> PattySon [dir = none] 
    PattySon -> SelmaSon [dir = none] 
  }

  AbrahamAndMona -> AbrahamAndMonaSons [dir = none]
  ClancyAndJackeline -> PattySon [dir = none]

  subgraph Generation1 {
    rank  =  same
    Herb [shape = box, color = blue] 
    Homer [shape = box, color = blue] 
    Marge [shape = box, color = pink] 
    Patty [shape = box, color = pink] 
    Selma [shape = box, color = pink] 

    HomerAndMarge [shape = point]
    Homer -> HomerAndMarge [dir = none]
    Marge -> HomerAndMarge [dir = none]
  }

  HerbSon -> Herb [dir = none]
  HomerSon -> Homer [dir = none]
  MargeSon -> Marge [dir = none]
  PattySon -> Patty [dir = none]
  SelmaSon -> Selma [dir = none]

  subgraph Generation1Sons {
    rank  =  same
    BartSon [shape = point] 
    LisaSon [shape = point] 
    MaggieSon [shape = point] 

    BartSon -> LisaSon [dir = none]
    LisaSon -> MaggieSon [dir = none]
  }

  HomerAndMarge -> LisaSon [dir = none]

  subgraph Generation2 {
    rank  =  same
    Bart [shape = box, color = blue] 
    Lisa [shape = box, color = pink] 
    Maggie [shape = box, color = pink] 
    Ling [shape = box, color = blue] 
  }

  Selma -> Ling [dir = none]
  BartSon -> Bart [dir = none]
  LisaSon -> Lisa [dir = none]
  MaggieSon -> Maggie [dir = none]
}

Produit :

http://dl.dropbox.com/u/72629/simpsons.png

2 votes

@patryk.beza utiliser splines=ortho; et n'ajoutez pas les noeuds cachés sur les noms (comme ceux sur Herb, Homer, Marge, Selma, Bart et Maggie).

3 votes

Lorsque j'effectue le rendu sur webgraphviz.com, l'image est superbe comme ci-dessus, mais pas sur dreampuf.github.io/GraphvizOnline, ni localement sur ma machine :/.

17voto

E L Points 131

Je ne pense pas que l'on puisse prendre un arbre généalogique arbitraire et générer automatiquement un fichier point pour qu'il ait toujours l'air bien dans GraphViz.

Mais je pense que vous peut toujours faire en sorte que ça ait l'air bien si vous :

  • Utilisez le rang=même que les autres réponses mentionnées pour obtenir les connexions 'T'. souhaitées par le PO
  • Utilisez l'astuce de commande de Brian Blank pour éviter les lignes bizarres.
  • Supposons qu'il n'y ait pas de second mariage ni de demi-frères ou de demi-sœurs.
  • Ne dessinez qu'un sous-ensemble de l'arbre qui obéit aux règles suivantes :
    • Soit S la personne "centrale".
    • Si S a des frères et sœurs, assurez-vous que S est à la droite de chacun d'eux.
    • Si S a un conjoint et que celui-ci a des frères et sœurs, assurez-vous que le conjoint est à gauche de tous ses frères et sœurs.
    • Ne montrez pas les neveux, nièces, tantes ou oncles de S ou de son conjoint.
    • Ne pas montrer les conjoints des frères et sœurs
    • Ne pas montrer les conjoints des frères et sœurs du conjoint.
    • Montrer les enfants de S, mais pas leurs conjoints ou enfants
    • Montrer les parents de S et les parents du conjoint

Cela finira par montrer pas plus de 3 générations à la fois, avec S au milieu de la génération.

Dans l'image ci-dessous, S=Homer (légèrement modifiée par rapport à la version de Brian Blank) :

digraph G {
  edge [dir=none];
  node [shape=box];
  graph [splines=ortho];

  "Herb"      [shape=box, regular=0, color="blue", style="filled" fillcolor="lightblue"] ;
  "Homer"     [shape=box, regular=0, color="blue", style="bold, filled" fillcolor="lightblue"] ;
  "Marge"     [shape=oval, regular=0, color="red", style="filled" fillcolor="pink"] ;
  "Clancy"    [shape=box, regular=0, color="blue", style="filled" fillcolor="lightblue"] ;
  "Jackeline" [shape=oval, regular=0, color="red", style="filled" fillcolor="pink"] ;
  "Abraham"   [shape=box, regular=0, color="blue", style="filled" fillcolor="lightblue"] ;
  "Mona"      [shape=oval, regular=0, color="red", style="filled" fillcolor="pink"] ;
  "Patty"     [shape=oval, regular=0, color="red", style="filled" fillcolor="pink"] ;
  "Selma"     [shape=oval, regular=0, color="red", style="filled" fillcolor="pink"] ;
  "Bart"      [shape=box, regular=0, color="blue", style="filled" fillcolor="lightblue"] ;
  "Lisa"      [shape=oval, regular=0, color="red", style="filled" fillcolor="pink"] ;
  "Maggie"    [shape=oval, regular=0, color="red", style="filled" fillcolor="pink"] ;

  a1 [shape=diamond,label="",height=0.25,width=0.25];
  b1 [shape=circle,label="",height=0.01,width=0.01];
  b2 [shape=circle,label="",height=0.01,width=0.01];
  b3 [shape=circle,label="",height=0.01,width=0.01];
  {rank=same; Abraham -> a1 -> Mona};
  {rank=same; b1 -> b2 -> b3};
  {rank=same; Herb; Homer};
  a1 -> b2
  b1 -> Herb
  b3 -> Homer

  p1 [shape=diamond,label="",height=0.25,width=0.25];
  q1 [shape=circle,label="",height=0.01,width=0.01];
  q2 [shape=circle,label="",height=0.01,width=0.01];
  q3 [shape=circle,label="",height=0.01,width=0.01];
  {rank=same; Homer -> p1 -> Marge};
  {rank=same; q1 -> q2 -> q3};
  {rank=same; Bart; Lisa; Maggie};
  p1 -> q2;
  q1 -> Bart;
  q2 -> Lisa;
  q3 -> Maggie;

  x1 [shape=diamond,label="",height=0.25,width=0.25];
  y1 [shape=circle,label="",height=0.01,width=0.01];
  y2 [shape=circle,label="",height=0.01,width=0.01];
  y3 [shape=circle,label="",height=0.01,width=0.01];
  {rank=same; Clancy -> x1 -> Jackeline};
  {rank=same; y1 -> y2 -> y3};
  {rank=same; Patty; Selma; Marge};
  x1 -> y2;
  y1 -> Marge;
  y2 -> Patty;
  y3 -> Selma;
}

Cela donne l'arbre suivant par GraphViz (avec des annotations que j'ai ajoutées avec Power Point) : enter image description here

14voto

Benny malengier Points 71

Gramps (www.gramps-project.org) génère des fichiers dot pour les arbres généalogiques, avec ou sans nœuds de mariage. Il y a aussi un moyen de voir cela dans l'interface de Gramps elle-même. http://gramps-project.org/wiki/index.php?title=Graph_View Donc je dirais, regardez le résultat de votre arbre généalogique tel que créé par Gramps.

0 votes

J'ai essayé d'utiliser Gramps mais tu dois te faire une idée des cultures européennes. Par exemple, dans l'écran "Add a Person", Gramps demande "Title", "Nick", "Call", "Given", "Suffix", "Surname". J'aimerais qu'ils proposent une version américaine simplifiée. Et comme je n'arrivais pas à comprendre le flux de travail, j'ai abandonné et j'ai écrit le mien. Parfois, être trop complet n'est pas le mieux.

6voto

Brian Blank Points 21

Bien que vous ne puissiez pas contrôler le placement des nœuds, j'ai découvert que vous pouviez l'aider en ordonnant les nœuds dans un ordre différent. J'ai réorganisé certains des nœuds comme indiqué ci-dessous et j'ai obtenu un graphique qui ne présente aucun croisement.

Le code suivant :

digraph G {
  edge [dir=none];
  node [shape=box];

  "Herb"      [shape=box, regular=1, color="blue"] ;
  "Homer"     [shape=box, regular=1, color="blue"] ;
  "Marge"     [shape=box, regular=1, color="pink"] ;
  "Clancy"    [shape=box, regular=1, color="blue"] ;
  "Jackeline" [shape=box, regular=1, color="pink"] ;
  "Abraham"   [shape=box, regular=1, color="blue"] ;
  "Mona"      [shape=box, regular=1, color="pink"] ;
  "Patty"     [shape=box, regular=1, color="pink"] ;
  "Selma"     [shape=box, regular=1, color="pink"] ;
  "Bart"      [shape=box, regular=1, color="blue"] ;
  "Lisa"      [shape=box, regular=1, color="pink"] ;
  "Maggie"    [shape=box, regular=1, color="pink"] ;
  "Ling"      [shape=box, regular=1, color="blue"] ;

  a1 [shape=circle,label="",height=0.01,width=0.01];
  b1 [shape=circle,label="",height=0.01,width=0.01];
  b2 [shape=circle,label="",height=0.01,width=0.01];
  b3 [shape=circle,label="",height=0.01,width=0.01];
  {rank=same; Abraham -> a1 -> Mona};
  {rank=same; b1 -> b2 -> b3};
  {rank=same; Herb; Homer};
  a1 -> b2
  b1 -> Herb
  b3 -> Homer

  p1 [shape=circle,label="",height=0.01,width=0.01];
  q1 [shape=circle,label="",height=0.01,width=0.01];
  q2 [shape=circle,label="",height=0.01,width=0.01];
  q3 [shape=circle,label="",height=0.01,width=0.01];
  {rank=same; Homer -> p1 -> Marge};
  {rank=same; q1 -> q2 -> q3};
  {rank=same; Bart; Lisa; Maggie};
  p1 -> q2;
  q1 -> Bart;
  q2 -> Lisa;
  q3 -> Maggie;

  x1 [shape=circle,label="",height=0.01,width=0.01];
  y1 [shape=circle,label="",height=0.01,width=0.01];
  y2 [shape=circle,label="",height=0.01,width=0.01];
  y3 [shape=circle,label="",height=0.01,width=0.01];
  {rank=same; Clancy -> x1 -> Jackeline};
  {rank=same; y1 -> y2 -> y3};
  {rank=same; Marge; Patty; Selma};
  {rank=same; Bart; Ling}
  x1 -> y2;
  y1 -> Marge;
  y2 -> Patty;
  y3 -> Selma;
  Selma -> Ling;
}

produit maintenant ceci :

family tree layout

Je ne comprends pas vraiment pourquoi cela fonctionne, mais voici le processus de réflexion qui a conduit aux changements que j'ai effectués.

  1. J'ai placé Clancy/Jackeline avant Abraham/Mona en pensant qu'ils étaient du mauvais côté. Cela a changé l'image, mais ce n'était toujours pas parfait.
  2. J'ai placé Homer/Marge en premier en pensant que le logiciel devait d'abord considérer ces pièces et peut-être placer tous les autres nœuds par rapport à Homer/Marge. Cela a encore aidé, mais n'était toujours pas parfait.
  3. Herb était toujours mal placé, donc j'ai mis Herb en premier pour que graphviz puisse considérer le placement de Herb en premier.

Cela a fonctionné, mais je n'arrive toujours pas à concevoir un algorithme qui garantirait des arbres cohérents, sans bords superposés. Je pense que Graphviz devrait faire un meilleur travail sans ces indications. Je ne connais pas l'algorithme utilisé, mais s'ils considèrent une fonction objective pour minimiser ou éliminer les bords qui se chevauchent, il devrait être possible de concevoir un meilleur algorithme.

4voto

doug Points 29567

Faire cela dans Graphviz est assez simple ; il y a quelques modèles syntaxiques dont vous avez besoin : (i) la syntaxe pour représenter la connexion ligne à ligne (la jonction en "T" dans vos graphiques ci-dessus) ; (ii) la syntaxe pour imposer la structure hiérarchique (c'est-à-dire, les nœuds de même génération sur le même plan sur l'axe vertical). C'est plus facile à montrer :

digraph G {
    nodesep=0.6;
    edge [arrowsize=0.3];

    "g1" -> "g2" -> "g3" -> "g4"

    { rank = same;
        "g1"; "King"; "ph1"; "Queen";
    };

    { rank = same; 
        "g2"; "ph2"; "ph2L"; "ph2R"; "ph2LL"; "ph2RR"
    };

    { rank = same;
        "g3"; "ps1"; "ps2"; "pr1"; "pr2"
    };

    "King" -> "ph1" [arrowsize=0.0];
    "ph1" -> "Queen" [arrowsize=0.0];

    "ph1" -> "ph2" [arrowsize=0.0];
    "ph2LL" -> "ph2L" [arrowsize=0.0];
    "ph2L" -> "ph2" [arrowsize=0.0];
    "ph2" -> "ph2R" [arrowsize=0.0];
    "ph2R" -> "ph2RR" [arrowsize=0.0];

    "ph2LL" -> "ps1" [arrowsize=0.0];
    "ph2L"-> "pr1" [arrowsize=0.0];
    "ph2R" -> "ps2" [arrowsize=0.0];
    "ph2RR" -> "pr2" [arrowsize=0.0];

}

Le code ci-dessus produira le graphique ci-dessous (j'ai omis le code que j'ai utilisé pour colorer les noeuds). J'ai laissé visible le "guide" sur la gauche (g1->g2....) juste pour vous montrer comment j'ai imposé les positions entre les noeuds de même rang, vous voudrez probablement le rendre invisible dans vos propres graphiques. Enfin, les noeuds dont l'étiquette commence par 'ph' sont les noeuds de remplacement pour les "jonctions en T".

alt text

0 votes

J'y suis presque, voir ma réponse ci-dessous. La seule chose qui me pose encore problème est le contrôle de l'ordre de placement sur l'axe horizontal (je veux qu'Abraham et Mona soient à gauche de Clancy et Jackeline pour que l'image soit bien alignée). Y a-t-il un moyen de le faire ?

0 votes

Bien sûr, regardez mon code ci-dessus - remarquez l'ordre dans lequel j'ai spécifié les bords (de gauche à droite).

0 votes

Pour cet exemple limité, cela fonctionne effectivement. Mais dans les données de l'arbre généalogique réel, tous les enfants ont aussi des partenaires. Et ces partenaires ne cessent de sauter les uns sur les autres. Il n'y a aucun moyen que je puisse trouver pour forcer les maris à toujours venir à la gauche de leurs épouses. Par exemple, dans i.imgur.com/Do7fz.png : Piet devrait se placer à la gauche d'Inge, Wim (et Jan C, son second mari) devrait se placer à la gauche de Manu et Jan devrait se placer à la gauche de Dominique.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X