Skip to content

Instantly share code, notes, and snippets.

@makotoshimazu
Last active August 29, 2015 13:57
Show Gist options
  • Save makotoshimazu/9814535 to your computer and use it in GitHub Desktop.
Save makotoshimazu/9814535 to your computer and use it in GitHub Desktop.
k-means clustering sample
<html>
<head>
<script type="text/javascript" src="kmeans.js"></script>
</head>
<body onload="kmeans.reset()">
<form name="f">
<input type="button" onclick="kmeans.reset()" value="start"><input type="button" value="step" onclick="kmeans.step()"><br/>
<br/>
<canvas id="field" width="1024" height="768"><br/>
</body>
</html>
var Kmeans = function (numDots, kinds) {
this.N = numDots;
this.K = kinds;
this.points = [];
this.color = ['rgb(192, 80, 77)',
'rgb(155, 187, 89)',
'rgb(128, 100, 162)',
'rgb(192, 32, 16)',
'rgb(16, 192, 32)',
'rgb(32, 16, 192)'];
function getRand( max, min ) {
if ( typeof max === 'undefined' ) {
return 0;
}
if ( typeof min === 'undefined' ) {
min = 0;
}
return Math.floor( Math.random()*max + min );
}
this.reset = function _reset() {
var canvas = document.getElementById('field');
var ctx = canvas.getContext('2d');
// Clear canvas
ctx.clearRect(0,0,canvas.width,canvas.height);
// Reset
this.points = []
for ( var i = 0; i < this.K; i++ ) {
this.points.push([]);
}
// Create points
for ( var i = 0; i < this.N; i++ ) {
var pos = { x: getRand( canvas.width-50, 50 ),
y: getRand( canvas.height-50, 50 ) };
var kind = getRand( this.K, 1 );
this.points[kind-1].push(pos);
}
// Plot points
for ( var i = 0; i < this.K; i++ ) {
ctx.fillStyle = this.color[i];
for ( var j = 0; j < this.points[i].length; j++ ) {
ctx.beginPath();
var p = this.points[i][j]
ctx.arc( p.x, p.y, 10, 0, 2*Math.PI);
ctx.fill();
}
}
}
function plotCross( ctx, p ) {
ctx.beginPath();
ctx.moveTo( p.x-10, p.y+10 );
ctx.lineTo( p.x+10, p.y-10 );
ctx.moveTo( p.x-10, p.y-10 );
ctx.lineTo( p.x+10, p.y+10 );
ctx.lineWidth = 3;
ctx.stroke();
}
function dist2( p1, p2 ) {
return (p1.x-p2.x)*(p1.x-p2.x) + (p1.y-p2.y)*(p1.y-p2.y);
}
function nearest ( p, means ) {
var dist = dist2(p, means[0]);
var n = 0;
for ( var i = 1; i < means.length; i++ ) {
var d = dist2(p, means[i]);
if ( dist > d ) {
dist = d;
n = i;
}
}
return n;
}
this.step = function _step () {
var canvas = document.getElementById('field');
var ctx = canvas.getContext('2d');
// Clear canvas
ctx.clearRect(0,0,canvas.width,canvas.height);
// Calculate mean position
var means = [];
for ( var i = 0; i < this.K; i++ ) {
var n = this.points[i].length;
var m = {x: 0, y: 0};
for ( var j = 0; j < n; j++ ) {
var p = this.points[i][j];
m.x += p.x;
m.y += p.y;
}
m.x /= n;
m.y /= n;
means.push(m);
}
// Re-destribute points
var newPoints = [];
for ( var i = 0; i < this.K; i++ ) {
newPoints.push([]);
}
for ( var i = 0; i < this.K; i++ ) {
for ( var j = 0; j < this.points[i].length; j++ ) {
var n = nearest( this.points[i][j], means );
newPoints[n].push(this.points[i][j]);
}
}
this.points = newPoints;
// Re-plot
for ( var i = 0; i < this.K; i++ ) {
ctx.fillStyle = this.color[i];
for ( var j = 0; j < this.points[i].length; j++ ) {
ctx.beginPath();
var p = this.points[i][j]
ctx.arc( p.x, p.y, 10, 0, 2*Math.PI);
ctx.fill();
}
plotCross( ctx, means[i] );
}
}
}
kmeans = new Kmeans(1000, 5);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment