Mercurial > repos > bornea > plot_edge_bundling
comparison plot_edge_bundling.py @ 1:7dc4b20f5974 draft default tip
Uploaded
| author | bornea |
|---|---|
| date | Wed, 18 Oct 2017 15:32:49 -0400 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 0:9b42fbe3faba | 1:7dc4b20f5974 |
|---|---|
| 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(node_attr_file,edge_file): | |
| 12 nodes = readTab(node_attr_file) | |
| 13 edges = readTab(edge_file) | |
| 14 | |
| 15 connections = {} | |
| 16 communities = {} | |
| 17 for i in nodes[1:]: | |
| 18 communities[i[0]] = i[1] | |
| 19 for i in nodes[1:]: | |
| 20 temp = [] | |
| 21 for j in edges: | |
| 22 if i[0] in j: | |
| 23 if i[0] != j[0]: | |
| 24 temp.append(str(communities[j[0]]) + "." + str(j[0])) | |
| 25 if i[0] != j[1]: | |
| 26 temp.append(str(communities[j[1]])+"."+str(j[1])) | |
| 27 connections[i[0]] = temp | |
| 28 json = "[" | |
| 29 for i in nodes[1:]: | |
| 30 json = json + '{"name":"' + i[1] + '.' + str(i[0]) + '" ,"imports":'+str(connections[i[0]])+'},' | |
| 31 json = json[:-1] | |
| 32 json = json + "]" | |
| 33 json = json.replace("'",'"') | |
| 34 return json | |
| 35 ############################################ | |
| 36 top = """<!DOCTYPE html> | |
| 37 <meta charset="utf-8"> | |
| 38 <style> | |
| 39 | |
| 40 .node { | |
| 41 font: 300 11px "Arial", Arial, Arial, Arial; | |
| 42 fill: #bbb; | |
| 43 } | |
| 44 | |
| 45 .node:hover { | |
| 46 fill: #d62728; | |
| 47 } | |
| 48 | |
| 49 .link { | |
| 50 stroke: steelblue; | |
| 51 stroke-opacity: .4; | |
| 52 fill: none; | |
| 53 pointer-events: none; | |
| 54 } | |
| 55 | |
| 56 .node:hover, | |
| 57 .node--source, | |
| 58 .node--target { | |
| 59 font-weight: 700; | |
| 60 } | |
| 61 | |
| 62 .node--source { | |
| 63 fill: black; | |
| 64 } | |
| 65 | |
| 66 .node--target { | |
| 67 fill: black; | |
| 68 } | |
| 69 | |
| 70 .link--source, | |
| 71 .link--target { | |
| 72 stroke-opacity: 1; | |
| 73 stroke-width: 2px; | |
| 74 } | |
| 75 | |
| 76 .link--source { | |
| 77 stroke: #d62728; | |
| 78 } | |
| 79 | |
| 80 .link--target { | |
| 81 stroke: #d62728; | |
| 82 } | |
| 83 | |
| 84 </style> | |
| 85 <body> | |
| 86 <script src="http://d3js.org/d3.v3.min.js"></script> | |
| 87 <script> | |
| 88 | |
| 89 var diameter = 960, | |
| 90 radius = diameter / 2, | |
| 91 innerRadius = radius - 120; | |
| 92 | |
| 93 var cluster = d3.layout.cluster() | |
| 94 .size([360, innerRadius]) | |
| 95 .sort(null) | |
| 96 .value(function(d) { return d.size; }); | |
| 97 | |
| 98 var bundle = d3.layout.bundle(); | |
| 99 | |
| 100 var line = d3.svg.line.radial() | |
| 101 .interpolate("bundle") | |
| 102 .tension(.85) | |
| 103 .radius(function(d) { return d.y; }) | |
| 104 .angle(function(d) { return d.x / 180 * Math.PI; }); | |
| 105 | |
| 106 var svg = d3.select("body").append("svg") | |
| 107 .attr("width", diameter) | |
| 108 .attr("height", diameter) | |
| 109 .append("g") | |
| 110 .attr("transform", "translate(" + radius + "," + radius + ")"); | |
| 111 | |
| 112 var link = svg.append("g").selectAll(".link"), | |
| 113 node = svg.append("g").selectAll(".node");""" | |
| 114 ############################################ | |
| 115 | |
| 116 middle = "\njsondata = '" + network2JSON(sys.argv[1],sys.argv[2]) + "'\n" | |
| 117 | |
| 118 ############################################ | |
| 119 bottom = """var data = JSON.parse(jsondata); | |
| 120 function bundle_edges(classes){ | |
| 121 | |
| 122 var nodes = cluster.nodes(packageHierarchy(classes)), | |
| 123 links = packageImports(nodes); | |
| 124 | |
| 125 link = link | |
| 126 .data(bundle(links)) | |
| 127 .enter().append("path") | |
| 128 .each(function(d) { d.source = d[0], d.target = d[d.length - 1]; }) | |
| 129 .attr("class", "link") | |
| 130 .attr("d", line); | |
| 131 | |
| 132 node = node | |
| 133 .data(nodes.filter(function(n) { return !n.children; })) | |
| 134 .enter().append("text") | |
| 135 .attr("class", "node") | |
| 136 .attr("dy", ".31em") | |
| 137 .attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + (d.y + 8) + ",0)" + (d.x < 180 ? "" : "rotate(180)"); }) | |
| 138 .style("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; }) | |
| 139 .text(function(d) { return d.key; }) | |
| 140 .on("mouseover", mouseovered) | |
| 141 .on("mouseout", mouseouted); | |
| 142 }; | |
| 143 | |
| 144 function mouseovered(d) { | |
| 145 node | |
| 146 .each(function(n) { n.target = n.source = false; }); | |
| 147 | |
| 148 link | |
| 149 .classed("link--target", function(l) { if (l.target === d) return l.source.source = true; }) | |
| 150 .classed("link--source", function(l) { if (l.source === d) return l.target.target = true; }) | |
| 151 .filter(function(l) { return l.target === d || l.source === d; }) | |
| 152 .each(function() { this.parentNode.appendChild(this); }); | |
| 153 | |
| 154 node | |
| 155 .classed("node--target", function(n) { return n.target; }) | |
| 156 .classed("node--source", function(n) { return n.source; }); | |
| 157 } | |
| 158 | |
| 159 function mouseouted(d) { | |
| 160 link | |
| 161 .classed("link--target", false) | |
| 162 .classed("link--source", false); | |
| 163 | |
| 164 node | |
| 165 .classed("node--target", false) | |
| 166 .classed("node--source", false); | |
| 167 } | |
| 168 | |
| 169 d3.select(self.frameElement).style("height", diameter + "px"); | |
| 170 | |
| 171 // Lazily construct the package hierarchy from class names. | |
| 172 function packageHierarchy(classes) { | |
| 173 var map = {}; | |
| 174 | |
| 175 function find(name, data) { | |
| 176 var node = map[name], i; | |
| 177 if (!node) { | |
| 178 node = map[name] = data || {name: name, children: []}; | |
| 179 if (name.length) { | |
| 180 node.parent = find(name.substring(0, i = name.lastIndexOf("."))); | |
| 181 node.parent.children.push(node); | |
| 182 node.key = name.substring(i + 1); | |
| 183 } | |
| 184 } | |
| 185 return node; | |
| 186 } | |
| 187 | |
| 188 classes.forEach(function(d) { | |
| 189 find(d.name, d); | |
| 190 }); | |
| 191 | |
| 192 return map[""]; | |
| 193 } | |
| 194 | |
| 195 // Return a list of imports for the given array of nodes. | |
| 196 function packageImports(nodes) { | |
| 197 var map = {}, | |
| 198 imports = []; | |
| 199 | |
| 200 // Compute a map from name to node. | |
| 201 nodes.forEach(function(d) { | |
| 202 map[d.name] = d; | |
| 203 }); | |
| 204 | |
| 205 // For each import, construct a link from the source to target node. | |
| 206 nodes.forEach(function(d) { | |
| 207 if (d.imports) d.imports.forEach(function(i) { | |
| 208 imports.push({source: map[d.name], target: map[i]}); | |
| 209 }); | |
| 210 }); | |
| 211 | |
| 212 return imports; | |
| 213 } | |
| 214 bundle_edges(data); | |
| 215 </script>""" | |
| 216 ############################################ | |
| 217 with open(sys.argv[3],"w") as x: | |
| 218 x.write(top + middle + bottom) |
