Skip to content

Commit

Permalink
feat(viz): improve domain data value handling
Browse files Browse the repository at this point in the history
- add DomainValues, DomainValueFn types
- update plot fns & processedPoints() to accept new types
- convert uniformDomain() to HOF form
- update deps & tests
  • Loading branch information
postspectacular committed Sep 12, 2020
1 parent beba35f commit ab89655
Show file tree
Hide file tree
Showing 8 changed files with 37 additions and 22 deletions.
1 change: 1 addition & 0 deletions packages/viz/package.json
Expand Up @@ -49,6 +49,7 @@
"@thi.ng/api": "^6.12.3",
"@thi.ng/arrays": "^0.7.0",
"@thi.ng/associative": "^5.0.5",
"@thi.ng/checks": "^2.7.7",
"@thi.ng/math": "^2.0.4",
"@thi.ng/strings": "^1.9.5",
"@thi.ng/transducers": "^7.3.0"
Expand Down
3 changes: 3 additions & 0 deletions packages/viz/src/api.ts
Expand Up @@ -3,6 +3,9 @@ import type { Fn, Fn2, FnN, FnU } from "@thi.ng/api";
export type Domain = number[];
export type Range = number[];

export type DomainValueFn<T = number> = Fn<Domain, Iterable<[number, T]>>;
export type DomainValues<T = number> = Iterable<[number, T]> | DomainValueFn<T>;

export type ScaleFn = FnN;

export type PlotFn = Fn<VizSpec, any>;
Expand Down
10 changes: 6 additions & 4 deletions packages/viz/src/domain.ts
Expand Up @@ -2,12 +2,14 @@ import type { Fn } from "@thi.ng/api";
import { ensureArray } from "@thi.ng/arrays";
import { mix } from "@thi.ng/math";
import { juxtR, map, max, min, transduce } from "@thi.ng/transducers";
import type { Domain } from "./api";
import type { DomainValueFn } from "./api";

export const uniformDomain = ([d1, d2]: Domain, src: Iterable<number>) => {
export const uniformDomain = (src: Iterable<number>): DomainValueFn => {
const vals = ensureArray(src);
const norm = vals.length > 1 ? 1 / (vals.length - 1) : 0;
return vals.map((x, i) => [mix(d1, d2, i * norm), x]);
return ([d1, d2]) => {
const norm = vals.length > 1 ? 1 / (vals.length - 1) : 0;
return vals.map((x, i) => [mix(d1, d2, i * norm), x]);
};
};

export const dataBounds = <T>(fn: Fn<T, number>, src: T[], pad = 0) => {
Expand Down
7 changes: 3 additions & 4 deletions packages/viz/src/plot/area.ts
@@ -1,14 +1,13 @@
import { ensureArray } from "@thi.ng/arrays";
import { map } from "@thi.ng/transducers";
import type { PlotFn } from "../api";
import type { DomainValues, PlotFn } from "../api";
import { processedPoints, valueMapper } from "./utils";

export interface AreaPlotOpts {
attribs: any;
}

export const areaPlot = (
data: Iterable<number[]>,
data: DomainValues,
opts: Partial<AreaPlotOpts> = {}
): PlotFn => (spec) => {
const $data = ensureArray(data);
Expand All @@ -19,7 +18,7 @@ export const areaPlot = (
opts.attribs || {},
[
mapper([$data[0][0], y0]),
...map((p) => p[0], processedPoints(spec, data)),
...processedPoints(spec, data, true),
mapper([$data[$data.length - 1][0], y0]),
],
];
Expand Down
7 changes: 3 additions & 4 deletions packages/viz/src/plot/line.ts
@@ -1,16 +1,15 @@
import { map } from "@thi.ng/transducers";
import type { PlotFn } from "../api";
import type { DomainValues, PlotFn } from "../api";
import { processedPoints } from "./utils";

export interface LinePlotOpts {
attribs: any;
}

export const linePlot = (
data: Iterable<number[]>,
data: DomainValues,
opts: Partial<LinePlotOpts> = {}
): PlotFn => (spec) => [
"polyline",
opts.attribs || {},
[...map((p) => p[0], processedPoints(spec, data))],
[...processedPoints(spec, data, true)],
];
6 changes: 3 additions & 3 deletions packages/viz/src/plot/scatter.ts
@@ -1,15 +1,15 @@
import type { PlotFn } from "../api";
import type { DomainValues, PlotFn } from "../api";
import { processedPoints } from "./utils";

export interface ScatterPlotOpts {
attribs: any;
}

export const scatterPlot = (
data: Iterable<number[]>,
data: DomainValues,
opts: Partial<ScatterPlotOpts> = {}
): PlotFn => (spec) => [
"points",
opts.attribs || {},
[...processedPoints(spec, data)],
[...processedPoints(spec, data, true)],
];
21 changes: 16 additions & 5 deletions packages/viz/src/plot/utils.ts
@@ -1,6 +1,7 @@
import type { Fn } from "@thi.ng/api";
import { isFunction } from "@thi.ng/checks";
import { clamp, inRange } from "@thi.ng/math";
import type { AxisSpec, VizSpec } from "../api";
import type { AxisSpec, DomainValues, VizSpec } from "../api";

/** @internal */
export const valueMapper = (
Expand All @@ -10,14 +11,24 @@ export const valueMapper = (
) => ([x, y]: number[]) => project([scaleX(x), scaleY(clamp(y, dmin, dmax))]);

/** @internal */
export function processedPoints(
{ xaxis, yaxis, project }: VizSpec,
data: DomainValues
): IterableIterator<[number[], number[]]>;
export function processedPoints(
{ xaxis, yaxis, project }: VizSpec,
data: DomainValues,
pointsOnly: true
): IterableIterator<number[]>;
export function* processedPoints(
{ xaxis, yaxis, project }: VizSpec,
data: Iterable<number[]>
) {
data: DomainValues,
pointOnly = false
): IterableIterator<any> {
const mapper = valueMapper(xaxis, yaxis, project);
const [dmin, dmax] = xaxis.domain;
for (let p of data) {
for (let p of isFunction(data) ? data(xaxis.domain) : data) {
if (!inRange(p[0], dmin, dmax)) continue;
yield <[number[], number[]]>[mapper(p), p];
yield pointOnly ? mapper(p) : [mapper(p), p];
}
}
4 changes: 2 additions & 2 deletions packages/viz/test/index.ts
Expand Up @@ -10,7 +10,7 @@ import {

describe("viz", () => {
it("uniformDomain", () => {
assert.deepStrictEqual(uniformDomain([100, 200], range(5)), [
assert.deepStrictEqual(uniformDomain(range(5))([100, 200]), [
[100, 0],
[125, 1],
[150, 2],
Expand Down Expand Up @@ -80,7 +80,7 @@ describe("viz", () => {
pos: 100,
labelAttribs: { "text-anchor": "end" },
labelOffset: [-15, 5],
major: { ticks: linearTicks(1), size: -10 },
major: { ticks: linearTicks(1) },
minor: { ticks: linearTicks(1) },
})
);
Expand Down

0 comments on commit ab89655

Please sign in to comment.