diff --git a/dev/Main.svelte b/dev/Main.svelte index 8d6c17607..56d372e89 100644 --- a/dev/Main.svelte +++ b/dev/Main.svelte @@ -1,49 +1,49 @@
- - + +
-
- -
+
\ No newline at end of file + diff --git a/dev/svelte/SizeSlider.svelte b/dev/svelte/SizeSlider.svelte new file mode 100644 index 000000000..a24146f1a --- /dev/null +++ b/dev/svelte/SizeSlider.svelte @@ -0,0 +1,21 @@ + + + diff --git a/package-lock.json b/package-lock.json index 2e2b013e6..77bb6a0d5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -54,6 +54,7 @@ "terser": "^5.28.1", "typedoc": "^0.25.8", "typescript": "^5.3.3", + "uvu": "^0.5.6", "vite": "^5.1.4" }, "peerDependencies": { @@ -2470,6 +2471,15 @@ "node": ">=6" } }, + "node_modules/diff": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -4729,6 +4739,15 @@ "dev": true, "license": "MIT" }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/ms": { "version": "2.1.2", "dev": true, @@ -5597,6 +5616,18 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/sade": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "dev": true, + "dependencies": { + "mri": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/safe-array-concat": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.0.tgz", @@ -6423,6 +6454,24 @@ "dev": true, "license": "MIT" }, + "node_modules/uvu": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.6.tgz", + "integrity": "sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==", + "dev": true, + "dependencies": { + "dequal": "^2.0.0", + "diff": "^5.0.0", + "kleur": "^4.0.3", + "sade": "^1.7.3" + }, + "bin": { + "uvu": "bin.js" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -8213,6 +8262,12 @@ "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", "dev": true }, + "diff": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", + "dev": true + }, "dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -9867,6 +9922,12 @@ "version": "1.2.6", "dev": true }, + "mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "dev": true + }, "ms": { "version": "2.1.2", "dev": true @@ -10466,6 +10527,15 @@ "queue-microtask": "^1.2.2" } }, + "sade": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "dev": true, + "requires": { + "mri": "^1.1.0" + } + }, "safe-array-concat": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.0.tgz", @@ -11051,6 +11121,18 @@ "version": "1.0.2", "dev": true }, + "uvu": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.6.tgz", + "integrity": "sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==", + "dev": true, + "requires": { + "dequal": "^2.0.0", + "diff": "^5.0.0", + "kleur": "^4.0.3", + "sade": "^1.7.3" + } + }, "validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", diff --git a/package.json b/package.json index 921be1aa6..69c4a18fa 100644 --- a/package.json +++ b/package.json @@ -90,6 +90,7 @@ "terser": "^5.28.1", "typedoc": "^0.25.8", "typescript": "^5.3.3", + "uvu": "^0.5.6", "vite": "^5.1.4" } } diff --git a/src/Dataset.ts b/src/Dataset.ts index e72392fa3..60a37e4b8 100644 --- a/src/Dataset.ts +++ b/src/Dataset.ts @@ -32,6 +32,7 @@ import { wrapArrowTable } from './wrap_arrow'; type Key = string; type ArrowBuildable = DS.ArrowBuildable; + type Transformation = DS.Transformation; // Some variables are universally available. diff --git a/src/scatterplot.ts b/src/scatterplot.ts index ce8d73efa..f7d948808 100644 --- a/src/scatterplot.ts +++ b/src/scatterplot.ts @@ -251,7 +251,7 @@ export class Scatterplot { return old_version.selection; } } - const selection = new DataSelection(this, params); + const selection = new DataSelection(this.dataset, params); this.selection_history.push({ selection, name: selection.name, diff --git a/src/selection.ts b/src/selection.ts index 0e9ee387e..527cc0a37 100644 --- a/src/selection.ts +++ b/src/selection.ts @@ -66,6 +66,12 @@ type BinaryOperation = 'AND' | 'OR' | 'XOR'; type UnaryOperation = 'NOT'; type CompArgs = DataSelection | Composition; + +/** + * A composition represents an operation on selections. The syntax is basically + * a lisp-like list of operations and selections. The first element is the operation, + * and the rest of the elements are the arguments. + */ type Composition = | [UnaryOperation, CompArgs] | [BinaryOperation, CompArgs, CompArgs] @@ -329,15 +335,14 @@ export class DataSelection { private events: { [key: string]: Array<(args) => void> } = {}; constructor( - plot: Scatterplot, + dataset: Dataset, params: | IdSelectParams | BooleanColumnParams | FunctionSelectParams | CompositeSelectParams, ) { - this.plot = plot; - this.dataset = plot.dataset; + this.dataset = dataset; this.name = params.name; let markReady = function () {}; this.ready = new Promise((resolve) => { @@ -424,7 +429,7 @@ export class DataSelection { * selection that is the union of the two. */ union(other: DataSelection, name: string | undefined): DataSelection { - return new DataSelection(this.plot, { + return new DataSelection(this.dataset, { name: name || this.name + ' union ' + other.name, composition: ['OR', this, other], }); @@ -438,7 +443,7 @@ export class DataSelection { * disjunctive normal form constructor. */ intersection(other: DataSelection, name: string | undefined): DataSelection { - return new DataSelection(this.plot, { + return new DataSelection(this.dataset, { name: name || this.name + ' intersection ' + other.name, composition: ['AND', this, other], }); @@ -606,7 +611,7 @@ export class DataSelection { } return mask.to_arrow(); }; - const selection = new DataSelection(this.plot, { + const selection = new DataSelection(this.dataset, { name: newName, tileFunction, }); @@ -648,7 +653,7 @@ export class DataSelection { if (this.dataset.has_column(name)) { throw new Error(`Column ${name} already exists, can't create`); } - this.plot.dataset.transformations[name] = + this.dataset.transformations[name] = this.wrapWithSelectionMetadata(tileFunction); // Await the application to the root tile, which may be necessary await this.dataset.root_tile.apply_transformation(name); @@ -766,43 +771,22 @@ export class DataSelection { } if (typeof codes[0] === 'string') { const matcher = stringmatcher(key_field, codes as string[]); - this.plot.dataset.transformations[name] = + this.dataset.transformations[name] = this.wrapWithSelectionMetadata(matcher); await this.dataset.root_tile.apply_transformation(name); } else if (typeof codes[0] === 'bigint') { const matcher = bigintmatcher(key_field, codes as bigint[]); - this.plot.dataset.transformations[name] = + this.dataset.transformations[name] = this.wrapWithSelectionMetadata(matcher); await this.dataset.root_tile.apply_transformation(name); } else { console.error('Unable to match type', typeof codes[0]); } - if (options.plot_after) { - return this.apply_to_foreground({}); - } } async add_boolean_column(name: string, field: string): Promise { throw new Error('Method not implemented.'); } - - apply_to_foreground(params: DS.BackgroundOptions): Promise { - const field = this.name; - const background_options: DS.BackgroundOptions = { - size: [0.5, 10], - ...params, - }; - return this.plot.plotAPI({ - background_options, - encoding: { - foreground: { - field, - op: 'gt', - a: 0, - }, - }, - }); - } } function bigintmatcher(field: string, matches: bigint[]) { diff --git a/src/shared.d.ts b/src/shared.d.ts index befb12c50..bd4768fa1 100644 --- a/src/shared.d.ts +++ b/src/shared.d.ts @@ -134,6 +134,7 @@ export type ArrowBuildable = | Uint8Array; type MaybePromise = T | Promise; + /** * A transformation is a batchwise operation that can be used to construct * a new column in the data table. It runs asynchronously so that it diff --git a/src/tile.ts b/src/tile.ts index a9c1ef89a..ab47fe700 100644 --- a/src/tile.ts +++ b/src/tile.ts @@ -39,9 +39,15 @@ export type RecordBatchCache = let tile_identifier = 0; /** - * A Tile is, essentially, code to create an Arrow RecordBatch - * and to associate metadata with it, in the context of a larger dataset. - * + * A Tile is a collection of points in the dataset that are grouped together: + * it represents the basic unit of operation for most batched operations in + * deepscatter including network packets, GPU calculations, + * transformations on data, and render calls. It corresponds to a record batch + * of data in the Arrow format, but a tile object can be instantiated without + * having the record batch present, and includes instructions for building it. + * The Tile object also holds its own place in a tree (usually, but not always, + * a quadtree), and is responsible for certain information about all of its descendants + * in the tree as well as itself. */ export class Tile { // public max_ix = -1;