diff options
| author | schneefux <schneefux+commit@schneefux.xyz> | 2016-03-31 16:09:45 +0200 |
|---|---|---|
| committer | schneefux <schneefux+commit@schneefux.xyz> | 2016-03-31 16:09:45 +0200 |
| commit | a24b803cb9065021f3ff4dfbd780606d8b072bf0 (patch) | |
| tree | 152d90b05dba438e823f9f234032ed6dda99b881 /index.js | |
| parent | 5f954f48f8ff55c339faed709ebd26b0984abfb2 (diff) | |
| download | vortrag-knn-a24b803cb9065021f3ff4dfbd780606d8b072bf0.tar.gz vortrag-knn-a24b803cb9065021f3ff4dfbd780606d8b072bf0.zip | |
further abstract weight vis; move dependencies; highlight hovers
Diffstat (limited to 'index.js')
| -rw-r--r-- | index.js | 366 |
1 files changed, 0 insertions, 366 deletions
diff --git a/index.js b/index.js deleted file mode 100644 index e58ddd7..0000000 --- a/index.js +++ /dev/null @@ -1,366 +0,0 @@ -/* custom d3 widgets */ - -// slider -function makeSlider(labelName, x, y, scale, cb) { - var brush = d3.svg.brush() - .x(scale) - .extent([0, 0]) - .on("brush", brushed); - - var label = svg.append("text") - .attr("x", x-5) - .attr("y", y) - .text(labelName); - - var brushg = svg.append("g") - .attr("transform", "translate(" + x + "," + (y+10) + ")"); - - brushg.append("g") - .attr("class", "x axis") - .call(d3.svg.axis() - .scale(scale) - .ticks(5) - .tickSize(1) - .tickFormat(function(d) { return Math.floor(d*100) + "%"; }) - .tickPadding(10) - .orient("bottom")); - - var slider = brushg.append("g") - .attr("class", "slider") - .call(brush); - - var handle = slider.append("circle") - .attr("r", 5) - .attr("cx", 0) - .attr("cy", 0) - .attr("stroke", "#000") - .attr("fill", "#DDD"); - - slider.call(brush); - - function brushed() { - var value = brush.extent()[0]; - - if (d3.event.sourceEvent) { // not a programmatic event - value = scale.invert(d3.mouse(this)[0]); - brush.extent([value, value]); - } - - handle.attr("cx", scale(value)); - cb(value); - } -} - - -/* network construction */ - -var Network = (function() { - function Network(layout) { - this.layout = layout; - } - - Network.prototype.init = function() { - this._createNodes(); - this._createLinks(); - }; - - Network.prototype.resize = function(env) { - var largestLayerSize = 0; - for (layer=0; layer<this.layout.net.layers; layer++) { - if (this.layout.net[layer].size > largestLayerSize) largestLayerSize = this.layout.net[layer].size; - } - this.responsiveRadius = d3.min([env.width, env.height]) / d3.max([this.layout.net.layers, largestLayerSize]); - this._updateNodes(env); - }; - - Network.prototype._createNodes = function() { - // create layers - this.nodes = []; - for (layer=0; layer<this.layout.net.layers; layer++) { - for (node=0; node<this.layout.net[layer].size; node++) { - this.nodes.push({ - id: layer.toString() + "_" + node.toString(), - fixed: true - }); - } - } - }; - - Network.prototype._createLinks = function() { - this.links = []; - var nodesMap = d3.map(); - this.nodes.forEach(function (n) { - return nodesMap.set(n.id, n); - }); - // create links between adjacent layers - for (layer=0; layer<this.layout.net.layers-1; layer++) { // for every layer except the last - for (src=0; src<this.layout.net[layer].size; src++) { // get all nodes - if (this.layout.net[layer].isBias) { - this.links.push({ // in case of a bias layer, connect 1:1 - source: nodesMap.get(layer.toString() + "_" + src.toString()), - target: nodesMap.get((layer+1).toString() + "_" + src.toString()), - weight: 1 - }); - } else { // normal layer - for (tar=0; tar<this.layout.net[layer+1].size; tar++) { // get all nodes of the next layer - this.links.push({ // connect both nodes - source: nodesMap.get(layer.toString() + "_" + src.toString()), - target: nodesMap.get((layer+1).toString() + "_" + tar.toString()), - weight: 1 - }); - } - } - } - } - }; - - Network.prototype._updateNodes = function(env) { - biasLayers = 0; - for (layer=0; layer<this.layout.net.layers; layer++) { - if (this.layout.net[layer].isBias) biasLayers++; - } - var cnt = 0; - for (layer=0; layer<this.layout.net.layers; layer++) { - for (node=0; node<this.layout.net[layer].size; node++) { - // dynamic ("responsive") attributes for all window sizes - if (this.layout.net[layer].isBias) { - this.nodes[cnt].x = (layer - biasLayers + 1.25) * (env.width / (this.layout.net.layers - biasLayers)); - this.nodes[cnt].y = (node + 0.25) * (env.height / this.layout.net[layer].size); - this.nodes[cnt].r = this.responsiveRadius * 0.2; - } else { - this.nodes[cnt].x = (layer - biasLayers + 0.5) * (env.width / (this.layout.net.layers - biasLayers)); - this.nodes[cnt].y = (node + 0.5) * (env.height / this.layout.net[layer].size); - this.nodes[cnt].r = this.responsiveRadius * 0.3; - } - cnt++; - } - } - }; - - Network.prototype.updateWeights = function(weights, epochLayout) { - var cnt = 0; - for (layer=0; layer<weights.length; layer++) { - for (layer2=0; layer2<weights[layer].length; layer2++) { - for (node=0; node<weights[layer][layer2].length; node++) { - // scaled = (x - min) / (max - min) - var scaled = (weights[layer][layer2][node] - epochLayout.min) / (epochLayout.max - epochLayout.min); - this.links[cnt++].weight = scaled; - } - } - } - }; - - return Network; -})(); - - -/* data handling */ - -var Loader = (function() { - function Loader() { - } - - Loader.prototype.load = function(url, callback) { - var self = this; - d3.json(url) - .get(function(e, json) { - if (e) console.log(e); - self._parse(json); - }); - this._finished = callback; - }; - - Loader.prototype._parse = function(json) { - // json format: - // json. - // [batch][epoch] [[sourceIndex x targetIndex]] (int) - // careful - root and first level nodes are objects and have no '.length' - - var layout = {}; - // layout format: - // layout. - // net.layers (int) - // net.[net.layers]. - // isBias (bool) - // size (int) - // layers.[batch][epoch]. - // min (int) - // max (int) - // data. - // batches (int) - // epochs (int) - layout.data = {}; - layout.data.batches = Object.keys(json).length; - layout.data.epochs = Object.keys(json[0]).length; - layout.net = {}; - // network structure - layout.net.layers = json[0][0].length; - for (layer=0; layer<layout.net.layers; layer++) { - layerObj = {}; - if (json[0][0][layer].length == 1) { // bias - layerObj.isBias = true; - layerObj.size = json[0][0][0][layer].length; // workaround - Matrix should be rotatet serverside - } else { - layerObj.isBias = false; - layerObj.size = json[0][0][layer].length; - } - layout.net[layer] = layerObj; - } - layout.net[layout.net.layers] = {'isBias': false, 'size': json[0][0][layout.net.layers-1][0].length}; - layout.net.layers += 1; // output layer - // layer properties - layout.layers = {}; - for (batch=0; batch<layout.data.batches; batch++) { - layout.layers[batch] = {}; - for (epoch=0; epoch<layout.data.epochs; epoch++) { - layout.layers[batch][epoch] = {}; - layout.layers[batch][epoch].max = 0; - layout.layers[batch][epoch].min = Infinity; - for (layer=0; layer<json[batch][epoch].length; layer++) { - var layerMin = d3.min(json[batch][epoch][layer]); - var layerMax = d3.max(json[batch][epoch][layer]); - if (layerMin < layout.layers[batch][epoch].min) layout.layers[batch][epoch].min = layerMin; - if (layerMax > layout.layers[batch][epoch].max) layout.layers[batch][epoch].max = layerMax; - } - } - } - console.log(layout); // DEBUG - - if (this._finished) this._finished(layout, json); - }; - - return Loader; -})(); - -var Animator = (function() { - function Animator(layout, time, step) { - this.layout = layout; - this.step = step; - this.batch = this.epoch = 0; - this.frameDuration = time / (this.layout.data.batches * this.layout.data.epochs / this.step); - console.log("frame duration:" + this.frameDuration); // DEBUG - } - - Animator.prototype.start = function(callback) { - var self = this; - wrapper = function() { - callback(self.batch, self.epoch, self.frameDuration); - self.animate(); - }; - this.pid = setInterval(wrapper, this.frameDuration); - }; - - Animator.prototype.animate = function() { - this.epoch += this.step; - if (this.epoch >= this.layout.data.epochs) { - this.epoch = 0; - if (++this.batch>= this.layout.data.batches) { - this.batch = 0; - clearInterval(this.pid); // suicide - console.log("finished"); - } - } - }; - - return Animator; -})(); - -var Visualizer = (function() { - function Visualizer(svg) { - this.loader = new Loader(); - this.svg = svg; - } - - Visualizer.prototype.start = function(url, animationTime, resolution) { - // animationTime in seconds per frame - // resolution in epochs per frame - var self = this; - this.animationTime = animationTime; - this.resolution = resolution; - function wrapper(layout, data) { - self.layout = layout; - self.data = data; - self._setup(); - } - this.loader.load("data/log.json", wrapper); - }; - - Visualizer.prototype._setup = function() { - console.log("setup"); // DEBUG - var self = this; - // create empty elements and determine the visualisation's size - this.svg - .attr("width", "100%") - .attr("height", "100%"); - var width = parseInt(this.svg.style("width")) || 800, - height = parseInt(this.svg.style("height")) || 600; - - /*var slideScaler = d3.scale.linear() - .domain([0, 180]) - .range([0, 200]) - .clamp(true); - function slid(val) { - console.log(val); - } - makeSlider("Test", 10, 20, slideScaler, slid);*/ - - this.network = new Network(this.layout); - this.network.init(); - this.network.resize({"width": width, "height": height}); - this.network.updateWeights(this.data[0][0], this.layout.layers[0][0]); - - function resized() { - width = parseInt(self.svg.style("width")) || 800; - height = parseInt(self.svg.style("height")) || 600; - - self.network.resize({"width": width, "height": height}); - - node - .attr("cx", function(d) { return d.x; }) - .attr("cy", function(d) { return d.y; }) - .attr("r", function(d) { return d.r; }); - link - .attr("x1", function(d) { return d.source.x; }) - .attr("y1", function(d) { return d.source.y; }) - .attr("x2", function(d) { return d.target.x; }) - .attr("y2", function(d) { return d.target.y; }); - } - window.addEventListener("resize", resized, true); - - var link = this.svg.selectAll(".link") - .data(this.network.links) - .enter().append("line") - .attr("class", "link") - .style("stroke", "grey") - .style("stroke-width", function(d) { return d.weight * 10; }) - .attr("x1", function(d) { return d.source.x; }) - .attr("y1", function(d) { return d.source.y; }) - .attr("x2", function(d) { return d.target.x; }) - .attr("y2", function(d) { return d.target.y; }); - var node = this.svg.selectAll(".node") - .data(this.network.nodes) - .enter().append("circle") - .attr("class", "node") - .attr("cx", function(d) { return d.x; }) - .attr("cy", function(d) { return d.y; }) - .attr("r", function(d) { return d.r; }); - - this.animator = new Animator(this.layout, this.animationTime * 1000, this.resolution); - this.animator.start(function(batch, epoch, duration) { - self.network.updateWeights(self.data[batch][epoch], self.layout.layers[batch][epoch]); - - // 10% extra time per frame for the code execution - duration = duration / 1.1; - link - .transition() - .duration(duration) - .style("stroke-width", function(d) { return d.weight * 10; }); - }); - }; - - return Visualizer; -})(); - -var svg = d3.select("#visContainer").append("svg"); -var visualizer = new Visualizer(svg); -visualizer.start("data/log.json", 30, 10); |
