annotate prolog/library/dot.pl @ 7:6d864126b45a tip

Arrggh! I think it's right now.
author samer
date Sat, 12 Apr 2014 12:50:11 +0100
parents 95ffac028d98
children
rev   line source
samer@0 1 :- module(dot,[
samer@0 2 dotrun/4
samer@0 3 , graph_dot/2
samer@0 4 ]).
samer@0 5
samer@0 6 /** <module> Graphviz language
samer@0 7
samer@1 8 Produces .dot language graphs from relational and functional schemata.
samer@0 9
samer@0 10 Graph strucure is as follows:
samer@0 11 ==
samer@0 12 digraph ---> digraph(Name:term, G:list(element)).
samer@0 13 subgraph ---> subgraph(Name:term, G:list(element)).
samer@0 14 element ---> subgraph
samer@0 15 ; option
samer@0 16 ; node_opts(list(option))
samer@0 17 ; edge_opts(list(option))
samer@0 18 ; with_opts(element, list(option))
samer@0 19 ; arrow(term,term) % directed edge
samer@0 20 ; line(term,term) % undirected edge
samer@0 21 ; node(term).
samer@0 22 option ---> opt_name=opt_value.
samer@0 23 opt_name == atom
samer@0 24 opt_value == phrase
samer@1 25 ==
samer@0 26 Graph, node and edge labels can be terms and are written using write/1 for
samer@0 27 writing in the dot file.
samer@0 28
samer@0 29 ---
samer@1 30 Samer Abdallah
samer@1 31 Centre for Digital Music, Queen Mary, University of London, 2007
samer@0 32 Department of Computer Science, UCL, 2014
samer@0 33 */
samer@0 34
samer@0 35 :- use_module(fileutils).
samer@0 36 :- use_module(dcgu).
samer@0 37
samer@0 38
samer@0 39 digraph(Name,G) -->
samer@0 40 "digraph ", wr(Name), cr,
samer@0 41 dotblock([ overlap=at(false)
samer@0 42 , spline=at(true)
samer@0 43 , contentrate=at(true)
samer@0 44 | G]).
samer@0 45
samer@0 46 subgraph(Name,G) --> "subgraph ", wr(Name), cr, dotblock(G).
samer@0 47
samer@0 48 dotblock(L) --> brace(( cr, dotlist(L), cr)), cr.
samer@0 49 dotline(L) --> "\t", L, ";\n".
samer@0 50 dotlist([]) --> "".
samer@0 51 dotlist([L|LS]) -->
samer@0 52 if(L=dotblock(B),
samer@0 53 dotblock(B),
samer@0 54 dotline(L)),
samer@0 55 dotlist(LS).
samer@0 56
samer@0 57
samer@0 58 with_opts(A,Opts) --> phrase(A), sp, sqbr(optlist(Opts)).
samer@0 59 optlist(L) --> seq(L,",").
samer@0 60
samer@0 61 node_opts(Opts) --> with_opts(at(node), Opts).
samer@0 62 edge_opts(Opts) --> with_opts(at(edge), Opts).
samer@0 63 nq(A) --> wr(A).
samer@0 64 node(A) --> qq(wr(A)).
samer@0 65 arrow(A,B) --> node(A), " -> ", node(B).
samer@0 66 line(A,B) --> node(A), " -- ", node(B).
samer@0 67 (A=B) --> at(A), "=", B.
samer@0 68
samer@0 69
samer@0 70 dot_method(M,M) :- member(M,[dot,neato,sfdp,fdp,circo,twopi]).
samer@0 71 dot_method(unflatten,M) :- dot_method(unflatten([]),M).
samer@0 72 dot_method(unflatten(Opts),M) :-
samer@0 73 phrase(("unflatten",seqmap(uopt,Opts)," | dot"),Codes,[]),
samer@0 74 atom_codes(M,Codes).
samer@0 75
samer@0 76 uopt(l(N)) --> " -l", wr(N).
samer@0 77 uopt(fl(N)) --> " -f -l", wr(N).
samer@0 78 uopt(c(N)) --> " -c", wr(N).
samer@0 79
samer@0 80 %% dotrun( +Method:graphviz_method, +Fmt:atom, G:digraph, +File:atom) is det.
samer@0 81 %
samer@0 82 % Method determines which GraphViz programs are used to render the graph:
samer@0 83 % ==
samer@0 84 % graphviz_method ---> dot ; neato; fdp ; sfdp ; circo ; twopi
samer@0 85 % ; unflatten
samer@0 86 % ; unflatten(list(unflatten_opt)).
samer@0 87 % unflatten_opt ---> l(N:natural) % -l<N>
samer@0 88 % ; fl(N:natural) % -f -l<N>
samer@0 89 % ; c(natural). % -c<N>
samer@0 90 % ==
samer@0 91 % The unflatten method attempts to alleviate the problem of very wide graphs,
samer@0 92 % and implies that dot is used to render the graph. The default option list is empty.
samer@2 93 %
samer@2 94 % Fmt can be any format supported by Graphviz under the -T option, including
samer@2 95 % ps, eps, pdf, svg, png.
samer@2 96 %
samer@0 97 % See man page for unflatten for more information.
samer@0 98 % TODO: Could add more options for dot.
samer@0 99 dotrun(Meth1,Fmt,Graph,File) :-
samer@0 100 dot_method(Meth1,Meth),
samer@0 101 member(Fmt,[ps,eps,pdf]),
samer@0 102 format(atom(Cmd),'~w -T~w > "~w.~w"',[Meth,Fmt,File,Fmt]),
samer@0 103 format('Running: ~w ...\n',Cmd),
samer@0 104 with_output_to_file(pipe(Cmd),writedcg(Graph)).
samer@0 105
samer@0 106 %% graph_dot( +G:digraph, +File:atom) is det.
samer@0 107 graph_dot(Graph,File) :-
samer@0 108 with_output_to_file(File,writedcg(Graph)).
samer@0 109
samer@0 110 %%% Options
samer@0 111
samer@0 112 % Graph options
samer@0 113 dotopt(graph,[size,page,ratio,margin,nodesep,ranksep,ordering,rankdir,
samer@0 114 pagedir,rank,rotate,center,nslimit,mclimit,layers,color,href,splines,
samer@0 115 start,epsilon,root,overlap, mindist,'K',maxiter]).
samer@0 116
samer@0 117
samer@0 118 % Node options
samer@0 119 dotopt(node, [label,fontsize,fontname,shape,color,fillcolor,fontcolor,style,
samer@0 120 layer,regular,peripheries,sides,orientation,distortion,skew,href,target,
samer@0 121 tooltip,root,pin]).
samer@0 122
samer@0 123 % Edge options
samer@0 124 dotopt(edge, [minlen,weight,label,fontsize,fontname,fontcolor,style,color,
samer@0 125 dir,tailclip,headclip,href,target,tooltip,arrowhead,arrowtail,
samer@0 126 headlabel,taillabel,labeldistance,port_label_distance,decorate,
samer@0 127 samehead,sametail,constraint,layer,w,len]).
samer@0 128
samer@0 129
samer@0 130 % Node options values
samer@0 131 dotopt(node, label, A) :- ground(A).
samer@0 132 dotopt(node, fontsize, N) :- between(1,256,N). % arbitrary maximum!
samer@0 133 dotopt(node, fontname, A) :- ground(A).
samer@0 134 dotopt(node, shape,
samer@0 135 [ plaintext,ellipse,box,circle,egg,triangle,diamond,
samer@0 136 trapezium,parallelogram,house,hexagon,octagon]).
samer@0 137 dotopt(node, style, [filled,solid,dashed,dotted,bold,invis]).
samer@0 138
samer@0 139
samer@0 140 % Edge options values
samer@0 141 dotopt(edge, fontsize, N) :- between(1,256,N). % arbitrary maximum!
samer@0 142 dotopt(edge, label, A) :- ground(A).
samer@0 143 dotopt(node, fontname, A) :- ground(A).
samer@0 144 dotopt(node, style, [solid,dashed,dotted,bold,invis]).