Skip to content

Instantly share code, notes, and snippets.

@saifuddin778
Last active June 30, 2016 03:55
Show Gist options
  • Save saifuddin778/5c0536d69886d10875e115b9720754d0 to your computer and use it in GitHub Desktop.
Save saifuddin778/5c0536d69886d10875e115b9720754d0 to your computer and use it in GitHub Desktop.
Color Clustering - I

This example achieves locality-sensitive color clustering by mimicing the behavior of Kohonen's Self Organizing Maps (a type of a neural network, commonly referred as SOM). With few modifications to Kohonen's idea, it is being demonstrated that how SOMs achieve a map of locality-sensitive soft data clustering, which is used in tasks like unsupervised (and supervised) modeling.

<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
text-align: center;
font-family: monospace;
}
.node {
opacity: 0.7;
}
.iter_container {
display: inline-block;
vertical-align: top;
margin-left: 19px;
background: mediumspringgreen;
padding: 8px;
border-radius: 3px;
width: 180px;
}
.item{
display: inline;
font-size: 12px;
}
</style>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script>
var n = 25;
var m = n*n;
var width = 500;
var height = 500;
function rb(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
function get_neighbors_params(node) {
var params = {};
var proximity = 1;
params.min_x = +node.attr("x") - proximity * (+node.attr("width") + 1);
params.max_x = +node.attr("x") + proximity * (+node.attr("width") + 1);
params.min_y = +node.attr("y") - proximity * (+node.attr("height") + 1);
params.max_y = +node.attr("y") + proximity * (+node.attr("height") + 1);
return params;
}
function setup_som(width, height, n) {
var space = d3.select("body").append("svg").attr("width", width).attr("height", height).append("g");
var m = n * n;
var x = 0;
var y = 0 - (height / n);
var nodes = d3.range(m).map(function(d, i) {
x = (width / n) * (d % n);
if (d % n == 0) {
y += (height / n);
}
var weight = [rb(rb(0, 800), rb(0, 800)), 1, Math.max(Math.random(), 0.2)];
return {
x: x,
y: y,
width: width / n,
height: height / n,
weight: weight,
i: i,
fill: d3.hsl.apply(null, weight),
}
});
space.selectAll()
.data(nodes)
.enter()
.append("rect")
.attr("class", "node")
.attr("width", function(d) {
return d.width
})
.attr("height", function(d) {
return d.height
})
.attr("x", function(d) {
return d.x
})
.attr("y", function(d) {
return d.y
})
.attr("rx", function(d) {
return d.width / 6
})
.attr("ry", function(d) {
return d.height / 6
})
.attr("fill", function(d) {
return d.fill
});
}
function init_som(m) {
var iter_limit = 6000;
var t = 0;
var nodes = d3.selectAll(".node");
var runner = setInterval(
function() {
var w;
var node_i = parseInt(rb(0, m));
var node = nodes.filter(function(d) {
return d.i == node_i;
});
node.each(function(g, i) {
w = g.weight;
});
var params = get_neighbors_params(node);
nodes.filter(function(e) {
return e.x >= params.min_x && e.x <= params.max_x;
})
.filter(function(e) {
return e.y >= params.min_y && e.y <= params.max_y;
})
.each(function(d, i) {
var nw = [];
for (var ut = 0; ut < w.length; ut++) {
if (ut == 0) {
nw.push(d.weight[ut] + 0.1 * (w[ut] - d.weight[ut]));
} else if (ut == 2) {
nw.push(d.weight[ut] + Math.random() * (w[ut] - d.weight[ut]));
}
}
d.weight[0] = nw[0];
d.weight[2] = nw[1];
return;
})
.style("fill", function(d) {
return d3.hsl.apply(null, d.weight);
});
d3.select("#n_iters").text(t+1+"/"+iter_limit);
t += 1;
if (t == iter_limit) {
clearTimeout(runner);
}
},
5
);
}
setup_som(width, height, n);
init_som(m);
</script>
<div class="iter_container">
<div class="item">ITERS: </div>
<div class="item" id="n_iters"></div>
</div>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment