@datagrok/eda 1.4.12 → 1.5.0
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/.eslintrc.json +0 -1
- package/CHANGELOG.md +10 -0
- package/CLAUDE.md +185 -0
- package/css/pmpo.css +9 -0
- package/dist/111.js +1 -1
- package/dist/111.js.map +1 -1
- package/dist/128.js +1 -1
- package/dist/128.js.map +1 -1
- package/dist/153.js +1 -1
- package/dist/153.js.map +1 -1
- package/dist/23.js +1 -1
- package/dist/23.js.map +1 -1
- package/dist/234.js +1 -1
- package/dist/234.js.map +1 -1
- package/dist/242.js +1 -1
- package/dist/242.js.map +1 -1
- package/dist/260.js +1 -1
- package/dist/260.js.map +1 -1
- package/dist/33.js +1 -1
- package/dist/33.js.map +1 -1
- package/dist/348.js +1 -1
- package/dist/348.js.map +1 -1
- package/dist/377.js +1 -1
- package/dist/377.js.map +1 -1
- package/dist/397.js +2 -0
- package/dist/397.js.map +1 -0
- package/dist/412.js +1 -1
- package/dist/412.js.map +1 -1
- package/dist/415.js +1 -1
- package/dist/415.js.map +1 -1
- package/dist/501.js +1 -1
- package/dist/501.js.map +1 -1
- package/dist/531.js +1 -1
- package/dist/531.js.map +1 -1
- package/dist/583.js +1 -1
- package/dist/583.js.map +1 -1
- package/dist/589.js +1 -1
- package/dist/589.js.map +1 -1
- package/dist/603.js +1 -1
- package/dist/603.js.map +1 -1
- package/dist/656.js +1 -1
- package/dist/656.js.map +1 -1
- package/dist/682.js +1 -1
- package/dist/682.js.map +1 -1
- package/dist/705.js +1 -1
- package/dist/705.js.map +1 -1
- package/dist/727.js +1 -1
- package/dist/727.js.map +1 -1
- package/dist/731.js +1 -1
- package/dist/731.js.map +1 -1
- package/dist/738.js +1 -1
- package/dist/738.js.map +1 -1
- package/dist/763.js +1 -1
- package/dist/763.js.map +1 -1
- package/dist/778.js +1 -1
- package/dist/778.js.map +1 -1
- package/dist/783.js +1 -1
- package/dist/783.js.map +1 -1
- package/dist/793.js +1 -1
- package/dist/793.js.map +1 -1
- package/dist/810.js +1 -1
- package/dist/810.js.map +1 -1
- package/dist/860.js +1 -1
- package/dist/860.js.map +1 -1
- package/dist/907.js +1 -1
- package/dist/907.js.map +1 -1
- package/dist/950.js +1 -1
- package/dist/950.js.map +1 -1
- package/dist/980.js +1 -1
- package/dist/980.js.map +1 -1
- package/dist/990.js +1 -1
- package/dist/990.js.map +1 -1
- package/dist/package-test.js +1 -1
- package/dist/package-test.js.map +1 -1
- package/dist/package.js +1 -1
- package/dist/package.js.map +1 -1
- package/eslintrc.json +0 -1
- package/files/drugs-props-train-scores.csv +664 -0
- package/package.json +11 -7
- package/src/package-api.ts +7 -3
- package/src/package-test.ts +4 -1
- package/src/package.g.ts +21 -9
- package/src/package.ts +33 -23
- package/src/pareto-optimization/pareto-computations.ts +6 -0
- package/src/pareto-optimization/pareto-optimizer.ts +1 -1
- package/src/pls/pls-constants.ts +3 -1
- package/src/pls/pls-tools.ts +73 -69
- package/src/probabilistic-scoring/data-generator.ts +202 -0
- package/src/probabilistic-scoring/nelder-mead.ts +204 -0
- package/src/probabilistic-scoring/pmpo-defs.ts +141 -3
- package/src/probabilistic-scoring/pmpo-utils.ts +240 -126
- package/src/probabilistic-scoring/prob-scoring.ts +862 -135
- package/src/probabilistic-scoring/stat-tools.ts +141 -6
- package/src/tests/anova-tests.ts +1 -1
- package/src/tests/classifiers-tests.ts +1 -1
- package/src/tests/dim-reduction-tests.ts +1 -1
- package/src/tests/linear-methods-tests.ts +1 -1
- package/src/tests/mis-vals-imputation-tests.ts +1 -1
- package/src/tests/pareto-tests.ts +251 -0
- package/src/tests/pmpo-tests.ts +797 -0
- package/test-console-output-1.log +303 -239
- package/test-record-1.mp4 +0 -0
- package/files/mpo-done.ipynb +0 -2123
package/package.json
CHANGED
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datagrok/eda",
|
|
3
3
|
"friendlyName": "EDA",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.5.0",
|
|
5
5
|
"description": "Exploratory Data Analysis Tools",
|
|
6
6
|
"dependencies": {
|
|
7
7
|
"@datagrok-libraries/math": "^1.2.6",
|
|
8
|
-
"@datagrok-libraries/ml": "^6.10.
|
|
9
|
-
"@datagrok-libraries/statistics": "^1.
|
|
8
|
+
"@datagrok-libraries/ml": "^6.10.10",
|
|
9
|
+
"@datagrok-libraries/statistics": "^1.12.0",
|
|
10
10
|
"@datagrok-libraries/tutorials": "^1.7.4",
|
|
11
|
-
"@datagrok-libraries/utils": "^4.
|
|
11
|
+
"@datagrok-libraries/utils": "^4.7.0",
|
|
12
12
|
"@keckelt/tsne": "^1.0.2",
|
|
13
13
|
"@webgpu/types": "^0.1.40",
|
|
14
14
|
"cash-dom": "^8.1.1",
|
|
15
|
-
"datagrok-api": "^1.
|
|
15
|
+
"datagrok-api": "^1.27.0",
|
|
16
16
|
"dayjs": "^1.11.9",
|
|
17
17
|
"jstat": "^1.9.6",
|
|
18
18
|
"mathjs": "^15.1.0",
|
|
19
19
|
"source-map-loader": "^4.0.1",
|
|
20
20
|
"umap-js": "^1.3.3",
|
|
21
21
|
"worker-loader": "^3.0.8",
|
|
22
|
-
"wu": "^2.1.0"
|
|
22
|
+
"wu": "^2.1.0",
|
|
23
|
+
"@datagrok-libraries/test": "^1.1.0"
|
|
23
24
|
},
|
|
24
25
|
"author": {
|
|
25
26
|
"name": "Viktor Makarichev",
|
|
@@ -29,7 +30,7 @@
|
|
|
29
30
|
"@typescript-eslint/eslint-plugin": "^5.32.0",
|
|
30
31
|
"@typescript-eslint/parser": "^5.32.0",
|
|
31
32
|
"css-loader": "^7.1.2",
|
|
32
|
-
"datagrok-tools": "^
|
|
33
|
+
"datagrok-tools": "^5.1.5",
|
|
33
34
|
"eslint": "^8.21.0",
|
|
34
35
|
"eslint-config-google": "^0.14.0",
|
|
35
36
|
"style-loader": "^4.0.0",
|
|
@@ -97,5 +98,8 @@
|
|
|
97
98
|
"Reduce Dimensionality": null
|
|
98
99
|
}
|
|
99
100
|
}
|
|
101
|
+
},
|
|
102
|
+
"overrides": {
|
|
103
|
+
"datagrok-api": "$datagrok-api"
|
|
100
104
|
}
|
|
101
105
|
}
|
package/src/package-api.ts
CHANGED
|
@@ -282,10 +282,14 @@ export namespace funcs {
|
|
|
282
282
|
return await grok.functions.call('EDA:TrainPmpo', {});
|
|
283
283
|
}
|
|
284
284
|
|
|
285
|
+
export async function getPmpoAppItems(view: DG.View ): Promise<any> {
|
|
286
|
+
return await grok.functions.call('EDA:GetPmpoAppItems', { view });
|
|
287
|
+
}
|
|
288
|
+
|
|
285
289
|
/**
|
|
286
|
-
|
|
290
|
+
Generates syntethetic dataset oriented on the pMPO modeling
|
|
287
291
|
*/
|
|
288
|
-
export async function
|
|
289
|
-
return await grok.functions.call('EDA:
|
|
292
|
+
export async function generatePmpoDataset(samples: number ): Promise<DG.DataFrame> {
|
|
293
|
+
return await grok.functions.call('EDA:GeneratePmpoDataset', { samples });
|
|
290
294
|
}
|
|
291
295
|
}
|
package/src/package-test.ts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import * as DG from 'datagrok-api/dg';
|
|
2
|
-
import {runTests, tests, TestContext, initAutoTests as initTests} from '@datagrok-libraries/
|
|
2
|
+
import {runTests, tests, TestContext, initAutoTests as initTests} from '@datagrok-libraries/test/src/test';
|
|
3
3
|
import './tests/dim-reduction-tests';
|
|
4
4
|
import './tests/linear-methods-tests';
|
|
5
5
|
import './tests/classifiers-tests';
|
|
6
6
|
import './tests/mis-vals-imputation-tests';
|
|
7
7
|
import './tests/anova-tests';
|
|
8
|
+
import './tests/pmpo-tests';
|
|
9
|
+
import './tests/pareto-tests';
|
|
10
|
+
|
|
8
11
|
export const _package = new DG.Package();
|
|
9
12
|
export {tests};
|
|
10
13
|
|
package/src/package.g.ts
CHANGED
|
@@ -7,6 +7,7 @@ export function info() : void {
|
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
//tags: init
|
|
10
|
+
//meta.role: init
|
|
10
11
|
export async function init() : Promise<void> {
|
|
11
12
|
await PackageFunctions.init();
|
|
12
13
|
}
|
|
@@ -37,34 +38,37 @@ export async function PCA(table: DG.DataFrame, features: DG.ColumnList, componen
|
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
//name: DBSCAN clustering
|
|
41
|
+
//tags: dim-red-postprocessing-function
|
|
40
42
|
//input: column col1
|
|
41
43
|
//input: column col2
|
|
42
44
|
//input: double epsilon = 0.01 { description: Minimum distance between two points to be considered as in the same neighborhood. }
|
|
43
45
|
//input: int minimumPoints = 5 { description: Minimum number of points to form a dense region. }
|
|
44
46
|
//meta.defaultPostProcessingFunction: true
|
|
45
|
-
//meta.role:
|
|
47
|
+
//meta.role: dim-red-postprocessing-function
|
|
46
48
|
export async function dbscanPostProcessingFunction(col1: DG.Column, col2: DG.Column, epsilon: number, minimumPoints: number) : Promise<void> {
|
|
47
49
|
await PackageFunctions.dbscanPostProcessingFunction(col1, col2, epsilon, minimumPoints);
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
//name: None (number)
|
|
53
|
+
//tags: dim-red-preprocessing-function
|
|
51
54
|
//input: column col
|
|
52
55
|
//input: string _metric { optional: true }
|
|
53
56
|
//output: object result
|
|
54
57
|
//meta.supportedTypes: int,float,double,qnum
|
|
55
58
|
//meta.supportedDistanceFunctions: Difference
|
|
56
|
-
//meta.role:
|
|
59
|
+
//meta.role: dim-red-preprocessing-function
|
|
57
60
|
export function numberPreprocessingFunction(col: DG.Column, _metric: string) {
|
|
58
61
|
return PackageFunctions.numberPreprocessingFunction(col, _metric);
|
|
59
62
|
}
|
|
60
63
|
|
|
61
64
|
//name: None (string)
|
|
65
|
+
//tags: dim-red-preprocessing-function
|
|
62
66
|
//input: column col
|
|
63
67
|
//input: string _metric { optional: true }
|
|
64
68
|
//output: object result
|
|
65
69
|
//meta.supportedTypes: string
|
|
66
70
|
//meta.supportedDistanceFunctions: One-Hot,Levenshtein,Hamming
|
|
67
|
-
//meta.role:
|
|
71
|
+
//meta.role: dim-red-preprocessing-function
|
|
68
72
|
export function stringPreprocessingFunction(col: DG.Column, _metric: string) {
|
|
69
73
|
return PackageFunctions.stringPreprocessingFunction(col, _metric);
|
|
70
74
|
}
|
|
@@ -77,6 +81,7 @@ export async function reduceDimensionality() : Promise<void> {
|
|
|
77
81
|
|
|
78
82
|
//tags: editor
|
|
79
83
|
//input: funccall call
|
|
84
|
+
//meta.role: editor
|
|
80
85
|
export function GetMCLEditor(call: DG.FuncCall) : void {
|
|
81
86
|
PackageFunctions.GetMCLEditor(call);
|
|
82
87
|
}
|
|
@@ -102,6 +107,7 @@ export async function MCLClustering(df: DG.DataFrame, cols: DG.Column[], metrics
|
|
|
102
107
|
|
|
103
108
|
//name: MCL
|
|
104
109
|
//description: Markov clustering viewer
|
|
110
|
+
//tags: viewer
|
|
105
111
|
//output: viewer result
|
|
106
112
|
//meta.showInGallery: false
|
|
107
113
|
//meta.role: viewer
|
|
@@ -532,6 +538,7 @@ export function paretoFront() : void {
|
|
|
532
538
|
|
|
533
539
|
//name: Pareto front
|
|
534
540
|
//description: Pareto front viewer
|
|
541
|
+
//tags: viewer
|
|
535
542
|
//output: viewer result
|
|
536
543
|
//meta.icon: icons/pareto-front-viewer.svg
|
|
537
544
|
//meta.role: viewer
|
|
@@ -540,14 +547,19 @@ export function paretoFrontViewer() : any {
|
|
|
540
547
|
}
|
|
541
548
|
|
|
542
549
|
//description: Train probabilistic multi-parameter optimization (pMPO) model
|
|
543
|
-
//top-menu: Chem | Calculate | Train pMPO...
|
|
544
550
|
export function trainPmpo() : void {
|
|
545
551
|
PackageFunctions.trainPmpo();
|
|
546
552
|
}
|
|
547
553
|
|
|
548
|
-
//
|
|
549
|
-
//
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
554
|
+
//input: view view
|
|
555
|
+
//output: object result
|
|
556
|
+
export function getPmpoAppItems(view: any) : any {
|
|
557
|
+
return PackageFunctions.getPmpoAppItems(view);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
//description: Generates syntethetic dataset oriented on the pMPO modeling
|
|
561
|
+
//input: int samples
|
|
562
|
+
//output: dataframe Synthetic
|
|
563
|
+
export async function generatePmpoDataset(samples: number) : Promise<any> {
|
|
564
|
+
return await PackageFunctions.generatePmpoDataset(samples);
|
|
553
565
|
}
|
package/src/package.ts
CHANGED
|
@@ -36,10 +36,12 @@ import {SoftmaxClassifier} from './softmax-classifier';
|
|
|
36
36
|
|
|
37
37
|
import {initXgboost} from '../wasm/xgbooster';
|
|
38
38
|
import {XGBooster} from './xgbooster';
|
|
39
|
+
|
|
39
40
|
import {ParetoOptimizer} from './pareto-optimization/pareto-optimizer';
|
|
40
41
|
import {ParetoFrontViewer} from './pareto-optimization/pareto-front-viewer';
|
|
42
|
+
|
|
41
43
|
import {Pmpo} from './probabilistic-scoring/prob-scoring';
|
|
42
|
-
import {
|
|
44
|
+
import {getSynteticPmpoData} from './probabilistic-scoring/data-generator';
|
|
43
45
|
|
|
44
46
|
export const _package = new DG.Package();
|
|
45
47
|
export * from './package.g';
|
|
@@ -53,7 +55,7 @@ export class PackageFunctions {
|
|
|
53
55
|
}
|
|
54
56
|
|
|
55
57
|
|
|
56
|
-
@grok.decorators.init({})
|
|
58
|
+
@grok.decorators.init({tags: ['init']})
|
|
57
59
|
static async init(): Promise<void> {
|
|
58
60
|
await _initEDAAPI();
|
|
59
61
|
await initXgboost();
|
|
@@ -115,8 +117,9 @@ export class PackageFunctions {
|
|
|
115
117
|
|
|
116
118
|
|
|
117
119
|
@grok.decorators.func({
|
|
118
|
-
'meta': {'defaultPostProcessingFunction': 'true', role: '
|
|
120
|
+
'meta': {'defaultPostProcessingFunction': 'true', 'role': 'dim-red-postprocessing-function'},
|
|
119
121
|
'name': 'DBSCAN clustering',
|
|
122
|
+
'tags': ['dim-red-postprocessing-function'],
|
|
120
123
|
})
|
|
121
124
|
static async dbscanPostProcessingFunction(
|
|
122
125
|
col1: DG.Column,
|
|
@@ -145,9 +148,10 @@ export class PackageFunctions {
|
|
|
145
148
|
'meta': {
|
|
146
149
|
'supportedTypes': 'int,float,double,qnum',
|
|
147
150
|
'supportedDistanceFunctions': 'Difference',
|
|
148
|
-
'role': '
|
|
151
|
+
'role': 'dim-red-preprocessing-function',
|
|
149
152
|
},
|
|
150
153
|
'name': 'None (number)',
|
|
154
|
+
'tags': ['dim-red-preprocessing-function'],
|
|
151
155
|
'outputs': [{name: 'result', type: 'object'}],
|
|
152
156
|
})
|
|
153
157
|
static numberPreprocessingFunction(
|
|
@@ -163,8 +167,9 @@ export class PackageFunctions {
|
|
|
163
167
|
'meta': {
|
|
164
168
|
'supportedTypes': 'string',
|
|
165
169
|
'supportedDistanceFunctions': 'One-Hot,Levenshtein,Hamming',
|
|
166
|
-
'role': '
|
|
170
|
+
'role': 'dim-red-preprocessing-function',
|
|
167
171
|
},
|
|
172
|
+
'tags': ['dim-red-preprocessing-function'],
|
|
168
173
|
'name': 'None (string)',
|
|
169
174
|
'outputs': [{name: 'result', type: 'object'}],
|
|
170
175
|
})
|
|
@@ -219,7 +224,7 @@ export class PackageFunctions {
|
|
|
219
224
|
}
|
|
220
225
|
|
|
221
226
|
|
|
222
|
-
@grok.decorators.editor()
|
|
227
|
+
@grok.decorators.editor({tags: ['editor']})
|
|
223
228
|
static GetMCLEditor(
|
|
224
229
|
call: DG.FuncCall): void {
|
|
225
230
|
try {
|
|
@@ -287,6 +292,7 @@ export class PackageFunctions {
|
|
|
287
292
|
@grok.decorators.func({
|
|
288
293
|
'outputs': [{'name': 'result', 'type': 'viewer'}],
|
|
289
294
|
'meta': {showInGallery: 'false', role: 'viewer'},
|
|
295
|
+
'tags': ['viewer'],
|
|
290
296
|
'name': 'MCL',
|
|
291
297
|
'description': 'Markov clustering viewer',
|
|
292
298
|
})
|
|
@@ -979,14 +985,14 @@ export class PackageFunctions {
|
|
|
979
985
|
'name': 'Pareto front',
|
|
980
986
|
'description': 'Pareto front viewer',
|
|
981
987
|
'outputs': [{'name': 'result', 'type': 'viewer'}],
|
|
982
|
-
'meta': {'icon': 'icons/pareto-front-viewer.svg', role: 'viewer'},
|
|
988
|
+
'meta': {'icon': 'icons/pareto-front-viewer.svg', 'role': 'viewer'},
|
|
989
|
+
'tags': ['viewer'],
|
|
983
990
|
})
|
|
984
991
|
static paretoFrontViewer(): DG.Viewer {
|
|
985
992
|
return new ParetoFrontViewer();
|
|
986
993
|
}
|
|
987
994
|
|
|
988
995
|
@grok.decorators.func({
|
|
989
|
-
'top-menu': 'Chem | Calculate | Train pMPO...',
|
|
990
996
|
'name': 'trainPmpo',
|
|
991
997
|
'description': 'Train probabilistic multi-parameter optimization (pMPO) model',
|
|
992
998
|
})
|
|
@@ -1004,22 +1010,26 @@ export class PackageFunctions {
|
|
|
1004
1010
|
pMPO.runTrainingApp();
|
|
1005
1011
|
}
|
|
1006
1012
|
|
|
1013
|
+
@grok.decorators.func({'name': 'getPmpoAppItems', 'outputs': [{name: 'result', type: 'object'}]})
|
|
1014
|
+
static getPmpoAppItems(@grok.decorators.param({type: 'view'}) view: DG.TableView): any | null {
|
|
1015
|
+
const df = view.dataFrame;
|
|
1016
|
+
if (!Pmpo.isTableValid(df))
|
|
1017
|
+
return null;
|
|
1018
|
+
|
|
1019
|
+
const pMPO = new Pmpo(df, view);
|
|
1020
|
+
|
|
1021
|
+
return pMPO.getPmpoAppItems();
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1007
1024
|
@grok.decorators.func({
|
|
1008
|
-
|
|
1009
|
-
'
|
|
1010
|
-
'
|
|
1025
|
+
'name': 'generatePmpoDataset',
|
|
1026
|
+
'description': 'Generates syntethetic dataset oriented on the pMPO modeling',
|
|
1027
|
+
'outputs': [{name: 'Synthetic', type: 'dataframe'}],
|
|
1011
1028
|
})
|
|
1012
|
-
static async
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
try {
|
|
1017
|
-
const params = await loadPmpoParams(file);
|
|
1018
|
-
const predName = table.columns.getUnusedName('pMPO score');
|
|
1019
|
-
const prediction = Pmpo.predict(table, params, predName);
|
|
1020
|
-
table.columns.add(prediction, true);
|
|
1021
|
-
} catch (err) {
|
|
1022
|
-
grok.shell.warning(`Failed to apply pMPO: ${err instanceof Error ? err.message : 'the platform issue.'}`);
|
|
1023
|
-
}
|
|
1029
|
+
static async generatePmpoDataset(@grok.decorators.param({'type': 'int'}) samples: number): Promise<DG.DataFrame> {
|
|
1030
|
+
const df = await getSynteticPmpoData(samples, false);
|
|
1031
|
+
df.name = 'Synthetic';
|
|
1032
|
+
return df;
|
|
1024
1033
|
}
|
|
1034
|
+
|
|
1025
1035
|
}
|
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
import {NumericArray, OPT_TYPE} from './defs';
|
|
4
4
|
|
|
5
|
+
/** Computes the Pareto front mask for a given dataset and optimization sense
|
|
6
|
+
* @param rawData Array of numeric arrays representing the dataset (each array corresponds to a feature/dimension)
|
|
7
|
+
* @param sense Array of optimization types (OPT_TYPE.MIN or OPT_TYPE.MAX) for each dimension
|
|
8
|
+
* @param nPoints Number of data points in the dataset
|
|
9
|
+
* @param nullIndices Optional set of indices corresponding to missing values (these points will be marked as non-optimal)
|
|
10
|
+
* @returns Boolean array where true indicates that the point is on the Pareto front */
|
|
5
11
|
export function getParetoMask(rawData: NumericArray[], sense: OPT_TYPE[], nPoints: number,
|
|
6
12
|
nullIndices?: Set<number>): boolean[] {
|
|
7
13
|
if (nPoints === 0)
|
|
@@ -19,7 +19,7 @@ export class ParetoOptimizer {
|
|
|
19
19
|
private toUpdatePcCols = false;
|
|
20
20
|
private paretoFrontViewer: DG.Viewer;
|
|
21
21
|
private resultColName: string;
|
|
22
|
-
private intervalId:
|
|
22
|
+
private intervalId: ReturnType<typeof setInterval> | null = null;
|
|
23
23
|
private inputsMap = new Map<string, DG.InputBase>();
|
|
24
24
|
private pcPlotNode: DG.DockNode | null = null;
|
|
25
25
|
private inputFormNode: DG.DockNode | null = null;
|
package/src/pls/pls-constants.ts
CHANGED
|
@@ -17,8 +17,10 @@ export enum ERROR_MSG {
|
|
|
17
17
|
ENOUGH = 'Not enough of features',
|
|
18
18
|
COMP_LIN_PLS = 'Components count must be less than the number of features',
|
|
19
19
|
COMP_QUA_PLS = 'Too large components count for the quadratic PLS regression',
|
|
20
|
-
|
|
20
|
+
COMP_ROWS = 'Components count must not exceed the number of rows',
|
|
21
|
+
COMPONENTS = 'Components count must be at least 1',
|
|
21
22
|
INV_INP = 'Invalid inputs',
|
|
23
|
+
NULL_COMPS = 'Components count is not specified',
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
/** Widget titles */
|
package/src/pls/pls-tools.ts
CHANGED
|
@@ -36,6 +36,24 @@ export type PlsInput = {
|
|
|
36
36
|
|
|
37
37
|
type TypedArray = Int32Array | Float32Array | Uint32Array | Float64Array;
|
|
38
38
|
|
|
39
|
+
/** Set style for input element depending on the validity of the value */
|
|
40
|
+
function setStyle(valid: boolean, element: HTMLElement, tooltip: string, errorMsg: string) {
|
|
41
|
+
if (valid) {
|
|
42
|
+
element.style.color = COLOR.VALID_TEXT;
|
|
43
|
+
element.style.borderBottomColor = COLOR.VALID_LINE;
|
|
44
|
+
ui.tooltip.bind(element, tooltip);
|
|
45
|
+
} else {
|
|
46
|
+
element.style.color = COLOR.INVALID;
|
|
47
|
+
element.style.borderBottomColor = COLOR.INVALID;
|
|
48
|
+
ui.tooltip.bind(element, () => {
|
|
49
|
+
const hint = ui.label(tooltip);
|
|
50
|
+
const err = ui.label(errorMsg);
|
|
51
|
+
err.style.color = COLOR.INVALID;
|
|
52
|
+
return ui.divV([hint, err]);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
39
57
|
/** Return lines */
|
|
40
58
|
export function getLines(names: string[]): DG.FormulaLine[] {
|
|
41
59
|
const lines: DG.FormulaLine[] = [];
|
|
@@ -137,7 +155,7 @@ function getQuadraticPlsInput(input: PlsInput): PlsInput {
|
|
|
137
155
|
|
|
138
156
|
for (let j = i; j < colsCount; ++j) {
|
|
139
157
|
col2 = cols[j];
|
|
140
|
-
raw2 = col2.getRawData();
|
|
158
|
+
raw2 = col2.getRawData();
|
|
141
159
|
qaudrRaw = new Float32Array(rowsCount);
|
|
142
160
|
|
|
143
161
|
for (let k = 0; k < rowsCount; ++k)
|
|
@@ -268,7 +286,7 @@ async function performMVA(input: PlsInput, analysisType: PLS_ANALYSIS): Promise<
|
|
|
268
286
|
});
|
|
269
287
|
|
|
270
288
|
|
|
271
|
-
// 4.3) create lines & circles
|
|
289
|
+
// 4.3) create lines & circles
|
|
272
290
|
view.addViewer(scoresScatter);
|
|
273
291
|
scoresScatter.meta.formulaLines.addAll(getLines(scoreNames));
|
|
274
292
|
|
|
@@ -321,7 +339,7 @@ async function performMVA(input: PlsInput, analysisType: PLS_ANALYSIS): Promise<
|
|
|
321
339
|
}));
|
|
322
340
|
|
|
323
341
|
// emphasize viewers in the demo case
|
|
324
|
-
if (analysisType === PLS_ANALYSIS.DEMO) {
|
|
342
|
+
if (analysisType === PLS_ANALYSIS.DEMO) {
|
|
325
343
|
grok.shell.windows.help.showHelp(ui.markdown(DEMO_RESULTS_MD));
|
|
326
344
|
|
|
327
345
|
describeElements(
|
|
@@ -372,38 +390,32 @@ export async function runMVA(analysisType: PLS_ANALYSIS): Promise<void> {
|
|
|
372
390
|
return;
|
|
373
391
|
}
|
|
374
392
|
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
let components = min(numColNames.length - 1, COMPONENTS.DEFAULT as number);
|
|
378
|
-
let isQuadratic = false;
|
|
379
|
-
|
|
380
|
-
const isPredictValid = () => {
|
|
381
|
-
for (const col of features)
|
|
382
|
-
if (col.name === predict.name)
|
|
383
|
-
return false;
|
|
384
|
-
return true;
|
|
393
|
+
const doFeaturesIncludePredict = () => {
|
|
394
|
+
return featuresInput.value.some((col) => col.name === predictInput.value!.name);
|
|
385
395
|
};
|
|
386
396
|
|
|
387
397
|
const isCompConsistent = () => {
|
|
388
|
-
if (
|
|
398
|
+
if (componentsInput.value! < 1)
|
|
389
399
|
return false;
|
|
390
400
|
|
|
391
|
-
|
|
401
|
+
if (componentsInput.value! > table.rowCount)
|
|
402
|
+
return false;
|
|
392
403
|
|
|
393
|
-
|
|
394
|
-
return components <= (n + 1) * n / 2 + n;
|
|
404
|
+
const n = featuresInput.value.length;
|
|
395
405
|
|
|
396
|
-
|
|
397
|
-
|
|
406
|
+
if (isQuadraticInput.value)
|
|
407
|
+
return componentsInput.value! <= (n + 1) * n / 2 + n;
|
|
408
|
+
|
|
409
|
+
return componentsInput.value! <= n;
|
|
410
|
+
};
|
|
398
411
|
|
|
399
412
|
// response (to predict)
|
|
400
413
|
const predictInput = ui.input.column(TITLE.PREDICT, {
|
|
401
414
|
table: table,
|
|
402
|
-
value:
|
|
415
|
+
value: numCols[numCols.length - 1],
|
|
403
416
|
nullable: false,
|
|
404
|
-
onValueChanged: (
|
|
405
|
-
|
|
406
|
-
updateIputs();
|
|
417
|
+
onValueChanged: (_) => {
|
|
418
|
+
updateInputStyles();
|
|
407
419
|
},
|
|
408
420
|
filter: (col: DG.Column) => isValidNumeric(col),
|
|
409
421
|
tooltipText: HINT.PREDICT,
|
|
@@ -413,21 +425,21 @@ export async function runMVA(analysisType: PLS_ANALYSIS): Promise<void> {
|
|
|
413
425
|
const featuresInput = ui.input.columns(TITLE.USING, {
|
|
414
426
|
table: table,
|
|
415
427
|
available: numColNames,
|
|
416
|
-
value:
|
|
417
|
-
onValueChanged: (
|
|
418
|
-
|
|
419
|
-
updateIputs();
|
|
428
|
+
value: numCols.slice(0, numCols.length - 1),
|
|
429
|
+
onValueChanged: (_) => {
|
|
430
|
+
updateInputStyles();
|
|
420
431
|
},
|
|
421
432
|
tooltipText: HINT.FEATURES,
|
|
433
|
+
nullable: false,
|
|
422
434
|
});
|
|
423
435
|
|
|
424
436
|
// components count
|
|
425
437
|
const componentsInput = ui.input.int(TITLE.COMPONENTS, {
|
|
426
|
-
value:
|
|
438
|
+
value: min(numColNames.length - 1, COMPONENTS.DEFAULT as number),
|
|
427
439
|
showPlusMinus: true,
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
440
|
+
nullable: false,
|
|
441
|
+
onValueChanged: (_) => {
|
|
442
|
+
updateInputStyles();
|
|
431
443
|
},
|
|
432
444
|
tooltipText: HINT.COMPONENTS,
|
|
433
445
|
});
|
|
@@ -446,28 +458,14 @@ export async function runMVA(analysisType: PLS_ANALYSIS): Promise<void> {
|
|
|
446
458
|
dlgRunBtnTooltip = HINT.MVA;
|
|
447
459
|
}
|
|
448
460
|
|
|
449
|
-
const
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
element.style.borderBottomColor = COLOR.VALID_LINE;
|
|
453
|
-
ui.tooltip.bind(element, tooltip);
|
|
454
|
-
} else {
|
|
455
|
-
element.style.color = COLOR.INVALID;
|
|
456
|
-
element.style.borderBottomColor = COLOR.INVALID;
|
|
457
|
-
ui.tooltip.bind(element, () => {
|
|
458
|
-
const hint = ui.label(tooltip);
|
|
459
|
-
const err = ui.label(errorMsg);
|
|
460
|
-
err.style.color = COLOR.INVALID;
|
|
461
|
-
return ui.divV([hint, err]);
|
|
462
|
-
});
|
|
463
|
-
}
|
|
464
|
-
};
|
|
465
|
-
|
|
466
|
-
const updateIputs = () => {
|
|
467
|
-
const predValid = isPredictValid();
|
|
461
|
+
const updateInputStyles = () => {
|
|
462
|
+
const featuresValid = featuresInput.value.length >= 1;
|
|
463
|
+
const predValid = featuresValid && !doFeaturesIncludePredict();
|
|
468
464
|
let compValid: boolean;
|
|
469
465
|
|
|
470
|
-
if (
|
|
466
|
+
if (!featuresValid)
|
|
467
|
+
setStyle(false, featuresInput.input, HINT.FEATURES, ERROR_MSG.ENOUGH);
|
|
468
|
+
else if (predValid) {
|
|
471
469
|
setStyle(true, predictInput.input, HINT.PREDICT, '');
|
|
472
470
|
setStyle(true, featuresInput.input, HINT.FEATURES, '');
|
|
473
471
|
} else {
|
|
@@ -475,9 +473,12 @@ export async function runMVA(analysisType: PLS_ANALYSIS): Promise<void> {
|
|
|
475
473
|
setStyle(false, featuresInput.input, HINT.FEATURES, ERROR_MSG.PREDICT);
|
|
476
474
|
}
|
|
477
475
|
|
|
478
|
-
if (
|
|
476
|
+
if (componentsInput.value == null) {
|
|
477
|
+
setStyle(false, componentsInput.input, HINT.COMPONENTS, ERROR_MSG.NULL_COMPS);
|
|
478
|
+
compValid = false;
|
|
479
|
+
} else if (componentsInput.value < 1) {
|
|
479
480
|
setStyle(false, componentsInput.input, HINT.COMPONENTS, ERROR_MSG.COMPONENTS);
|
|
480
|
-
compValid = false;
|
|
481
|
+
compValid = false;
|
|
481
482
|
} else {
|
|
482
483
|
compValid = isCompConsistent();
|
|
483
484
|
|
|
@@ -486,7 +487,9 @@ export async function runMVA(analysisType: PLS_ANALYSIS): Promise<void> {
|
|
|
486
487
|
if (predValid)
|
|
487
488
|
setStyle(true, featuresInput.input, HINT.FEATURES, '');
|
|
488
489
|
} else {
|
|
489
|
-
const errMsg =
|
|
490
|
+
const errMsg = componentsInput.value! > table.rowCount ?
|
|
491
|
+
ERROR_MSG.COMP_ROWS :
|
|
492
|
+
isQuadraticInput.value ? ERROR_MSG.COMP_QUA_PLS : ERROR_MSG.COMP_LIN_PLS;
|
|
490
493
|
setStyle(false, componentsInput.input, HINT.COMPONENTS, errMsg);
|
|
491
494
|
setStyle(false, featuresInput.input, HINT.FEATURES, ERROR_MSG.ENOUGH);
|
|
492
495
|
}
|
|
@@ -497,10 +500,18 @@ export async function runMVA(analysisType: PLS_ANALYSIS): Promise<void> {
|
|
|
497
500
|
dlg.getButton(TITLE.RUN).disabled = !isValid;
|
|
498
501
|
|
|
499
502
|
return isValid;
|
|
503
|
+
}; // updateInputStyles
|
|
504
|
+
|
|
505
|
+
const getStrColWithUniqueVals = () => {
|
|
506
|
+
for (const col of strCols) {
|
|
507
|
+
if (col.stats.uniqueCount === table.rowCount)
|
|
508
|
+
return col;
|
|
509
|
+
}
|
|
510
|
+
return undefined;
|
|
500
511
|
};
|
|
501
512
|
|
|
502
513
|
// names of samples
|
|
503
|
-
let names = (
|
|
514
|
+
let names = getStrColWithUniqueVals();
|
|
504
515
|
const namesInputs = ui.input.column(TITLE.NAMES, {
|
|
505
516
|
table: table,
|
|
506
517
|
value: names,
|
|
@@ -512,11 +523,10 @@ export async function runMVA(analysisType: PLS_ANALYSIS): Promise<void> {
|
|
|
512
523
|
|
|
513
524
|
// quadratic/linear model
|
|
514
525
|
const isQuadraticInput = ui.input.bool(TITLE.QUADRATIC, {
|
|
515
|
-
value:
|
|
526
|
+
value: false,
|
|
516
527
|
tooltipText: HINT.QUADRATIC,
|
|
517
|
-
onValueChanged: (
|
|
518
|
-
|
|
519
|
-
updateIputs();
|
|
528
|
+
onValueChanged: (_) => {
|
|
529
|
+
updateInputStyles();
|
|
520
530
|
},
|
|
521
531
|
});
|
|
522
532
|
|
|
@@ -527,21 +537,15 @@ export async function runMVA(analysisType: PLS_ANALYSIS): Promise<void> {
|
|
|
527
537
|
|
|
528
538
|
await performMVA({
|
|
529
539
|
table: table,
|
|
530
|
-
features: DG.DataFrame.fromColumns(
|
|
531
|
-
predict:
|
|
532
|
-
components:
|
|
533
|
-
isQuadratic:
|
|
540
|
+
features: DG.DataFrame.fromColumns(featuresInput.value).columns,
|
|
541
|
+
predict: predictInput.value!,
|
|
542
|
+
components: componentsInput.value!,
|
|
543
|
+
isQuadratic: isQuadraticInput.value,
|
|
534
544
|
names: names,
|
|
535
545
|
}, analysisType);
|
|
536
546
|
}, undefined, dlgRunBtnTooltip)
|
|
537
547
|
.show({x: X_COORD, y: Y_COORD});
|
|
538
548
|
|
|
539
|
-
// the following delay provides correct styles (see https://reddata.atlassian.net/browse/GROK-15196)
|
|
540
|
-
setTimeout(() => {
|
|
541
|
-
featuresInput.value = numCols.filter((col) => col !== predict);
|
|
542
|
-
features = featuresInput.value;
|
|
543
|
-
}, TIMEOUT);
|
|
544
|
-
|
|
545
549
|
grok.shell.v.append(dlg.root);
|
|
546
550
|
} // runMVA
|
|
547
551
|
|