@thi.ng/fuzzy-viz 2.1.101 → 2.1.103
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/CHANGELOG.md +1 -1
- package/README.md +1 -1
- package/api.js +0 -1
- package/package.json +13 -10
- package/strategy.js +57 -102
- package/var.js +96 -95
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
package/api.js
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thi.ng/fuzzy-viz",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.103",
|
|
4
4
|
"description": "Visualization, instrumentation & introspection utils for @thi.ng/fuzzy",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./index.js",
|
|
@@ -24,7 +24,9 @@
|
|
|
24
24
|
"author": "Karsten Schmidt (https://thi.ng)",
|
|
25
25
|
"license": "Apache-2.0",
|
|
26
26
|
"scripts": {
|
|
27
|
-
"build": "yarn
|
|
27
|
+
"build": "yarn build:esbuild && yarn build:decl",
|
|
28
|
+
"build:decl": "tsc --declaration --emitDeclarationOnly",
|
|
29
|
+
"build:esbuild": "esbuild --format=esm --platform=neutral --target=es2022 --tsconfig=tsconfig.json --outdir=. src/**/*.ts",
|
|
28
30
|
"clean": "rimraf --glob '*.js' '*.d.ts' '*.map' doc",
|
|
29
31
|
"doc": "typedoc --excludePrivate --excludeInternal --out doc src/index.ts",
|
|
30
32
|
"doc:ae": "mkdir -p .ae/doc .ae/temp && api-extractor run --local --verbose",
|
|
@@ -33,16 +35,17 @@
|
|
|
33
35
|
"test": "bun test"
|
|
34
36
|
},
|
|
35
37
|
"dependencies": {
|
|
36
|
-
"@thi.ng/api": "^8.9.
|
|
37
|
-
"@thi.ng/fuzzy": "^2.1.
|
|
38
|
-
"@thi.ng/hiccup": "^5.1.
|
|
39
|
-
"@thi.ng/hiccup-svg": "^5.0.
|
|
40
|
-
"@thi.ng/math": "^5.7.
|
|
41
|
-
"@thi.ng/strings": "^3.7.
|
|
42
|
-
"@thi.ng/text-canvas": "^2.6.
|
|
38
|
+
"@thi.ng/api": "^8.9.12",
|
|
39
|
+
"@thi.ng/fuzzy": "^2.1.53",
|
|
40
|
+
"@thi.ng/hiccup": "^5.1.1",
|
|
41
|
+
"@thi.ng/hiccup-svg": "^5.0.39",
|
|
42
|
+
"@thi.ng/math": "^5.7.7",
|
|
43
|
+
"@thi.ng/strings": "^3.7.3",
|
|
44
|
+
"@thi.ng/text-canvas": "^2.6.24"
|
|
43
45
|
},
|
|
44
46
|
"devDependencies": {
|
|
45
47
|
"@microsoft/api-extractor": "^7.38.3",
|
|
48
|
+
"esbuild": "^0.19.8",
|
|
46
49
|
"rimraf": "^5.0.5",
|
|
47
50
|
"tools": "^0.0.1",
|
|
48
51
|
"typedoc": "^0.25.4",
|
|
@@ -89,5 +92,5 @@
|
|
|
89
92
|
"parent": "@thi.ng/fuzzy",
|
|
90
93
|
"year": 2020
|
|
91
94
|
},
|
|
92
|
-
"gitHead": "
|
|
95
|
+
"gitHead": "22e36fa838e5431d40165384918b395603bbd92f\n"
|
|
93
96
|
}
|
package/strategy.js
CHANGED
|
@@ -5,108 +5,63 @@ import { fit } from "@thi.ng/math/fit";
|
|
|
5
5
|
import { repeat } from "@thi.ng/strings/repeat";
|
|
6
6
|
import { barChartHLines } from "@thi.ng/text-canvas/bars";
|
|
7
7
|
import { varToHiccup } from "./var.js";
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
* outputs) and/or produce secondary results (e.g. visualizations). The latter
|
|
19
|
-
* can be obtained through the
|
|
20
|
-
* [`IDeref`](https://docs.thi.ng/umbrella/api/interfaces/IDeref.html) mechanism
|
|
21
|
-
* implemented by the returned function. Since {@link defuzz} might call the
|
|
22
|
-
* strategy multiple times (i.e. if there are multiple output vars used),
|
|
23
|
-
* `.deref()` will always return an array of secondary results.
|
|
24
|
-
*
|
|
25
|
-
* Note: The secondary results from the instrumentation function will persist &
|
|
26
|
-
* accumulate. If re-using the instrumented strategy for multiple `defuzz()`
|
|
27
|
-
* invocations, it's highly recommended to clear any previous results using
|
|
28
|
-
* `.clear()`.
|
|
29
|
-
*
|
|
30
|
-
* @example
|
|
31
|
-
* ```ts
|
|
32
|
-
* const strategy = instrumentStrategy(
|
|
33
|
-
* cogStrategy({ samples: 1000 }),
|
|
34
|
-
* fuzzySetToAscii({ width: 40, height: 8 })
|
|
35
|
-
* );
|
|
36
|
-
*
|
|
37
|
-
* strategy(gaussian(5, 2), [0, 10]);
|
|
38
|
-
* // 4.995
|
|
39
|
-
*
|
|
40
|
-
* console.log(strategy.deref()[0])
|
|
41
|
-
* // .................▄▆█|█▆▄.................
|
|
42
|
-
* // ...............▅████|████▅...............
|
|
43
|
-
* // .............▄██████|██████▄.............
|
|
44
|
-
* // ...........▂▇███████|███████▇▂...........
|
|
45
|
-
* // ..........▅█████████|█████████▅..........
|
|
46
|
-
* // .......▁▅███████████|███████████▅▁.......
|
|
47
|
-
* // .....▃▆█████████████|█████████████▆▃.....
|
|
48
|
-
* // ▃▄▅▇████████████████|████████████████▇▅▄▃
|
|
49
|
-
* // ^ 5.00
|
|
50
|
-
*
|
|
51
|
-
* // cleanup (optional)
|
|
52
|
-
* strategy.clear();
|
|
53
|
-
* ```
|
|
54
|
-
*
|
|
55
|
-
* @param strategy -
|
|
56
|
-
* @param instrument -
|
|
57
|
-
*/
|
|
58
|
-
export const instrumentStrategy = (strategy, instrument) => {
|
|
59
|
-
const acc = [];
|
|
60
|
-
const impl = (fn, domain) => {
|
|
61
|
-
const res = strategy(fn, domain);
|
|
62
|
-
acc.push(instrument(fn, domain, res));
|
|
63
|
-
return res;
|
|
64
|
-
};
|
|
65
|
-
impl.clear = () => (acc.length = 0);
|
|
66
|
-
impl.deref = () => acc;
|
|
67
|
-
return impl;
|
|
8
|
+
const instrumentStrategy = (strategy, instrument) => {
|
|
9
|
+
const acc = [];
|
|
10
|
+
const impl = (fn, domain) => {
|
|
11
|
+
const res = strategy(fn, domain);
|
|
12
|
+
acc.push(instrument(fn, domain, res));
|
|
13
|
+
return res;
|
|
14
|
+
};
|
|
15
|
+
impl.clear = () => acc.length = 0;
|
|
16
|
+
impl.deref = () => acc;
|
|
17
|
+
return impl;
|
|
68
18
|
};
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
19
|
+
const fuzzySetToHiccup = (opts) => (fn, domain, res) => {
|
|
20
|
+
const tree = varToHiccup(variable(domain, { main: fn }), {
|
|
21
|
+
labels: false,
|
|
22
|
+
stroke: () => "#333",
|
|
23
|
+
fill: () => "#999",
|
|
24
|
+
...opts
|
|
25
|
+
});
|
|
26
|
+
const { width, height } = tree[1];
|
|
27
|
+
const x = fit(res, domain[0], domain[1], 0, width);
|
|
28
|
+
tree.push([
|
|
29
|
+
"g",
|
|
30
|
+
{ translate: [x, 0] },
|
|
31
|
+
["line", { stroke: "red" }, [0, 0], [0, height - 12]],
|
|
32
|
+
[
|
|
33
|
+
"text",
|
|
34
|
+
{ align: "center", fill: "red" },
|
|
35
|
+
[0, height - 2],
|
|
36
|
+
res.toFixed(2)
|
|
37
|
+
]
|
|
38
|
+
]);
|
|
39
|
+
return tree;
|
|
90
40
|
};
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
41
|
+
const fuzzySetToSvg = (opts) => (fn, domain, res) => serialize(convertTree(fuzzySetToHiccup(opts)(fn, domain, res)));
|
|
42
|
+
const fuzzySetToAscii = (opts) => (fn, domain, res) => {
|
|
43
|
+
const { width, height, empty } = {
|
|
44
|
+
width: 100,
|
|
45
|
+
height: 16,
|
|
46
|
+
empty: ".",
|
|
47
|
+
...opts
|
|
48
|
+
};
|
|
49
|
+
const [min, max] = domain;
|
|
50
|
+
const delta = (max - min) / width;
|
|
51
|
+
const vals = [];
|
|
52
|
+
for (let i = min; i <= max; i += delta) {
|
|
53
|
+
vals.push(fn(i));
|
|
54
|
+
}
|
|
55
|
+
const index = Math.round(fit(res, min, max, 0, vals.length));
|
|
56
|
+
let chart = barChartHLines(height, vals, 0, 1).map(
|
|
57
|
+
(line) => line.substring(0, index) + "|" + line.substring(index + 1)
|
|
58
|
+
).join("\n").replace(/ /g, empty);
|
|
59
|
+
const legend = repeat(" ", index) + "^ " + res.toFixed(2);
|
|
60
|
+
return chart + "\n" + legend;
|
|
61
|
+
};
|
|
62
|
+
export {
|
|
63
|
+
fuzzySetToAscii,
|
|
64
|
+
fuzzySetToHiccup,
|
|
65
|
+
fuzzySetToSvg,
|
|
66
|
+
instrumentStrategy
|
|
112
67
|
};
|
package/var.js
CHANGED
|
@@ -3,101 +3,102 @@ import { svg } from "@thi.ng/hiccup-svg/svg";
|
|
|
3
3
|
import { serialize } from "@thi.ng/hiccup/serialize";
|
|
4
4
|
import { fit } from "@thi.ng/math/fit";
|
|
5
5
|
import { inRange } from "@thi.ng/math/interval";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const curr = [];
|
|
38
|
-
for (let i = 0; i <= samples; i++) {
|
|
39
|
-
curr.push([i * ds, (1 - f(min + i * dt)) * height]);
|
|
40
|
-
}
|
|
41
|
-
curr.push([width, height], [0, height]);
|
|
42
|
-
curves.push([
|
|
43
|
-
"polygon",
|
|
44
|
-
{
|
|
45
|
-
stroke,
|
|
46
|
-
fill: fillFn(i * dn),
|
|
47
|
-
},
|
|
48
|
-
curr,
|
|
49
|
-
]);
|
|
50
|
-
if (labels) {
|
|
51
|
-
legend.push(["line", { stroke }, [0, y], [20, y]], [
|
|
52
|
-
"text",
|
|
53
|
-
{
|
|
54
|
-
baseline: "middle",
|
|
55
|
-
fill: "black",
|
|
56
|
-
},
|
|
57
|
-
[30, y],
|
|
58
|
-
id,
|
|
59
|
-
]);
|
|
60
|
-
}
|
|
6
|
+
const varToHiccup = ({ domain: [min, max], terms }, opts = {}) => {
|
|
7
|
+
const {
|
|
8
|
+
samples,
|
|
9
|
+
width,
|
|
10
|
+
height,
|
|
11
|
+
labels,
|
|
12
|
+
stroke: strokeFn,
|
|
13
|
+
fill: fillFn
|
|
14
|
+
} = {
|
|
15
|
+
samples: 200,
|
|
16
|
+
width: 600,
|
|
17
|
+
height: 100,
|
|
18
|
+
labels: true,
|
|
19
|
+
stroke: (x) => `hsl(${x * 360 | 0},100%,40%)`,
|
|
20
|
+
fill: (x) => `hsla(${x * 360 | 0},100%,50%,20%)`,
|
|
21
|
+
...opts
|
|
22
|
+
};
|
|
23
|
+
const keys = Object.keys(terms);
|
|
24
|
+
const dt = (max - min) / samples;
|
|
25
|
+
const ds = width / samples;
|
|
26
|
+
const dn = 1 / keys.length;
|
|
27
|
+
const curves = [];
|
|
28
|
+
const legend = [];
|
|
29
|
+
for (let i = 0; i < keys.length; i++) {
|
|
30
|
+
const id = keys[i];
|
|
31
|
+
const f = terms[id];
|
|
32
|
+
const y = (i + 1) * 12;
|
|
33
|
+
const stroke = strokeFn(i * dn);
|
|
34
|
+
const curr = [];
|
|
35
|
+
for (let i2 = 0; i2 <= samples; i2++) {
|
|
36
|
+
curr.push([i2 * ds, (1 - f(min + i2 * dt)) * height]);
|
|
61
37
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
? [
|
|
71
|
-
"g",
|
|
72
|
-
{},
|
|
73
|
-
[
|
|
74
|
-
"line",
|
|
75
|
-
{
|
|
76
|
-
stroke: "black",
|
|
77
|
-
dash: [1, 1],
|
|
78
|
-
},
|
|
79
|
-
[zero, 0],
|
|
80
|
-
[zero, height],
|
|
81
|
-
],
|
|
82
|
-
[
|
|
83
|
-
"text",
|
|
84
|
-
{ align: "center", fill: "black" },
|
|
85
|
-
[zero, height + 10],
|
|
86
|
-
"0.00",
|
|
87
|
-
],
|
|
88
|
-
]
|
|
89
|
-
: null, [
|
|
90
|
-
"g",
|
|
91
|
-
{ fill: "black" },
|
|
92
|
-
["text", {}, [0, height + 10], min.toFixed(2)],
|
|
93
|
-
["text", { align: "end" }, [width, height + 10], max.toFixed(2)],
|
|
38
|
+
curr.push([width, height], [0, height]);
|
|
39
|
+
curves.push([
|
|
40
|
+
"polygon",
|
|
41
|
+
{
|
|
42
|
+
stroke,
|
|
43
|
+
fill: fillFn(i * dn)
|
|
44
|
+
},
|
|
45
|
+
curr
|
|
94
46
|
]);
|
|
47
|
+
if (labels) {
|
|
48
|
+
legend.push(
|
|
49
|
+
["line", { stroke }, [0, y], [20, y]],
|
|
50
|
+
[
|
|
51
|
+
"text",
|
|
52
|
+
{
|
|
53
|
+
baseline: "middle",
|
|
54
|
+
fill: "black"
|
|
55
|
+
},
|
|
56
|
+
[30, y],
|
|
57
|
+
id
|
|
58
|
+
]
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const zero = fit(0, min, max, 0, width);
|
|
63
|
+
return svg(
|
|
64
|
+
{
|
|
65
|
+
width,
|
|
66
|
+
height: height + 12,
|
|
67
|
+
fill: "none",
|
|
68
|
+
"font-family": "sans-serif",
|
|
69
|
+
"font-size": 10
|
|
70
|
+
},
|
|
71
|
+
...curves,
|
|
72
|
+
...legend,
|
|
73
|
+
inRange(zero, width * 0.05, width * 0.95) ? [
|
|
74
|
+
"g",
|
|
75
|
+
{},
|
|
76
|
+
[
|
|
77
|
+
"line",
|
|
78
|
+
{
|
|
79
|
+
stroke: "black",
|
|
80
|
+
dash: [1, 1]
|
|
81
|
+
},
|
|
82
|
+
[zero, 0],
|
|
83
|
+
[zero, height]
|
|
84
|
+
],
|
|
85
|
+
[
|
|
86
|
+
"text",
|
|
87
|
+
{ align: "center", fill: "black" },
|
|
88
|
+
[zero, height + 10],
|
|
89
|
+
"0.00"
|
|
90
|
+
]
|
|
91
|
+
] : null,
|
|
92
|
+
[
|
|
93
|
+
"g",
|
|
94
|
+
{ fill: "black" },
|
|
95
|
+
["text", {}, [0, height + 10], min.toFixed(2)],
|
|
96
|
+
["text", { align: "end" }, [width, height + 10], max.toFixed(2)]
|
|
97
|
+
]
|
|
98
|
+
);
|
|
99
|
+
};
|
|
100
|
+
const varToSvg = ($var, opts) => serialize(convertTree(varToHiccup($var, opts)));
|
|
101
|
+
export {
|
|
102
|
+
varToHiccup,
|
|
103
|
+
varToSvg
|
|
95
104
|
};
|
|
96
|
-
/**
|
|
97
|
-
* Similar to {@link varToHiccup}, but then also serializes the result to an
|
|
98
|
-
* actual SVG string.
|
|
99
|
-
*
|
|
100
|
-
* @param $var
|
|
101
|
-
* @param opts -
|
|
102
|
-
*/
|
|
103
|
-
export const varToSvg = ($var, opts) => serialize(convertTree(varToHiccup($var, opts)));
|