Project high-dimensional data down to two or three dimensions while preserving the structure each method is designed to keep. DruidJS gives you 20 dimensionality reduction methods, 7 nearest-neighbor indices and 7 clustering algorithms behind one API, with SIMD-accelerated WebAssembly kernels and a pure-JavaScript fallback everywhere.
If you use npm, install with npm install @saehrimnir/druidjs, and use it with
import*asdruidfrom"@saehrimnir/druidjs";Otherwise download the files here, or use for instance unpkg this way:
<scriptsrc="https://unpkg.com/@saehrimnir/druidjs"></script>import*asdruidfrom"@saehrimnir/druidjs";constX=druid.Matrix.from(data);// n ⨯ dconstY=newdruid.UMAP(X,{d: 2,seed: 1212}).transform();Y.to2dArray();// [[x, y], ...] — ready for d3Every method has the same shape: construct it with the data and a parameters object, then call transform().
For a one-off projection there is a static shorthand:
constY=druid.PCA.transform(X,{d: 2});The iterative methods can be stepped instead of run to completion, so you can draw the embedding while it converges:
for(constYofnewdruid.TSNE(X,{d: 2,perplexity: 30}).generator()){draw(Y.to2dArray());}Dimensionality reduction — PCA · LDA · MDS · SMACOF · StressMDS · KKMDS · SQDMDS · t-SNE · UMAP · TriMap · PaCMAP · LocalMAP · Sammon · ISOMAP · LLE · LTSA · LSP · FastMap · TopoMap · MINFOTree
Nearest neighbors — BallTree, KDTree, HNSW, Annoy, LSH, NNDescent, NaiveKNN
constindex=newdruid.HNSW(points,{seed: 1212});index.search(points[0],10);// the 10 nearest pointsClustering — KMeans, KMedoids, XMeans, OPTICS, CURE, MeanShift, HierarchicalClustering (single, complete, average and Ward linkage)
The hot paths run through WebAssembly kernels once the input is large enough to pay for crossing the boundary, and fall back to JavaScript otherwise — automatically, with no difference in the API. Measured between the published 0.8.0 and 0.9.0 packages: 2.35⨯ on dimensionality reduction, 2.24⨯ on nearest-neighbor search, 2.21⨯ on matrix operations.
The kernels can be turned off, which is the easiest way to compare them against the fallback:
druid.setWasmEnabled(false);druid.isWasmAvailable();DruidJS uses internally the Matrix class for storing data. You can use it by creating a druid.Matrix object for instance with the function from, in example:
import*asdruidfrom"@saehrimnir/druidjs";letdata=[[...],[...], ...];letmatrix=druid.Matrix.from(data);You can create a druid.Matrix object programmatically by:
letfn=(row,col)=>(row==col ? 1 : 0);letmatrix=newdruid.Matrix(rows,columns,fn);If rows == columns, then matrix would be a identity matrix.
A shortcut for a identity matrix is:
letmatrix=newdruid.Matrix(rows,columns,"I");// orletmatrix=newdruid.Matrix(rows,columns,"identity");There are more shortcuts for creating matrices:
letmatrix=newdruid.Matrix(3,3,"zeros");// matrix would be a 3x3 matrix with zeroesletmatrix=newdruid.Matrix(3,3,"center");// matrix would be a 3x3 center matrix;letnumber=12;letmatrix=newdruid.Matrix(3,3,number);// matrix would be a 3x3 matrix filled with 'number'If you want to use a druid.Matrix object, for instance, with d3, you can use either the to2dArray method, the iterate_rows generator function, or just use the druid.Matrix object as an iterable (works with d3 since version 6).
letdata=awaitd3.csv("data.csv");letmatrix=druid.Matrix.from(data);d3.selectAll("datapoints").data(matrix.to2dArray());//...d3.selectAll("datapoints").data(matrix.iterate_rows());//...d3.selectAll("datapoints").data(matrix);//...Live, interactive examples in the documentation:
- Projections — the DR methods side by side on the Iris dataset
- Clustering and Cluster Diagnostics
- k-Nearest Neighbors — the indices compared
- Topology · Dendrograms · Geospatial · Image Search
All showcases → · Every method, one page each →
@inproceedings{cutura2020druid,
title={{DRUIDJS — A JavaScript Library for Dimensionality Reduction}},
author={Cutura, Rene and Kralj, Christoph and Sedlmair, Michael},
booktitle={2020 IEEE Visualization Conference (VIS)},
pages={111--115},
year={2020},
organization={IEEE}
}