summaryrefslogtreecommitdiff
path: root/index.js
diff options
context:
space:
mode:
authorschneefux <schneefux+commit@schneefux.xyz>2016-03-31 16:09:45 +0200
committerschneefux <schneefux+commit@schneefux.xyz>2016-03-31 16:09:45 +0200
commita24b803cb9065021f3ff4dfbd780606d8b072bf0 (patch)
tree152d90b05dba438e823f9f234032ed6dda99b881 /index.js
parent5f954f48f8ff55c339faed709ebd26b0984abfb2 (diff)
downloadvortrag-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.js366
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);