svelteplot 0.0.1-alpha.9 → 0.1.3-next.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +5 -0
- package/README.md +3 -36
- package/dist/Mark.svelte +290 -0
- package/dist/Mark.svelte.d.ts +22 -0
- package/dist/Plot.svelte +148 -156
- package/dist/Plot.svelte.d.ts +15 -15
- package/dist/constants.d.ts +14 -0
- package/dist/constants.js +109 -0
- package/dist/core/Facet.svelte +59 -0
- package/dist/core/Facet.svelte.d.ts +18 -0
- package/dist/core/FacetAxes.svelte +66 -0
- package/dist/core/FacetAxes.svelte.d.ts +4 -0
- package/dist/core/FacetGrid.svelte +86 -0
- package/dist/core/FacetGrid.svelte.d.ts +13 -0
- package/dist/core/Plot.svelte +567 -0
- package/dist/core/Plot.svelte.d.ts +14 -0
- package/dist/helpers/arrowPath.d.ts +14 -0
- package/dist/helpers/arrowPath.js +129 -0
- package/dist/helpers/autoProjection.d.ts +19 -0
- package/dist/helpers/autoProjection.js +87 -0
- package/dist/helpers/autoScales.d.ts +23 -0
- package/dist/helpers/autoScales.js +203 -0
- package/dist/helpers/autoTicks.d.ts +3 -0
- package/dist/helpers/autoTicks.js +40 -0
- package/dist/helpers/autoTimeFormat.d.ts +2 -2
- package/dist/helpers/autoTimeFormat.js +34 -5
- package/dist/helpers/callWithProps.d.ts +8 -0
- package/dist/helpers/callWithProps.js +13 -0
- package/dist/helpers/colors.js +17 -2
- package/dist/helpers/curves.d.ts +3 -0
- package/dist/helpers/curves.js +42 -0
- package/dist/helpers/data.d.ts +9 -0
- package/dist/helpers/data.js +16 -0
- package/dist/helpers/facets.d.ts +12 -0
- package/dist/helpers/facets.js +49 -0
- package/dist/helpers/formats.d.ts +3 -0
- package/dist/helpers/formats.js +3 -0
- package/dist/helpers/getBaseStyles.d.ts +7 -2
- package/dist/helpers/getBaseStyles.js +34 -10
- package/dist/helpers/getLogTicks.js +5 -5
- package/dist/helpers/group.d.ts +6 -0
- package/dist/helpers/group.js +53 -0
- package/dist/helpers/index.d.ts +18 -0
- package/dist/helpers/index.js +53 -0
- package/dist/helpers/isRawValue.d.ts +2 -0
- package/dist/helpers/isRawValue.js +5 -0
- package/dist/helpers/isValid.d.ts +6 -0
- package/dist/helpers/isValid.js +6 -0
- package/dist/helpers/math.d.ts +19 -0
- package/dist/helpers/math.js +116 -0
- package/dist/helpers/mergeDeep.d.ts +1 -1
- package/dist/helpers/noise.d.ts +1 -0
- package/dist/helpers/noise.js +72 -0
- package/dist/helpers/projection.d.ts +33 -0
- package/dist/helpers/projection.js +100 -0
- package/dist/helpers/reduce.d.ts +10 -0
- package/dist/helpers/reduce.js +85 -0
- package/dist/helpers/regressionLoess.d.ts +12 -0
- package/dist/helpers/regressionLoess.js +47 -0
- package/dist/helpers/removeIdenticalLines.d.ts +8 -1
- package/dist/helpers/removeIdenticalLines.js +14 -7
- package/dist/helpers/resolve.d.ts +17 -0
- package/dist/helpers/resolve.js +152 -0
- package/dist/helpers/roundedRect.d.ts +9 -0
- package/dist/helpers/roundedRect.js +31 -0
- package/dist/helpers/scales.d.ts +42 -0
- package/dist/helpers/scales.js +309 -0
- package/dist/helpers/time.d.ts +6 -0
- package/dist/helpers/time.js +282 -0
- package/dist/helpers/typeChecks.d.ts +8 -5
- package/dist/helpers/typeChecks.js +27 -6
- package/dist/index.d.ts +49 -1
- package/dist/index.js +53 -2
- package/dist/marks/Area.svelte +146 -0
- package/dist/marks/Area.svelte.d.ts +30 -0
- package/dist/marks/AreaX.svelte +27 -0
- package/dist/marks/AreaX.svelte.d.ts +12 -0
- package/dist/marks/AreaY.svelte +38 -0
- package/dist/marks/AreaY.svelte.d.ts +19 -0
- package/dist/marks/Arrow.svelte +139 -0
- package/dist/marks/Arrow.svelte.d.ts +44 -0
- package/dist/marks/AxisX.svelte +198 -93
- package/dist/marks/AxisX.svelte.d.ts +17 -16
- package/dist/marks/AxisY.svelte +176 -62
- package/dist/marks/AxisY.svelte.d.ts +17 -14
- package/dist/marks/BarX.svelte +81 -0
- package/dist/marks/BarX.svelte.d.ts +4 -0
- package/dist/marks/BarY.svelte +95 -0
- package/dist/marks/BarY.svelte.d.ts +4 -0
- package/dist/marks/BollingerX.svelte +44 -0
- package/dist/marks/BollingerX.svelte.d.ts +18 -0
- package/dist/marks/BollingerY.svelte +39 -0
- package/dist/marks/BollingerY.svelte.d.ts +18 -0
- package/dist/marks/BoxX.svelte +89 -0
- package/dist/marks/BoxX.svelte.d.ts +4 -0
- package/dist/marks/BoxY.svelte +110 -0
- package/dist/marks/BoxY.svelte.d.ts +29 -0
- package/dist/marks/Cell.svelte +110 -0
- package/dist/marks/Cell.svelte.d.ts +16 -0
- package/dist/marks/CellX.svelte +24 -0
- package/dist/marks/CellX.svelte.d.ts +3 -0
- package/dist/marks/CellY.svelte +24 -0
- package/dist/marks/CellY.svelte.d.ts +3 -0
- package/dist/marks/ColorLegend.svelte +148 -27
- package/dist/marks/ColorLegend.svelte.d.ts +12 -13
- package/dist/marks/CustomMark.svelte +43 -0
- package/dist/marks/CustomMark.svelte.d.ts +16 -0
- package/dist/marks/CustomMarkHTML.svelte +103 -0
- package/dist/marks/CustomMarkHTML.svelte.d.ts +17 -0
- package/dist/marks/DifferenceY.svelte +144 -0
- package/dist/marks/DifferenceY.svelte.d.ts +30 -0
- package/dist/marks/Dot.svelte +128 -73
- package/dist/marks/Dot.svelte.d.ts +24 -14
- package/dist/marks/DotX.svelte +15 -3
- package/dist/marks/DotX.svelte.d.ts +8 -16
- package/dist/marks/DotY.svelte +8 -3
- package/dist/marks/DotY.svelte.d.ts +5 -17
- package/dist/marks/Frame.svelte +32 -31
- package/dist/marks/Frame.svelte.d.ts +7 -14
- package/dist/marks/Geo.svelte +102 -0
- package/dist/marks/Geo.svelte.d.ts +10 -0
- package/dist/marks/Graticule.svelte +28 -0
- package/dist/marks/Graticule.svelte.d.ts +9 -0
- package/dist/marks/GridX.svelte +67 -36
- package/dist/marks/GridX.svelte.d.ts +7 -18
- package/dist/marks/GridY.svelte +64 -25
- package/dist/marks/GridY.svelte.d.ts +7 -14
- package/dist/marks/HTMLTooltip.svelte +91 -0
- package/dist/marks/HTMLTooltip.svelte.d.ts +11 -0
- package/dist/marks/Line.svelte +219 -58
- package/dist/marks/Line.svelte.d.ts +30 -14
- package/dist/marks/LineX.svelte +8 -8
- package/dist/marks/LineX.svelte.d.ts +4 -17
- package/dist/marks/LineY.svelte +7 -8
- package/dist/marks/LineY.svelte.d.ts +4 -17
- package/dist/marks/Link.svelte +173 -0
- package/dist/marks/Link.svelte.d.ts +21 -0
- package/dist/marks/Pointer.svelte +126 -0
- package/dist/marks/Pointer.svelte.d.ts +23 -0
- package/dist/marks/Rect.svelte +103 -0
- package/dist/marks/Rect.svelte.d.ts +15 -0
- package/dist/marks/RectX.svelte +33 -0
- package/dist/marks/RectX.svelte.d.ts +15 -0
- package/dist/marks/RectY.svelte +33 -0
- package/dist/marks/RectY.svelte.d.ts +15 -0
- package/dist/marks/RegressionX.svelte +26 -0
- package/dist/marks/RegressionX.svelte.d.ts +4 -0
- package/dist/marks/RegressionY.svelte +26 -0
- package/dist/marks/RegressionY.svelte.d.ts +4 -0
- package/dist/marks/RuleX.svelte +52 -28
- package/dist/marks/RuleX.svelte.d.ts +14 -14
- package/dist/marks/RuleY.svelte +52 -28
- package/dist/marks/RuleY.svelte.d.ts +14 -14
- package/dist/marks/Sphere.svelte +8 -0
- package/dist/marks/Sphere.svelte.d.ts +51 -0
- package/dist/marks/Spike.svelte +15 -0
- package/dist/marks/Spike.svelte.d.ts +4 -0
- package/dist/marks/SymbolLegend.svelte +27 -12
- package/dist/marks/SymbolLegend.svelte.d.ts +8 -14
- package/dist/marks/Text.svelte +185 -0
- package/dist/marks/Text.svelte.d.ts +26 -0
- package/dist/marks/TickX.svelte +89 -0
- package/dist/marks/TickX.svelte.d.ts +22 -0
- package/dist/marks/TickY.svelte +90 -0
- package/dist/marks/TickY.svelte.d.ts +22 -0
- package/dist/marks/Vector.svelte +213 -0
- package/dist/marks/Vector.svelte.d.ts +31 -0
- package/dist/marks/helpers/BaseAxisX.svelte +210 -0
- package/dist/marks/helpers/BaseAxisX.svelte.d.ts +24 -0
- package/dist/marks/helpers/BaseAxisY.svelte +187 -0
- package/dist/marks/helpers/BaseAxisY.svelte.d.ts +23 -0
- package/dist/marks/helpers/CanvasLayer.svelte +38 -0
- package/dist/marks/helpers/CanvasLayer.svelte.d.ts +13 -0
- package/dist/marks/helpers/DotCanvas.svelte +184 -0
- package/dist/marks/helpers/DotCanvas.svelte.d.ts +11 -0
- package/dist/marks/helpers/GeoCanvas.svelte +165 -0
- package/dist/marks/helpers/GeoCanvas.svelte.d.ts +13 -0
- package/dist/marks/helpers/GroupMultiple.svelte +17 -0
- package/dist/marks/helpers/GroupMultiple.svelte.d.ts +9 -0
- package/dist/marks/helpers/Marker.svelte +93 -0
- package/dist/marks/helpers/Marker.svelte.d.ts +10 -0
- package/dist/marks/helpers/MarkerPath.svelte +164 -0
- package/dist/marks/helpers/MarkerPath.svelte.d.ts +44 -0
- package/dist/marks/helpers/Regression.svelte +174 -0
- package/dist/marks/helpers/Regression.svelte.d.ts +26 -0
- package/dist/marks/helpers/events.d.ts +8 -0
- package/dist/marks/helpers/events.js +64 -0
- package/dist/transforms/bin.d.ts +51 -0
- package/dist/transforms/bin.js +171 -0
- package/dist/transforms/bollinger.d.ts +21 -0
- package/dist/transforms/bollinger.js +53 -0
- package/dist/transforms/centroid.d.ts +9 -0
- package/dist/transforms/centroid.js +13 -0
- package/dist/transforms/facet.d.ts +1 -0
- package/dist/transforms/facet.js +1 -0
- package/dist/transforms/filter.d.ts +2 -0
- package/dist/transforms/filter.js +8 -0
- package/dist/transforms/group.d.ts +66 -0
- package/dist/transforms/group.js +109 -0
- package/dist/transforms/interval.d.ts +11 -0
- package/dist/transforms/interval.js +34 -0
- package/dist/transforms/jitter.d.ts +0 -0
- package/dist/transforms/jitter.js +1 -0
- package/dist/transforms/map.d.ts +10 -0
- package/dist/transforms/map.js +89 -0
- package/dist/transforms/normalize.d.ts +9 -0
- package/dist/transforms/normalize.js +86 -0
- package/dist/transforms/recordize.d.ts +13 -0
- package/dist/transforms/recordize.js +75 -0
- package/dist/transforms/rename.d.ts +14 -0
- package/dist/transforms/rename.js +42 -0
- package/dist/transforms/select.d.ts +35 -0
- package/dist/transforms/select.js +55 -0
- package/dist/transforms/shift.d.ts +13 -0
- package/dist/transforms/shift.js +45 -0
- package/dist/transforms/sort.d.ts +28 -0
- package/dist/transforms/sort.js +61 -0
- package/dist/transforms/stack.d.ts +10 -0
- package/dist/transforms/stack.js +110 -0
- package/dist/transforms/window.d.ts +22 -0
- package/dist/transforms/window.js +73 -0
- package/dist/types.d.ts +625 -188
- package/dist/ui/Checkbox.svelte +6 -0
- package/dist/ui/Checkbox.svelte.d.ts +13 -0
- package/dist/ui/RadioInput.svelte +27 -0
- package/dist/ui/RadioInput.svelte.d.ts +9 -0
- package/dist/ui/Select.svelte +27 -0
- package/dist/ui/Select.svelte.d.ts +9 -0
- package/dist/ui/Slider.svelte +47 -0
- package/dist/ui/Slider.svelte.d.ts +11 -0
- package/dist/ui/Spiral.svelte +46 -0
- package/dist/ui/Spiral.svelte.d.ts +15 -0
- package/dist/ui/index.d.ts +4 -0
- package/dist/ui/index.js +4 -0
- package/package.json +79 -40
- package/LICENSE +0 -11
- package/dist/classes/Channel.svelte.js +0 -74
- package/dist/classes/Mark.svelte.js +0 -17
- package/dist/classes/Plot.svelte.js +0 -98
- package/dist/contants.d.ts +0 -3
- package/dist/contants.js +0 -40
- package/dist/helpers/GroupMultiple.svelte +0 -8
- package/dist/helpers/GroupMultiple.svelte.d.ts +0 -19
- package/dist/helpers/createScale.d.ts +0 -5
- package/dist/helpers/createScale.js +0 -57
- package/dist/helpers/resolveChannel.d.ts +0 -2
- package/dist/helpers/resolveChannel.js +0 -28
- package/dist/helpers/wrapArray.d.ts +0 -2
- package/dist/helpers/wrapArray.js +0 -4
- package/dist/marks/BaseMark.svelte +0 -22
- package/dist/marks/BaseMark.svelte.d.ts +0 -19
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { geoClipRectangle, geoPath, geoTransform } from 'd3-geo';
|
|
2
|
+
import { constant, isObject, isValid } from './index.js';
|
|
3
|
+
const identity = constant({ stream: (stream) => stream });
|
|
4
|
+
const defaultAspectRatio = 0.618;
|
|
5
|
+
export function createProjection({ projOptions, inset: globalInset = 2, insetTop = globalInset, insetRight = globalInset, insetBottom = globalInset, insetLeft = globalInset } = {}, dimensions) {
|
|
6
|
+
// no projection defined
|
|
7
|
+
if (projOptions == null)
|
|
8
|
+
return;
|
|
9
|
+
// projection function passed as projection option
|
|
10
|
+
if (typeof projOptions.stream === 'function')
|
|
11
|
+
return projOptions; // d3 projection
|
|
12
|
+
let options;
|
|
13
|
+
let domain;
|
|
14
|
+
let clip = 'frame';
|
|
15
|
+
// If the projection was specified as an object with additional options,
|
|
16
|
+
// extract those. The order of precedence for insetTop (and other insets) is:
|
|
17
|
+
// projection.insetTop, projection.inset, (global) insetTop, (global) inset.
|
|
18
|
+
// Any other options on this object will be passed through to the initializer.
|
|
19
|
+
if (isObject(projOptions)) {
|
|
20
|
+
let inset;
|
|
21
|
+
({
|
|
22
|
+
type: projOptions,
|
|
23
|
+
domain,
|
|
24
|
+
inset,
|
|
25
|
+
insetTop = inset !== undefined ? inset : insetTop,
|
|
26
|
+
insetRight = inset !== undefined ? inset : insetRight,
|
|
27
|
+
insetBottom = inset !== undefined ? inset : insetBottom,
|
|
28
|
+
insetLeft = inset !== undefined ? inset : insetLeft,
|
|
29
|
+
clip = clip,
|
|
30
|
+
...options
|
|
31
|
+
} = projOptions);
|
|
32
|
+
if (projOptions == null)
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
// let projFactory;
|
|
36
|
+
let aspectRatio = defaultAspectRatio;
|
|
37
|
+
const projFactory = projOptions;
|
|
38
|
+
// Compute the frame dimensions and invoke the projection initializer.
|
|
39
|
+
const { width, height, marginLeft, marginRight, marginTop, marginBottom } = dimensions;
|
|
40
|
+
const dx = width - marginLeft - marginRight - insetLeft - insetRight;
|
|
41
|
+
const dy = height - marginTop - marginBottom - insetTop - insetBottom;
|
|
42
|
+
const projInstance = projFactory?.({ width: dx, height: dy, clip, ...options });
|
|
43
|
+
// The projection initializer might decide to not use a projection.
|
|
44
|
+
if (projInstance == null)
|
|
45
|
+
return;
|
|
46
|
+
clip = maybePostClip(clip, marginLeft, marginTop, width - marginRight, height - marginBottom);
|
|
47
|
+
// Translate the origin to the top-left corner, respecting margins and insets.
|
|
48
|
+
let tx = marginLeft + insetLeft;
|
|
49
|
+
let ty = marginTop + insetTop;
|
|
50
|
+
let transform;
|
|
51
|
+
let invertTransform = (d) => d;
|
|
52
|
+
// If a domain is specified, fit the projection to the frame.
|
|
53
|
+
if (domain != null) {
|
|
54
|
+
const [[x0, y0], [x1, y1]] = geoPath(projInstance).bounds(domain);
|
|
55
|
+
const k = Math.min(dx / (x1 - x0), dy / (y1 - y0));
|
|
56
|
+
aspectRatio = (y1 - y0) / (x1 - x0);
|
|
57
|
+
// aspectRatio = 1/k;
|
|
58
|
+
if (k > 0) {
|
|
59
|
+
tx -= (k * (x0 + x1) - dx) / 2;
|
|
60
|
+
ty -= (k * (y0 + y1) - dy) / 2;
|
|
61
|
+
transform = geoTransform({
|
|
62
|
+
point(x, y) {
|
|
63
|
+
this.stream.point(x * k + tx, y * k + ty);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
invertTransform = ([x, y]) => [(x - tx) / k, (y - ty) / k];
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
throw new Error(`Warning: the projection could not be fit to the specified domain; using the default scale.`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
transform ??=
|
|
73
|
+
tx === 0 && ty === 0
|
|
74
|
+
? identity()
|
|
75
|
+
: geoTransform({
|
|
76
|
+
point(x, y) {
|
|
77
|
+
this.stream.point(x + tx, y + ty);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
invertTransform ??= ([x, y]) => [x - tx, y - ty];
|
|
81
|
+
return {
|
|
82
|
+
aspectRatio,
|
|
83
|
+
invert([x, y]) {
|
|
84
|
+
return projInstance.invert(invertTransform([x, y]));
|
|
85
|
+
},
|
|
86
|
+
stream: (s) => projInstance.stream(transform.stream(clip(s)))
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
function maybePostClip(clip, x1, y1, x2, y2) {
|
|
90
|
+
if (clip === false || clip == null || typeof clip === 'number')
|
|
91
|
+
return (s) => s;
|
|
92
|
+
if (clip === true)
|
|
93
|
+
clip = 'frame';
|
|
94
|
+
switch (`${clip}`.toLowerCase()) {
|
|
95
|
+
case 'frame':
|
|
96
|
+
return geoClipRectangle(x1, y1, x2, y2);
|
|
97
|
+
default:
|
|
98
|
+
throw new Error(`unknown projection clip type: ${clip}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ChannelName, Channels, DataRecord, DataRow, RawValue } from '../types.js';
|
|
2
|
+
type ReducerFunc = (group: Iterable<DataRow>) => RawValue;
|
|
3
|
+
type ReducerOption = ReducerName | ReducerFunc;
|
|
4
|
+
type Digit = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
|
|
5
|
+
export type ReducerPercentile = (`p${Digit}${Digit}` & Record<never, never>) | 'p25' | 'p50' | 'p75';
|
|
6
|
+
export type ReducerName = 'count' | 'deviation' | 'difference' | 'first' | 'last' | 'max' | 'mean' | 'median' | 'min' | 'mode' | 'ratio' | 'sum' | 'variance' | ReducerPercentile;
|
|
7
|
+
export declare const Reducer: Record<ReducerName, ReducerFunc>;
|
|
8
|
+
export declare function mayberReducer(r: ReducerOption): ReducerFunc;
|
|
9
|
+
export declare function reduceOutputs(newDatum: DataRecord, data: DataRecord[], options: Record<ChannelName, ReducerOption>, outputs: Iterable<ChannelName>, channels: Channels, newChannels: Channels): void;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { min, max, mode, sum, mean, median, variance, deviation, quantile, range } from 'd3-array';
|
|
2
|
+
import { resolveChannel } from './resolve.js';
|
|
3
|
+
import { POSITION_CHANNELS } from './index.js';
|
|
4
|
+
const niceReduceNames = {
|
|
5
|
+
count: 'Frequency',
|
|
6
|
+
deviation: 'Standard Deviation',
|
|
7
|
+
mean: 'Average'
|
|
8
|
+
};
|
|
9
|
+
const StaticReducer = {
|
|
10
|
+
count: (d) => Array.from(d).length,
|
|
11
|
+
min,
|
|
12
|
+
max,
|
|
13
|
+
mode,
|
|
14
|
+
sum,
|
|
15
|
+
mean,
|
|
16
|
+
median,
|
|
17
|
+
identity: (d) => d,
|
|
18
|
+
variance,
|
|
19
|
+
deviation,
|
|
20
|
+
first: (d) => d[0],
|
|
21
|
+
last: (d) => d.at(-1),
|
|
22
|
+
difference: (d) => d.at(-1) - d[0],
|
|
23
|
+
ratio: (d) => d.at(-1) / d[0]
|
|
24
|
+
// TODO: proportion
|
|
25
|
+
// TODO: proportion-facet
|
|
26
|
+
// TODO: min-index
|
|
27
|
+
// TODO: max-index
|
|
28
|
+
};
|
|
29
|
+
// use proxy to allow for percentile reducers
|
|
30
|
+
export const Reducer = new Proxy(StaticReducer, {
|
|
31
|
+
get(target, prop) {
|
|
32
|
+
if (String(prop).charAt(0) === 'p' && String(prop).length === 3) {
|
|
33
|
+
const p = +String(prop).slice(1) / 100;
|
|
34
|
+
return percentile(p);
|
|
35
|
+
}
|
|
36
|
+
return Reflect.get(target, prop);
|
|
37
|
+
},
|
|
38
|
+
has(target, prop) {
|
|
39
|
+
if (String(prop).charAt(0) === 'p' && String(prop).length === 3) {
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
return Reflect.has(target, prop);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
function percentile(p) {
|
|
46
|
+
return (I, f) => quantile(I, p, f);
|
|
47
|
+
}
|
|
48
|
+
function isReducerName(r) {
|
|
49
|
+
return typeof r === 'string' && r in Reducer;
|
|
50
|
+
}
|
|
51
|
+
export function mayberReducer(r) {
|
|
52
|
+
if (typeof r === 'function')
|
|
53
|
+
return r;
|
|
54
|
+
if (typeof r === 'string' && isReducerName(r)) {
|
|
55
|
+
return Reducer[r];
|
|
56
|
+
}
|
|
57
|
+
throw new Error('unknown reducer ' + r);
|
|
58
|
+
}
|
|
59
|
+
export function reduceOutputs(newDatum, data, options, outputs, channels, newChannels) {
|
|
60
|
+
for (const k of outputs) {
|
|
61
|
+
if (options[k] != null) {
|
|
62
|
+
const values = channels[k] == null ? data : data.map((d) => resolveChannel(k, d, channels));
|
|
63
|
+
const reducer = mayberReducer(options[k]);
|
|
64
|
+
newDatum[`__${k}`] = reducer(values);
|
|
65
|
+
newChannels[k] = `__${k}`;
|
|
66
|
+
if (typeof options[k] === 'string') {
|
|
67
|
+
const reducerName = niceReduceNames[options[k]] ??
|
|
68
|
+
`${String(options[k]).charAt(0).toUpperCase()}${String(options[k]).slice(1)}`;
|
|
69
|
+
// we have a named reducer like 'count', so let's try to preserve the
|
|
70
|
+
// source channel mapping for axis labels
|
|
71
|
+
if (POSITION_CHANNELS.has(k)) {
|
|
72
|
+
if (typeof channels[k] === 'string') {
|
|
73
|
+
// the named reducer is applied to a column name, so we can use a combination
|
|
74
|
+
// of both as axis labels, e.g. MEAN(weight)
|
|
75
|
+
// eslint-disable-next-line no-irregular-whitespace
|
|
76
|
+
newChannels[`__${k}_origField`] = `${reducerName} ( ${channels[k]} )`;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
newChannels[`__${k}_origField`] = reducerName;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { DataRow } from '../types.js';
|
|
2
|
+
type AccessorFn = (d: any) => number;
|
|
3
|
+
export default function (): {
|
|
4
|
+
(data: DataRow[]): {
|
|
5
|
+
predict(x: number): any;
|
|
6
|
+
predictMany(x: number[]): any;
|
|
7
|
+
};
|
|
8
|
+
x(_: AccessorFn): void;
|
|
9
|
+
y(_: AccessorFn): void;
|
|
10
|
+
span(_: number): void;
|
|
11
|
+
};
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import Loess from 'loess';
|
|
2
|
+
function toNumber(d) {
|
|
3
|
+
if (typeof d.getTime === 'function')
|
|
4
|
+
return d.getTime();
|
|
5
|
+
return d;
|
|
6
|
+
}
|
|
7
|
+
export default function () {
|
|
8
|
+
let accessX = (d) => d[0];
|
|
9
|
+
let accessY = (d) => d[1];
|
|
10
|
+
let span = 0.75;
|
|
11
|
+
// const degree = 2;
|
|
12
|
+
const fn = (data) => {
|
|
13
|
+
const filteredData = data
|
|
14
|
+
.map((d) => ({
|
|
15
|
+
x: toNumber(accessX(d)),
|
|
16
|
+
y: accessY(d)
|
|
17
|
+
}))
|
|
18
|
+
.filter((d) => Number.isFinite(d.x) && Number.isFinite(d.y));
|
|
19
|
+
// .sort((a,b) => a.x - b.x);
|
|
20
|
+
// compute loess regression for data
|
|
21
|
+
const model = new Loess({
|
|
22
|
+
x: filteredData.map((d) => d.x),
|
|
23
|
+
y: filteredData.map((d) => d.y)
|
|
24
|
+
}, { span: Math.max(0.1, span), iterations: 2 });
|
|
25
|
+
// return;
|
|
26
|
+
return {
|
|
27
|
+
predict(x) {
|
|
28
|
+
const fit = model.predict({ x: [toNumber(x)] });
|
|
29
|
+
return fit.fitted[0];
|
|
30
|
+
},
|
|
31
|
+
predictMany(x) {
|
|
32
|
+
const fit = model.predict({ x: x.map(toNumber) });
|
|
33
|
+
return fit.fitted;
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
fn.x = (_) => {
|
|
38
|
+
accessX = _;
|
|
39
|
+
};
|
|
40
|
+
fn.y = (_) => {
|
|
41
|
+
accessY = _;
|
|
42
|
+
};
|
|
43
|
+
fn.span = (_) => {
|
|
44
|
+
span = _;
|
|
45
|
+
};
|
|
46
|
+
return fn;
|
|
47
|
+
}
|
|
@@ -1,16 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Remove identical lines from a set of ticks
|
|
3
|
+
*/
|
|
1
4
|
export default function removeIdenticalLines(input) {
|
|
2
|
-
const
|
|
5
|
+
const uniqueTicks = [];
|
|
3
6
|
if (!input.length)
|
|
4
7
|
return input;
|
|
5
8
|
for (let c = 0; c < input.length; c++) {
|
|
6
|
-
|
|
9
|
+
// initialize new tick array with empty text lines
|
|
10
|
+
uniqueTicks.push({
|
|
11
|
+
...input[c],
|
|
12
|
+
text: []
|
|
13
|
+
});
|
|
7
14
|
}
|
|
8
|
-
for (let l = 0; l < input[0].length; l++) {
|
|
9
|
-
const isIdentical = input.every((
|
|
15
|
+
for (let l = 0; l < input[0].text.length; l++) {
|
|
16
|
+
const isIdentical = input.length > 1 && input.every((tick) => input[0].text[l] === tick.text[l]);
|
|
10
17
|
for (let c = 0; c < input.length; c++) {
|
|
11
|
-
if (!isIdentical)
|
|
12
|
-
|
|
18
|
+
if (!isIdentical && input[c].text[l])
|
|
19
|
+
uniqueTicks[c].text.push(input[c].text[l]);
|
|
13
20
|
}
|
|
14
21
|
}
|
|
15
|
-
return
|
|
22
|
+
return uniqueTicks;
|
|
16
23
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { MarkStyleProps, PlotState, ScaledDataRecord } from '../types.js';
|
|
2
|
+
import type { ScaleName, ChannelName, ScaledChannelName, ChannelAccessor, DataRow, RawValue, DataRecord, ConstantAccessor } from '../types.js';
|
|
3
|
+
type ChannelAlias = {
|
|
4
|
+
channel: ScaledChannelName;
|
|
5
|
+
};
|
|
6
|
+
export declare function resolveProp<T>(accessor: ConstantAccessor<T>, datum: DataRecord | null, _defaultValue?: T | null): T | null;
|
|
7
|
+
type ChannelOptions = {
|
|
8
|
+
value: ChannelAccessor;
|
|
9
|
+
scale?: ScaleName | null;
|
|
10
|
+
channel?: ScaledChannelName | null;
|
|
11
|
+
};
|
|
12
|
+
export declare function toChannelOption(name: ScaledChannelName, channel: ChannelAccessor | ChannelAlias): ChannelOptions;
|
|
13
|
+
export declare function resolveChannel(channel: ChannelName, datum: DataRow, channels: Partial<Record<ChannelName, ChannelAccessor | ChannelAlias>>): RawValue;
|
|
14
|
+
export declare function resolveScaledStyleProps(datum: DataRecord, channels: Partial<Record<ScaledChannelName, ChannelAccessor>>, useScale: Record<ScaledChannelName, boolean>, plot: PlotState, defaultColorProp?: 'fill' | 'stroke' | null): any;
|
|
15
|
+
export declare function resolveScaledStyles(datum: DataRecord, channels: Partial<Record<ScaledChannelName, ChannelAccessor>>, useScale: Record<ScaledChannelName, boolean>, plot: PlotState, defaultColorProp?: 'fill' | 'stroke' | null): string;
|
|
16
|
+
export declare function resolveStyles(plot: PlotState, datum: ScaledDataRecord, channels: Partial<Record<ChannelName & MarkStyleProps, ChannelAccessor>>, defaultColorProp: "fill" | "stroke" | null | undefined, useScale: Record<ScaledChannelName, boolean>): [string | null, string | null];
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { CHANNEL_SCALE } from '../constants.js';
|
|
2
|
+
import isDataRecord from './isDataRecord.js';
|
|
3
|
+
import isRawValue from './isRawValue.js';
|
|
4
|
+
import { isValid } from './isValid.js';
|
|
5
|
+
import { pick } from 'es-toolkit';
|
|
6
|
+
import { getBaseStylesObject } from './getBaseStyles.js';
|
|
7
|
+
export function resolveProp(accessor, datum, _defaultValue = null) {
|
|
8
|
+
if (typeof accessor === 'function') {
|
|
9
|
+
// datum.___orig___ exists if an array of raw values was used as dataset and got
|
|
10
|
+
// "recordized" by the recordize transform. We want to hide this wrapping to the user
|
|
11
|
+
// so we're passing the original value to accessor functions instead of our wrapped record
|
|
12
|
+
return datum == null
|
|
13
|
+
? accessor()
|
|
14
|
+
: accessor(datum.___orig___ != null ? datum.___orig___ : datum);
|
|
15
|
+
}
|
|
16
|
+
else if (typeof accessor === 'string' && datum && datum[accessor] !== undefined) {
|
|
17
|
+
return datum[accessor];
|
|
18
|
+
}
|
|
19
|
+
return isRawValue(accessor) ? accessor : _defaultValue;
|
|
20
|
+
}
|
|
21
|
+
export function toChannelOption(name, channel) {
|
|
22
|
+
const isPositionScale = CHANNEL_SCALE[name] === 'x' || CHANNEL_SCALE[name] === 'y';
|
|
23
|
+
const isOpacityScale = CHANNEL_SCALE[name] === 'opacity';
|
|
24
|
+
return isDataRecord(channel)
|
|
25
|
+
? channel
|
|
26
|
+
: {
|
|
27
|
+
value: channel,
|
|
28
|
+
scale: (!isPositionScale && !isOpacityScale && typeof channel === 'number') ||
|
|
29
|
+
typeof channel === 'undefined'
|
|
30
|
+
? null
|
|
31
|
+
: CHANNEL_SCALE[name],
|
|
32
|
+
channel: null
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export function resolveChannel(channel, datum, channels) {
|
|
36
|
+
const scale = CHANNEL_SCALE[channel];
|
|
37
|
+
// the z channel has an automatic alias mechanism
|
|
38
|
+
const accessor = channel === 'z' ? channels.z || channels.fill || channels.stroke : channels[channel];
|
|
39
|
+
const channelOptions = toChannelOption(channel, accessor);
|
|
40
|
+
if (channelOptions.channel) {
|
|
41
|
+
return resolveChannel(channelOptions.channel, datum, channels);
|
|
42
|
+
}
|
|
43
|
+
return resolve(datum, channelOptions.value, channel, scale);
|
|
44
|
+
}
|
|
45
|
+
function resolve(datum, accessor, channel, scale) {
|
|
46
|
+
if (isDataRecord(datum)) {
|
|
47
|
+
// use accessor function
|
|
48
|
+
if (typeof accessor === 'function')
|
|
49
|
+
// datum.___orig___ exists if an array of raw values was used as dataset and got
|
|
50
|
+
// "recordized" by the recordize transform. We want to hide this wrapping to the user
|
|
51
|
+
// so we're passing the original value to accessor functions instead of our wrapped record
|
|
52
|
+
return accessor(datum.___orig___ != null ? datum.___orig___ : datum);
|
|
53
|
+
// use accessor string
|
|
54
|
+
if (typeof accessor === 'string' && datum[accessor] !== undefined)
|
|
55
|
+
return datum[accessor];
|
|
56
|
+
// fallback to channel name as accessor
|
|
57
|
+
if (accessor === null && datum[channel] !== undefined)
|
|
58
|
+
return datum[channel];
|
|
59
|
+
return isRawValue(accessor) ? accessor : null;
|
|
60
|
+
}
|
|
61
|
+
else if (Array.isArray(datum) &&
|
|
62
|
+
(typeof accessor === 'string' || typeof accessor === 'number') &&
|
|
63
|
+
datum[accessor] != null) {
|
|
64
|
+
return datum[accessor];
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
// return single value or accessor
|
|
68
|
+
return typeof accessor === 'function'
|
|
69
|
+
? accessor(datum)
|
|
70
|
+
: accessor !== null && isRawValue(accessor)
|
|
71
|
+
? accessor
|
|
72
|
+
: !Array.isArray(datum) && (scale === 'x' || scale === 'y')
|
|
73
|
+
? datum
|
|
74
|
+
: null;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const scaledStyleProps = {
|
|
78
|
+
fill: 'fill',
|
|
79
|
+
stroke: 'stroke',
|
|
80
|
+
fillOpacity: 'fill-opacity',
|
|
81
|
+
strokeOpacity: 'stroke-opacity',
|
|
82
|
+
opacity: 'opacity'
|
|
83
|
+
};
|
|
84
|
+
const scaledStylePropsKeys = Object.keys(scaledStyleProps);
|
|
85
|
+
// TODO: find a better name
|
|
86
|
+
const oppositeColor = {
|
|
87
|
+
fill: 'stroke',
|
|
88
|
+
stroke: 'fill'
|
|
89
|
+
};
|
|
90
|
+
export function resolveScaledStyleProps(datum, channels, useScale, plot, defaultColorProp = null) {
|
|
91
|
+
return {
|
|
92
|
+
...getBaseStylesObject(datum, channels),
|
|
93
|
+
fill: 'none',
|
|
94
|
+
stroke: 'none',
|
|
95
|
+
...(defaultColorProp && channels[oppositeColor[defaultColorProp]] == null
|
|
96
|
+
? { [defaultColorProp]: 'currentColor' }
|
|
97
|
+
: {}),
|
|
98
|
+
...Object.fromEntries(Object.entries(scaledStyleProps)
|
|
99
|
+
.filter(([key]) => channels[key] != null)
|
|
100
|
+
.map(([key, cssAttr]) => [key, cssAttr, resolveChannel(key, datum, channels)])
|
|
101
|
+
.filter(([key, , value]) => isValid(value) || key === 'fill' || key === 'stroke')
|
|
102
|
+
.map(([key, cssAttr, value]) => {
|
|
103
|
+
if (useScale[key]) {
|
|
104
|
+
if (value == undefined &&
|
|
105
|
+
(key === 'fill' || key === 'stroke') &&
|
|
106
|
+
plot.options.color.unknown) {
|
|
107
|
+
return [cssAttr, plot.options.color.unknown];
|
|
108
|
+
}
|
|
109
|
+
return [cssAttr, plot.scales[CHANNEL_SCALE[key]].fn(value)];
|
|
110
|
+
}
|
|
111
|
+
return [cssAttr, value];
|
|
112
|
+
}))
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
export function resolveScaledStyles(datum, channels, useScale, plot, defaultColorProp = null) {
|
|
116
|
+
return `${stylePropsToCSS(resolveScaledStyleProps(datum, channels, useScale, plot, defaultColorProp))};${channels.style || ''}`;
|
|
117
|
+
}
|
|
118
|
+
function stylePropsToCSS(props) {
|
|
119
|
+
return `${Object.entries(props)
|
|
120
|
+
.map(([key, value]) => `${key}: ${value}`)
|
|
121
|
+
.join(';')}`;
|
|
122
|
+
}
|
|
123
|
+
export function resolveStyles(plot, datum, channels, defaultColorProp = null, useScale) {
|
|
124
|
+
const styleProps = {
|
|
125
|
+
...getBaseStylesObject(datum.datum, channels),
|
|
126
|
+
fill: 'none',
|
|
127
|
+
stroke: 'none',
|
|
128
|
+
...(defaultColorProp && channels[oppositeColor[defaultColorProp]] == null
|
|
129
|
+
? { [defaultColorProp]: 'currentColor' }
|
|
130
|
+
: {}),
|
|
131
|
+
...Object.fromEntries(Object.entries(scaledStyleProps)
|
|
132
|
+
.filter(([key]) => channels[key] != null)
|
|
133
|
+
.map(([key, cssAttr]) => [key, cssAttr, datum[key]])
|
|
134
|
+
.filter(([key, , value]) => isValid(value) || key === 'fill' || key === 'stroke')
|
|
135
|
+
.map(([key, cssAttr, value]) => {
|
|
136
|
+
if (useScale[key]) {
|
|
137
|
+
if (value == undefined &&
|
|
138
|
+
(key === 'fill' || key === 'stroke') &&
|
|
139
|
+
plot.options.color.unknown) {
|
|
140
|
+
return [cssAttr, plot.options.color.unknown];
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return [cssAttr, value];
|
|
144
|
+
}))
|
|
145
|
+
};
|
|
146
|
+
if (plot.css) {
|
|
147
|
+
return [null, plot.css(stylePropsToCSS(styleProps))];
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
return [stylePropsToCSS(styleProps), null];
|
|
151
|
+
}
|
|
152
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
*/
|
|
4
|
+
export function roundedRect(x, y, width, height, borderRadius = {
|
|
5
|
+
topLeft: 0,
|
|
6
|
+
topRight: 0,
|
|
7
|
+
bottomLeft: 0,
|
|
8
|
+
bottomRight: 0
|
|
9
|
+
}) {
|
|
10
|
+
const maxRadius = Math.min(width, height) / 2;
|
|
11
|
+
const [tl, tr, bl, br] = (typeof borderRadius === 'number'
|
|
12
|
+
? new Array(4).fill(borderRadius)
|
|
13
|
+
: [
|
|
14
|
+
borderRadius?.topLeft || 0,
|
|
15
|
+
borderRadius?.topRight || 0,
|
|
16
|
+
borderRadius?.bottomLeft || 0,
|
|
17
|
+
borderRadius?.bottomRight || 0
|
|
18
|
+
]).map((r) => Math.min(r, maxRadius));
|
|
19
|
+
return `
|
|
20
|
+
M ${x + tl} ${y}
|
|
21
|
+
H ${x + width - tr}
|
|
22
|
+
${tr ? `A ${tr} ${tr} 0 0 1 ${x + width} ${y + tr}` : ''}
|
|
23
|
+
V ${y + height - br}
|
|
24
|
+
${br ? `A ${br} ${br} 0 0 1 ${x + width - br} ${y + height}` : ''}
|
|
25
|
+
H ${x + bl}
|
|
26
|
+
${bl ? `A ${bl} ${bl} 0 0 1 ${x} ${y + height - bl}` : ''}
|
|
27
|
+
V ${y + tl}
|
|
28
|
+
${tl ? `A ${tl} ${tl} 0 0 1 ${x + tl} ${y}` : ''}
|
|
29
|
+
Z
|
|
30
|
+
`;
|
|
31
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { ChannelAccessor, GenericMarkOptions, Mark, MarkType, PlotDefaults, PlotOptions, PlotScales, PlotState, RawValue, ScaleName, ScaleOptions, ScaleType, ScaledChannelName } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* compute the plot scales
|
|
4
|
+
*/
|
|
5
|
+
export declare function computeScales(plotOptions: PlotOptions, plotWidth: number, plotHeight: number, plotHasFilledDotMarks: boolean, marks: Mark<GenericMarkOptions>[], plotDefaults: PlotDefaults): PlotScales;
|
|
6
|
+
export declare function createScale<T extends ScaleOptions>(name: ScaleName, scaleOptions: T, marks: Mark<GenericMarkOptions>[], plotOptions: PlotOptions, plotWidth: number, plotHeight: number, plotHasFilledDotMarks: boolean, plotDefaults: PlotDefaults): {
|
|
7
|
+
type: string;
|
|
8
|
+
domain: number[];
|
|
9
|
+
range: number[];
|
|
10
|
+
fn: (() => string) | (() => number);
|
|
11
|
+
skip: Map<any, any>;
|
|
12
|
+
isDummy: boolean;
|
|
13
|
+
manualActiveMarks?: undefined;
|
|
14
|
+
uniqueScaleProps?: undefined;
|
|
15
|
+
autoTitle?: undefined;
|
|
16
|
+
} | {
|
|
17
|
+
type: ScaleType;
|
|
18
|
+
domain: RawValue[] | [undefined, undefined];
|
|
19
|
+
range: any;
|
|
20
|
+
fn: any;
|
|
21
|
+
skip: Map<ScaledChannelName, Set<symbol>>;
|
|
22
|
+
manualActiveMarks: number;
|
|
23
|
+
uniqueScaleProps: Set<ChannelAccessor>;
|
|
24
|
+
autoTitle: string | null;
|
|
25
|
+
isDummy?: undefined;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Infer a scale type based on the scale name, the data values mapped to it and
|
|
29
|
+
* the mark types that are bound to the scale
|
|
30
|
+
*/
|
|
31
|
+
export declare function inferScaleType(name: ScaleName, dataValues: RawValue[], markTypes: Set<MarkType>): ScaleType;
|
|
32
|
+
/**
|
|
33
|
+
* Mark channels can explicitely or implicitely be exempt from being
|
|
34
|
+
* mapped to a scale, so everywhere where values are being mapped to
|
|
35
|
+
* scales, we need to check if the the scale is supposed to be used
|
|
36
|
+
* not. That's what this function is used for.
|
|
37
|
+
*/
|
|
38
|
+
export declare function getUsedScales(plot: PlotState, options: GenericMarkOptions, mark: Mark<GenericMarkOptions>): { [k in ScaledChannelName]: boolean; };
|
|
39
|
+
export declare function looksLikeANumber(input: string | number): boolean;
|
|
40
|
+
export declare function projectXY(scales: PlotScales, x: RawValue, y: RawValue, useXScale?: boolean, useYScale?: boolean): [number, number];
|
|
41
|
+
export declare function projectX(channel: 'x' | 'x1' | 'x2', scales: PlotScales, value: RawValue): number;
|
|
42
|
+
export declare function projectY(channel: 'y' | 'y1' | 'y2', scales: PlotScales, value: RawValue): number;
|