-
Notifications
You must be signed in to change notification settings - Fork 1
/
graphviz.jl
245 lines (216 loc) · 7.15 KB
/
graphviz.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
## for each possible vizualization, there exist three different output
## ways:
## - print dot code to Julia console
## - visualize dot code through x11
## - write visualization of dot code to output file
##
## all three output ways make use of the same core: Julia code that
## automatically creates dot code
## chart consists of:
## - cmd (dot, neato)
## - dot code
## dot code depends on:
## - data type
## - chart name (trees, graph)
## cmd depends on:
## - data type
## - chart name
function toConsole(obj::Any; chrt="default", args...)
stdin = IOBuffer()
toGviz(obj, stdin, chrt; args...)
takebuf_string(stdin)
end
@doc doc"""
Plot tree in x11 window.
"""->
function viz(obj::Any; chrt="default", args...)
cmd = getCmd(obj, chrt)
stdin, proc = open(`$cmd -Tx11`, "w")
toGviz(obj, stdin, chrt; args...)
close(stdin)
end
@doc doc"""
Render chart to output file.
"""->
function render(obj::Any,
fmt::String,
fname::String;
chrt="default",
args...)
cmd = getCmd(obj, chrt)
stdin, proc = open(`$cmd -T$fmt -o $fname.$fmt`, "w")
toGviz(obj, stdin, chrt; args...)
close(stdin)
end
@doc doc"""
Render chart to default output file.
"""->
function render(obj::Any; chrt="default", args...)
## create tmp file
fname = tempname()
render(obj, "svg", fname; chrt=chrt, args...)
return string(fname, ".", "svg")
end
###############
## tree plot ##
###############
@doc doc"""
Core of the graphviz interface: this function determines how a CTree
from Julia is actually translated into graphviz code. To keep it
general, this function will write to a given stream. This way one can
easily replace the stream with for example a file or a process.
Chrt input is irrelevant, as long as there is only one kind of
visualization for this data type.
"""->
function toGviz(tr::CTreeParRef,
stream::IO,
chrt::String;
shape="circle",
arrowhead="none",
emph1=[], emphFillColor1="lawngreen",
emphShape1="circle",
emph2=[], emphFillColor2="lawngreen",
emphShape2="circle"
)
## emph1 and emph2 sets need to be non-overlapping
if !isempty(intersect(emph1, emph2))
error("emphasized sets need to be non-overlapping")
end
nVars = size(tr.tree, 1)
write(stream, "digraph {\n")
write(stream, "node [shape=$shape];\n")
write(stream, "edge [arrowhead=$arrowhead];\n")
for ii=1:nVars
parNode = tr.tree[ii]
if parNode != 0
if ii in emph1
write(stream, "$ii [style=filled; fillcolor=$emphFillColor1; shape=$emphShape1];")
elseif ii in emph2
write(stream, "$ii [style=filled; fillcolor=$emphFillColor2; shape=$emphShape2];")
else
end
write(stream, "$parNode -> $ii ;\n")
end
end
write(stream, "}")
end
function toGviz(tr::AbstractCTree, stream::IO, chrt::String; args...)
trPar = convert(CTreeParRef, tr)
return toGviz(trPar, stream, chrt; args...)
end
function getCmd(tr::CTreeParRef, chrt::String)
if chrt == "default"
return "dot"
end
end
function getCmd(tr::AbstractCTree, chrt::String)
if chrt == "default"
return "dot"
end
end
###############
## vine plot ##
###############
## header function to delegate to distinct vine visualization
## functions
function toGviz(vn::Copulas.Vine,
stream::IO,
chrt::String;
args...)
if chrt == "default"
toGviz_graph(vn, stream; args...)
else
toGviz_trees(vn, stream; args...)
end
end
function getCmd(vn::Copulas.Vine, chrt::String)
if chrt == "default"
return "neato"
else
return "dot"
end
end
## graph visualization
##--------------------
function toGviz_graph(vn::Copulas.Vine,
stream::IO;
maxLayer=2)
nVars = size(vn.trees, 1)
layers = Copulas.linkLayers(vn)
write(stream, "graph G {\n")
write(stream, "node [shape=circle];\n")
for ii=1:nVars
for jj=ii+1:nVars
currLayer = layers[ii, jj]
if currLayer <= maxLayer
if currLayer == 1
write(stream, "$ii -- $jj [style=bold];\n")
elseif currLayer == 2
write(stream, "$ii -- $jj [len=1.3];\n")
elseif currLayer == 3
write(stream, "$ii -- $jj;\n")
end
end
end
end
write(stream, "}")
end
## conditioning tree visualization
##--------------------------------
@doc doc"""
Emph1 will emphasize root nodes and other nodes, emph2 will only
emphasize root nodes.
"""->
function toGviz_trees(vn::Copulas.Vine,
stream::IO;
shape="circle",
arrowhead="none",
emph1=[], emphFillColor1="lawngreen",
emphFontColor1="black",
emphShape1="circle",
emph2=[], emphFillColor2="lawngreen",
emphFontColor2="black",
emphShape2="circle",
rootEmph=[],
rootEmphFillColor1="lawngreen",
rootEmphFontColor1="black",
rootEmphShape1="circle",
)
nVars = size(vn.trees, 1)
write(stream, "digraph {\n")
write(stream, "node [shape=$shape];\n")
write(stream, "edge [arrowhead=$arrowhead];\n")
for rootVar=1:nVars
if rootVar in emph1
write(stream, "\"$rootVar in $rootVar\"
[label=\"$rootVar\"; color=$emphFillColor1; fontcolor=$emphFontColor1; style=filled; fillcolor=$emphFillColor1; shape=$emphShape1];\n")
elseif rootVar in emph2
write(stream, "\"$rootVar in $rootVar\"
[label=\"$rootVar\"; color=$emphFillColor2; fontcolor=$emphFontColor2;
style=filled; fillcolor=$emphFillColor2; shape=$emphShape2];\n")
elseif rootVar in rootEmph
write(stream, "\"$rootVar in $rootVar\"
[label=\"$rootVar\"; color=$rootEmphFillColor1; fontcolor=$rootEmphFontColor1;
style=filled; fillcolor=$rootEmphFillColor1; shape=$rootEmphShape1];\n")
else
write(stream, "\"$rootVar in $rootVar\" [label=\"$rootVar\"];\n")
end
for ii=1:nVars
parNode = vn.trees[ii, rootVar]
if parNode > 0
if ii in emph1
write(stream, "\"$ii in $rootVar\"
[label=\"$ii\"; color=$emphFillColor1; fontcolor=$emphFontColor1;
style=filled; fillcolor=$emphFillColor1; shape=$emphShape1];\n")
elseif ii in emph2
write(stream, "\"$ii in $rootVar\"
[label=\"$ii\"; color=$emphFillColor2; fontcolor=$emphFontColor2; style=filled; fillcolor=$emphFillColor2; shape=$emphShape2];\n")
else
write(stream, "\"$ii in $rootVar\" [label=\"$ii\"];\n")
end
write(stream, "\"$parNode in $rootVar\" -> \"$ii in $rootVar\";\n")
end
end
end
write(stream, "}")
end