Mercurial > repos > bornea > plot_force
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) |