Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow subfield access #141

Closed
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
3 changes: 3 additions & 0 deletions src/Deeptable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,9 @@ export class Deeptable {
this.root_tile = new Tile(defaultManifest, null, this);
const preProcessRootTile = this.root_tile.preprocessRootTileInfo();

// At instantiation, the deeptable isn't ready; only once this
// async stuff is done can the deeptable be used.
// TODO: Add an async static method as the preferred initialization method.
this.promise = preProcessRootTile.then(async () => {
const batch = await this.root_tile.get_arrow(null);
const schema = batch.schema;
Expand Down
44 changes: 37 additions & 7 deletions src/aesthetics/Aesthetic.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import type { TextureSet } from './AestheticSet';
import { isConstantChannel } from '../typing';
import { Type, Vector } from 'apache-arrow';
import { Struct, Type, Vector } from 'apache-arrow';
import { StructRowProxy } from 'apache-arrow/row/struct';
import { isNumber } from 'lodash';
import type * as DS from '../types';
import { Scatterplot } from '../scatterplot';
import { Some } from '../utilityFunctions';

/**
* An Aesthetic bundles all operations in mapping from user dataspace to webGL based aesthetics.
Expand All @@ -26,6 +27,7 @@ export abstract class Aesthetic<
public abstract default_range: [Output['rangeType'], Output['rangeType']];
public scatterplot: Scatterplot;
public field: string | null = null;
public subfield: string[] = [];
public _texture_buffer: Float32Array | Uint8Array | null = null;
protected abstract _func?: (d: Input['domainType']) => Output['rangeType'];
public aesthetic_map: TextureSet;
Expand Down Expand Up @@ -76,9 +78,25 @@ export abstract class Aesthetic<
this.field = null;
} else {
this.field = encoding.field;
if (encoding.subfield) {
this.subfield = Array.isArray(encoding.subfield)
? encoding.subfield
: [encoding.subfield];
}
}
}

/**
* Returns the keys that are used to access the data in the record batch,
* including with any nesting.
*/
get columnKeys(): null | Some<string> {
if (this.field === null) {
return null;
}
return [this.field, ...this.subfield] as Some<string>;
}

get deeptable() {
return this.scatterplot.deeptable;
}
Expand All @@ -100,10 +118,14 @@ export abstract class Aesthetic<

value_for(point: Datum): Input['domainType'] | null {
if (this.field && point[this.field]) {
return point[this.field] as Input['domainType'];
let v = point[this.field] as Input['domainType'];
for (let i = 0; i < this.subfield.length; i++) {
v = v[this.subfield[i]] as Input['domainType'];
}
return v;
Copy link

Choose a reason for hiding this comment

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

Unreachable code after return v; in value_for method. Remove the redundant return null; statement.

Copy link

Choose a reason for hiding this comment

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

Redundant return statement. Remove the line after return v;.

// Needs a default perhaps?
return null;
}
bmschmidt marked this conversation as resolved.
Show resolved Hide resolved
// Needs a default perhaps?
return null;
}

get map_position() {
Expand Down Expand Up @@ -136,9 +158,17 @@ export abstract class Aesthetic<
if (this.field === null || this.field === undefined) {
return (this.column = null);
}
return (this.column = this.deeptable.root_tile.record_batch.getChild(
this.field,
) as Vector<Input['arrowType']>);
let output: Vector<Input['arrowType']> | Vector<Struct> | null = null;
for (const f of [this.field, ...this.subfield]) {
if (output === null) {
output = this.deeptable.root_tile.record_batch.getChild(f) as Vector<
Input['arrowType']
>;
} else {
output = (output as Vector<Struct>).getChild(f) as Vector<Struct>;
}
}
return (this.column = output as Vector<Input['arrowType']>);
}

is_dictionary(): boolean {
Expand Down
18 changes: 18 additions & 0 deletions src/aesthetics/AestheticSet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type { Deeptable } from '../Deeptable';
import { StatefulAesthetic } from './StatefulAesthetic';
import type { Encoding } from '../types';
import type * as DS from '../types';
import { TupleSet } from '../utilityFunctions';

type AesMap = {
[K in keyof typeof dimensions]: StatefulAesthetic<
Expand Down Expand Up @@ -83,6 +84,12 @@ export class AestheticSet {
}
}

_neededFields: TupleSet<string> = new TupleSet();

get neededFields(): string[][] {
return [...this._neededFields.values()];
}

apply_encoding(encoding: Encoding) {
if (
encoding['jitter_radius'] &&
Expand All @@ -107,6 +114,17 @@ export class AestheticSet {
this.dim(k).update(encoding[k] as DS.ChannelType | null);
}

// Update the needed fields.
this._neededFields.clear();

for (const v of Object.values(this.store)) {
if (v instanceof StatefulAesthetic) {
for (const f of v.neededFields) {
this._neededFields.add(f);
}
}
}

// Apply settings that are not full-on aesthetics.
for (const setting of ['jitter_method'] as const) {
this.options[setting].last = this.options[setting].current;
Expand Down
8 changes: 5 additions & 3 deletions src/aesthetics/StatefulAesthetic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export type ConcreteScaledAesthetic =
import type { Deeptable } from '../Deeptable';
import type { Regl } from 'regl';
import type { TextureSet } from './AestheticSet';
import { Some } from '../utilityFunctions';

export class StatefulAesthetic<T extends ConcreteAesthetic> {
/**
Expand Down Expand Up @@ -97,11 +98,12 @@ export class StatefulAesthetic<T extends ConcreteAesthetic> {
] as [T, T];
}

get neededFields(): string[] {
return [this.current.field, this.last.field].filter(
get neededFields(): Some<string>[] {
return [this.current.columnKeys, this.last.columnKeys].filter(
(f) => f !== null,
) as string[];
);
}

get current() {
return this.states[0];
}
Expand Down
Loading