comparison plotForce.py @ 0:4324d3f925fe draft

Uploaded
author bornea
date Wed, 18 Oct 2017 15:34:12 -0400
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4324d3f925fe
1 import sys
2 def readTab(infile): # read in txt file
3 with open(infile, 'r') as input_file:
4 # read in tab-delim text
5 output = []
6 for input_line in input_file:
7 input_line = input_line.strip()
8 temp = input_line.split('\t')
9 output.append(temp)
10 return output
11 def network2JSON(nodes_att_file, edge_file):
12 nodes = readTab(nodes_att_file)
13 edges = readTab(edge_file)
14
15 start = """{"nodes": ["""
16 node_numbers = {}
17 cnt=0
18 for i in nodes[1:]:
19 node_numbers[i[0]] = cnt
20 cnt+=1
21 start = start + '{"id":'+'"'+i[0]+'", "size":'+str(float(i[2])*1)+', "score":'+i[1]+',"type":"circle"},'
22 start = start[:-1]
23 start = start+"""], "links": ["""
24 for i in edges:
25 start = start + """{"source":"""+str(node_numbers[i[0]])+""","target":"""+str(node_numbers[i[1]])+"""},"""
26 start = start[:-1]
27 start = start + """]}"""
28 return start
29
30
31 output = """<!DOCTYPE html>
32 <meta charset="utf-8">
33 <style>
34 body {
35 overflow:hidden;
36 margin:0;
37 }
38
39 text {
40 font-family: sans-serif;
41 pointer-events: none;
42 }
43
44 </style>
45 <body>
46 <script src="http://d3js.org/d3.v3.min.js"></script>
47 <script>
48 jsondata='"""
49
50 output = output + network2JSON(sys.argv[1],sys.argv[2]) + "'\n"
51
52 output = output + """var w = window.innerWidth;
53 var h = window.innerHeight;
54
55 var keyc = true, keys = true, keyt = true, keyr = true, keyx = true, keyd = true, keyl = true, keym = true, keyh = true, key1 = true, key2 = true, key3 = true, key0 = true
56
57 var focus_node = null, highlight_node = null;
58
59 var text_center = false;
60 var outline = false;
61
62 var min_score = 0;
63 var max_score = 1;
64
65 var color = d3.scale.category20()
66 .range(["green", "orange", "red","black","steelblue","purple","gray","blue","yellow","lime"]);
67
68 var highlight_color = "red";
69 var highlight_trans = 0.1;
70
71 var size = d3.scale.pow().exponent(1)
72 .domain([1,100])
73 .range([8,24]);
74
75 var force = d3.layout.force()
76 .linkDistance(60)
77 .charge(-500)
78 .size([w,h]);
79
80 var default_node_color = "#000";
81 //var default_node_color = "rgb(3,190,100)";
82 var default_link_color = "#888";
83 var nominal_base_node_size = 8;
84 var nominal_text_size = 10;
85 var max_text_size = 24;
86 var nominal_stroke = 1.5;
87 var max_stroke = 4.5;
88 var max_base_node_size = 36;
89 var min_zoom = 0.1;
90 var max_zoom = 7;
91 var svg = d3.select("body").append("svg");
92 var zoom = d3.behavior.zoom().scaleExtent([min_zoom,max_zoom])
93 var g = svg.append("g");
94 svg.style("cursor","move");
95
96 var data = JSON.parse(jsondata);
97 function plot_graph(graph) {
98
99 var linkedByIndex = {};
100 graph.links.forEach(function(d) {
101 linkedByIndex[d.source + "," + d.target] = true;
102 });
103
104 function isConnected(a, b) {
105 return linkedByIndex[a.index + "," + b.index] || linkedByIndex[b.index + "," + a.index] || a.index == b.index;
106 }
107
108 function hasConnections(a) {
109 for (var property in linkedByIndex) {
110 s = property.split(",");
111 if ((s[0] == a.index || s[1] == a.index) && linkedByIndex[property]) return true;
112 }
113 return false;
114 }
115
116 force
117 .nodes(graph.nodes)
118 .links(graph.links)
119 .start();
120
121 var link = g.selectAll(".link")
122 .data(graph.links)
123 .enter().append("line")
124 .attr("class", "link")
125 .style("stroke-width",nominal_stroke)
126 .style("stroke", function(d) {
127 if (isNumber(d.score) && d.score>=0) return color(d.score);
128 else return default_link_color; })
129
130
131 var node = g.selectAll(".node")
132 .data(graph.nodes)
133 .enter().append("g")
134 .attr("class", "node")
135
136 .call(force.drag)
137
138
139 node.on("dblclick.zoom", function(d) { d3.event.stopPropagation();
140 var dcx = (window.innerWidth/2-d.x*zoom.scale());
141 var dcy = (window.innerHeight/2-d.y*zoom.scale());
142 zoom.translate([dcx,dcy]);
143 g.attr("transform", "translate("+ dcx + "," + dcy + ")scale(" + zoom.scale() + ")");
144
145
146 });
147
148
149
150
151 var tocolor = "fill";
152 var towhite = "stroke";
153 if (outline) {
154 tocolor = "stroke"
155 towhite = "fill"
156 }
157
158
159
160 var circle = node.append("path")
161
162
163 .attr("d", d3.svg.symbol()
164 .size(function(d) { return Math.PI*Math.pow(size(d.size)||nominal_base_node_size,2); })
165 .type(function(d) { return d.type; }))
166
167 .style(tocolor, function(d) {
168 if (isNumber(d.score) && d.score>=0) return color(d.score);
169 else return default_node_color; })
170 //.attr("r", function(d) { return size(d.size)||nominal_base_node_size; })
171 .style("stroke-width", nominal_stroke)
172 .style(towhite, "white");
173
174
175 var text = g.selectAll(".text")
176 .data(graph.nodes)
177 .enter().append("text")
178 .attr("dy", ".35em")
179 .style("font-size", nominal_text_size + "px")
180
181 if (text_center)
182 text.text(function(d) { return d.id; })
183 .style("text-anchor", "middle");
184 else
185 text.attr("dx", function(d) {return (size(d.size)||nominal_base_node_size);})
186 .text(function(d) { return '\u2002'+d.id; });
187
188 node.on("mouseover", function(d) {
189 set_highlight(d);
190 })
191 .on("mousedown", function(d) { d3.event.stopPropagation();
192 focus_node = d;
193 set_focus(d)
194 if (highlight_node === null) set_highlight(d)
195
196 } ).on("mouseout", function(d) {
197 exit_highlight();
198
199 } );
200
201 d3.select(window).on("mouseup",
202 function() {
203 if (focus_node!==null)
204 {
205 focus_node = null;
206 if (highlight_trans<1)
207 {
208
209 circle.style("opacity", 1);
210 text.style("opacity", 1);
211 link.style("opacity", 1);
212 }
213 }
214
215 if (highlight_node === null) exit_highlight();
216 });
217
218 function exit_highlight()
219 {
220 highlight_node = null;
221 if (focus_node===null)
222 {
223 svg.style("cursor","move");
224 if (highlight_color!="white")
225 {
226 circle.style(towhite, "white");
227 text.style("font-weight", "normal");
228 link.style("stroke", function(o) {return (isNumber(o.score) && o.score>=0)?color(o.score):default_link_color});
229 }
230
231 }
232 }
233
234 function set_focus(d)
235 {
236 if (highlight_trans<1) {
237 circle.style("opacity", function(o) {
238 return isConnected(d, o) ? 1 : highlight_trans;
239 });
240
241 text.style("opacity", function(o) {
242 return isConnected(d, o) ? 1 : highlight_trans;
243 });
244
245 link.style("opacity", function(o) {
246 return o.source.index == d.index || o.target.index == d.index ? 1 : highlight_trans;
247 });
248 }
249 }
250
251
252 function set_highlight(d)
253 {
254 svg.style("cursor","pointer");
255 if (focus_node!==null) d = focus_node;
256 highlight_node = d;
257
258 if (highlight_color!="white")
259 {
260 circle.style(towhite, function(o) {
261 return isConnected(d, o) ? highlight_color : "white";});
262 text.style("font-weight", function(o) {
263 return isConnected(d, o) ? "bold" : "normal";});
264 link.style("stroke", function(o) {
265 return o.source.index == d.index || o.target.index == d.index ? highlight_color : ((isNumber(o.score) && o.score>=0)?color(o.score):default_link_color);
266
267 });
268 }
269 }
270
271
272 zoom.on("zoom", function() {
273
274 var stroke = nominal_stroke;
275 if (nominal_stroke*zoom.scale()>max_stroke) stroke = max_stroke/zoom.scale();
276 link.style("stroke-width",stroke);
277 circle.style("stroke-width",stroke);
278
279 var base_radius = nominal_base_node_size;
280 if (nominal_base_node_size*zoom.scale()>max_base_node_size) base_radius = max_base_node_size/zoom.scale();
281 circle.attr("d", d3.svg.symbol()
282 .size(function(d) { return Math.PI*Math.pow(size(d.size)*base_radius/nominal_base_node_size||base_radius,2); })
283 .type(function(d) { return d.type; }))
284
285 //circle.attr("r", function(d) { return (size(d.size)*base_radius/nominal_base_node_size||base_radius); })
286 if (!text_center) text.attr("dx", function(d) { return (size(d.size)*base_radius/nominal_base_node_size||base_radius); });
287
288 var text_size = nominal_text_size;
289 if (nominal_text_size*zoom.scale()>max_text_size) text_size = max_text_size/zoom.scale();
290 text.style("font-size",text_size + "px");
291
292 g.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
293 });
294
295 svg.call(zoom);
296
297 resize();
298 //window.focus();
299 d3.select(window).on("resize", resize).on("keydown", keydown);
300
301 force.on("tick", function() {
302
303 node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
304 text.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
305
306 link.attr("x1", function(d) { return d.source.x; })
307 .attr("y1", function(d) { return d.source.y; })
308 .attr("x2", function(d) { return d.target.x; })
309 .attr("y2", function(d) { return d.target.y; });
310
311 node.attr("cx", function(d) { return d.x; })
312 .attr("cy", function(d) { return d.y; });
313 });
314
315 function resize() {
316 var width = window.innerWidth, height = window.innerHeight;
317 svg.attr("width", width).attr("height", height);
318
319 force.size([force.size()[0]+(width-w)/zoom.scale(),force.size()[1]+(height-h)/zoom.scale()]).resume();
320 w = width;
321 h = height;
322 }
323
324 function keydown() {
325 if (d3.event.keyCode==32) { force.stop();}
326 else if (d3.event.keyCode>=48 && d3.event.keyCode<=90 && !d3.event.ctrlKey && !d3.event.altKey && !d3.event.metaKey)
327 {
328 switch (String.fromCharCode(d3.event.keyCode)) {
329 case "C": keyc = !keyc; break;
330 case "S": keys = !keys; break;
331 case "T": keyt = !keyt; break;
332 case "R": keyr = !keyr; break;
333 case "X": keyx = !keyx; break;
334 case "D": keyd = !keyd; break;
335 case "L": keyl = !keyl; break;
336 case "M": keym = !keym; break;
337 case "H": keyh = !keyh; break;
338 case "1": key1 = !key1; break;
339 case "2": key2 = !key2; break;
340 case "3": key3 = !key3; break;
341 case "0": key0 = !key0; break;
342 }
343
344 link.style("display", function(d) {
345 var flag = vis_by_type(d.source.type)&&vis_by_type(d.target.type)&&vis_by_node_score(d.source.score)&&vis_by_node_score(d.target.score)&&vis_by_link_score(d.score);
346 linkedByIndex[d.source.index + "," + d.target.index] = flag;
347 return flag?"inline":"none";});
348 node.style("display", function(d) {
349 return (key0||hasConnections(d))&&vis_by_type(d.type)&&vis_by_node_score(d.score)?"inline":"none";});
350 text.style("display", function(d) {
351 return (key0||hasConnections(d))&&vis_by_type(d.type)&&vis_by_node_score(d.score)?"inline":"none";});
352
353 if (highlight_node !== null)
354 {
355 if ((key0||hasConnections(highlight_node))&&vis_by_type(highlight_node.type)&&vis_by_node_score(highlight_node.score)) {
356 if (focus_node!==null) set_focus(focus_node);
357 set_highlight(highlight_node);
358 }
359 else {exit_highlight();}
360 }
361
362 }
363 }
364
365 };
366
367 function vis_by_type(type)
368 {
369 switch (type) {
370 case "circle": return keyc;
371 case "circle": return keys;
372 case "triangle-up": return keyt;
373 case "diamond": return keyr;
374 case "cross": return keyx;
375 case "triangle-down": return keyd;
376 default: return true;
377 }
378 }
379 function vis_by_node_score(score)
380 {
381 if (isNumber(score))
382 {
383 if (score>=0.666) return keyh;
384 else if (score>=0.333) return keym;
385 else if (score>=0) return keyl;
386 }
387 return true;
388 }
389
390 function vis_by_link_score(score)
391 {
392 if (isNumber(score))
393 {
394 if (score>=0.666) return key3;
395 else if (score>=0.333) return key2;
396 else if (score>=0) return key1;
397 }
398 return true;
399 }
400
401 function isNumber(n) {
402 return !isNaN(parseFloat(n)) && isFinite(n);
403 }
404 plot_graph(data)
405
406 </script>"""
407
408 with open(sys.argv[3],"w") as x:
409 x.write(output)