@thi.ng/fuzzy-viz 2.1.101 → 2.1.102

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # Change Log
2
2
 
3
- - **Last updated**: 2023-12-09T19:12:03Z
3
+ - **Last updated**: 2023-12-11T10:07:09Z
4
4
  - **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
5
5
 
6
6
  All notable changes to this project will be documented in this file.
package/README.md CHANGED
@@ -50,7 +50,7 @@ For Node.js REPL:
50
50
  const fuzzyViz = await import("@thi.ng/fuzzy-viz");
51
51
  ```
52
52
 
53
- Package sizes (brotli'd, pre-treeshake): ESM: 1.00 KB
53
+ Package sizes (brotli'd, pre-treeshake): ESM: 1.01 KB
54
54
 
55
55
  ## Dependencies
56
56
 
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.101",
3
+ "version": "2.1.102",
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 clean && tsc --declaration",
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.11",
37
- "@thi.ng/fuzzy": "^2.1.52",
38
- "@thi.ng/hiccup": "^5.1.0",
39
- "@thi.ng/hiccup-svg": "^5.0.37",
40
- "@thi.ng/math": "^5.7.6",
41
- "@thi.ng/strings": "^3.7.2",
42
- "@thi.ng/text-canvas": "^2.6.22"
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.38",
42
+ "@thi.ng/math": "^5.7.7",
43
+ "@thi.ng/strings": "^3.7.3",
44
+ "@thi.ng/text-canvas": "^2.6.23"
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": "25f2ac8ff795a432a930119661b364d4d93b59a0\n"
95
+ "gitHead": "5e7bafedfc3d53bc131469a28de31dd8e5b4a3ff\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
- * Higher order function. Takes an existing
10
- * [`DefuzzStrategy`](https://docs.thi.ng/umbrella/fuzzy/types/DefuzzStrategy.html)
11
- * and an instrumentation function. Returns new `DefuzzStrategy` which first
12
- * executes original `strategy`, then calls `instrument` with the same args AND
13
- * the computed result obtained from `strategy`. Returns result of original
14
- * `strategy`.
15
- *
16
- * @remarks
17
- * The instrumentation function is intended to perform side effects (e.g. debug
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
- export const fuzzySetToHiccup = (opts) => (fn, domain, res) => {
70
- const tree = varToHiccup(variable(domain, { main: fn }), {
71
- labels: false,
72
- stroke: () => "#333",
73
- fill: () => "#999",
74
- ...opts,
75
- });
76
- const { width, height } = tree[1];
77
- const x = fit(res, domain[0], domain[1], 0, width);
78
- tree.push([
79
- "g",
80
- { translate: [x, 0] },
81
- ["line", { stroke: "red" }, [0, 0], [0, height - 12]],
82
- [
83
- "text",
84
- { align: "center", fill: "red" },
85
- [0, height - 2],
86
- res.toFixed(2),
87
- ],
88
- ]);
89
- return tree;
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
- export const fuzzySetToSvg = (opts) => (fn, domain, res) => serialize(convertTree(fuzzySetToHiccup(opts)(fn, domain, res)));
92
- export const fuzzySetToAscii = (opts) => (fn, domain, res) => {
93
- const { width, height, empty } = {
94
- width: 100,
95
- height: 16,
96
- empty: ".",
97
- ...opts,
98
- };
99
- const [min, max] = domain;
100
- const delta = (max - min) / width;
101
- const vals = [];
102
- for (let i = min; i <= max; i += delta) {
103
- vals.push(fn(i));
104
- }
105
- const index = Math.round(fit(res, min, max, 0, vals.length));
106
- let chart = barChartHLines(height, vals, 0, 1)
107
- .map((line) => line.substring(0, index) + "|" + line.substring(index + 1))
108
- .join("\n")
109
- .replace(/ /g, empty);
110
- const legend = repeat(" ", index) + "^ " + res.toFixed(2);
111
- return chart + "\n" + legend;
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
- * Takes an [`LVar`](https://docs.thi.ng/umbrella/fuzzy/interfaces/LVar.html)
8
- * and visualization options. Evaluates all of the var's fuzzy sets in the var's
9
- * value domain and visualizes them as polygons. Returns a
10
- * [thi.ng/hiccup-canvas](https://thi.ng/thi.ng/hiccup-canvas) compatible shape
11
- * component tree.
12
- *
13
- * @param var -
14
- * @param opts -
15
- */
16
- export const varToHiccup = ({ domain: [min, max], terms }, opts = {}) => {
17
- const { samples, width, height, labels, stroke: strokeFn, fill: fillFn, } = {
18
- samples: 200,
19
- width: 600,
20
- height: 100,
21
- labels: true,
22
- stroke: (x) => `hsl(${(x * 360) | 0},100%,40%)`,
23
- fill: (x) => `hsla(${(x * 360) | 0},100%,50%,20%)`,
24
- ...opts,
25
- };
26
- const keys = Object.keys(terms);
27
- const dt = (max - min) / samples;
28
- const ds = width / samples;
29
- const dn = 1 / keys.length;
30
- const curves = [];
31
- const legend = [];
32
- for (let i = 0; i < keys.length; i++) {
33
- const id = keys[i];
34
- const f = terms[id];
35
- const y = (i + 1) * 12;
36
- const stroke = strokeFn(i * dn);
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
- const zero = fit(0, min, max, 0, width);
63
- return svg({
64
- width,
65
- height: height + 12,
66
- fill: "none",
67
- "font-family": "sans-serif",
68
- "font-size": 10,
69
- }, ...curves, ...legend, inRange(zero, width * 0.05, width * 0.95)
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)));