Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ build/
dist/
distlib/
target/
pkg/
.svelte-kit/
.env
.env.*
Expand Down
9 changes: 9 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"packages/viewer",
"packages/table",
"packages/umap-wasm",
"packages/density-clustering",
"packages/embedding-atlas",
"packages/examples",
"packages/backend",
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (c) 2025 Apple Inc. Licensed under MIT License.

import { findClusters } from "../../density_clustering/find_clusters.js";
import { findClusters } from "@embedding-atlas/density-clustering";
import { dynamicLabelPlacement } from "../../dynamic_label_placement/dynamic_label_placement.js";

export { dynamicLabelPlacement, findClusters };
2 changes: 0 additions & 2 deletions packages/component/src/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ export {
type EmbeddingViewProps,
} from "./embedding_view/api.js";

export { findClusters, type Cluster, type FindClustersOptions } from "./density_clustering/find_clusters.js";

export { defaultCategoryColors } from "./colors.js";

export type { Theme } from "./embedding_view/theme.js";
Expand Down
9 changes: 0 additions & 9 deletions packages/density-clustering/density_clustering_wasm/build.sh

This file was deleted.

42 changes: 42 additions & 0 deletions packages/density-clustering/density_clustering_wasm/js/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/** A resulting cluster from the find clusters function */
export interface Cluster {
/** Cluster identifier */
identifier: number;
/** The total density */
sum_density: number;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose these are mapping to native names so we use snake case instead of camel case which would be common in js?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, they map to Rust code. I think camel case would be better for JS, but this PR is just to move the code to a new home, so no changes to the naming.

/** The mean x location (weighted by density) */
mean_x: number;
/** The mean y location (weighted by density) */
mean_y: number;
/** The maximum density */
max_density: number;
/** The location with the maximum density */
max_density_location: [number, number];
/** The number of pixels in the cluster */
pixel_count: number;
/** The cluster's boundary represented as a list of polygons */
boundary?: [number, number][][];
/** The cluster's boundary approximated with a list of rectangles */
boundary_rect_approximation?: [number, number, number, number][];
}

/** Options of the find clusters function */
export interface FindClustersOptions {
/** The threshold for unioning two clusters */
union_threshold: number;
}

/**
* Find clusters from a density map
* @param density_map the density map, a `Float32Array` with `width * height` elements
* @param width the width of the density map
* @param height the height of the density map
* @param options algorithm options
* @returns
*/
export async function findClusters(
density_map: Float32Array,
width: number,
height: number,
options: Partial<FindClustersOptions> = {},
): Promise<Cluster[]>;
Original file line number Diff line number Diff line change
@@ -1,34 +1,6 @@
// Copyright (c) 2025 Apple Inc. Licensed under MIT License.

import * as cluster from "./wasm/density_clustering_wasm.js";

/** A resulting cluster from the find clusters function */
export interface Cluster {
/** Cluster identifier */
identifier: number;
/** The total density */
sum_density: number;
/** The mean x location (weighted by density) */
mean_x: number;
/** The mean y location (weighted by density) */
mean_y: number;
/** The maximum density */
max_density: number;
/** The location with the maximum density */
max_density_location: [number, number];
/** The number of pixels in the cluster */
pixel_count: number;
/** The cluster's boundary represented as a list of polygons */
boundary?: [number, number][][];
/** The cluster's boundary approximated with a list of rectangles */
boundary_rect_approximation?: [number, number, number, number][];
}

/** Options of the find clusters function */
export interface FindClustersOptions {
/** The threshold for unioning two clusters */
union_threshold: number;
}
import * as cluster from "../pkg/density_clustering_wasm.js";

/**
* Find clusters from a density map
Expand All @@ -38,12 +10,7 @@ export interface FindClustersOptions {
* @param options algorithm options
* @returns
*/
export async function findClusters(
density_map: Float32Array,
width: number,
height: number,
options: Partial<FindClustersOptions> = {},
): Promise<Cluster[]> {
export async function findClusters(density_map, width, height, options = {}) {
await cluster.default();
// console.debug(`find clusters start, size: ${width}x${height}`);
let t0 = new Date().getTime();
Expand All @@ -62,7 +29,7 @@ export async function findClusters(
smooth_boundaries: true,
});
input.free();
let clusters: Cluster[] = [];
let clusters = [];
for (let [id, summary] of result.summaries) {
clusters.push({
identifier: id,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,40 +1,13 @@
let wasm;

const cachedTextDecoder = (typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }) : { decode: () => { throw Error('TextDecoder not available') } } );

if (typeof TextDecoder !== 'undefined') { cachedTextDecoder.decode(); };

let cachedUint8Memory0 = null;

function getUint8Memory0() {
if (cachedUint8Memory0 === null || cachedUint8Memory0.byteLength === 0) {
cachedUint8Memory0 = new Uint8Array(wasm.memory.buffer);
}
return cachedUint8Memory0;
}

function getStringFromWasm0(ptr, len) {
ptr = ptr >>> 0;
return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len));
}

const heap = new Array(128).fill(undefined);

heap.push(undefined, null, true, false);

let heap_next = heap.length;

function addHeapObject(obj) {
if (heap_next === heap.length) heap.push(heap.length + 1);
const idx = heap_next;
heap_next = heap[idx];

heap[idx] = obj;
return idx;
}

function getObject(idx) { return heap[idx]; }

let heap_next = heap.length;

function dropObject(idx) {
if (idx < 132) return;
heap[idx] = heap_next;
Expand Down Expand Up @@ -69,6 +42,33 @@ function getInt32Memory0() {
return cachedInt32Memory0;
}

const cachedTextDecoder = (typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }) : { decode: () => { throw Error('TextDecoder not available') } } );

if (typeof TextDecoder !== 'undefined') { cachedTextDecoder.decode(); };

let cachedUint8Memory0 = null;

function getUint8Memory0() {
if (cachedUint8Memory0 === null || cachedUint8Memory0.byteLength === 0) {
cachedUint8Memory0 = new Uint8Array(wasm.memory.buffer);
}
return cachedUint8Memory0;
}

function getStringFromWasm0(ptr, len) {
ptr = ptr >>> 0;
return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len));
}

function addHeapObject(obj) {
if (heap_next === heap.length) heap.push(heap.length + 1);
const idx = heap_next;
heap_next = heap[idx];

heap[idx] = obj;
return idx;
}

let WASM_VECTOR_LEN = 0;

const cachedTextEncoder = (typeof TextEncoder !== 'undefined' ? new TextEncoder('utf-8') : { encode: () => { throw Error('TextEncoder not available') } } );
Expand Down Expand Up @@ -303,10 +303,6 @@ async function __wbg_load(module, imports) {
function __wbg_get_imports() {
const imports = {};
imports.wbg = {};
imports.wbg.__wbindgen_error_new = function(arg0, arg1) {
const ret = new Error(getStringFromWasm0(arg0, arg1));
return addHeapObject(ret);
};
imports.wbg.__wbindgen_boolean_get = function(arg0) {
const v = getObject(arg0);
const ret = typeof(v) === 'boolean' ? (v ? 1 : 0) : 2;
Expand Down Expand Up @@ -338,6 +334,10 @@ function __wbg_get_imports() {
const ret = typeof(getObject(arg0)) === 'string';
return ret;
};
imports.wbg.__wbindgen_error_new = function(arg0, arg1) {
const ret = new Error(getStringFromWasm0(arg0, arg1));
return addHeapObject(ret);
};
imports.wbg.__wbindgen_jsval_loose_eq = function(arg0, arg1) {
const ret = getObject(arg0) == getObject(arg1);
return ret;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,43 +4,14 @@ export function __wbg_set_wasm(val) {
}


const lTextDecoder = typeof TextDecoder === 'undefined' ? (0, module.require)('util').TextDecoder : TextDecoder;

let cachedTextDecoder = new lTextDecoder('utf-8', { ignoreBOM: true, fatal: true });

cachedTextDecoder.decode();

let cachedUint8Memory0 = null;

function getUint8Memory0() {
if (cachedUint8Memory0 === null || cachedUint8Memory0.byteLength === 0) {
cachedUint8Memory0 = new Uint8Array(wasm.memory.buffer);
}
return cachedUint8Memory0;
}

function getStringFromWasm0(ptr, len) {
ptr = ptr >>> 0;
return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len));
}

const heap = new Array(128).fill(undefined);

heap.push(undefined, null, true, false);

let heap_next = heap.length;

function addHeapObject(obj) {
if (heap_next === heap.length) heap.push(heap.length + 1);
const idx = heap_next;
heap_next = heap[idx];

heap[idx] = obj;
return idx;
}

function getObject(idx) { return heap[idx]; }

let heap_next = heap.length;

function dropObject(idx) {
if (idx < 132) return;
heap[idx] = heap_next;
Expand Down Expand Up @@ -75,6 +46,35 @@ function getInt32Memory0() {
return cachedInt32Memory0;
}

const lTextDecoder = typeof TextDecoder === 'undefined' ? (0, module.require)('util').TextDecoder : TextDecoder;

let cachedTextDecoder = new lTextDecoder('utf-8', { ignoreBOM: true, fatal: true });

cachedTextDecoder.decode();

let cachedUint8Memory0 = null;

function getUint8Memory0() {
if (cachedUint8Memory0 === null || cachedUint8Memory0.byteLength === 0) {
cachedUint8Memory0 = new Uint8Array(wasm.memory.buffer);
}
return cachedUint8Memory0;
}

function getStringFromWasm0(ptr, len) {
ptr = ptr >>> 0;
return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len));
}

function addHeapObject(obj) {
if (heap_next === heap.length) heap.push(heap.length + 1);
const idx = heap_next;
heap_next = heap[idx];

heap[idx] = obj;
return idx;
}

let WASM_VECTOR_LEN = 0;

const lTextEncoder = typeof TextEncoder === 'undefined' ? (0, module.require)('util').TextEncoder : TextEncoder;
Expand Down Expand Up @@ -277,11 +277,6 @@ export class DensityMap {
}
}

export function __wbindgen_error_new(arg0, arg1) {
const ret = new Error(getStringFromWasm0(arg0, arg1));
return addHeapObject(ret);
};

export function __wbindgen_boolean_get(arg0) {
const v = getObject(arg0);
const ret = typeof(v) === 'boolean' ? (v ? 1 : 0) : 2;
Expand Down Expand Up @@ -320,6 +315,11 @@ export function __wbindgen_is_string(arg0) {
return ret;
};

export function __wbindgen_error_new(arg0, arg1) {
const ret = new Error(getStringFromWasm0(arg0, arg1));
return addHeapObject(ret);
};

export function __wbindgen_jsval_loose_eq(arg0, arg1) {
const ret = getObject(arg0) == getObject(arg1);
return ret;
Expand Down
Binary file not shown.
17 changes: 17 additions & 0 deletions packages/density-clustering/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "@embedding-atlas/density-clustering",
"version": "0.0.0",
"private": true,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to publish this as a package or leave it internal?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The API is already published as part of the embedding-atlas npm package.

"description": "A WebAssembly implementation of a density-based clustering algorithm",
"main": "density_clustering_wasm/js/index.js",
"module": "density_clustering_wasm/js/index.js",
"type": "module",
"scripts": {
"build": "npx wasm-pack build --release --target web density_clustering_wasm && rm density_clustering_wasm/pkg/.gitignore density_clustering_wasm/pkg/package.json"
},
"files": [
"density_clustering_wasm/js/index.js",
"density_clustering_wasm/pkg/density_clustering_wasm.js",
"density_clustering_wasm/pkg/density_clustering_wasm_bg.wasm"
]
}
Loading