Skip to content

Commit

Permalink
move selections to datasets from scatterplots
Browse files Browse the repository at this point in the history
  • Loading branch information
bmschmidt committed May 15, 2024
1 parent eede8dd commit 3021f00
Show file tree
Hide file tree
Showing 9 changed files with 295 additions and 196 deletions.
161 changes: 90 additions & 71 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"d3-timer": "^3.0.1",
"d3-transition": "^3.0.1",
"d3-zoom": "^3.0.0",
"deepscatter": "^3.0.0-next.6",
"glsl-easings": "^1.0.0",
"glsl-fast-gaussian-blur": "^1.0.2",
"glsl-read-float": "^1.1.0",
Expand Down
102 changes: 80 additions & 22 deletions src/Dataset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ import {
} from 'apache-arrow';
import { Scatterplot } from './scatterplot';
import { wrapArrowTable } from './wrap_arrow';
import type {
BooleanColumnParams,
CompositeSelectParams,
FunctionSelectParams,
IdSelectParams,
} from './selection';
import { DataSelection } from './selection';

type TransformationStatus = 'queued' | 'in progress' | 'complete' | 'failed';

Expand Down Expand Up @@ -76,39 +83,41 @@ export class Dataset {
func: () => Promise<void>;
// The status of the transformation.
status: TransformationStatus;
// The urgency of the transformation.
// The urgency of the transformation. This vocabulary may be extended over time.
priority: 'high' | 'low';
// An optional resolve function to call when the call is complete.
resolve?: () => void;
}> = new Set();
public selection_history: DS.SelectionRecord[] = [];

public promise: Promise<void>;
public root_tile: Tile;
public manifest?: DS.TileManifest;
public fetcherId?: number;
private _downloaderId?: number;
// Whether the tileset is structured as a pure quadtree.

public readonly tileStucture: DS.TileStructure = 'quadtree';
public readonly tileStucture: DS.TileStructure;
/**
* @param plot The plot to which this dataset belongs.
**/

constructor(
base_url: string,
plot: Scatterplot | null = null,
options: DS.DatasetOptions = {},
) {
constructor({
// Required
plot, // note--may be null.
baseUrl,
// optional
tileProxy,
extent,
tileManifest,
// optional with non-undefined defaults.
rootKey = '0/0/0',
tileStructure = 'quadtree',
}: DS.DatasetCreateParams) {
this._plot = plot;
this.tileProxy = options.tileProxy;

const rootKey = options['rootKey'] || '0/0/0';
if (options.tileStructure) {
this.tileStucture = options.tileStructure;
}

if (options.extent) {
this._extent = options.extent;
}
this.tileProxy = tileProxy;
this.tileStucture = tileStructure;
this._extent = extent;

// If no manifest is passed, we still know
// that there is a root tile at the root key.
Expand All @@ -118,10 +127,10 @@ export class Dataset {
children: undefined,
min_ix: 0,
max_ix: Number.MAX_SAFE_INTEGER,
...(options.tileManifest || {}),
...(tileManifest || {}),
};
// Must come after manifest is set.
this.base_url = base_url;
this.base_url = baseUrl;
this.root_tile = new Tile(defaultManifest, null, this);
const preProcessRootTile = this.root_tile.preprocessRootTileInfo();

Expand Down Expand Up @@ -265,12 +274,17 @@ export class Dataset {
);
}

static from_quadfeather(url: string, plot: Scatterplot): Dataset {
const options: Partial<DS.DatasetOptions> = {};
static from_quadfeather(url: string, plot: Scatterplot | null): Dataset {
const options: Partial<DS.DatasetCreateParams> = {};
if (plot.tileProxy) {
options['tileProxy'] = plot.tileProxy;
}
return new Dataset(url, plot, options);
return new Dataset({
tileProxy: plot.tileProxy ? plot.tileProxy : undefined,
baseUrl: url,
rootKey: '0/0/0',
plot,
});
}

/**
Expand Down Expand Up @@ -730,6 +744,50 @@ export class Dataset {
}
}

/**
*
* @param params A set of parameters for selecting data based on ids, a boolean column, or a function.
* @returns A DataSelection object that can be used to extend the selection.
*
* See `select_and_plot` for a method that will select data and plot it.
*/
async select_data(
params:
| IdSelectParams
| BooleanColumnParams
| FunctionSelectParams
| CompositeSelectParams,
): Promise<DataSelection> {
if (
params.useNameCache &&
params.name &&
this.selection_history.length > 0
) {
const old_version = this.selection_history.find(
(x) => x.name === params.name,
);
// If we have a cached version, move the cached version to the end and return it.
if (old_version) {
this.selection_history = [
...this.selection_history.filter((x) => x.name !== params.name),
old_version,
];
// type safety only.
if (old_version.selection !== null) {
return old_version.selection;
}
}
}
const selection = new DataSelection(this, params);
this.selection_history.push({
selection,
name: selection.name,
flushed: false,
});
await selection.ready;
return selection;
}

/**
* Flushes the transformation queue.
*/
Expand Down
1 change: 1 addition & 0 deletions src/aesthetics/Aesthetic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export abstract class Aesthetic<
public _texture_buffer: Float32Array | Uint8Array | null = null;
protected abstract _func?: (d: Input['domainType']) => Output['rangeType'];
public aesthetic_map: TextureSet;
// TODO strict: @ts-expect-error We know this column is set to null if it doesn't exist.
public column: Vector<Input['arrowType']> | null = null;

// cache of the d3 scale
Expand Down
91 changes: 22 additions & 69 deletions src/scatterplot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import { isURLLabels, isLabelset } from './typing';
import { DataSelection } from './selection';
import type {
BooleanColumnParams,
CompositeSelectParams,
FunctionSelectParams,
IdSelectParams,
} from './selection';
Expand Down Expand Up @@ -63,7 +62,6 @@ export class Scatterplot {
public _root?: Dataset;
public elements?: Selection<SVGElement, unknown, Element, unknown>[];
public secondary_renderers: Record<string, Renderer> = {};
public selection_history: DS.SelectionRecord[] = [];
public tileProxy?: DS.TileProxy;
public div?: Selection<BaseType | HTMLDivElement, number, BaseType, unknown>;
public bound: boolean;
Expand Down Expand Up @@ -207,7 +205,7 @@ export class Scatterplot {
params: IdSelectParams | BooleanColumnParams | FunctionSelectParams,
duration = this.prefs.duration,
): Promise<DataSelection> {
const selection = await this.select_data(params);
const selection = await this.dataset.select_data(params);
if (selection === null) {
throw new Error(`Invalid selection: ${JSON.stringify(params)}`);
}
Expand All @@ -224,46 +222,6 @@ export class Scatterplot {
});
return selection;
}
/**
*
* @param params A set of parameters for selecting data based on ids, a boolean column, or a function.
* @returns A DataSelection object that can be used to extend the selection.
*
* See `select_and_plot` for a method that will select data and plot it.
*/
async select_data(
params:
| IdSelectParams
| BooleanColumnParams
| FunctionSelectParams
| CompositeSelectParams,
) {
if (
params.useNameCache &&
params.name &&
this.selection_history.length > 0
) {
const old_version = this.selection_history.find(
(x) => x.name === params.name,
);
// If we have a cached version, move the cached version to the end and return it.
if (old_version) {
this.selection_history = [
...this.selection_history.filter((x) => x.name !== params.name),
old_version,
];
return old_version.selection;
}
}
const selection = new DataSelection(this.dataset, params);
this.selection_history.push({
selection,
name: selection.name,
flushed: false,
});
await selection.ready;
return selection;
}

/**
*
Expand Down Expand Up @@ -424,7 +382,7 @@ export class Scatterplot {
HTMLDivElement,
HTMLCanvasElement
>;
const ctx = bkgd.node()!.getContext('2d');
const ctx = bkgd.node().getContext('2d');

if (ctx === null) throw new Error("Can't acquire canvas context");
ctx.fillStyle = prefs.background_color ?? 'rgba(133, 133, 111, .8)';
Expand Down Expand Up @@ -472,16 +430,16 @@ export class Scatterplot {
* loaded tiles. Useful for debugging and illustration.
*/

const canvas = this.elements![2].selectAll(
'canvas',
).node() as HTMLCanvasElement;
const canvas = this.elements[2]
.selectAll('canvas')
.node() as HTMLCanvasElement;

const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
const ctx = canvas.getContext('2d');

// as CanvasRenderingContext2D;

ctx.clearRect(0, 0, 10_000, 10_000);
const { x_, y_ } = this._zoom!.scales();
const { x_, y_ } = this._zoom.scales();
ctx.strokeStyle = '#888888';
const tiles = this.dataset.map((t) => t);
for (const i of range(20)) {
Expand Down Expand Up @@ -613,7 +571,9 @@ export class Scatterplot {
}

get label_click(): LabelClick['f'] {
return this.label_click_handler.f.bind(this.label_click_handler);
return this.label_click_handler.f.bind(
this.label_click_handler,
) as LabelClick['f'];
}

set highlit_point_change(
Expand Down Expand Up @@ -787,9 +747,15 @@ export class Scatterplot {
await this.reinitialize();
}

const renderer = this._renderer as ReglRenderer;
const zoom = this._zoom as Zoom;
this._renderer!.render_props.apply_prefs(this.prefs);
const renderer = this._renderer;
const zoom = this._zoom;

if (renderer === undefined || zoom === undefined) {
throw new Error(
'Error: plot called on scatterplot without defined renderer.',
);
}
renderer.render_props.apply_prefs(this.prefs);

const { width, height } = this;
this.update_prefs(prefs);
Expand Down Expand Up @@ -929,25 +895,12 @@ class LabelClick extends SettableFunction<void, GeoJsonProperties> {
plot: Scatterplot | undefined = undefined,
labelset: LabelMaker | undefined = undefined,
) {
let filter: DS.LambdaChannel<string, boolean> | null;
if (feature === null) {
return;
}
if (feature.__activated == true) {
filter = null;
feature.__activated = undefined;
} else {
feature.__activated = true;
const k = labelset.label_key;
const value = feature[k] as string;
filter = {
field: labelset.label_key,
lambda: (d) => d === value,
};
}
void this.plot.plotAPI({
encoding: { filter },
});
if (labelset === null) {
return;
}
}
}

Expand Down
Loading

0 comments on commit 3021f00

Please sign in to comment.