nysol-view 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/bin/m2gv.rb +812 -0
- data/bin/mautocolor.rb +244 -0
- data/bin/mbar.rb +818 -0
- data/bin/mdtree.rb +1017 -0
- data/bin/mgv.rb +809 -0
- data/bin/mnest2tree.rb +159 -0
- data/bin/mpie.rb +733 -0
- data/bin/msankey.rb +644 -0
- data/lib/nysol/viewjs.rb +13490 -0
- metadata +101 -0
data/bin/m2gv.rb
ADDED
@@ -0,0 +1,812 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#-*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
require "rubygems"
|
5
|
+
require "nysol/mcmd"
|
6
|
+
require "set"
|
7
|
+
|
8
|
+
# ver="1.0" # 初期リリース 2016/12/13
|
9
|
+
$cmd=$0.sub(/.*\//,"")
|
10
|
+
|
11
|
+
$version=1.0
|
12
|
+
$revision="###VERSION###"
|
13
|
+
|
14
|
+
def help
|
15
|
+
|
16
|
+
STDERR.puts <<EOF
|
17
|
+
------------------------
|
18
|
+
#{$cmd} version #{$version}
|
19
|
+
------------------------
|
20
|
+
概要) CSVによるグラフ構造データをDOTフォーマットで出力する
|
21
|
+
|
22
|
+
書式1) #{$cmd} [type=flat|nest] [k=] [ni=] [nf=] [nv=] [nc=] [col=] [nl=] [nw=]
|
23
|
+
[-clusterLabel] [-noiso] ei= ef= [ev=] [er=] [el=] [-d] [o=]
|
24
|
+
|
25
|
+
type= : グラフのタイプ(省略時はflat)
|
26
|
+
flat: key項目をクラスタとした木構造グラフ
|
27
|
+
nest: 木構造であることを前提にした入れ子構造グラフ(データが木構造でない場合の描画は不定)
|
28
|
+
k= : 入れ子グラフのクラスタ項目名(ni=を指定した場合は同じ項目名でなければならない)
|
29
|
+
複数項目指定不可
|
30
|
+
k=を省略すればtype=に関わらずクラスタを伴わない普通のグラフ描画となる。
|
31
|
+
|
32
|
+
ni= : 節点集合ファイル名
|
33
|
+
nf= : 節点ID項目名
|
34
|
+
nv= : 節点の大きさ項目名(この値に応じて節点の楕円の大きさが変化する,1項目のみ指定可)。
|
35
|
+
nc= : 節点カラー項目名(この値に応じて枠線カラーが変化する,1項目のみ指定可)。
|
36
|
+
カラーは、RGBを16進数2桁づつ6桁で表現する。ex) FF00FF:紫
|
37
|
+
さらに最後に2桁追加すればそれは透過率となる。
|
38
|
+
nl= : ノードラベルの項目(複数指定したら"_"で区切って結合される)
|
39
|
+
省略すればnf=でしてした項目をラベルとする。
|
40
|
+
nw= : 節点の枠線の幅を指定する(デフォルトは1)
|
41
|
+
-clusterLabel : k=を指定して入れ子グラフを作成する場合、クラスタのラベルも表示する
|
42
|
+
-noiso : 孤立節点(隣接節点のない節点で、本コマンドではni=に出てきてei=に出てこない節点のこと)は出力しない
|
43
|
+
|
44
|
+
ei= : 枝集合ファイル名
|
45
|
+
ef= : 開始節点ID項目名,終了節点ID項目名
|
46
|
+
ev= : 枝の幅項目名
|
47
|
+
ec= : 枝の色を表す項目(色の値はnc=と同じ)
|
48
|
+
ed= : 枝の矢印を表す項目(-dの指定、未指定に関わらず優先される)
|
49
|
+
値としては、F,B,W,N,nullの5つの値のいずれかでなければならない。
|
50
|
+
ef=e1,e2とした場合、それぞれで描画される矢印は以下の通り。
|
51
|
+
F: e1->e2, B: e1<-e2, W: e1<->e2, N:e1-e2(矢印なし),null:デフォルト
|
52
|
+
デフォルトは、-dが指定されていればF、-dの指定がなければNとなる。
|
53
|
+
el= : エッジラベルの項目(複数指定したら"_"で区切って結合される)
|
54
|
+
省略すれば、エッジラベルは表示されない。
|
55
|
+
|
56
|
+
-d : 有向グラフと見なす。"edge [dir=none]"を記述する。
|
57
|
+
o= : 出力ファイル名
|
58
|
+
|
59
|
+
-h,--help : ヘルプの表示
|
60
|
+
|
61
|
+
基本例)
|
62
|
+
$ cat edge.csv
|
63
|
+
e1,e2,v
|
64
|
+
a,b,11
|
65
|
+
a,c,20
|
66
|
+
b,d,11
|
67
|
+
d,e,8
|
68
|
+
c,e,9
|
69
|
+
|
70
|
+
$ #{$cmd} ei=edge.csv ef=e1,e2 ev=v el=v er=20 o=result.dot
|
71
|
+
$ cat result.dot
|
72
|
+
digraph G {
|
73
|
+
edge [dir=none]
|
74
|
+
n_2 [label="a" style="setlinewidth(1)" ]
|
75
|
+
n_3 [label="b" style="setlinewidth(1)" ]
|
76
|
+
n_4 [label="c" style="setlinewidth(1)" ]
|
77
|
+
n_5 [label="d" style="setlinewidth(1)" ]
|
78
|
+
n_6 [label="e" style="setlinewidth(1)" ]
|
79
|
+
n_2 -> n_3 [label="11" style="setlinewidth(5.75)" ]
|
80
|
+
n_2 -> n_4 [label="20" style="setlinewidth(20)" ]
|
81
|
+
n_3 -> n_5 [label="11" style="setlinewidth(5.75)" ]
|
82
|
+
n_4 -> n_6 [label="9" style="setlinewidth(2.583333333)" ]
|
83
|
+
n_5 -> n_6 [label="8" style="setlinewidth(1)" ]
|
84
|
+
}
|
85
|
+
|
86
|
+
ネストグラフの例)
|
87
|
+
$ cat edge4.csv
|
88
|
+
cluster,node1,node2,support
|
89
|
+
#1_1,a,b,0.1
|
90
|
+
#1_2,d,e,0.1
|
91
|
+
#2_1,#1_1,c,0.2
|
92
|
+
#3_1,#1_2,#2_1,0.3
|
93
|
+
#3_1,#2_1,f,0.4
|
94
|
+
|
95
|
+
$ #{$cmd} mgv.rb type=flat k=cluster ei=edge4.csv ef=node1,node2 o=result.dot
|
96
|
+
# fdpはgraphVizのコマンド, nested graphはdotコマンドでは描画できない
|
97
|
+
$ fdp -Tpdf result.dot >result.pdf
|
98
|
+
$ open result.pdf
|
99
|
+
$ cat result.dot
|
100
|
+
digraph G {
|
101
|
+
edge [dir=none]
|
102
|
+
subgraph cluster_1 {
|
103
|
+
n_5 [label="a" style="setlinewidth(1)" ]
|
104
|
+
n_6 [label="b" style="setlinewidth(1)" ]
|
105
|
+
n_5 -> n_6 []
|
106
|
+
}
|
107
|
+
subgraph cluster_2 {
|
108
|
+
n_8 [label="d" style="setlinewidth(1)" ]
|
109
|
+
n_9 [label="e" style="setlinewidth(1)" ]
|
110
|
+
n_8 -> n_9 []
|
111
|
+
}
|
112
|
+
subgraph cluster_3 {
|
113
|
+
cluster_1 []
|
114
|
+
n_7 [label="c" style="setlinewidth(1)" ]
|
115
|
+
cluster_1 -> n_7 []
|
116
|
+
}
|
117
|
+
subgraph cluster_4 {
|
118
|
+
cluster_2 []
|
119
|
+
cluster_3 []
|
120
|
+
n_10 [label="f" style="setlinewidth(1)" ]
|
121
|
+
cluster_2 -> cluster_3 []
|
122
|
+
cluster_3 -> n_10 []
|
123
|
+
}
|
124
|
+
}
|
125
|
+
EOF
|
126
|
+
exit
|
127
|
+
end
|
128
|
+
def ver()
|
129
|
+
$revision ="0" if $revision =~ /VERSION/
|
130
|
+
STDERR.puts "version #{$version} revision #{$revision}"
|
131
|
+
exit
|
132
|
+
end
|
133
|
+
|
134
|
+
help() if ARGV.size <= 0 or ARGV[0]=="--help"
|
135
|
+
ver() if ARGV[0]=="--version"
|
136
|
+
|
137
|
+
# ===================================================================
|
138
|
+
# パラメータ処理
|
139
|
+
args=MCMD::Margs.new(ARGV,"type=,k=,ni=,nf=,nv=,nc=,ei=,ef=,ev=,ec=,o=,nl=,el=,ed=,-d,nw=,-clusterLabel,-noiso,-debug","ei=,ef=")
|
140
|
+
|
141
|
+
# mcmdのメッセージは警告とエラーのみ
|
142
|
+
ENV["KG_VerboseLevel"]="2" unless args.bool("-mcmdenv")
|
143
|
+
|
144
|
+
type = args. str("type=","flat") # グラフタイプ
|
145
|
+
if type!="nest" and type!="flat"
|
146
|
+
raise "type= takes `nest' or `flat'"
|
147
|
+
end
|
148
|
+
|
149
|
+
ni = args. file("ni=","r") # nodeファイル名
|
150
|
+
nf = args.field("nf=", ni) # nodeID項目名
|
151
|
+
nv = args.field("nv=", ni) # node value項目名
|
152
|
+
nc = args.field("nc=", ni) # node color項目名
|
153
|
+
nl = args.field("nl=", ni) # nodeラベル項目名
|
154
|
+
nw =args.int("nw=",1,1) # nodeの枠線の太さ
|
155
|
+
unless args.keyValue["ni="]
|
156
|
+
if args.keyValue["nf="] or args.keyValue["nv="] or args.keyValue["nc="] or args.keyValue["-nl"] or args.keyValue["-cl"] or args.keyValue["nw="]
|
157
|
+
raise "nf=,nv=,nc=,-nl,-cl cannot be specified without ni="
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
if args.keyValue["ni="]
|
162
|
+
#unless args.keyValue["nf="] or args.keyValue["nv="]
|
163
|
+
unless args.keyValue["nf="]
|
164
|
+
raise "nf= must be specified when ni= is given"
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
ei = args. file("ei=","r") # edgeファイル名
|
169
|
+
key= args.field("k=", ei,nil,1,1) # nested graph クラスタ項目
|
170
|
+
key=key["names"][0] if key
|
171
|
+
ef = args.field("ef=", ei) # edge始点node項目名,終了節点項目名
|
172
|
+
ev = args.field("ev=", ei) # edge value項目名
|
173
|
+
ec = args.field("ec=", ei) # edge color項目名
|
174
|
+
ed = args.field("ed=", ei) # edge direction項目名
|
175
|
+
el = args.field("el=", ei) # edgeラベル項目
|
176
|
+
ef1=ef["names"][0]
|
177
|
+
ef2=ef["names"][1]
|
178
|
+
if ef1==nil or ef2==nil then
|
179
|
+
raise "ef= takes two field names"
|
180
|
+
end
|
181
|
+
|
182
|
+
if ni
|
183
|
+
nf=nf["names"][0]
|
184
|
+
nv=nv["names"][0] if nv
|
185
|
+
nc=nc["names"][0] if nc
|
186
|
+
end
|
187
|
+
|
188
|
+
ev=ev["names"][0] if ev
|
189
|
+
ed=ed["names"][0] if ed
|
190
|
+
ec=ec["names"][0] if ec
|
191
|
+
|
192
|
+
directed = args. bool("-d") #有向グラフ
|
193
|
+
directedStr="edge []"
|
194
|
+
directedStr="edge [dir=none]" unless directed
|
195
|
+
oFile = args.file("o=","w") # 出力ファイル名
|
196
|
+
|
197
|
+
clusterLabel=args.bool("-clusterLabel")
|
198
|
+
noiso=args.bool("-noiso")
|
199
|
+
|
200
|
+
# edgeデータからnested graphのtree構造を作る
|
201
|
+
# clusterのみの構造を作る
|
202
|
+
def mkTree(iFile,oFile)
|
203
|
+
temp=MCMD::Mtemp.new
|
204
|
+
xxroot =temp.file
|
205
|
+
xxbase=[]
|
206
|
+
xxbase << temp.file
|
207
|
+
|
208
|
+
# #{iFile}
|
209
|
+
# key,nam%0,keyNum,num,nv,nc
|
210
|
+
# #2_1,#1_1,4,1,6,1
|
211
|
+
# #2_1,#1_2,4,2,0.9999999996,1
|
212
|
+
xxiFile1=temp.file
|
213
|
+
xxiFile2=temp.file
|
214
|
+
xxkey =temp.file
|
215
|
+
xxnum =temp.file
|
216
|
+
xxleaf =temp.file
|
217
|
+
xxcheck =temp.file
|
218
|
+
|
219
|
+
# keyNumとnum項目のuniqリストを作り、お互いの包含関係でrootノードとleafノードを識別する。
|
220
|
+
system "mcut f=keyNum,num i=#{iFile} | msortf f=keyNum o=#{xxiFile1}"
|
221
|
+
system "mcut f=keyNum i=#{xxiFile1} | muniq k=keyNum o=#{xxkey}"
|
222
|
+
system "mcut f=num i=#{xxiFile1} | muniq k=num o=#{xxnum}"
|
223
|
+
|
224
|
+
# leaf nodesの選択
|
225
|
+
system "mcommon k=num K=keyNum m=#{xxkey} -r i=#{xxnum} | mcut f=num o=#{xxleaf}"
|
226
|
+
|
227
|
+
# root nodesの選択
|
228
|
+
system "mcommon k=keyNum K=num m=#{xxnum} -r i=#{xxkey} | mcut f=keyNum:node0 o=#{xxbase[0]}"
|
229
|
+
|
230
|
+
# leaf nodeの構造を知る必要はないので入力ファイルのnodeからleafを除外
|
231
|
+
system "mcommon k=num m=#{xxleaf} -r i=#{xxiFile1} o=#{xxiFile2}"
|
232
|
+
|
233
|
+
# root nodesファイルから親子関係noodeを次々にjoinしていく
|
234
|
+
# xxbase0 : root nodes
|
235
|
+
# node0%0
|
236
|
+
# 3
|
237
|
+
# 4
|
238
|
+
# xxbase1
|
239
|
+
# node0%0,node1
|
240
|
+
# 3,
|
241
|
+
# 4,1
|
242
|
+
# 4,2
|
243
|
+
# xxbase2
|
244
|
+
# node0,node1%0,node2
|
245
|
+
# 3,,
|
246
|
+
# 4,1,
|
247
|
+
# 4,2,
|
248
|
+
# join項目(node2)の非null項目が0件で終了
|
249
|
+
|
250
|
+
# system "cat #{xxbase[0]}"
|
251
|
+
# node0%0
|
252
|
+
# #1_3
|
253
|
+
# #2_1
|
254
|
+
i=0
|
255
|
+
depth=nil
|
256
|
+
while true
|
257
|
+
# puts "xxbase[#{i}]"
|
258
|
+
# system "cat #{xxbase[i]}"
|
259
|
+
xxbase << temp.file
|
260
|
+
system "mnjoin k=node#{i} K=keyNum m=#{xxiFile2} f=num:node#{i+1} -n i=#{xxbase[i]} o=#{xxbase[i+1]}"
|
261
|
+
system "mdelnull f=node#{i+1} i=#{xxbase[i+1]} o=#{xxcheck}"
|
262
|
+
size=MCMD::mrecount("i=#{xxcheck}")
|
263
|
+
if size==0
|
264
|
+
system "msortf f=* i=#{xxbase[i]} o=#{oFile}"
|
265
|
+
depth=i+1
|
266
|
+
break
|
267
|
+
end
|
268
|
+
i+=1
|
269
|
+
end
|
270
|
+
# system "cat #{oFile}"
|
271
|
+
# node0%0,node1
|
272
|
+
# 3,
|
273
|
+
# 4,1
|
274
|
+
# 4,2
|
275
|
+
#puts "depth=#{depth}"
|
276
|
+
# depth=2
|
277
|
+
return depth
|
278
|
+
end
|
279
|
+
|
280
|
+
# edgeデータからflat graph構造を作る
|
281
|
+
# clusterのみの構造を作る
|
282
|
+
def mkFlat(iFile,oFile)
|
283
|
+
f=""
|
284
|
+
f << "mcut f=keyNum:node0 i=#{iFile} |"
|
285
|
+
f << "muniq k=node0 o=#{oFile}"
|
286
|
+
system(f)
|
287
|
+
return 1
|
288
|
+
end
|
289
|
+
|
290
|
+
|
291
|
+
def keyBreakDepth(newFlds,oldFlds)
|
292
|
+
return 0 unless oldFlds # 先頭行
|
293
|
+
(0...newFlds.size).each{|i|
|
294
|
+
return i if newFlds[i]!=oldFlds[i]
|
295
|
+
}
|
296
|
+
end
|
297
|
+
|
298
|
+
##########################
|
299
|
+
# creating tree structure
|
300
|
+
#
|
301
|
+
# digraph G {edge [dir=none]
|
302
|
+
# subgraph n_3 {
|
303
|
+
# ##3
|
304
|
+
# }
|
305
|
+
# subgraph n_4 {
|
306
|
+
# ##4
|
307
|
+
# subgraph n_1 {
|
308
|
+
# ##1
|
309
|
+
# }
|
310
|
+
# subgraph n_2 {
|
311
|
+
# ##2
|
312
|
+
# }
|
313
|
+
# }
|
314
|
+
# }
|
315
|
+
def dotTree(iFile,depth,header,footer,oFile)
|
316
|
+
File.open(oFile,"w"){|fpw|
|
317
|
+
fpw.puts header
|
318
|
+
fpw.puts "##0" # 孤立node(keyがnullのnode)
|
319
|
+
iCSV=MCMD::Mcsvin.new("i=#{iFile} -array")
|
320
|
+
oldFlds=nil
|
321
|
+
stack=[] # "subgraph {"に対応する終了括弧"}"のスタック
|
322
|
+
lastDepth=0 # 前行で出力されたsubgraphの深さ
|
323
|
+
iCSV.each{|newFlds|
|
324
|
+
next if newFlds[0]=="0" # 孤立nodeはスキップ
|
325
|
+
kbd=keyBreakDepth(newFlds,oldFlds) # 前行に比べてどの位置でkeybreakがあったか
|
326
|
+
(0...lastDepth-kbd).each{|i| # 前行より深さが戻った分終了括弧"}"を出力
|
327
|
+
fpw.puts stack.pop
|
328
|
+
}
|
329
|
+
# keybreakした位置から最深の位置までsubgraphを出力
|
330
|
+
(kbd...depth).each{|i|
|
331
|
+
break unless newFlds[i] # nullはその深さにsubgraphなしということ
|
332
|
+
indent=' '*(i+1) # インデント
|
333
|
+
fpw.puts "#{indent}subgraph cluster_#{newFlds[i]} {"
|
334
|
+
fpw.puts "###{newFlds[i]}"
|
335
|
+
stack.push("#{indent}}") # 対応する終了括弧をスタックしておく
|
336
|
+
lastDepth=i+1 # 出力した最深位置の更新
|
337
|
+
}
|
338
|
+
oldFlds=newFlds
|
339
|
+
}
|
340
|
+
(0...lastDepth).each{|i| # 深さが戻った分終了括弧"}"を出力
|
341
|
+
fpw.puts stack.pop
|
342
|
+
}
|
343
|
+
fpw.puts footer
|
344
|
+
}
|
345
|
+
end
|
346
|
+
|
347
|
+
# 全てをsubgraphを付けずにnodeとして出力する
|
348
|
+
def dotPlain(iFile,depth,header,footer,oFile)
|
349
|
+
File.open(oFile,"w"){|fpw|
|
350
|
+
fpw.puts header
|
351
|
+
fpw.puts "##0" # 孤立node(keyがnullのnode)
|
352
|
+
iCSV=MCMD::Mcsvin.new("i=#{iFile} -array")
|
353
|
+
iCSV.each{|flds|
|
354
|
+
flds.each{|fld|
|
355
|
+
break if fld==nil or fld==""
|
356
|
+
fpw.puts "###{fld}"
|
357
|
+
}
|
358
|
+
}
|
359
|
+
fpw.puts footer
|
360
|
+
}
|
361
|
+
end
|
362
|
+
|
363
|
+
def replace(treeFile,nodePath,edgePath,clusterLabel,oFile)
|
364
|
+
File.open(oFile,"w"){|dot|
|
365
|
+
File.open(treeFile,"r"){|tree|
|
366
|
+
while line=tree.gets
|
367
|
+
if line[0]=="#"
|
368
|
+
num=line.strip.sub("##","")
|
369
|
+
# 孤立nodeのclusterラベル(null)は出力しない
|
370
|
+
if clusterLabel and File.exist?("#{nodePath}/L_#{num}") and num!="0"
|
371
|
+
File.open("#{nodePath}/L_#{num}","r"){|label|
|
372
|
+
dot.puts label.read
|
373
|
+
}
|
374
|
+
end
|
375
|
+
if File.exist?("#{nodePath}/c_#{num}") # このifにマッチしないケースはないけど念のため
|
376
|
+
File.open("#{nodePath}/c_#{num}","r"){|node|
|
377
|
+
dot.puts node.read
|
378
|
+
}
|
379
|
+
end
|
380
|
+
if File.exist?("#{edgePath}/c_#{num}") # 孤立nodeはedgeなしなのでマッチする
|
381
|
+
File.open("#{edgePath}/c_#{num}","r"){|edge|
|
382
|
+
dot.puts edge.read
|
383
|
+
}
|
384
|
+
end
|
385
|
+
else
|
386
|
+
dot.puts line
|
387
|
+
end
|
388
|
+
end
|
389
|
+
}
|
390
|
+
}
|
391
|
+
end
|
392
|
+
|
393
|
+
####################
|
394
|
+
# mapファイルの作成
|
395
|
+
# 1) key,node名の値に一対一対応するnodeIDを作成(niがなければeiから作成)
|
396
|
+
def mkMap(key,nf,ni,ef1,ef2,ei,oFile)
|
397
|
+
temp=MCMD::Mtemp.new
|
398
|
+
xxa=temp.file
|
399
|
+
xxb=temp.file
|
400
|
+
xxc=temp.file
|
401
|
+
xxL1=temp.file
|
402
|
+
xxL2=temp.file
|
403
|
+
xxleaf=temp.file
|
404
|
+
|
405
|
+
# leaf nodeの構築
|
406
|
+
system "mcommon k=#{ef1} K=#{key} m=#{ei} -r i=#{ei} | mcut f=#{ef1}:nam o=#{xxa}"
|
407
|
+
system "mcommon k=#{ef2} K=#{key} m=#{ei} -r i=#{ei} | mcut f=#{ef2}:nam o=#{xxb}"
|
408
|
+
system "mcommon k=#{nf} K=#{key} m=#{ei} -r i=#{ni} | mcut f=#{nf}:nam o=#{xxc}" if ni
|
409
|
+
f=""
|
410
|
+
if ni
|
411
|
+
f << "mcat i=#{xxa},#{xxb},#{xxc} |"
|
412
|
+
else
|
413
|
+
f << "mcat i=#{xxa},#{xxb} |"
|
414
|
+
end
|
415
|
+
f << "muniq k=nam |"
|
416
|
+
f << "msetstr v=1 a=leaf o=#{xxleaf}"
|
417
|
+
system(f)
|
418
|
+
|
419
|
+
f=""
|
420
|
+
if ni then
|
421
|
+
system "mcut f=#{nf}:nam i=#{ni} o=#{xxa}"
|
422
|
+
system "mcut f=#{key}:nam i=#{ni} o=#{xxb}"
|
423
|
+
f=""
|
424
|
+
f << "mcat i=#{xxa},#{xxb} |"
|
425
|
+
f << "muniq k=nam |"
|
426
|
+
f << "mjoin k=nam m=#{xxleaf} f=leaf -n |"
|
427
|
+
# nullは最初に来るはずなので、mcalでなくmnumberでもnullを0に採番できるはずだが念のために
|
428
|
+
f << "mcal c='if(isnull($s{nam}),0,line()+1)' a=num |"
|
429
|
+
f << "mnullto f=nam v=##NULL## o=#{oFile}"
|
430
|
+
system(f)
|
431
|
+
else
|
432
|
+
system "mcut f=#{ef1}:nam i=#{ei} o=#{xxa}"
|
433
|
+
system "mcut f=#{ef2}:nam i=#{ei} o=#{xxb}"
|
434
|
+
system "mcut f=#{key}:nam i=#{ei} o=#{xxc}"
|
435
|
+
f=""
|
436
|
+
f << "mcat i=#{xxa},#{xxb},#{xxc} |"
|
437
|
+
f << "muniq k=nam |"
|
438
|
+
f << "mjoin k=nam m=#{xxleaf} f=leaf -n |"
|
439
|
+
f << "mcal c='if(isnull($s{nam}),0,line()+1)' a=num |"
|
440
|
+
f << "mnullto f=nam v=##NULL## o=#{oFile}"
|
441
|
+
system(f)
|
442
|
+
end
|
443
|
+
end
|
444
|
+
|
445
|
+
####################
|
446
|
+
# nodeファイルの作成
|
447
|
+
# 1) key,node名すべての値に一対一対応するnodeIDを作成=>xxmap
|
448
|
+
# niがなければeiから作成
|
449
|
+
# 1) key,node名に対応するnodeIDをjoinする
|
450
|
+
# 2) nvがなければ全データ1をセット
|
451
|
+
# 3) ncがなければ全データnullをセット
|
452
|
+
#
|
453
|
+
# オリジナルのkey,node名に一意のnodeID(num)をつけて、nodeマスターを作成する
|
454
|
+
def mkNode(key,nf,nl,nv,nc,ni,ef1,ef2,ei,noiso,mapFile,oFile)
|
455
|
+
temp=MCMD::Mtemp.new
|
456
|
+
xxbyEdge=temp.file
|
457
|
+
xxbyNode=temp.file
|
458
|
+
xxa=temp.file
|
459
|
+
xxb=temp.file
|
460
|
+
|
461
|
+
# edgeファイルからnode情報を生成
|
462
|
+
# noiso(孤立node排除)の場合は、edgeにあってnodeにないidを省く必要があるので計算する。
|
463
|
+
if ni==nil or (ni!=nil and noiso)
|
464
|
+
system "mcut f=#{key}:key,#{ef1}:nam,#{ef1}:nl i=#{ei} o=#{xxa}"
|
465
|
+
system "mcut f=#{key}:key,#{ef2}:nam,#{ef2}:nl i=#{ei} o=#{xxb}"
|
466
|
+
f=""
|
467
|
+
f << "mcat i=#{xxa},#{xxb} |"
|
468
|
+
f << "mnullto f=key v=##NULL## |"
|
469
|
+
f << "muniq k=key,nam |"
|
470
|
+
f << "mjoin k=key K=nam m=#{mapFile} f=num:keyNum |"
|
471
|
+
f << "mjoin k=nam K=nam m=#{mapFile} f=num,leaf |"
|
472
|
+
f << "msetstr v=,,,, a=nv,nc,nlKey,nvKey,ncKey |"
|
473
|
+
f << "mcut f=key,nam,keyNum,num,nl,nv,nc,leaf,nvKey,ncKey o=#{xxbyEdge}"
|
474
|
+
system(f)
|
475
|
+
end
|
476
|
+
|
477
|
+
# nodeファイルから作成
|
478
|
+
if ni
|
479
|
+
# mcal cat用のlabel項目の作成
|
480
|
+
label=[]
|
481
|
+
if nl
|
482
|
+
nl["names"].each{|name|
|
483
|
+
label << "$s{#{name}}"
|
484
|
+
}
|
485
|
+
else
|
486
|
+
label << "$s{#{nf}}"
|
487
|
+
end
|
488
|
+
|
489
|
+
nvcStr=""
|
490
|
+
nvcStr << ",#{nv}:nv" if nv
|
491
|
+
nvcStr << ",#{nc}:nc" if nc
|
492
|
+
|
493
|
+
# map
|
494
|
+
# nam,leaf,num
|
495
|
+
# ##NULL##,,0
|
496
|
+
# #1_1,,2
|
497
|
+
# #1_2,,3
|
498
|
+
# #1_3,,4
|
499
|
+
# #2_1,,5
|
500
|
+
# a,1,6
|
501
|
+
# b,1,7
|
502
|
+
# c,1,8
|
503
|
+
f=""
|
504
|
+
f << "mcal c='cat(\"_\",#{label.join(',')})' a=##label i=#{ni} |"
|
505
|
+
f << "mcut f=#{key}:key,#{nf}:nam,##label:nl#{nvcStr} |"
|
506
|
+
f << "mnullto f=key v=##NULL## |"
|
507
|
+
f << "msetstr v= a=nv |" unless nv
|
508
|
+
f << "msetstr v= a=nc |" unless nc
|
509
|
+
f << "mjoin k=key K=nam m=#{mapFile} f=num:keyNum |"
|
510
|
+
f << "mjoin k=nam K=nam m=#{mapFile} f=num,leaf |"
|
511
|
+
f << "mcut f=key,nam,keyNum,num,nl,nv,nc,leaf o=#{xxa}"
|
512
|
+
system(f)
|
513
|
+
# key(cluster)のnvとncを結合しておく
|
514
|
+
f=""
|
515
|
+
f << "mjoin k=keyNum K=num m=#{xxa} f=nl:nlk,nv:nvKey,nc:ncKey -n i=#{xxa} |"
|
516
|
+
# rootのclusterはnlkがnullになるので、keyをlabelとしておく
|
517
|
+
f << "mcal c='if(isnull($s{nlk}),$s{key},$s{nlk})' a=nlKey |"
|
518
|
+
f << "mcut f=nlk -r o=#{xxbyNode}"
|
519
|
+
system(f)
|
520
|
+
end
|
521
|
+
|
522
|
+
if ni!=nil and noiso
|
523
|
+
system "mcommon k=key,nam m=#{xxbyEdge} i=#{xxbyNode} o=#{oFile}"
|
524
|
+
elsif ni!=nil
|
525
|
+
system "mv #{xxbyNode} #{oFile}"
|
526
|
+
else
|
527
|
+
system "mv #{xxbyEdge} #{oFile}"
|
528
|
+
end
|
529
|
+
# system "head #{oFile}"
|
530
|
+
# key,nam,keyNum%0,num,nv,nvv,nc,leaf,nvKey,ncKey
|
531
|
+
# ##NULL##,j,0,15,0.09090909091,1,FF0000,1,,
|
532
|
+
# ##NULL##,i,0,14,0.09090909091,1,FF0000,1,,
|
533
|
+
# #1_1,a,2,6,0.3636363636,1.857142857,FF0000,1,0.7272727273,
|
534
|
+
# #1_1,b,2,7,0.3636363636,1.857142857,00FF00,1,0.7272727273,
|
535
|
+
# #1_1,d,2,9,0.3636363636,1.857142857,00FF00,1,0.7272727273,
|
536
|
+
# #1_1,e,2,10,0.4545454545,2.142857143,0000FF,1,0.7272727273,
|
537
|
+
# #1_2,c,3,8,0.2727272727,1.571428571,FF0000,1,0.2727272727,
|
538
|
+
# #1_2,f,3,11,0.1818181818,1.285714286,FF0000,1,0.2727272727,
|
539
|
+
# #1_3,g,4,12,0.1818181818,1.285714286,00FF00,1,,
|
540
|
+
end
|
541
|
+
|
542
|
+
#####################
|
543
|
+
# edgeフィアルの作成
|
544
|
+
# 1) key,node名に対応するnodeIDをjoinする
|
545
|
+
# 2) ev項目を基準化
|
546
|
+
# 3) evがなければ全データ1をセット
|
547
|
+
def mkEdge(key,ef1,ef2,el,ec,ed,ev,ei,mapFile,oFile)
|
548
|
+
# mcal cat用のlabel項目の作成
|
549
|
+
label=[]
|
550
|
+
if el
|
551
|
+
el["names"].each{|name|
|
552
|
+
label << "$s{#{name}}"
|
553
|
+
}
|
554
|
+
end
|
555
|
+
|
556
|
+
evcdStr=""
|
557
|
+
evcdStr << ",#{ev}:ev" if ev
|
558
|
+
evcdStr << ",#{ec}:ec" if ec
|
559
|
+
evcdStr << ",#{ed}:ed" if ed
|
560
|
+
f=""
|
561
|
+
if el
|
562
|
+
f << "mcal c='cat(\"_\",#{label.join(',')})' a=##label i=#{ei} |"
|
563
|
+
else
|
564
|
+
f << "msetstr v= a=##label i=#{ei} |"
|
565
|
+
end
|
566
|
+
f << "mcut f=#{key}:key,#{ef1}:nam1,#{ef2}:nam2,##label:el#{evcdStr} |"
|
567
|
+
f << "msetstr v= a=ev |" unless ev
|
568
|
+
f << "msetstr v= a=ed |" unless ed
|
569
|
+
f << "msetstr v= a=ec |" unless ec
|
570
|
+
f << "mnullto f=key v=##NULL## |"
|
571
|
+
f << "mjoin k=key K=nam m=#{mapFile} f=num:keyNum |"
|
572
|
+
f << "mjoin k=nam1 K=nam m=#{mapFile} f=num:num1,leaf:leaf1 |"
|
573
|
+
f << "mjoin k=nam2 K=nam m=#{mapFile} f=num:num2,leaf:leaf2 |"
|
574
|
+
f << "mcut f=key,nam1,nam2,keyNum,num1,num2,el,ev,ed,ec,leaf1,leaf2 o=#{oFile}"
|
575
|
+
system(f)
|
576
|
+
system "cp #{oFile} xxo"
|
577
|
+
end
|
578
|
+
|
579
|
+
#########################################
|
580
|
+
# dot用のnodeデータをcluster別に作成する
|
581
|
+
def dotNode(iFile,nw,type,clusterLabel,oPath)
|
582
|
+
#system "cat #{iFile}"
|
583
|
+
# key,nam,keyNum%0,num,nl,nv,nvv,nc,leaf,nvKey,ncKey
|
584
|
+
# ##NULL##,j,0,15,j_A,0.09090909091,1,FF0000,1,,
|
585
|
+
# ##NULL##,i,0,14,i_A,0.09090909091,1,FF0000,1,,
|
586
|
+
# #1_1,a,2,6,a_A,0.3636363636,1.857142857,FF0000,1,0.7272727273,
|
587
|
+
# #1_1,b,2,7,b_B,0.3636363636,1.857142857,00FF00,1,0.7272727273,
|
588
|
+
# #1_1,d,2,9,d_B,0.3636363636,1.857142857,00FF00,1,0.7272727273,
|
589
|
+
# #1_1,e,2,10,e_C,0.4545454545,2.142857143,0000FF,1,0.7272727273,
|
590
|
+
# #1_2,c,3,8,c_A,0.2727272727,1.571428571,FF0000,1,0.2727272727,
|
591
|
+
# #1_2,f,3,11,f_A,0.1818181818,1.285714286,FF0000,1,0.2727272727,
|
592
|
+
# #1_3,g,4,12,g_B,0.1818181818,1.285714286,00FF00,1,,
|
593
|
+
# #1_3,h,4,13,h_C,0.1818181818,1.285714286,0000FF,1,,
|
594
|
+
# #2_1,#1_2,5,3,#1_2_,0.2727272727,1.571428571,,,,
|
595
|
+
# #2_1,#1_1,5,2,#1_1_,0.7272727273,3,,,,
|
596
|
+
iCSV=MCMD::Mcsvin.new("k=keyNum i=#{iFile}")
|
597
|
+
block=""
|
598
|
+
iCSV.each{|flds,top,bot|
|
599
|
+
nam=flds["nam"]
|
600
|
+
nl =flds["nl"]
|
601
|
+
nv =flds["nv"]
|
602
|
+
nc =flds["nc"]
|
603
|
+
leaf=flds["leaf"]
|
604
|
+
|
605
|
+
prefix="n"
|
606
|
+
prefix="cluster" unless leaf
|
607
|
+
nStr ="#{prefix}_#{flds["num"]}"
|
608
|
+
attrStr=""
|
609
|
+
|
610
|
+
unless prefix=="cluster"
|
611
|
+
# node label
|
612
|
+
# labelがleafでなければ、-clusterLabelが指定されていない限りlabelを表示しない
|
613
|
+
if leaf or clusterLabel
|
614
|
+
attrStr << "label=\"#{nl}\" "
|
615
|
+
else
|
616
|
+
attrStr << "label=\"\" "
|
617
|
+
end
|
618
|
+
|
619
|
+
# node shape
|
620
|
+
if nv
|
621
|
+
nRatioNorm=nv.to_f
|
622
|
+
attrStr << "height=#{0.5*nRatioNorm} width=#{0.75*nRatioNorm} "
|
623
|
+
end
|
624
|
+
|
625
|
+
# node color
|
626
|
+
if nc
|
627
|
+
attrStr << "color=\"##{nc}\" "
|
628
|
+
end
|
629
|
+
|
630
|
+
# node linewidth
|
631
|
+
if nw
|
632
|
+
attrStr << "style=\"setlinewidth(#{nw})\" "
|
633
|
+
end
|
634
|
+
end
|
635
|
+
block << "#{nStr} [#{attrStr}]\n"
|
636
|
+
|
637
|
+
if bot
|
638
|
+
keyNum=flds["keyNum"]
|
639
|
+
key=flds["key"]
|
640
|
+
nlKey=flds["nlKey"]
|
641
|
+
nvKey=flds["nvKey"]
|
642
|
+
ncKey=flds["ncKey"]
|
643
|
+
File.open("#{oPath}/c_#{keyNum}","w"){|fpw|
|
644
|
+
fpw.write(block)
|
645
|
+
}
|
646
|
+
# クラスタのラベルや色も出力しておく
|
647
|
+
attrStr=""
|
648
|
+
attrStr << "label=\"#{nlKey}\"\n"
|
649
|
+
|
650
|
+
# node color
|
651
|
+
if ncKey
|
652
|
+
attrStr << "color=\"##{ncKey}\"\n"
|
653
|
+
end
|
654
|
+
# node linewidth
|
655
|
+
if nw and ncKey
|
656
|
+
if ncKey
|
657
|
+
attrStr << "style=\"setlinewidth(#{nw})\"\n"
|
658
|
+
end
|
659
|
+
end
|
660
|
+
File.open("#{oPath}/L_#{keyNum}","w"){|fpw|
|
661
|
+
fpw.write(attrStr)
|
662
|
+
}
|
663
|
+
block=""
|
664
|
+
end
|
665
|
+
}
|
666
|
+
end
|
667
|
+
|
668
|
+
#########################################
|
669
|
+
# dot用のedgeデータをcluster別に作成する
|
670
|
+
def dotEdge(iFile,oPath)
|
671
|
+
# key,nam1,nam2%0,keyNum,num1,num2,ev,evv
|
672
|
+
# #2_1,#1_1,#1_2,4,1,2,0.2727272727,20
|
673
|
+
# #1_1,a,b,1,5,6,0.1818181818,0
|
674
|
+
iCSV=MCMD::Mcsvin.new("k=keyNum i=#{iFile}")
|
675
|
+
block=""
|
676
|
+
iCSV.each{|flds,top,bot|
|
677
|
+
num1=flds["num1"]
|
678
|
+
num2=flds["num2"]
|
679
|
+
el=flds["el"]
|
680
|
+
ev=flds["ev"]
|
681
|
+
ec=flds["ec"]
|
682
|
+
ed=flds["ed"]
|
683
|
+
leaf1=flds["leaf1"]
|
684
|
+
leaf2=flds["leaf2"]
|
685
|
+
|
686
|
+
prefix1="n"
|
687
|
+
prefix2="n"
|
688
|
+
prefix1="cluster" unless leaf1
|
689
|
+
prefix2="cluster" unless leaf2
|
690
|
+
e1Str ="#{prefix1}_#{num1}"
|
691
|
+
e2Str ="#{prefix2}_#{num2}"
|
692
|
+
|
693
|
+
attrStr=""
|
694
|
+
attrStr << "label=\"#{el}\" " if el
|
695
|
+
attrStr << "style=\"setlinewidth(#{ev})\" " if ev
|
696
|
+
attrStr << "color=\"##{ec}\" " if ec
|
697
|
+
if ed
|
698
|
+
if ed=="F"
|
699
|
+
attrStr << "dir=forward "
|
700
|
+
elsif ed=="B"
|
701
|
+
attrStr << "dir=back "
|
702
|
+
elsif ed=="W"
|
703
|
+
attrStr << "dir=both "
|
704
|
+
elsif ed=="N"
|
705
|
+
attrStr << "dir=none "
|
706
|
+
end
|
707
|
+
end
|
708
|
+
|
709
|
+
block << "#{e1Str} -> #{e2Str} [#{attrStr}]\n"
|
710
|
+
|
711
|
+
if bot
|
712
|
+
keyNum=flds["keyNum"]
|
713
|
+
File.open("#{oPath}/c_#{keyNum}","w"){|fpw|
|
714
|
+
fpw.write(block)
|
715
|
+
}
|
716
|
+
block=""
|
717
|
+
end
|
718
|
+
}
|
719
|
+
end
|
720
|
+
|
721
|
+
#############
|
722
|
+
# entry point
|
723
|
+
|
724
|
+
temp=MCMD::Mtemp.new
|
725
|
+
xxni =temp.file
|
726
|
+
xxei =temp.file
|
727
|
+
xxmap =temp.file
|
728
|
+
xxnode=temp.file
|
729
|
+
xxedge=temp.file
|
730
|
+
xxnode2=temp.file
|
731
|
+
xxedge2=temp.file
|
732
|
+
xxtree=temp.file
|
733
|
+
xxdotNode=temp.file
|
734
|
+
xxdotEdge=temp.file
|
735
|
+
MCMD::mkDir(xxdotNode)
|
736
|
+
MCMD::mkDir(xxdotEdge)
|
737
|
+
|
738
|
+
# 処理前のデータ修正
|
739
|
+
unless key
|
740
|
+
if ni
|
741
|
+
system "msetstr v= a=#key i=#{ni} o=#{xxni}"
|
742
|
+
ni=xxni
|
743
|
+
end
|
744
|
+
system "msetstr v= a=#key i=#{ei} o=#{xxei}"
|
745
|
+
ei=xxei
|
746
|
+
key="#key"
|
747
|
+
end
|
748
|
+
|
749
|
+
# ノードファイルの作成
|
750
|
+
mkMap(key,nf,ni,ef1,ef2,ei,xxmap)
|
751
|
+
mkNode(key,nf,nl,nv,nc,ni,ef1,ef2,ei,noiso,xxmap,xxnode)
|
752
|
+
mkEdge(key,ef1,ef2,el,ec,ed,ev,ei,xxmap,xxedge)
|
753
|
+
#system "head #{xxmap}"
|
754
|
+
# nam%0,num
|
755
|
+
# ,0
|
756
|
+
# #1_1,1
|
757
|
+
# #1_2,2
|
758
|
+
#
|
759
|
+
#system "cat #{xxnode}"
|
760
|
+
#exit
|
761
|
+
# key,nam,keyNum%0,num,nv,nvv,nc,leaf,nvKey,ncKey
|
762
|
+
# #1_1,a,1,5,0.4666666667,3.222222223,,1,0.6666666667,
|
763
|
+
# #1_1,b,1,6,0.4,2.666666666,,1,0.6666666667,
|
764
|
+
#system "cat #{xxedge}"
|
765
|
+
# key,nam1,nam2%0,keyNum,num1,num2,ev,evv,leaf1,leaf2
|
766
|
+
# #3_1,#1_2,#2_1,4,2,3,0.3,13.66666667,,
|
767
|
+
# #1_1,a,b,1,5,6,0.1,1,1,1
|
768
|
+
#exit
|
769
|
+
# dot用のnodeとedgeデータをcluster別ファイルとして生成
|
770
|
+
dotNode(xxnode,nw,type,clusterLabel,xxdotNode)
|
771
|
+
dotEdge(xxedge ,xxdotEdge)
|
772
|
+
#system "rm -rf ./xxdotNode"
|
773
|
+
#system "cp -R #{xxdotNode} ./xxdotNode"
|
774
|
+
#system "rm -rf ./xxdotEdge"
|
775
|
+
#system "cp -R #{xxdotEdge} ./xxdotEdge"
|
776
|
+
|
777
|
+
depth=nil
|
778
|
+
if type=="flat"
|
779
|
+
depth=mkFlat(xxnode,xxtree)
|
780
|
+
elsif type=="nest"
|
781
|
+
# tree構造の処理
|
782
|
+
# クラスタのみtree構造に格納する
|
783
|
+
depth=mkTree(xxnode,xxtree)
|
784
|
+
# puts "xxtree"
|
785
|
+
# system "cat #{xxtree}"
|
786
|
+
# node0%0,node1%1
|
787
|
+
# 3,
|
788
|
+
# 4,1
|
789
|
+
# 4,2
|
790
|
+
end
|
791
|
+
|
792
|
+
# tree構造をdotとして書き出す。その時、node,edgeを置換するためのキーワードを埋め込む
|
793
|
+
xxdotTree=temp.file
|
794
|
+
header=""
|
795
|
+
header << "digraph G {\n"
|
796
|
+
header << " #{directedStr}\n"
|
797
|
+
footer=""
|
798
|
+
footer << "}\n"
|
799
|
+
#system "cat #{xxtree}"
|
800
|
+
dotTree(xxtree,depth,header,footer,xxdotTree)
|
801
|
+
#puts "--------"
|
802
|
+
#system "cat #{xxdotTree}"
|
803
|
+
#exit
|
804
|
+
# xxdotTreeのnode,edge keywordをxxdotNode,xxdotEdgeで置換してdotの完成
|
805
|
+
replace(xxdotTree,xxdotNode,xxdotEdge,clusterLabel,oFile)
|
806
|
+
#system "cp #{xxdotTree} ./xxdotTree"
|
807
|
+
#system "cp -R #{xxdotNode} ./xxdotNode"
|
808
|
+
#system "cp -R #{xxdotEdge} ./xxdotEdge"
|
809
|
+
|
810
|
+
# 終了メッセージ
|
811
|
+
MCMD::endLog(args.cmdline)
|
812
|
+
|