nysol-view 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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/mgv.rb
ADDED
@@ -0,0 +1,809 @@
|
|
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/11/07
|
9
|
+
# ver="1.1" # k=除外対応 2016/11/08
|
10
|
+
# ver="1.2" # nested graph対応,色対応 2016/11/09
|
11
|
+
$cmd=$0.sub(/.*\//,"")
|
12
|
+
|
13
|
+
$version=1.2
|
14
|
+
$revision="###VERSION###"
|
15
|
+
|
16
|
+
def help
|
17
|
+
|
18
|
+
STDERR.puts <<EOF
|
19
|
+
------------------------
|
20
|
+
#{$cmd} version #{$version}
|
21
|
+
------------------------
|
22
|
+
概要) CSVによるグラフ構造データをDOTフォーマットで出力する
|
23
|
+
|
24
|
+
書式1) #{$cmd} [type=flat|nest] [k=] [ni=] [nf=] [nv=] [nc=] [nr=] [col=] [nl=] [nw=]
|
25
|
+
[-clusterLabel] [-noiso] ei= ef= [ev=] [er=] [el=] [-d] [o=]
|
26
|
+
|
27
|
+
type= : グラフのタイプ
|
28
|
+
flat: key項目をクラスタとした木構造グラフ
|
29
|
+
nest: 木構造であることを前提にした入れ子構造グラフ(データが木構造でない場合の描画は不定)
|
30
|
+
k= : 入れ子グラフのクラスタ項目名(ni=を指定した場合は同じ項目名でなければならない)
|
31
|
+
複数項目指定不可
|
32
|
+
k=を省略すればtype=に関わらずクラスタを伴わない普通のグラフ描画となる。
|
33
|
+
|
34
|
+
ni= : 節点集合ファイル名
|
35
|
+
nf= : 節点ID項目名
|
36
|
+
nv= : 節点の大きさ項目名(この値に応じて節点の楕円の大きさが変化する,1項目のみ指定可)。
|
37
|
+
nc= : 節点カラー項目名(この値に応じて枠線カラーが変化する,1項目のみ指定可)。
|
38
|
+
カラーは、RGBを16進数2桁づつ6桁で表現する。ex) FF00FF:紫
|
39
|
+
さらに最後に2桁追加すればそれは透過率となる。
|
40
|
+
nr= : ノードの拡大率(デフォルト=3.0,最大10.0まで指定可能)
|
41
|
+
節点の楕円のサイズを1.0〜nr=の値に基準化する。
|
42
|
+
すなわちnv=が最小の節点の大きさが1.0、最大の節点の大きさがnr=で指定した値となる。
|
43
|
+
nl= : ノードラベルの項目(複数指定したら"_"で区切って結合される)
|
44
|
+
nw= : 節点の枠線の幅を指定する(デフォルトは1)
|
45
|
+
-clusterLabel : k=を指定して入れ子グラフを作成する場合、クラスタのラベルも表示する
|
46
|
+
-noiso : 孤立節点(隣接節点のない節点)は出力しない
|
47
|
+
|
48
|
+
ei= : 枝集合ファイル名
|
49
|
+
ef= : 開始節点ID項目名,終了節点ID項目名
|
50
|
+
ev= : 枝の幅項目名(この値に応じて枝の幅(太さ)が変化する)
|
51
|
+
ec= : 枝の色を表す項目
|
52
|
+
ed= : 枝の矢印を表す項目(-dの指定、未指定に関わらず優先される)
|
53
|
+
値としては、F,B,W,N,nullの5つの値のいずれかでなければならない。
|
54
|
+
ef=e1,e2とした場合、それぞれで描画される矢印は以下の通り。
|
55
|
+
F: e1->e2, B: e1<-e2, W: e1<->e2, N:e1-e2(矢印なし),null:デフォルト
|
56
|
+
デフォルトは、-dが指定されていればF、-dの指定がなければNとなる。
|
57
|
+
er= : エッジの拡大率(デフォルト=10.0,最大20.0まで指定可能)
|
58
|
+
枝の太さを1.0〜er=の値に基準化する。
|
59
|
+
すなわちev=が最小の枝の太さが1.0、最大の枝の太さer=で指定した値となる。
|
60
|
+
el= : エッジラベルの項目(複数指定したら"_"で区切って結合される)
|
61
|
+
|
62
|
+
-d : 有向グラフと見なす。"edge [dir=none]"を記述する。
|
63
|
+
o= : 出力ファイル名
|
64
|
+
|
65
|
+
-h,--help : ヘルプの表示
|
66
|
+
|
67
|
+
基本例)
|
68
|
+
$ cat node.csv
|
69
|
+
cluster%0,node%1,support
|
70
|
+
#1_1,a,0.4666666667
|
71
|
+
#1_1,b,0.4
|
72
|
+
#1_2,d,0.2666666667
|
73
|
+
#1_2,e,0.3333333333
|
74
|
+
#2_1,#1_1,0.6666666667
|
75
|
+
#2_1,c,0.3333333333
|
76
|
+
#3_1,#1_2,0.4
|
77
|
+
#3_1,#2_1,0.8
|
78
|
+
#3_1,f,0.2
|
79
|
+
|
80
|
+
$ cat edge.csv
|
81
|
+
cluster,node1,node2,support
|
82
|
+
#1_1,a,b,0.1
|
83
|
+
#1_2,d,e,0.1
|
84
|
+
#2_1,#1_1,c,0.2
|
85
|
+
#3_1,#1_2,#2_1,0.3
|
86
|
+
#3_1,#2_1,f,0.4
|
87
|
+
|
88
|
+
$ #{$cmd} k=cluster ni=node.csv nf=node nv=support ei=edge.csv ef=node1,node2 ev=support -el -nl nr=6.0 er=20 o=result.dot
|
89
|
+
# fdpはgraphVizのコマンド, nested graphはdotコマンドでは描画できない
|
90
|
+
$ fdp -Tpdf result.dot >result.pdf
|
91
|
+
$ open result.png
|
92
|
+
$ cat result.dot
|
93
|
+
digraph G {
|
94
|
+
edge [dir=none color="#00000050"]
|
95
|
+
n_15 [label="j_0.09090909091" height=0.5 width=0.75 style="setlinewidth(1)" ]
|
96
|
+
n_14 [label="i_0.09090909091" height=0.5 width=0.75 style="setlinewidth(1)" ]
|
97
|
+
subgraph cluster_4 {
|
98
|
+
n_12 [label="g_0.1818181818" height=0.857142857 width=1.2857142855 style="setlinewidth(1)" ]↩
|
99
|
+
n_13 [label="h_0.1818181818" height=0.857142857 width=1.2857142855 style="setlinewidth(1)" ]↩
|
100
|
+
n_12 -> n_13 [label="0.1818181818" style="setlinewidth(1)" ]↩
|
101
|
+
}
|
102
|
+
subgraph cluster_5 {
|
103
|
+
cluster_3 []
|
104
|
+
cluster_2 []
|
105
|
+
cluster_2 -> cluster_3 [label="0.2727272727" style="setlinewidth(20)" ]
|
106
|
+
subgraph cluster_2 {
|
107
|
+
n_6 [label="a_0.3636363636" height=1.5714285715 width=2.35714285725 style="setlinewidth(1)" ]
|
108
|
+
n_7 [label="b_0.3636363636" height=1.5714285715 width=2.35714285725 style="setlinewidth(1)" ]
|
109
|
+
n_9 [label="d_0.3636363636" height=1.5714285715 width=2.35714285725 style="setlinewidth(1)" ]
|
110
|
+
n_10 [label="e_0.4545454545" height=1.9285714285 width=2.89285714275 style="setlinewidth(1)" ]
|
111
|
+
n_6 -> n_7 [label="0.1818181818" style="setlinewidth(1)" ]
|
112
|
+
n_6 -> n_9 [label="0.1818181818" style="setlinewidth(1)" ]
|
113
|
+
n_7 -> n_9 [label="0.1818181818" style="setlinewidth(1)" ]
|
114
|
+
n_6 -> n_10 [label="0.2727272727" style="setlinewidth(20)" ]
|
115
|
+
n_7 -> n_10 [label="0.1818181818" style="setlinewidth(1)" ]
|
116
|
+
n_9 -> n_10 [label="0.2727272727" style="setlinewidth(20)" ]
|
117
|
+
}
|
118
|
+
subgraph cluster_3 {
|
119
|
+
n_8 [label="c_0.2727272727" height=1.2142857145 width=1.8214285717499998 style="setlinewidth(1)" ]
|
120
|
+
n_11 [label="f_0.1818181818" height=0.857142857 width=1.2857142855 style="setlinewidth(1)" ]
|
121
|
+
n_8 -> n_11 [label="0.1818181818" style="setlinewidth(1)" ]
|
122
|
+
}
|
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=,o=,nl=,el=,nr=,er=,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 "key= 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
|
+
nr = args.float("nr=" , 3.0 ,1.0 ,10.0 ) # node 拡大率
|
154
|
+
nl = args.field("nl=", ni) # nodeラベル項目名
|
155
|
+
nw =args.int("nw=",1,1) # nodeの枠線の太さ
|
156
|
+
unless args.keyValue["ni="]
|
157
|
+
if args.keyValue["nf="] or args.keyValue["nv="] or args.keyValue["nc="] or args.keyValue["nr="] or args.keyValue["-nl"] or args.keyValue["-cl"] or args.keyValue["nw="]
|
158
|
+
raise "nf=,nv=,nc=,nr=,-nl,-cl cannot be specified without ni="
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
if args.keyValue["ni="]
|
163
|
+
#unless args.keyValue["nf="] or args.keyValue["nv="]
|
164
|
+
unless args.keyValue["nf="]
|
165
|
+
raise "nf= must be specified when ni= is given"
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
ei = args. file("ei=","r") # edgeファイル名
|
170
|
+
key= args.field("k=", ei,nil,1,1) # nested graph クラスタ項目
|
171
|
+
key=key["names"][0] if key
|
172
|
+
ef = args.field("ef=", ei) # edge始点node項目名,終了節点項目名
|
173
|
+
ev = args.field("ev=", ei) # edge value項目名
|
174
|
+
ec = args.field("ec=", ei) # edge color項目名
|
175
|
+
ed = args.field("ed=", ei) # edge direction項目名
|
176
|
+
er = args.float("er=" , 10.0 ,1.0 ,20.0 ) # edge 拡大率
|
177
|
+
el = args.field("el=", ei) # edgeラベル項目
|
178
|
+
ef1=ef["names"][0]
|
179
|
+
ef2=ef["names"][1]
|
180
|
+
if ef1==nil or ef2==nil then
|
181
|
+
raise "ef= takes two field names"
|
182
|
+
end
|
183
|
+
|
184
|
+
if ni
|
185
|
+
nf=nf["names"][0]
|
186
|
+
nv=nv["names"][0] if nv
|
187
|
+
nc=nc["names"][0] if nc
|
188
|
+
end
|
189
|
+
|
190
|
+
ev=ev["names"][0] if ev
|
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,noiso,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
|
+
unless noiso and num=="0" # -noisoが指定されたら孤立ノードは出力しない
|
377
|
+
File.open("#{nodePath}/c_#{num}","r"){|node|
|
378
|
+
dot.puts node.read
|
379
|
+
}
|
380
|
+
end
|
381
|
+
end
|
382
|
+
if File.exist?("#{edgePath}/c_#{num}") # 孤立nodeはedgeなしなのでマッチする
|
383
|
+
File.open("#{edgePath}/c_#{num}","r"){|edge|
|
384
|
+
dot.puts edge.read
|
385
|
+
}
|
386
|
+
end
|
387
|
+
else
|
388
|
+
dot.puts line
|
389
|
+
end
|
390
|
+
end
|
391
|
+
}
|
392
|
+
}
|
393
|
+
end
|
394
|
+
|
395
|
+
####################
|
396
|
+
# mapファイルの作成
|
397
|
+
# 1) key,node名の値に一対一対応するnodeIDを作成(niがなければeiから作成)
|
398
|
+
def mkMap(key,nf,ni,ef1,ef2,ei,oFile)
|
399
|
+
temp=MCMD::Mtemp.new
|
400
|
+
xxa=temp.file
|
401
|
+
xxb=temp.file
|
402
|
+
xxc=temp.file
|
403
|
+
xxL1=temp.file
|
404
|
+
xxL2=temp.file
|
405
|
+
xxleaf=temp.file
|
406
|
+
|
407
|
+
f=""
|
408
|
+
if ni then
|
409
|
+
f=""
|
410
|
+
f << "mcommon k=#{nf} K=#{key} m=#{ni} -r i=#{ni} |"
|
411
|
+
f << "mcut f=#{nf}:nam |"
|
412
|
+
f << "msetstr v=1 a=leaf o=#{xxleaf}"
|
413
|
+
system(f)
|
414
|
+
system "mcut f=#{nf}:nam i=#{ni} o=#{xxa}"
|
415
|
+
system "mcut f=#{key}:nam i=#{ni} o=#{xxb}"
|
416
|
+
f=""
|
417
|
+
f << "mcat i=#{xxa},#{xxb} |"
|
418
|
+
f << "muniq k=nam |"
|
419
|
+
f << "mjoin k=nam m=#{xxleaf} f=leaf -n |"
|
420
|
+
# nullは最初に来るはずなので、mcalでなくmnumberでもnullを0に採番できるはずだが念のために
|
421
|
+
f << "mcal c='if(isnull($s{nam}),0,line()+1)' a=num |"
|
422
|
+
f << "mnullto f=nam v=##NULL## o=#{oFile}"
|
423
|
+
system(f)
|
424
|
+
else
|
425
|
+
f=""
|
426
|
+
f << "mcommon k=#{ef1} K=#{key} m=#{ei} -r i=#{ei} |"
|
427
|
+
f << "mcut f=#{ef1}:nam o=#{xxL1}"
|
428
|
+
system(f)
|
429
|
+
f=""
|
430
|
+
f << "mcommon k=#{ef2} K=#{key} m=#{ei} -r i=#{ei} |"
|
431
|
+
f << "mcut f=#{ef2}:nam o=#{xxL2}"
|
432
|
+
system(f)
|
433
|
+
f=""
|
434
|
+
f << "mcat i=#{xxL1},#{xxL2} |"
|
435
|
+
f << "muniq k=nam |"
|
436
|
+
f << "msetstr v=1 a=leaf o=#{xxleaf}"
|
437
|
+
system(f)
|
438
|
+
system "mcut f=#{ef1}:nam i=#{ei} o=#{xxa}"
|
439
|
+
system "mcut f=#{ef2}:nam i=#{ei} o=#{xxb}"
|
440
|
+
system "mcut f=#{key}:nam i=#{ei} o=#{xxc}"
|
441
|
+
f=""
|
442
|
+
f << "mcat i=#{xxa},#{xxb},#{xxc} |"
|
443
|
+
f << "muniq k=nam |"
|
444
|
+
f << "mjoin k=nam m=#{xxleaf} f=leaf -n |"
|
445
|
+
f << "mcal c='if(isnull($s{nam}),0,line()+1)' a=num |"
|
446
|
+
f << "mnullto f=nam v=##NULL## o=#{oFile}"
|
447
|
+
system(f)
|
448
|
+
end
|
449
|
+
end
|
450
|
+
|
451
|
+
####################
|
452
|
+
# nodeファイルの作成
|
453
|
+
# 1) key,node名すべての値に一対一対応するnodeIDを作成=>xxmap
|
454
|
+
# niがなければeiから作成
|
455
|
+
# 1) key,node名に対応するnodeIDをjoinする
|
456
|
+
# 2) nv項目を基準化
|
457
|
+
# 3) nvがなければ全データ1をセット
|
458
|
+
# 4) 基準化された値をnr倍する
|
459
|
+
# 3) ncがなければ全データnullをセット
|
460
|
+
#
|
461
|
+
# オリジナルのkey,node名に一意のnodeID(num)をつけて、nodeマスターを作成する
|
462
|
+
def mkNode(key,nf,nl,nv,nr,nc,ni,ef1,ef2,ei,mapFile,oFile)
|
463
|
+
temp=MCMD::Mtemp.new
|
464
|
+
xxa=temp.file
|
465
|
+
xxb=temp.file
|
466
|
+
|
467
|
+
# nodeファイルから作成
|
468
|
+
if ni
|
469
|
+
# mcal cat用のlabel項目の作成
|
470
|
+
label=[]
|
471
|
+
if nl
|
472
|
+
nl["names"].each{|name|
|
473
|
+
label << "$s{#{name}}"
|
474
|
+
}
|
475
|
+
else
|
476
|
+
label << "$s{#{nf}}"
|
477
|
+
end
|
478
|
+
|
479
|
+
nvcStr=""
|
480
|
+
nvcStr << ",#{nv}:nv" if nv
|
481
|
+
nvcStr << ",#{nc}:nc" if nc
|
482
|
+
|
483
|
+
# map
|
484
|
+
# nam,leaf,num
|
485
|
+
# ##NULL##,,0
|
486
|
+
# #1_1,,2
|
487
|
+
# #1_2,,3
|
488
|
+
# #1_3,,4
|
489
|
+
# #2_1,,5
|
490
|
+
# a,1,6
|
491
|
+
# b,1,7
|
492
|
+
# c,1,8
|
493
|
+
f=""
|
494
|
+
f << "mcal c='cat(\"_\",#{label.join(',')})' a=##label i=#{ni} |"
|
495
|
+
f << "mcut f=#{key}:key,#{nf}:nam,##label:nl#{nvcStr} |"
|
496
|
+
f << "mnullto f=key v=##NULL## |"
|
497
|
+
f << "msetstr v= a=nv |" unless nv
|
498
|
+
f << "msetstr v= a=nc |" unless nc
|
499
|
+
f << "mjoin k=key K=nam m=#{mapFile} f=num:keyNum |"
|
500
|
+
f << "mjoin k=nam K=nam m=#{mapFile} f=num,leaf |"
|
501
|
+
f << "mnormalize f=nv:nv2 c=range |"
|
502
|
+
f << "mcal c='${nv2}*(#{nr}-1)+1' a=nvv |"
|
503
|
+
f << "mcut f=key,nam,keyNum,num,nl,nv,nvv,nc,leaf o=#{xxa}"
|
504
|
+
system(f)
|
505
|
+
# key(cluster)のnvとncを結合しておく
|
506
|
+
f=""
|
507
|
+
f << "mjoin k=keyNum K=num m=#{xxa} f=nl:nlk,nv:nvKey,nc:ncKey -n i=#{xxa} |"
|
508
|
+
# rootのclusterはnlkがnullになるので、keyをlabelとしておく
|
509
|
+
f << "mcal c='if(isnull($s{nlk}),$s{key},$s{nlk})' a=nlKey |"
|
510
|
+
f << "mcut f=nlk -r o=#{oFile}"
|
511
|
+
system(f)
|
512
|
+
|
513
|
+
# edgeファイルから作成
|
514
|
+
else
|
515
|
+
system "mcut f=#{key}:key,#{ef1}:nam,#{ef1}:nl i=#{ei} o=#{xxa}"
|
516
|
+
system "mcut f=#{key}:key,#{ef2}:nam,#{ef2}:nl i=#{ei} o=#{xxb}"
|
517
|
+
f=""
|
518
|
+
f << "mcat i=#{xxa},#{xxb} |"
|
519
|
+
f << "mnullto f=key v=##NULL## |"
|
520
|
+
f << "muniq k=key,nam |"
|
521
|
+
f << "mjoin k=key K=nam m=#{mapFile} f=num:keyNum |"
|
522
|
+
f << "mjoin k=nam K=nam m=#{mapFile} f=num,leaf |"
|
523
|
+
f << "msetstr v=,,,,, a=nv,nvv,nc,nlKey,nvKey,ncKey |"
|
524
|
+
f << "mcut f=key,nam,keyNum,num,nl,nv,nvv,nc,leaf,nvKey,ncKey o=#{oFile}"
|
525
|
+
system(f)
|
526
|
+
end
|
527
|
+
# system "head #{oFile}"
|
528
|
+
# key,nam,keyNum%0,num,nv,nvv,nc,leaf,nvKey,ncKey
|
529
|
+
# ##NULL##,j,0,15,0.09090909091,1,FF0000,1,,
|
530
|
+
# ##NULL##,i,0,14,0.09090909091,1,FF0000,1,,
|
531
|
+
# #1_1,a,2,6,0.3636363636,1.857142857,FF0000,1,0.7272727273,
|
532
|
+
# #1_1,b,2,7,0.3636363636,1.857142857,00FF00,1,0.7272727273,
|
533
|
+
# #1_1,d,2,9,0.3636363636,1.857142857,00FF00,1,0.7272727273,
|
534
|
+
# #1_1,e,2,10,0.4545454545,2.142857143,0000FF,1,0.7272727273,
|
535
|
+
# #1_2,c,3,8,0.2727272727,1.571428571,FF0000,1,0.2727272727,
|
536
|
+
# #1_2,f,3,11,0.1818181818,1.285714286,FF0000,1,0.2727272727,
|
537
|
+
# #1_3,g,4,12,0.1818181818,1.285714286,00FF00,1,,
|
538
|
+
end
|
539
|
+
|
540
|
+
#####################
|
541
|
+
# edgeフィアルの作成
|
542
|
+
# 1) key,node名に対応するnodeIDをjoinする
|
543
|
+
# 2) ev項目を基準化
|
544
|
+
# 3) evがなければ全データ1をセット
|
545
|
+
# 4) 基準化された値をer倍する
|
546
|
+
def mkEdge(key,ef1,ef2,el,ec,ed,ev,er,ei,mapFile,oFile)
|
547
|
+
# mcal cat用のlabel項目の作成
|
548
|
+
label=[]
|
549
|
+
if el
|
550
|
+
el["names"].each{|name|
|
551
|
+
label << "$s{#{name}}"
|
552
|
+
}
|
553
|
+
end
|
554
|
+
|
555
|
+
evcdStr=""
|
556
|
+
evcdStr << ",#{ev}:ev" if ev
|
557
|
+
evcdStr << ",#{ec}:ec" if ec
|
558
|
+
evcdStr << ",#{ed}:ed" if ed
|
559
|
+
f=""
|
560
|
+
if el
|
561
|
+
f << "mcal c='cat(\"_\",#{label.join(',')})' a=##label i=#{ei} |"
|
562
|
+
else
|
563
|
+
f << "msetstr v= a=##label i=#{ei} |"
|
564
|
+
end
|
565
|
+
f << "mcut f=#{key}:key,#{ef1}:nam1,#{ef2}:nam2,##label:el#{evcdStr} |"
|
566
|
+
f << "msetstr v=1 a=ev |" unless ev
|
567
|
+
f << "mnullto f=key v=##NULL## |"
|
568
|
+
f << "mjoin k=key K=nam m=#{mapFile} f=num:keyNum |"
|
569
|
+
f << "mjoin k=nam1 K=nam m=#{mapFile} f=num:num1,leaf:leaf1 |"
|
570
|
+
f << "mjoin k=nam2 K=nam m=#{mapFile} f=num:num2,leaf:leaf2 |"
|
571
|
+
f << "mnormalize f=ev:ev2 c=range |"
|
572
|
+
f << "mcal c='${ev2}*(#{er}-1)+1' a=evv |"
|
573
|
+
f << "mcut f=key,nam1,nam2,keyNum,num1,num2,el,ev,evv,leaf1,leaf2 o=#{oFile}"
|
574
|
+
system(f)
|
575
|
+
end
|
576
|
+
|
577
|
+
#########################################
|
578
|
+
# dot用のnodeデータをcluster別に作成する
|
579
|
+
def dotNode(iFile,nw,type,clusterLabel,oPath)
|
580
|
+
# system "cat #{iFile}"
|
581
|
+
# key,nam,keyNum%0,num,nl,nv,nvv,nc,leaf,nvKey,ncKey
|
582
|
+
# ##NULL##,j,0,15,j_A,0.09090909091,1,FF0000,1,,
|
583
|
+
# ##NULL##,i,0,14,i_A,0.09090909091,1,FF0000,1,,
|
584
|
+
# #1_1,a,2,6,a_A,0.3636363636,1.857142857,FF0000,1,0.7272727273,
|
585
|
+
# #1_1,b,2,7,b_B,0.3636363636,1.857142857,00FF00,1,0.7272727273,
|
586
|
+
# #1_1,d,2,9,d_B,0.3636363636,1.857142857,00FF00,1,0.7272727273,
|
587
|
+
# #1_1,e,2,10,e_C,0.4545454545,2.142857143,0000FF,1,0.7272727273,
|
588
|
+
# #1_2,c,3,8,c_A,0.2727272727,1.571428571,FF0000,1,0.2727272727,
|
589
|
+
# #1_2,f,3,11,f_A,0.1818181818,1.285714286,FF0000,1,0.2727272727,
|
590
|
+
# #1_3,g,4,12,g_B,0.1818181818,1.285714286,00FF00,1,,
|
591
|
+
# #1_3,h,4,13,h_C,0.1818181818,1.285714286,0000FF,1,,
|
592
|
+
# #2_1,#1_2,5,3,#1_2_,0.2727272727,1.571428571,,,,
|
593
|
+
# #2_1,#1_1,5,2,#1_1_,0.7272727273,3,,,,
|
594
|
+
iCSV=MCMD::Mcsvin.new("k=keyNum i=#{iFile}")
|
595
|
+
block=""
|
596
|
+
iCSV.each{|flds,top,bot|
|
597
|
+
nam=flds["nam"]
|
598
|
+
nl =flds["nl"]
|
599
|
+
nv =flds["nv"]
|
600
|
+
nvv=flds["nvv"]
|
601
|
+
nc =flds["nc"]
|
602
|
+
leaf=flds["leaf"]
|
603
|
+
|
604
|
+
prefix="n"
|
605
|
+
prefix="cluster" unless leaf
|
606
|
+
nStr ="#{prefix}_#{flds["num"]}"
|
607
|
+
attrStr=""
|
608
|
+
|
609
|
+
unless prefix=="cluster"
|
610
|
+
# node label
|
611
|
+
# labelが#で始まる場合は、clusterLabelが指定されていない限りlabelを表示しない
|
612
|
+
if nl[0]!="#" or clusterLabel
|
613
|
+
attrStr << "label=\"#{nl}\" "
|
614
|
+
else
|
615
|
+
attrStr << "label=\"\" "
|
616
|
+
end
|
617
|
+
|
618
|
+
# node shape
|
619
|
+
if nvv
|
620
|
+
nRatioNorm=nvv.to_f
|
621
|
+
attrStr << "height=#{0.5*nRatioNorm} width=#{0.75*nRatioNorm} "
|
622
|
+
end
|
623
|
+
|
624
|
+
# node color
|
625
|
+
if nc
|
626
|
+
attrStr << "color=\"##{nc}\" "
|
627
|
+
end
|
628
|
+
|
629
|
+
# node linewidth
|
630
|
+
if nw
|
631
|
+
attrStr << "style=\"setlinewidth(#{nw})\" "
|
632
|
+
end
|
633
|
+
end
|
634
|
+
block << "#{nStr} [#{attrStr}]\n"
|
635
|
+
|
636
|
+
if bot
|
637
|
+
keyNum=flds["keyNum"]
|
638
|
+
key=flds["key"]
|
639
|
+
nlKey=flds["nlKey"]
|
640
|
+
nvKey=flds["nvKey"]
|
641
|
+
ncKey=flds["ncKey"]
|
642
|
+
File.open("#{oPath}/c_#{keyNum}","w"){|fpw|
|
643
|
+
fpw.write(block)
|
644
|
+
}
|
645
|
+
# クラスタのラベルや色も出力しておく
|
646
|
+
attrStr=""
|
647
|
+
attrStr << "label=\"#{nlKey}\"\n"
|
648
|
+
|
649
|
+
# node color
|
650
|
+
if ncKey
|
651
|
+
attrStr << "color=\"##{ncKey}\"\n"
|
652
|
+
end
|
653
|
+
# node linewidth
|
654
|
+
if nw and ncKey
|
655
|
+
if ncKey
|
656
|
+
attrStr << "style=\"setlinewidth(#{nw})\"\n"
|
657
|
+
end
|
658
|
+
end
|
659
|
+
File.open("#{oPath}/L_#{keyNum}","w"){|fpw|
|
660
|
+
fpw.write(attrStr)
|
661
|
+
}
|
662
|
+
block=""
|
663
|
+
end
|
664
|
+
}
|
665
|
+
end
|
666
|
+
|
667
|
+
#########################################
|
668
|
+
# dot用のedgeデータをcluster別に作成する
|
669
|
+
def dotEdge(iFile,oPath)
|
670
|
+
# key,nam1,nam2%0,keyNum,num1,num2,ev,evv
|
671
|
+
# #2_1,#1_1,#1_2,4,1,2,0.2727272727,20
|
672
|
+
# #1_1,a,b,1,5,6,0.1818181818,0
|
673
|
+
iCSV=MCMD::Mcsvin.new("k=keyNum i=#{iFile}")
|
674
|
+
block=""
|
675
|
+
iCSV.each{|flds,top,bot|
|
676
|
+
num1=flds["num1"]
|
677
|
+
num2=flds["num2"]
|
678
|
+
el=flds["el"]
|
679
|
+
ev=flds["ev"]
|
680
|
+
ec=flds["ec"]
|
681
|
+
ed=flds["ed"]
|
682
|
+
evv=flds["evv"]
|
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(#{evv})\" " if evv
|
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,nr,nc,ni,ef1,ef2,ei,xxmap,xxnode)
|
752
|
+
mkEdge(key,ef1,ef2,el,ec,ed,ev,er,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,noiso,oFile)
|
806
|
+
|
807
|
+
# 終了メッセージ
|
808
|
+
MCMD::endLog(args.cmdline)
|
809
|
+
|