Commit bd002fcf authored by Daniel Król's avatar Daniel Król

Show iteration history

parent 00bea8e7
......@@ -20,6 +20,7 @@
<label>Display Voronoi cells <input id="voronoi" value="1" type="checkbox"/></label><br/>
<button type="button" id="resetData">New point set</button><br/>
<button type="button" id="recluster">Cluster again</button>
<input type="range" min="0" max="5" step="1" id="iteration"/>
</form>
</div>
<div style="height: 100%;" id="graph"></div>
......
import * as d3 from "d3";
import {Delaunay} from "d3-delaunay";
import {kmeans} from "../";
import { Cluster } from "./../src/kmeans";
const colors = ["blue", "green", "yellow", "cyan", "magenta", "brown", "grey"];
let data: any = {};
......@@ -14,6 +15,7 @@ window.onload = () => {
document.getElementById("clusterSeeds").onchange = render;
document.getElementById("voronoi").onchange = render;
document.getElementById("iteration").oninput = render;
loadForm();
};
......@@ -36,12 +38,23 @@ const seed = () => {
};
const clusterize = () => {
data.clusters = kmeans(data.points, data.clusterCount);
const iterations = [];
data.clusters = kmeans(data.points, data.clusterCount, {
onIteration: (c: Cluster[]) => {
iterations.push(c);
}
});
data.iterations = iterations;
data.iterationIdx = iterations.length - 1;
document.getElementById("iteration")["max"] = iterations.length - 1;
document.getElementById("iteration")["value"] = iterations.length - 1;
render();
};
const render = () => {
const {clusters, width, height, seeds} = data;
const iterationIdx = parseInt(document.getElementById("iteration")["value"]);
const {iterations, width, height, seeds} = data;
const clusters = iterations[iterationIdx];
document.getElementById("graph").innerHTML = null;
const svg = d3.select("#graph").append("svg").attr("width", width).attr("height", height);
......
import { merge } from "typescript-object-utils";
import { Cluster, optimizeCentroids } from "./src/kmeans";
import { Point } from "./src/point";
import { randomPick } from "./src/randomPick";
export { Cluster };
export function kmeans(points: Point[], k: number, options?: Partial<KMeansOptions>): Cluster[] {
options = merge(defaults, options);
const centroids = options.initFunction(points, k);
return optimizeCentroids(centroids, points);
}
export interface KMeansOptions {
initFunction: (points: Point[], k: number) => Point[];
}
const defaults: KMeansOptions = {
initFunction: randomPick
};
\ No newline at end of file
export { Cluster, kmeans, KMeansOptions } from "./src";
import { merge } from "typescript-object-utils";
import { Cluster, optimizeCentroids } from "./kmeans";
import { Point } from "./point";
import { randomPick } from "./randomPick";
export { Cluster };
export function kmeans(points: Point[], k: number, options?: Partial<KMeansOptions>): Cluster[] {
options = merge(defaults, options);
const centroids = options.initFunction(points, k);
return optimizeCentroids(centroids, points, options.onIteration);
}
export interface KMeansOptions {
initFunction: (points: Point[], k: number) => Point[];
onIteration?: (clusters: Cluster[]) => any;
}
const defaults: KMeansOptions = {
initFunction: randomPick
};
\ No newline at end of file
import {assembleClusters} from "./assembleClusters";
import { arePointsEqual, Point } from "./point";
export function optimizeCentroids<L>(centroids: Point[], points: Point[]): Cluster[] {
let clusters = assembleClusters(centroids, points);
let run = true;
while(run) {
run = false;
export function optimizeCentroids(centroids: Point[], points: Point[], onIteration?: (clusters: Cluster[]) => any): Cluster[] {
let clusters = [];
let anyCentroidChanged = false;
do {
clusters = assembleClusters(centroids, points);
if(onIteration) {
onIteration(clusters);
}
anyCentroidChanged = false;
centroids = [];
for(const cluster of clusters) {
const centroid = clusterCentroid(cluster);
centroids.push(centroid);
if(!arePointsEqual(centroid, cluster.centroid)) {
run = true;
anyCentroidChanged = true;
}
}
clusters = assembleClusters(centroids, points);
}
} while( anyCentroidChanged );
return clusters;
}
......
......@@ -24,4 +24,15 @@ describe("kMeans", () => {
return a.centroid[0] - b.centroid[0];
});
});
it("should call iteration listener", () => {
const points = [[0], [1], [9], [10]];
let iterations = 0;
const clusters = kmeans(points, 2, {
onIteration: () => {
iterations++;
}
});
assert.strictEqual(iterations > 0, true);
});
});
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment