mercredi 14 avril 2010

graphviz : générer des graphes en ligne de commande


Description


L'outil en ligne de commande graphviz créé par ATT permet de générer des graphes orientés ou non, circulaires ou non à partir d'un fichier texte de description.
Voici quelques exemples permettant de générer des graphes hautement paramétrables.


Exemple d'un fichier de configuration


Un fichier de configuration simple comprend :
  • le type de graphe i.e. "graph" pour un graphe non-orienté.
  • le nom du projet i.e. "mcd" dans cet exemple.
  • des noeuds "node" définis par une forme "shape" et des objets à créer "voiture" et "marque".
  • chaque noeud est caractérisé par du texte décrit entre des crochets "[label="personne|insee\nnom\nprenom"]".
  • des liens ( non-orientés ici liant deux objets à la fois ( encore que ) comme "voiture -- "fabriquer" [label="1,1"]".
  • un titre, voir "label" et "fontsize" en fin de code.

à supposer que le fichier d'exemple ci-après se nomme mcd.xml,
pour générer une image nommée "mcd.png", il faut lancer en ligne de commande :
dot.exe -Tpng -omcd.png mcd.txt -Gcharset=latin1

graph mcd {
node [shape=box]; voiture; marque;
node [shape=record]; personne;
node [shape=ellipse,style=filled,color=lightgrey]; "posseder"; "fabriquer";

personne [label="personne|insee\nnom\nprenom"];

personne -- "posseder" [label="0,n"];
"posseder" -- voiture [label="1,1"];

voiture -- "fabriquer" [label="1,1"];
"fabriquer" -- marque [label="1,n"];

label = "\n\nMCD by NEATO";
fontsize=16;
}



Quelques fonctions avancées


Voici quelques paramètres et autres types de données permettant d'améliorer la lecture des graphes :
  • "#rankdir=LR ;" permet d'écrire les noeuds de gauche à droite.
  • "subgraph" permet de définir des sous-graphes avec des composants connexes.
  • "\n" dans des labels permet des sauts de ligne.
  • Les noeuds liés peuvent être chaînés linéairement : "sql0 -> sql1 -> sql2 -> sql3 -> sql4 -> sql5 ;".
  • Les noeuds liés peuvent être chaînés par destination : "sql4 -> { sql0 ; sql2 }".
  • définir des compartiments "boîte" dans les labels : "e0 [shape="record",label="e0|{0|0}"] ;".
  • le couplage de graphviz à un dictionnaire de données pour analyser un schéma ( utilisateur "scott" d'Oracle ) permet de visualiser graphiquement les tables. L'outil SchemaSpy génère le même genre de graphe et s'appuie sur graphviz ! ...


digraph wc_sql
{
#rankdir=LR ;
edge [color="tan",fontname="arial"] ;
node [color="white",fontname="arial",fontsize="10",shape="box",style="filled"] ;
bgcolor="white" ;
fontname="arial";
fontsize="10";

subgraph cluster_uml
{
color="whitesmoke"
style="filled" ;
label="SQL" ;

sql0 [label="étape\nSQL",color="orange",shape="ellipse"] ;
sql1 [label="vérifier\ntaille sources"] ;
sql2 [label="dropper le package généré \n(en cas de besoin)"] ;
sql3 [label="builder les packages"] ;
sql4 [label="vérifier\nvalidité",color="darkorange",shape="ellipse"] ;
sql5 [label="étape\njava",color="orange",shape="ellipse"] ;

sql0 -> sql1 -> sql2 -> sql3 -> sql4 -> sql5 ;

sql4 -> { sql0 ; sql2 } [ label="tant que pas OK" ,color="red",fontname="arial",fontsize="10" ] ;
sql1 -> sql0 [ label="tant que pas OK" ,color="red",fontname="arial",fontsize="10" ] ;
}
}


"Diagramme PERT"


digraph PERT {

rankdir="LR" ;

e0 [shape="record",label="e0|{0|0}"] ;
e1 [shape="record",label="e1|{5|5}"] ;
e2 [shape="record",label="e2|{7|17}"] ;
e3 [shape="record",label="e3|{13|13}"] ;
e4 [shape="record",label="e4|{16|17}"] ;
e5 [shape="record",label="e5|{23|24}"] ;
e6 [shape="record",label="e6|{0|3}"] ;
e7 [shape="record",label="e7|{3|6}"] ;
e8 [shape="record",label="e8|{4|7}"] ;
e9 [shape="record",label="e9|{8|13}"] ;
e10 [shape="record",label="e10|{4|15}"] ;
e11 [shape="record",label="e11|{13|13}"] ;
e12 [shape="record",label="e12|{15|15}"] ;
e13 [shape="record",label="e13|{24|24}"] ;

e1 -> e2 [label="j 2"] ;
e2 -> e4 [label="---"] ;
e3 -> e4 [label="k 3"] ;
e4 -> e5 [label="l 7"] ;
e5 -> e13 [label="---"] ;

e0 -> e6 [label="---"] ;
e6 -> e7 [label="a 3"] ;
e7 -> e8 [label="b 1"] ;
e7 -> e9 [label="c 5"] ;
e8 -> e10 [label="e 4"] ;
e8 -> e11 [label="d 6"] ;
e9 -> e11 [label="---"] ;
e10 -> e12 [label="---"] ;

e0 -> e1 [label="h 5"] ;
e1 -> e3 [label="i 8"] ;
e3 -> e11 [label="---"] ;
e11 -> e12 [label="f 2"] ;
e12 -> e13 [label="g 9"] ;

{
rank="same" ;
node [ fillcolor="red"] ;
e0 ; e1 ;
}

label = "\n\nPERT by DOT";
fontsize=16;
}











Autres exemples de graphes










































 

 

 

 

 

 

 

 

 





Programme java permettant de traiter tous les fichiers txt d'un même répertoire


import java.io.File;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.Map.Entry;


public class TaiterFichiersDot
{
//-------------------------------------------
String dotPath = "\"C:\\Program Files\\ATT\\Graphviz\\bin\\dot\"" ;
String rep = "C:/_cmd/" ;
String repWin = "C:\\_cmd\\" ;
String format = "png" ;
String winShell = "c:\\WINNT\\system32\\cmd.exe /K " ;
SortedMap<String, String> smFichiers = new TreeMap<String, String>() ;
int nb = 0 ;
int nbOk = 0 ;
int nbKo = 0 ;
//-------------------------------------------
TaiterFichiersDot()
{
}
//-------------------------------------------
void faire()
{
lireRep(rep) ;
for(Entry<String, String> entry : smFichiers.entrySet())
{
{
String fic = entry.getValue() ;
executerCommandLine(fic) ;
}
}
}
//-------------------------------------------
String construireCommande( String _fichier )
{
return dotPath + " -T" + format + " -o" + repWin + "" + _fichier + "." + format + " " + repWin + "" + _fichier + " -Gcharset=latin1" ;
}
//-------------------------------------------
void lireRep( String _rep )
{
String [] s = new File(_rep).list();
int iMax = s.length ;
int i ;
String ff,match,matchLow ;
//
for ( i=0 ; i<iMax ; i++ )
{
ff = s[i].toLowerCase() ;
if ( ff.endsWith(".txt"))
{
match = s[i] ;
matchLow = match.toLowerCase() ;
smFichiers.put(matchLow,match) ;
nb++ ;
}
}
}
//-------------------------------------------
void afficherResume()
{
System.out.println("commandes OK : " + nbOk );
System.out.println("commandes KO : " + nbKo );
}
//-------------------------------------------
void executerCommandLine( String _fichier )
{
String chCmd = winShell + construireCommande(_fichier) ;
try
{
Runtime.getRuntime().exec(chCmd);
System.out.println("OK pour : "+chCmd);
nbOk++ ;
}
catch(Exception ie)
{
System.out.println("erreur : " + chCmd );
nbKo++ ;
}
}
//-------------------------------------------
public static void main(String[] args)
{
TaiterFichiersDot appli = new TaiterFichiersDot() ;
appli.faire() ;
appli.afficherResume() ;
}
//-------------------------------------------
}


Plus d'informations sur


  • Graphviz site ici.
  • Graphviz galleries ici.
  • Graphviz documentation ici.
  • Doxygen site ici.
  • SchemaSpy site ici.




3 commentaires:

  1. l'un des meilleurs tutos sur le sujet
    petite question
    pourquoi digraph ou graph ?
    bravo en tout cas

    RépondreSupprimer
  2. Bonjour et merci pour votre question.

    digraph pour "direct graph" ou "graphe orienté" en français. Cela va avec la notation "->". Dans les graphes non-orientés, le symbole normalement à utiliser est "--".

    Cordialement,

    RépondreSupprimer
  3. Bonjour et bravo pour ces infos,

    Je rame pas mal avec dot...

    je suis sur Win XP et Win7 et crée un prog en vb qui, à partir d'une bd Acces, génère des graphes hierarchiques...

    La sortie HPGL de dot qui me serait bien utile pour mon bon vieux HPDraftPro ne fonctionne pas chez moi.
    Y a-t-il un addon ou quelque chose pour activer cette possibilité de format de sortie?

    Les sorties pdf que je pensait utiliser en second choix me causent du soucis.
    les sorties Tps et Tps2 produisent des fichier ok à l'écran, mais pas de texte sur le plotter.
    Sans doute problème de fonts, mais quoi faire?

    Seul 'Tps:cairo' donne du texte sur le plotter, mais le graph est tjs coupé au format A4, même en placant un 'size' en début du fichier dot.
    Le fichier ps semble contenir l'ensemble des données, et en passant à pdf c'est coupé, même en configurant l'imprimante Acrobat sur un format ISO B2...
    Re-Que faire ;-)

    D'avance grand merci
    Sylvain

    RépondreSupprimer