Skip to content

Instantly share code, notes, and snippets.

@tgk
Last active December 18, 2015 07:09
Show Gist options
  • Save tgk/5744943 to your computer and use it in GitHub Desktop.
Save tgk/5744943 to your computer and use it in GitHub Desktop.
String histogram

This graphic illustrates string frequency over a period of time. Press left and right arrow keys to cycle through the data. A hash code adapted from Java is used to determine the color of the strings and the bars. log-scales are used to allow for visibility of small sample sizes at early time.

<!DOCTYPE html>
<meta charset="utf-8">
<style>
text {
font: bold 48px monospace;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
hashCode = function(str){
var hash = 0;
if (str.length == 0) return hash;
for (i = 0; i < str.length; i++) {
char = str.charCodeAt(i);
hash = ((hash<<5)-hash)+char;
hash = hash & hash; // Convert to 32bit integer
}
return hash;
}
colorfn = function(d) { return d3.hsl(hashCode(d.word) % 360, 0.5, 0.5) };
var width = 960,
height = 500;
xlog = d3.scale.log();
xlog.domain([1, 100]);
xlog.range([200, width - 20]);
x = function(x) { if (x == 0) { return 200; } else { return 200 + xlog(x); } };
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(32, 132)");
function update(data)
{
// TEXT
var text = svg.selectAll("text")
.data(data, function(d) {return d.word;});
// update
text
.transition()
.duration(750)
.attr("y", function(d, i) { return i * 45; })
.style("fill-opacity", 1);
// enter
text.enter().append("text")
.style("fill-opacity", 1e-6)
.style("fill", colorfn)
.attr("y", height)
.attr("x", 32)
.text(function(d) { return d.word; })
.transition()
.duration(750)
.style("fill-opacity", 1)
.attr("y", function(d, i) { return i * 45; });
// exit
text.exit()
.transition()
.duration(750)
.style("fill-opacity", 1e-6)
.attr("y", height)
.remove();
// LINES
var line = svg.selectAll(".bar")
.data(data, function(d) {return d.word; });
// update
line
.transition()
.duration(750)
.attr("x2", function(d) { return x(d.count) })
.attr("y1", function(d, i) { return i * 45 - 15; })
.attr("y2", function(d, i) { return i * 45 - 15; })
.style("stroke-opacity", "1");
// enter
line.enter().append("line")
.attr("class", "bar")
.attr("y1", height)
.attr("y2", height)
.attr("x1", x(0))
.attr("x2", function(d) { return x(d.count); })
.style("stroke-width", "10")
.style("stroke", colorfn)
.style("stroke-opacity", 1e-6)
.transition()
.duration(750)
.attr("y1", function(d, i) { return i * 45 - 15; })
.attr("y2", function(d, i) { return i * 45 - 15; })
.style("stroke-opacity", 1);
// exit
line.exit()
.transition()
.duration(750)
.attr("y1", height)
.attr("y2", height)
.style("stroke-opacity", "0");
// TICKS
var tick = svg.selectAll(".tick")
.data(xlog.ticks());
// enter
tick.enter().append("line")
.attr("class", "tick")
.attr("x1", x)
.attr("x2", x)
.attr("y1", -100)
.attr("y2", height)
.style("stroke-width", 3)
.style("stroke", "rgb(255,255,255)");
}
var test = [[{word: "hello", count: 10},
{word: "world", count: 5}],
[{word: "world", count: 25},
{word: "hello", count: 8}],
[{word: "world", count: 6}],
[{word: "hi" , count: 2}]];
var counter = 0;
window.focus();
d3.select(window).on("keydown", function() {
switch (d3.event.keyCode) {
case 37: counter--; break;
case 39: counter++; break;
}
counter = ((counter % test.length) + test.length) % test.length;
update(test[counter]);
});
update(test[counter]);
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment