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]).
|