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

Improve Typing for Aesthetics and Transforms #46

Closed
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
49 changes: 26 additions & 23 deletions src/Aesthetic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import {
scaleOrdinal,
scaleSequential, scaleSequentialLog,
scaleSequentialPow,
ScaleContinuousNumeric,
ScaleIdentity,
} from 'd3-scale';
import { rgb } from 'd3-color';
import * as d3Chromatic from 'd3-scale-chromatic';
Expand All @@ -16,7 +18,8 @@ import type {
TextureSet
} from './AestheticSet';
import { isOpChannel, isLambdaChannel,
isConstantChannel } from './types';
isConstantChannel,
Transform} from './types';
import type {
OpChannel, LambdaChannel,
Channel, BasicChannel, ConstantChannel,
Expand All @@ -27,7 +30,10 @@ import { Vector } from 'apache-arrow';
import { StructRowProxy } from 'apache-arrow/row/struct';
import { QuadTile } from './tile';

const scales : { [key : string] : Function } = {
const scales: Record<
Transform,
(range?: Iterable<number>) => ScaleContinuousNumeric<number, number, never> | ScaleIdentity<never>
> = {
Comment on lines -30 to +36
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is nice, glad to see this signature clarified.

sqrt: scaleSqrt,
log: scaleLog,
linear: scaleLinear,
Expand Down Expand Up @@ -98,19 +104,17 @@ function okabe() {

okabe();

type Transform = 'log' | 'sqrt' | 'linear' | 'literal';

abstract class Aesthetic {
public abstract default_range : [number, number];
public abstract default_constant : number | [number, number, number];
public abstract default_transform : 'log' | 'sqrt' | 'linear' | 'literal';
public abstract default_transform : Transform
public scatterplot : Scatterplot;
public field: string | null = null;
public regl : Regl;
public _texture_buffer : Float32Array | Uint8Array | null = null;
public _domain : [number, number];
public _range : [number, number] | Uint8Array;
public _transform : 'log' | 'sqrt' | 'linear' | 'literal' | undefined;
public _transform : Transform | undefined;
public dataset : QuadtileSet;
public partner : Aesthetic | null = null;
public _textures : Record<string, Texture2D> = {};
Expand Down Expand Up @@ -149,14 +153,11 @@ abstract class Aesthetic {
}

get transform() {
if (this._transform) return this._transform;
return this.default_transform;
return this._transform || this.default_transform;
}

set transform(transform) {

this._transform = transform;

}

get scale() {
Expand All @@ -165,9 +166,9 @@ abstract class Aesthetic {
return r.charAt(0).toUpperCase() + r.slice(1);
}

let scale = scales[this.transform]()
.domain(this.domain)
.range(this.range);
const domain = scales[this.transform]()
.domain(this.domain) as ScaleContinuousNumeric<number, number, never>;
let scale = domain.range(this.range);

const range = this.range;

Expand Down Expand Up @@ -688,15 +689,16 @@ export const dimensions = {
y : Y
};

type concrete_aesthetics = X |
Y |
Size |
Jitter_speed |
Jitter_radius |
Color |
Filter;
type ConcreteAesthetic =
| X
| Y
| Size
| Jitter_speed
Comment on lines +692 to +696
Copy link
Collaborator

Choose a reason for hiding this comment

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

What's up with this formatting, especially the line before the first X? I'm conditioned to think of leading lines as guard rather than an OR.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's the same formatting that OCaml uses - I prefer it for multi-line union types as it keeps everything consistent.

| Jitter_radius
| Color
| Filter;

export abstract class StatefulAesthetic<T extends concrete_aesthetics> {
export abstract class StatefulAesthetic<T extends ConcreteAesthetic> {
// An aesthetic that tracks two states--current and last.
// The point is to handle transitions.
// It might make sense to handle more than two states, but there are
Expand Down Expand Up @@ -775,7 +777,7 @@ class StatefulColor extends StatefulAesthetic<Color> { get Factory() { return Co
class StatefulFilter extends StatefulAesthetic<Filter> { get Factory() { return Filter; }}
class StatefulFilter2 extends StatefulAesthetic<Filter> { get Factory() { return Filter; }}

export const stateful_aesthetics : Record<string, StatefulAesthetic<typeof Aesthetic>> = {
export const stateful_aesthetics = {
x : StatefulX,
x0 : StatefulX0,
y : StatefulY,
Expand All @@ -787,6 +789,7 @@ export const stateful_aesthetics : Record<string, StatefulAesthetic<typeof Aesth
filter : StatefulFilter,
filter2 : StatefulFilter2
};
export type StatefulAestheticSet = typeof stateful_aesthetics;

function parseLambdaString(lambdastring : string) {
// Materialize an arrow function from its string.
Expand Down Expand Up @@ -856,4 +859,4 @@ function lambda_to_function(input : LambdaChannel) : (d : any) => number {
//@ts-ignore
const func : (d : any) => number = new Function(arg, code);
return func;
}
}
25 changes: 17 additions & 8 deletions src/AestheticSet.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
/* eslint-disable no-param-reassign */
import type { Regl, Texture2D } from 'regl';
import {
StatefulAestheticSet,
stateful_aesthetics,
} from './Aesthetic';
import type Scatterplot from './deepscatter';
import type QuadtreeRoot from './tile';
import type { Encoding } from './types';
import type { StatefulAesthetic } from './Aesthetic';

type StatefulAestheticStore = {
[K in keyof StatefulAestheticSet]?: InstanceType<StatefulAestheticSet[K]>
};

export class AestheticSet {
public tileSet : QuadtreeRoot;
public scatterplot : Scatterplot;
public regl : Regl;
public encoding : Encoding;
public position_interpolation : boolean;
private store : Record<string, StatefulAesthetic<any>>;
private store : StatefulAestheticStore;
public aesthetic_map : TextureSet;
constructor(scatterplot : Scatterplot, regl : Regl, tileSet : QuadtreeRoot) {
this.scatterplot = scatterplot;
Expand All @@ -26,17 +31,21 @@ export class AestheticSet {
return this;
}

public dim(aesthetic : string) {
public dim<K extends keyof StatefulAestheticSet>(aesthetic : K): NonNullable<StatefulAestheticStore[K]> {
// Returns the stateful aesthetic corresponding to the given aesthetic.
if (this.store[aesthetic]) {
return this.store[aesthetic];
const storedAesthetic = this.store[aesthetic]!;
return storedAesthetic;
}
if (stateful_aesthetics[aesthetic] !== undefined) {
this.store[aesthetic] = new stateful_aesthetics[aesthetic](

// if (stateful_aesthetics[aesthetic] !== undefined) {
if (aesthetic in stateful_aesthetics) {
const newAesthetic = (new stateful_aesthetics[aesthetic](
this.scatterplot, this.regl, this.tileSet,
this.aesthetic_map
);
return this.store[aesthetic];
)) as NonNullable<StatefulAestheticStore[K]>;
this.store[aesthetic] = newAesthetic;
return newAesthetic;
}
throw new Error(`Unknown aesthetic ${aesthetic}`);
}
Expand Down Expand Up @@ -204,4 +213,4 @@ export class TextureSet {
});
return this._color_texture;
}
}
}
4 changes: 2 additions & 2 deletions src/Dataset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export abstract class Dataset<T extends Tile> {

map<U>(callback : (tile: T) => U, after = false) : U[] {
const results : U[] = [];
this.visit((d : T) => { results.push(callback(d)); }, after = after);
this.visit((d : T) => { results.push(callback(d)); }, after);
return results;
}

Expand Down Expand Up @@ -248,4 +248,4 @@ function check_overlap(tile : Tile, bbox : Rectangle) : number {
return disqualify;
}
return area(intersection) / area(bbox);
}
}
2 changes: 1 addition & 1 deletion src/regl_rendering.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ export class ReglRenderer extends Renderer {
const { prefs } = this;
const { transform } = this.zoom;
const { aes_to_buffer_num, buffer_num_to_variable, variable_to_buffer_num } = this.allocate_aesthetic_buffers();
console.log(prefs.arrow_table);
// console.log(prefs.arrow_table);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Feel free to just kill anything that isn't a console.warn or console.error. I would lint them out of existence except there are few cases that they're actually intentional, alas.

const props = {
// Copy the aesthetic as a string.
aes: { encoding: this.aes.encoding },
Expand Down
5 changes: 3 additions & 2 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export type ConstantChannel = {
constant : number;
};

export type Transform = 'log' | 'linear' | 'sqrt' | 'literal';

/**
* A channel represents the information necessary to map a single dimension
Expand All @@ -56,7 +57,7 @@ export interface BasicChannel {
* 'literal' maps in the implied dataspace set by 'x', 'y', while
* 'linear' transforms the data by the range and domain.
*/
transform? : 'log' | 'linear' | 'sqrt' | 'literal';
transform? : Transform;
// The domain over which the data extends
domain? : [number, number];
// The range into which to map the data.
Expand Down Expand Up @@ -167,4 +168,4 @@ export function isLambdaChannel(input: Channel): input is LambdaChannel {

export function isConstantChannel(input: Channel): input is ConstantChannel {
return (input as ConstantChannel).constant !== undefined;
}
}