@datagrok/eda 1.4.13 → 1.5.1

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.
Files changed (87) hide show
  1. package/CHANGELOG.md +11 -5
  2. package/dist/111.js +1 -1
  3. package/dist/111.js.map +1 -1
  4. package/dist/128.js +1 -1
  5. package/dist/128.js.map +1 -1
  6. package/dist/153.js +1 -1
  7. package/dist/153.js.map +1 -1
  8. package/dist/23.js +1 -1
  9. package/dist/23.js.map +1 -1
  10. package/dist/234.js +1 -1
  11. package/dist/234.js.map +1 -1
  12. package/dist/242.js +1 -1
  13. package/dist/242.js.map +1 -1
  14. package/dist/260.js +1 -1
  15. package/dist/260.js.map +1 -1
  16. package/dist/33.js +1 -1
  17. package/dist/33.js.map +1 -1
  18. package/dist/348.js +1 -1
  19. package/dist/348.js.map +1 -1
  20. package/dist/377.js +1 -1
  21. package/dist/377.js.map +1 -1
  22. package/dist/397.js +2 -0
  23. package/dist/397.js.map +1 -0
  24. package/dist/412.js +1 -1
  25. package/dist/412.js.map +1 -1
  26. package/dist/415.js +1 -1
  27. package/dist/415.js.map +1 -1
  28. package/dist/501.js +1 -1
  29. package/dist/501.js.map +1 -1
  30. package/dist/531.js +1 -1
  31. package/dist/531.js.map +1 -1
  32. package/dist/583.js +1 -1
  33. package/dist/583.js.map +1 -1
  34. package/dist/589.js +1 -1
  35. package/dist/589.js.map +1 -1
  36. package/dist/603.js +1 -1
  37. package/dist/603.js.map +1 -1
  38. package/dist/656.js +1 -1
  39. package/dist/656.js.map +1 -1
  40. package/dist/682.js +1 -1
  41. package/dist/682.js.map +1 -1
  42. package/dist/705.js +1 -1
  43. package/dist/705.js.map +1 -1
  44. package/dist/727.js +1 -1
  45. package/dist/727.js.map +1 -1
  46. package/dist/731.js +1 -1
  47. package/dist/731.js.map +1 -1
  48. package/dist/738.js +1 -1
  49. package/dist/738.js.map +1 -1
  50. package/dist/763.js +1 -1
  51. package/dist/763.js.map +1 -1
  52. package/dist/778.js +1 -1
  53. package/dist/778.js.map +1 -1
  54. package/dist/783.js +1 -1
  55. package/dist/783.js.map +1 -1
  56. package/dist/793.js +1 -1
  57. package/dist/793.js.map +1 -1
  58. package/dist/810.js +1 -1
  59. package/dist/810.js.map +1 -1
  60. package/dist/860.js +1 -1
  61. package/dist/860.js.map +1 -1
  62. package/dist/907.js +1 -1
  63. package/dist/907.js.map +1 -1
  64. package/dist/950.js +1 -1
  65. package/dist/950.js.map +1 -1
  66. package/dist/980.js +1 -1
  67. package/dist/980.js.map +1 -1
  68. package/dist/990.js +1 -1
  69. package/dist/990.js.map +1 -1
  70. package/dist/package-test.js +1 -1
  71. package/dist/package-test.js.map +1 -1
  72. package/dist/package.js +1 -1
  73. package/dist/package.js.map +1 -1
  74. package/package.json +5 -5
  75. package/src/package.ts +2 -1
  76. package/src/pareto-optimization/pareto-optimizer.ts +1 -1
  77. package/src/pls/pls-constants.ts +8 -1
  78. package/src/pls/pls-tools.ts +176 -74
  79. package/src/probabilistic-scoring/data-generator.ts +48 -3
  80. package/src/probabilistic-scoring/pmpo-defs.ts +30 -2
  81. package/src/probabilistic-scoring/pmpo-utils.ts +143 -52
  82. package/src/probabilistic-scoring/prob-scoring.ts +477 -104
  83. package/src/probabilistic-scoring/stat-tools.ts +1 -1
  84. package/src/tests/pareto-tests.ts +13 -15
  85. package/src/tests/pmpo-tests.ts +643 -3
  86. package/test-console-output-1.log +224 -86
  87. package/test-record-1.mp4 +0 -0
@@ -1,16 +1,18 @@
1
1
  // Utility functions for probabilistic scoring (pMPO)
2
- // Link: https://pmc.ncbi.nlm.nih.gov/articles/PMC4716604/
2
+ // Source paper https://pmc.ncbi.nlm.nih.gov/articles/PMC4716604/
3
3
 
4
4
  import * as grok from 'datagrok-api/grok';
5
5
  import * as ui from 'datagrok-api/ui';
6
6
  import * as DG from 'datagrok-api/dg';
7
7
 
8
+ import {generateMpoFileName, MPO_PROFILE_CHANGED_EVENT} from '@datagrok-libraries/statistics/src/mpo/utils';
8
9
  import '../../css/pmpo.css';
9
10
 
10
11
  import {COLORS, DESCR_TABLE_TITLE, DESCR_TITLE, DescriptorStatistics, DesirabilityProfileProperties,
11
12
  DESIRABILITY_COL_NAME, FOLDER, P_VAL, PMPO_COMPUTE_FAILED, PmpoParams, SCORES_TITLE,
12
13
  SELECTED_TITLE, STAT_TO_TITLE_MAP, TINY, WEIGHT_TITLE, CorrelationTriple,
13
- BASIC_RANGE_SIGMA_COEFFS, EXTENDED_RANGE_SIGMA_COEFFS} from './pmpo-defs';
14
+ BASIC_RANGE_SIGMA_COEFFS, EXTENDED_RANGE_SIGMA_COEFFS, EQUALITY_SIGN,
15
+ PREFERABLE_CATEGORIES} from './pmpo-defs';
14
16
  import {computeSigmoidParamsFromX0, getCutoffs, gaussDesirabilityFunc, sigmoidS,
15
17
  solveNormalIntersection} from './stat-tools';
16
18
  import {getColorScaleDiv} from '../pareto-optimization/utils';
@@ -369,38 +371,13 @@ export function getDesirabilityProfileJson(params: Map<string, PmpoParams>, useS
369
371
  */
370
372
  export async function saveModel(params: Map<string, PmpoParams>, modelName: string,
371
373
  useSigmoidalCorrection: boolean): Promise<void> {
372
- let fileName = modelName;
373
- const nameInput = ui.input.string('File', {
374
- value: fileName,
375
- nullable: false,
376
- onValueChanged: (val) => {
377
- fileName = val;
378
- dlg.getButton('Save').disabled = (fileName.length < 1) || (folderName.length < 1);
379
- },
380
- });
381
-
382
- let folderName = FOLDER;
383
- const folderInput = ui.input.string('Folder', {
384
- value: folderName,
385
- nullable: false,
386
- onValueChanged: (val) => {
387
- folderName = val;
388
- dlg.getButton('Save').disabled = (fileName.length < 1) || (folderName.length < 1);
389
- },
374
+ const nameInput = ui.input.string('Name', {value: modelName, nullable: false});
375
+ const descriptionInput = ui.input.textArea('Description', {value: ' ', nullable: true});
376
+ const typeInput = ui.input.bool('Desirability Profile', {
377
+ value: true,
378
+ tooltipText: 'Save the model as an MPO Desirability Profile. If disabled, the model is saved in the pMPO format.',
390
379
  });
391
380
 
392
- const save = async () => {
393
- const path = `${folderName}/${fileName}.json`;
394
- try {
395
- const jsonString = JSON.stringify(objectToSave(), null, 2);
396
- await grok.dapi.files.writeAsText(path, jsonString);
397
- grok.shell.info(`Saved to ${path}`);
398
- } catch (err) {
399
- grok.shell.error(`Failed to save: ${err instanceof Error ? err.message : 'the platform issue'}.`);
400
- }
401
- dlg.close();
402
- };
403
-
404
381
  const objectToSave = () => {
405
382
  if (typeInput.value) {
406
383
  return getDesirabilityProfileJson(
@@ -420,34 +397,29 @@ export async function saveModel(params: Map<string, PmpoParams>, modelName: stri
420
397
  };
421
398
  };
422
399
 
423
- const modelNameInput = ui.input.string('Name', {value: modelName, nullable: true});
424
- const descriptionInput = ui.input.textArea('Description', {value: ' ', nullable: true});
425
- const typeInput = ui.input.bool('Desirability Profile', {
426
- value: true,
427
- tooltipText: 'Save the model as an MPO Desirability Profile. If disabled, the model is saved in the pMPO format.',
428
- });
429
-
430
400
  const dlg = ui.dialog({title: 'Save model'})
431
- .add(ui.h2('Path'))
432
- .add(folderInput)
433
401
  .add(nameInput)
434
- .add(ui.h2('Model'))
435
- .add(modelNameInput)
436
402
  .add(descriptionInput)
437
403
  .add(typeInput)
438
404
  .addButton('Save', async () => {
439
- const exist = await grok.dapi.files.exists(`${folderName}/${fileName}.json`);
440
- if (!exist)
441
- await save();
442
- else {
443
- // Handle overwrite confirmation
444
- ui.dialog({title: 'Warning'})
445
- .add(ui.label('Overwrite existing file?'))
446
- .onOK(async () => await save())
447
- .show();
405
+ try {
406
+ const files = await grok.dapi.files.list(FOLDER);
407
+ const existingFileNames = new Set(files.map((f) => f.name));
408
+ const fileName = generateMpoFileName(nameInput.value, existingFileNames);
409
+ const path = `${FOLDER}/${fileName}`;
410
+ const jsonString = JSON.stringify(objectToSave(), null, 2);
411
+ await grok.dapi.files.writeAsText(path, jsonString);
412
+ grok.events.fireCustomEvent(MPO_PROFILE_CHANGED_EVENT, {});
413
+ grok.shell.info(`Saved to ${path}`);
414
+ } catch (err) {
415
+ grok.shell.error(`Failed to save: ${err instanceof Error ? err.message : 'the platform issue'}.`);
448
416
  }
417
+ dlg.close();
449
418
  })
450
419
  .show();
420
+
421
+ dlg.getButton('Save').disabled = !nameInput.validate();
422
+ nameInput.onInput.subscribe(() => dlg.getButton('Save').disabled = !nameInput.validate());
451
423
  } // saveModel
452
424
 
453
425
  /** Adds columns with correlation coefficients between descriptors.
@@ -601,3 +573,122 @@ export class PmpoError extends Error {
601
573
  this.name = 'PmpoError';
602
574
  }
603
575
  }
576
+
577
+ /** Returns the initial column for the desirability input, preferring boolean columns.
578
+ * @param cols List of columns to choose from.
579
+ * @return The initial column for the desirability input.
580
+ */
581
+ export function getInitCol(cols: DG.Column[]): DG.Column {
582
+ for (const col of cols) {
583
+ if ((col.type === DG.COLUMN_TYPE.BOOL) && (col.stats.stdev > 0))
584
+ return col;
585
+ }
586
+
587
+ for (const col of cols) {
588
+ if ((col.isNumerical) && (col.stats.stdev > 0))
589
+ return col;
590
+ }
591
+
592
+ return cols[0];
593
+ }
594
+
595
+ /** Returns a comparator function based on the given equality sign.
596
+ * @param sign Equality sign ('<', '<=', '>', '>=').
597
+ * @return Comparator function that takes two numbers and returns a boolean.
598
+ */
599
+ function getComparator(sign: EQUALITY_SIGN): (a: number, b: number) => boolean {
600
+ switch (sign) {
601
+ case EQUALITY_SIGN.LESS: return (a, b) => a < b;
602
+ case EQUALITY_SIGN.LESS_OR_EQUAL: return (a, b) => a <= b;
603
+ case EQUALITY_SIGN.GREATER: return (a, b) => a > b;
604
+ case EQUALITY_SIGN.GREATER_OR_EQUAL: return (a, b) => a >= b;
605
+
606
+ default:
607
+ throw new Error(`Unsupported sign: ${sign}`);
608
+ }
609
+ }
610
+
611
+ /** Converts a numeric column to a boolean column based on the given threshold and equality sign.
612
+ * @param numericCol Numeric column to convert.
613
+ * @param threshold Threshold value for comparison.
614
+ * @param sign Equality sign for comparison ('<', '<=', '>', '>=').
615
+ * @return Boolean column resulting from the comparison.
616
+ */
617
+ export function getBoolDesirabilityColData(numericCol: DG.Column,
618
+ threshold: number, sign: EQUALITY_SIGN): {column: DG.Column, tooltip: string} {
619
+ const boolArr = new Array<boolean>(numericCol.length);
620
+ const numericArr = numericCol.getRawData();
621
+
622
+ const comparator = getComparator(sign);
623
+
624
+ for (let i = 0; i < numericCol.length; ++i)
625
+ boolArr[i] = comparator(numericArr[i], threshold);
626
+
627
+ return {
628
+ column: DG.Column.fromList(DG.COLUMN_TYPE.BOOL, '', boolArr),
629
+ tooltip: `Desirability based on the condition:\n\n **${numericCol.name} ${sign} ${threshold}**`,
630
+ };
631
+ }
632
+
633
+ /** Checks whether the desirability column is valid based on the given threshold and equality sign.
634
+ * @param desCol Desirability column to check.
635
+ * @param threshold Threshold value for comparison.
636
+ * @param sign Equality sign for comparison ('<', '<=', '>', '>=').
637
+ * @return True if the desirability column is valid, false otherwise.
638
+ */
639
+ export function isDesirabilityValid(desCol: DG.Column, threshold: number, sign: EQUALITY_SIGN): boolean {
640
+ const min = desCol.stats.min;
641
+ const max = desCol.stats.max;
642
+
643
+ switch (sign) {
644
+ case EQUALITY_SIGN.LESS:
645
+ return (max >= threshold) && (min < threshold);
646
+
647
+ case EQUALITY_SIGN.LESS_OR_EQUAL:
648
+ return (max > threshold) && (min <= threshold);
649
+
650
+ case EQUALITY_SIGN.GREATER:
651
+ return (min <= threshold) && (max > threshold);
652
+
653
+ default:
654
+ return (min < threshold) && (max >= threshold);
655
+ }
656
+ }
657
+
658
+ /** Converts a string column to a boolean column based on the given desirable categories.
659
+ * @param stringCol String column to convert.
660
+ * @param desirableCategories List of categories that should be considered as desirable.
661
+ * @return Boolean column resulting from the conversion and a tooltip describing the desirability.
662
+ */
663
+ export function getDesirabilityColumnFromCategories(stringCol: DG.Column, desirableCategories: string[]):
664
+ {column: DG.Column, tooltip: string} {
665
+ const boolArr = new Array<boolean>(stringCol.length);
666
+ const raw = stringCol.getRawData();
667
+ const categories = stringCol.categories;
668
+
669
+ for (let i = 0; i < stringCol.length; ++i)
670
+ boolArr[i] = desirableCategories.includes(categories[raw[i]]);
671
+
672
+ const nonDesirableCategories = categories.filter((cat) => !desirableCategories.includes(cat));
673
+
674
+ const c = `\u2705 ${desirableCategories.join(', ')}`;
675
+ const unchecked = `\u274c ${nonDesirableCategories.join(', ')}`;
676
+
677
+ return {
678
+ column: DG.Column.fromList(DG.COLUMN_TYPE.BOOL, '', boolArr),
679
+ tooltip: `Desirability based on the selected categories:\n\n **${c}**\n\n **${unchecked}**`,
680
+ };
681
+ } // getDesirabilityColumnFromCategories
682
+
683
+ /** Returns a list of selected categories based on the given list of categories and preferable categories.
684
+ * @param categories List of categories to select from.
685
+ * @return List of selected categories.
686
+ */
687
+ export function getSelectedCategories(categories: string[]): string[] {
688
+ const selected = categories.filter((cat) => PREFERABLE_CATEGORIES.includes(cat));
689
+
690
+ if (selected.length > 0)
691
+ return selected;
692
+
693
+ return [categories[0]];
694
+ }