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/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
|
+
|