Skip to content

Commit

Permalink
feat: add demo page (#170)
Browse files Browse the repository at this point in the history
  • Loading branch information
sd2k authored Nov 16, 2024
1 parent 937c102 commit 125af81
Show file tree
Hide file tree
Showing 146 changed files with 30,452 additions and 0 deletions.
973 changes: 973 additions & 0 deletions demo/changepoint.js

Large diffs are not rendered by default.

13 changes: 13 additions & 0 deletions demo/changepoint.worker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import initChangepoint, {
ChangepointDetector,
} from "./dist/@bsull/augurs/changepoint.js";

await initChangepoint();

self.onmessage = (e) => {
const { y } = e.data;
const cpd = new ChangepointDetector("normal-gamma");
const cps = cpd.detectChangepoints(y);
self.postMessage(cps);
};
self.postMessage("ready");
102 changes: 102 additions & 0 deletions demo/clustering.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import uPlot from "./dist/uPlot/uPlot.esm.js";

import { getSize } from "./helpers.js";
import { legendAsTooltipPlugin } from "./plugins.js";

function setUpPlot(data) {
const opts = {
...getSize(),
series: [
{},
...data.slice(1).map((_, i) => {
return {
label: `${i + 1}`,
stroke: "black",
width: 1,
};
}),
],
plugins: [legendAsTooltipPlugin()],
};
const u = uPlot(opts, data, document.getElementById("clustering-plot"));
window.addEventListener("resize", () => {
u.setSize(getSize());
});
return u;
}

class ClusteringWorker {
constructor() {
this.worker = new Worker("./clustering.worker.js", { type: "module" });
this.dataPromise = fetch("./outlier.data.json").then((res) => res.json());
this.dataPromise.then((data) => {
this.data = data.data;
});
}

static create = () => {
return new Promise((resolve, reject) => {
const worker = new ClusteringWorker();
worker.worker.onmessage = (e) => {
if (e.data === "ready") {
worker.dataPromise.then(() => resolve(worker));
} else {
reject();
}
}
})
}

cluster = async (dtwOpts, dbscanOpts) => {
return new Promise((resolve, reject) => {
const start = performance.now();
this.worker.postMessage({
dtwOpts,
dbscanOpts,
data: this.data.slice(1).map(arr => new Float64Array(arr)),
});
this.worker.onmessage = (e) => {
const elapsed = (performance.now() - start).toFixed(0);
resolve({ clusterLabels: e.data, elapsed });
};
});
}
}

async function main() {
const worker = await ClusteringWorker.create();

const u = setUpPlot(worker.data);
async function runClustering(dtwOpts, dbscanOpts) {
const { clusterLabels, elapsed } = await worker.cluster(dtwOpts, dbscanOpts);
clusterLabels.forEach((cluster, i) => {
const seriesIdx = i + 1;
u.delSeries(seriesIdx);
u.addSeries({
label: `${i} (cluster ${cluster})`,
stroke: cluster === -1 ? "black" : cluster === 0 ? "blue" : cluster === 1 ? "red" : "yellow",
width: 1,
}, seriesIdx);
});
u.redraw()
document.getElementById("clustering-title").innerText = `Clustering with DBSCAN - done in ${elapsed}ms`;
}
const dtwOpts = { window: 2 };
const dbscanOpts = { epsilon: 5000, minClusterSize: 2 };
runClustering(dtwOpts, dbscanOpts);

document.getElementById("clustering-dtw-window").addEventListener("change", function() {
dtwOpts.window = parseFloat(this.value);
runClustering(dtwOpts, dbscanOpts);
});
document.getElementById("clustering-dbscan-epsilon").addEventListener("change", function() {
dbscanOpts.epsilon = parseFloat(this.value);
runClustering(dtwOpts, dbscanOpts);
});
document.getElementById("clustering-dbscan-min-cluster-size").addEventListener("change", function() {
dbscanOpts.minClusterSize = parseInt(this.value);
runClustering(dtwOpts, dbscanOpts);
});
}

export default main;
16 changes: 16 additions & 0 deletions demo/clustering.worker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import initDtw, { Dtw } from "./dist/@bsull/augurs/dtw.js";
import initClustering, {
DbscanClusterer,
} from "./dist/@bsull/augurs/clustering.js";

await Promise.all([initDtw(), initClustering()]);

self.onmessage = (e) => {
const { dtwOpts, dbscanOpts, data } = e.data;
const dtw = Dtw.euclidean(dtwOpts);
const distanceMatrix = dtw.distanceMatrix(data);
const clusterer = new DbscanClusterer(dbscanOpts);
const labels = clusterer.fit(distanceMatrix);
self.postMessage(labels);
};
self.postMessage("ready");
49 changes: 49 additions & 0 deletions demo/dist/@bsull/augurs-prophet-wasmstan/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Prophet Stan model, compiled to WASM

This is a WASM-compiled version of the [Prophet](https://facebook.github.io/prophet/) Stan model, for use with the [@bsull/augurs](https://github.com/grafana/augurs) library.

## Usage

```js
import { Prophet } from '@bsull/augurs';
import { optimizer } from '@bsull/augurs-prophet-wasmstan';

// Create some fake data.
// `ds` must be timestamps since the epoch, in seconds.
const ds = [1704067200, 1704871384, 1705675569, 1706479753, 1707283938, 1708088123,
1708892307, 1709696492, 1710500676, 1711304861, 1712109046, 1712913230,
];
const y = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0];
const trainingData = { ds, y };

// Create a Prophet model and fit it to the training data.
const prophet = new Prophet();
prophet.fit(trainingdata);
// Predict for the training set.
prophet.predict();
// Predict for a new time point.
prophet.predict({ ds: [ 1713717414 ]})
```

See the documentation for `@bsull/augurs` for more details.

## Troubleshooting

### Webpack

The generated Javascript bindings in this package may require some additional Webpack configuration to work.
Adding this to your `webpack.config.js` should be enough:

```javascript
{
experiments: {
// Required to load WASM modules.
asyncWebAssembly: true,
},
resolve: {
fallback: {
fs: false,
},
},
}
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export namespace AugursProphetWasmstanOptimizer {
/**
* Optimize the initial parameters given the data, returning the
* optimal values under maximum likelihood estimation.
*/
export function optimize(init: Inits, data: DataJson, opts: OptimizeOpts): OptimizeOutput;
}
import type { Inits } from './augurs-prophet-wasmstan-types.js';
export { Inits };
import type { DataJson } from './augurs-prophet-wasmstan-types.js';
export { DataJson };
import type { OptimizeOpts } from './augurs-prophet-wasmstan-types.js';
export { OptimizeOpts };
import type { OptimizeOutput } from './augurs-prophet-wasmstan-types.js';
export { OptimizeOutput };
Loading

0 comments on commit 125af81

Please sign in to comment.