Skip to content

Commit

Permalink
feat(examples): add kmeans-viz example
Browse files Browse the repository at this point in the history
  • Loading branch information
postspectacular committed Feb 11, 2023
1 parent f94d68a commit eaa93e9
Show file tree
Hide file tree
Showing 9 changed files with 252 additions and 71 deletions.
Binary file added assets/examples/kmean-viz.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
141 changes: 71 additions & 70 deletions examples/README.md

Large diffs are not rendered by default.

15 changes: 15 additions & 0 deletions examples/kmeans-viz/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# kmeans-viz

![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/kmeans-viz.jpg)

[Live demo](http://demo.thi.ng/umbrella/kmeans-viz/)

Please refer to the [example build instructions](https://github.com/thi-ng/umbrella/wiki/Example-build-instructions) on the wiki.

## Authors

- Karsten Schmidt

## License

© 2023 Karsten Schmidt // Apache Software License 2.0
30 changes: 30 additions & 0 deletions examples/kmeans-viz/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<!DOCTYPE html>
<html lang="en">
<head>
<link
rel="icon"
href='data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><text y=".9em" font-size="90">⛱️</text></svg>'
/>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>kmeans-viz · @thi.ng/umbrella</title>
<link
href="https://unpkg.com/tachyons@4/css/tachyons.min.css"
rel="stylesheet"
/>
<style></style>
</head>
<body class="sans-serif">
<div id="app"></div>
<div>Reload for variations.</div>
<div>
<a
class="link"
href="https://github.com/thi-ng/umbrella/tree/develop/examples/kmeans-viz"
>Source code</a
>
</div>
<script type="module" src="/src/index.ts"></script>
</body>
</html>
40 changes: 40 additions & 0 deletions examples/kmeans-viz/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"name": "@example/kmeans-viz",
"version": "0.0.1",
"private": true,
"description": "k-means clustering visualization",
"repository": "https://github.com/thi-ng/umbrella",
"author": "Karsten Schmidt <k+npm@thi.ng>",
"license": "Apache-2.0",
"scripts": {
"start": "vite --open",
"build": "tsc && vite build --base='./'",
"preview": "vite preview --host --open"
},
"devDependencies": {
"typescript": "^4.9.5",
"vite": "^4.1.1"
},
"dependencies": {
"@thi.ng/arrays": "workspace:^",
"@thi.ng/color": "workspace:^",
"@thi.ng/geom": "workspace:^",
"@thi.ng/k-means": "workspace:^",
"@thi.ng/random": "workspace:^",
"@thi.ng/transducers": "workspace:^",
"@thi.ng/vectors": "workspace:^"
},
"browser": {
"process": false
},
"thi.ng": {
"readme": [
"color",
"geom",
"k-means",
"random",
"vectors"
],
"screenshot": "examples/kmeans-viz.jpg"
}
}
72 changes: 72 additions & 0 deletions examples/kmeans-viz/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { shuffle } from "@thi.ng/arrays";
import { colorsFromRange } from "@thi.ng/color";
import {
asSvg,
convexHull,
group,
points,
Polygon,
svgDoc,
withAttribs,
} from "@thi.ng/geom";
import { kmeans } from "@thi.ng/k-means";
import { SYSTEM } from "@thi.ng/random";
import { repeatedly } from "@thi.ng/transducers";
import { add2, randNormDistrib2, Vec } from "@thi.ng/vectors";

const W = 600;
const W2 = W / 2;

// number of points to generate per cluster
const NUM = 5000;
// cluster radius
const R = 150;
// cluster offset
const OFFSET = R * 0.8;
// number of target clusters
const K = SYSTEM.minmaxInt(2, 25);
// color themes
// see: https://github.com/thi-ng/umbrella/blob/develop/packages/color/README.md#color-theme-generation
const THEME = [...colorsFromRange("hard", { num: K })];

// generates points scattered in given radius around pos
const makeCluster = (pos: Vec, r: number, num: number) => [
...repeatedly(
() => add2(null, randNormDistrib2([], SYSTEM.float(r * r) ** 0.5), pos),
num
),
];

// generate & combine points from 3 overlapping clusters
// (the shuffling is unnecessary, just to show initial order is irrelevant)
const allPoints = shuffle([
...makeCluster([W2, W2 + OFFSET], R, NUM),
...makeCluster([W2 + OFFSET, W2 - OFFSET], R, NUM),
...makeCluster([W2 - OFFSET, W2 - OFFSET], R, NUM),
]);

// now segment all points into K new clusters
// k-means clustering is non-deterministic, multiple runs might produce different results
const clusters = kmeans(K, allPoints);

// visualize result clusters as SVG
document.getElementById("app")!.innerHTML = asSvg(
svgDoc(
{ width: W, height: W, viewBox: `0 0 ${W} ${W}`, stroke: "none" },
...clusters.map((x, id) => {
// result clusters contain only point indices
// here we look up their actual positions again and add styling info
const pts = points(
x.items.map((i) => allPoints[i]),
{ fill: THEME[id], size: 3 }
);
// also compute the convex hull polygon
const hull = <Polygon>withAttribs(convexHull(pts), {
stroke: "black",
fill: "none",
});
// return both as group
return group({}, [pts, hull]);
})
)
);
1 change: 1 addition & 0 deletions examples/kmeans-viz/src/vite-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/// <reference types="vite/client" />
6 changes: 6 additions & 0 deletions examples/kmeans-viz/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"extends": "../tsconfig.json",
"include": ["src/**/*"],
"compilerOptions": {
}
}
18 changes: 17 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1080,6 +1080,22 @@ __metadata:
languageName: unknown
linkType: soft

"@example/kmeans-viz@workspace:examples/kmeans-viz":
version: 0.0.0-use.local
resolution: "@example/kmeans-viz@workspace:examples/kmeans-viz"
dependencies:
"@thi.ng/arrays": "workspace:^"
"@thi.ng/color": "workspace:^"
"@thi.ng/geom": "workspace:^"
"@thi.ng/k-means": "workspace:^"
"@thi.ng/random": "workspace:^"
"@thi.ng/transducers": "workspace:^"
"@thi.ng/vectors": "workspace:^"
typescript: ^4.9.5
vite: ^4.1.1
languageName: unknown
linkType: soft

"@example/login-form@workspace:examples/login-form":
version: 0.0.0-use.local
resolution: "@example/login-form@workspace:examples/login-form"
Expand Down Expand Up @@ -4139,7 +4155,7 @@ __metadata:
languageName: unknown
linkType: soft

"@thi.ng/k-means@^0.6.1, @thi.ng/k-means@workspace:packages/k-means":
"@thi.ng/k-means@^0.6.1, @thi.ng/k-means@workspace:^, @thi.ng/k-means@workspace:packages/k-means":
version: 0.0.0-use.local
resolution: "@thi.ng/k-means@workspace:packages/k-means"
dependencies:
Expand Down

0 comments on commit eaa93e9

Please sign in to comment.