summaryrefslogtreecommitdiff
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
parent5f954f48f8ff55c339faed709ebd26b0984abfb2 (diff)
downloadvortrag-knn-a24b803cb9065021f3ff4dfbd780606d8b072bf0.tar.gz
vortrag-knn-a24b803cb9065021f3ff4dfbd780606d8b072bf0.zip
further abstract weight vis; move dependencies; highlight hovers
-rw-r--r--.gitmodules6
-rw-r--r--code/weightvis.js (renamed from index.js)188
m---------d30
-rw-r--r--dep/d3.js (renamed from d3.js)0
-rw-r--r--index.html23
5 files changed, 112 insertions, 105 deletions
diff --git a/.gitmodules b/.gitmodules
deleted file mode 100644
index bc54fcc..0000000
--- a/.gitmodules
+++ /dev/null
@@ -1,6 +0,0 @@
-[submodule "brain"]
- path = brain
- url = https://github.com/harthur/brain
-[submodule "d3"]
- path = d3
- url = https://github.com/mbostock/d3
diff --git a/index.js b/code/weightvis.js
index e58ddd7..7b4b5ef 100644
--- a/index.js
+++ b/code/weightvis.js
@@ -1,55 +1,28 @@
-/* custom d3 widgets */
+// material colors
+var
+ // 50 100 200 300 400 500
+ pDeepPurple = ['#ede7f6', '#d1c4e9', '#b39ddb', '#9575cd', '#7e57c2', '#673ab7',
+ // 600 700 800 900
+ '#5e35b1', '#512da8', '#4527a0', '#311b92',
+ // A100 A200 A400 A700
+ '#b388ff', '#7c4dff', '#651fff', '#6200ea'],
+ // A100 A200 A400 A700
+ pGreen = ['#b9f6ca', '#69f0ae', '#00e676', '#00c853'],
+ pDark = ['#000000', '#212121', '#303030', '#424242'],
+ pLight = ['#E0E0E0', '#F5F5F5', '#FAFAFA', '#FFFFFF'],
-// slider
-function makeSlider(labelName, x, y, scale, cb) {
- var brush = d3.svg.brush()
- .x(scale)
- .extent([0, 0])
- .on("brush", brushed);
+ primaryColor = [pDeepPurple[1], pDeepPurple[5], pDeepPurple[7]],
+ secondaryColor = pGreen[3],
+ themeColor = pLight,
- var label = svg.append("text")
- .attr("x", x-5)
- .attr("y", y)
- .text(labelName);
+ accentColor = secondaryColor,
+ bgColor = themeColor[3],
- 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);
- }
-}
+ linkColor = primaryColor[0],
+ linkHighlightColor = primaryColor[1],
+ nodeColor = primaryColor[1],
+ nodeHighlightColor = accentColor
+;
/* network construction */
@@ -224,21 +197,21 @@ var Loader = (function() {
}
}
}
- console.log(layout); // DEBUG
-
if (this._finished) this._finished(layout, json);
};
return Loader;
})();
+
+/* animation stepping */
+
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) {
@@ -265,51 +238,71 @@ var Animator = (function() {
return Animator;
})();
+
+/* main */
+
var Visualizer = (function() {
+ var _weightScaler = 10; // size of thickest line
+
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
+ Visualizer.prototype.getSteps = function() {
+ return this.layout.data.batches * this.layout.data.epochs;
+ };
+
+ Visualizer.prototype.load = function(url, callback) {
var self = this;
- this.animationTime = animationTime;
- this.resolution = resolution;
function wrapper(layout, data) {
self.layout = layout;
self.data = data;
self._setup();
+ callback();
}
this.loader.load("data/log.json", wrapper);
};
+ Visualizer.prototype.animate = function(animationTime, resolution) {
+ // animationTime in seconds per frame
+ // resolution in epochs per frame
+ var self = this;
+ this.domLink = this.svg.selectAll(".link");
+
+ this.animator = new Animator(this.layout, animationTime * 1000, resolution);
+ this.animator.start(function(batch, epoch){self.show(batch, epoch);});
+ };
+
+ Visualizer.prototype.showStep = function(step) {
+ var epoch = step % this.layout.data.epochs,
+ batch = Math.floor(step / this.layout.data.epochs);
+ this.show(batch, epoch);
+ };
+
+ Visualizer.prototype.show = function(batch, epoch, transitionDuration) {
+ this.network.updateWeights(this.data[batch][epoch], this.layout.layers[batch][epoch]);
+ if (transitionDuration) {
+ // 10% extra time per frame for the code execution
+ this.domLink
+ .transition()
+ .duration(transitionDuration / 1.1);
+ }
+ this.domLink.style("stroke-width", function(d) { return d.weight * _weightScaler; });
+ };
+
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() {
+ function reposition() {
width = parseInt(self.svg.style("width")) || 800;
height = parseInt(self.svg.style("height")) || 600;
@@ -325,42 +318,43 @@ var Visualizer = (function() {
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
}
- window.addEventListener("resize", resized, true);
+ window.addEventListener("resize", reposition, 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; });
+ .attr("class", function(d) { return "link source-" + d.source.id + " target-" + d.target.id; })
+ .style("stroke", linkColor)
+ .style("stroke-width", function(d) { return d.weight * _weightScaler; })
+ .on("mouseover", function(d) {
+ d3.select("#node-" + d.source.id).style("fill", nodeHighlightColor);
+ d3.select("#node-" + d.target.id).style("fill", nodeHighlightColor);
+ d3.select(this).style("stroke", linkHighlightColor);
+ })
+ .on("mouseout", function(d) {
+ d3.select("#node-" + d.source.id).style("fill", nodeColor);
+ d3.select("#node-" + d.target.id).style("fill", nodeColor);
+ d3.select(this).style("stroke", linkColor);
+ });
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]);
+ .attr("id", function(d) { return "node-" + d.id; })
+ .style("fill", nodeColor)
+ .on("mouseover", function(d) {
+ d3.selectAll(".source-" + d.id).style("stroke", linkHighlightColor);
+ d3.selectAll(".target-" + d.id).style("stroke", linkHighlightColor);
+ d3.select(this).style("fill", nodeHighlightColor);
+ })
+ .on("mouseout", function(d) {
+ d3.selectAll(".source-" + d.id).style("stroke", linkColor);
+ d3.selectAll(".target-" + d.id).style("stroke", linkColor);
+ d3.select(this).style("fill", nodeColor);
+ });
- // 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; });
- });
+ reposition();
};
return Visualizer;
})();
-
-var svg = d3.select("#visContainer").append("svg");
-var visualizer = new Visualizer(svg);
-visualizer.start("data/log.json", 30, 10);
diff --git a/d3 b/d3
deleted file mode 160000
-Subproject c36befc7361cd61538294048c387a8a407b65dd
diff --git a/d3.js b/dep/d3.js
index 2e70a83..2e70a83 100644
--- a/d3.js
+++ b/dep/d3.js
diff --git a/index.html b/index.html
index 73da26e..823982e 100644
--- a/index.html
+++ b/index.html
@@ -4,10 +4,29 @@
<meta charset="UTF-8">
<title></title>
<link rel="stylesheet" href="index.css">
+ <link rel="stylesheet" href="dep/material-icons.css">
+ <link rel="stylesheet" href="dep/material.deep_purple-blue.min.css">
</head>
<body>
+ <script src="dep/d3.js" type="text/javascript"></script>
+ <script src="dep/material.min.js"></script>
+
+ <script src="code/weightvis.js" type="text/javascript"></script>
+
<div id="visContainer" />
- <script src="d3.js" type="text/javascript"></script>
- <script src="index.js" type="text/javascript"></script>
+ <script type="text/javascript">
+ var svg = d3.select("#visContainer").append("svg");
+ svg
+ .attr("width", "100%")
+ .attr("height", "100%");
+ svg.append("rect")
+ .attr("width", "100%")
+ .attr("height", "100%")
+ .attr("fill", bgColor);
+ var visualizer = new Visualizer(svg);
+ visualizer.load("data/log.json", function(){
+ visualizer.animate(10, 20);
+ });
+ </script>
</body>
</html>