@datagrok/bio 2.22.8 → 2.22.10

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/src/package.ts CHANGED
@@ -70,7 +70,7 @@ import {GetRegionFuncEditor} from './utils/get-region-func-editor';
70
70
  import {sequenceToMolfile} from './utils/sequence-to-mol';
71
71
  import {detectMacromoleculeProbeDo} from './utils/detect-macromolecule-probe';
72
72
  import {getMolColumnFromHelm} from './utils/helm-to-molfile/utils';
73
- import {MonomerManager} from './utils/monomer-lib/monomer-manager/monomer-manager';
73
+ import {MonomerManager, standardizeMonomerLibrary} from './utils/monomer-lib/monomer-manager/monomer-manager';
74
74
  import {calculateScoresWithEmptyValues} from './utils/calculate-scores';
75
75
  import {SeqHelper} from './utils/seq-helper/seq-helper';
76
76
  import {_toAtomicLevel} from '@datagrok-libraries/bio/src/monomer-works/to-atomic-level';
@@ -82,6 +82,35 @@ export * from './package.g';
82
82
  // /** Avoid reassigning {@link monomerLib} because consumers subscribe to {@link IMonomerLib.onChanged} event */
83
83
  // let monomerLib: MonomerLib | null = null;
84
84
  let initBioPromise: Promise<void> | null = null;
85
+ /** Temporary polyfill */
86
+
87
+ function getDecoratorFunc() {
88
+ return function(args: any) {
89
+ return function(
90
+ target: any,
91
+ propertyKey: string,
92
+ descriptor: PropertyDescriptor
93
+ ) { };
94
+ };
95
+ }
96
+
97
+ // Ensure decorators object exists and polyfill missing decorators
98
+ if (!grok.decorators)
99
+ (grok as any).decorators = {};
100
+
101
+ const decorators = [
102
+ 'func', 'init', 'param', 'panel', 'editor', 'demo', 'app',
103
+ 'appTreeBrowser', 'fileHandler', 'fileExporter', 'model', 'viewer', 'filter', 'cellRenderer', 'autostart',
104
+ 'dashboard', 'folderViewer', 'semTypeDetector', 'packageSettingsEditor', 'functionAnalysis', 'converter',
105
+ 'fileViewer', 'model', 'treeBrowser', 'polyfill'
106
+ ];
107
+
108
+ decorators.forEach((decorator) => {
109
+ if (!(grok.decorators as any)[decorator])
110
+ (grok.decorators as any)[decorator] = getDecoratorFunc();
111
+ });
112
+
113
+ /** End temporary polyfill */
85
114
 
86
115
  export class PackageFunctions {
87
116
  @grok.decorators.func({description: 'Returns an instance of the monomer library helper', outputs: [{type: 'object', name: 'result'}]})
@@ -109,6 +138,11 @@ export class PackageFunctions {
109
138
  return resWidget;
110
139
  }
111
140
 
141
+ @grok.decorators.func({})
142
+ static async standardiseMonomerLibrary(library: string): Promise<string> {
143
+ return await standardizeMonomerLibrary(library);
144
+ }
145
+
112
146
  // Keep for backward compatibility
113
147
  @grok.decorators.func({outputs: [{type: 'object', name: 'monomerLib'}]})
114
148
  static getBioLib(): IMonomerLib {
@@ -356,7 +390,7 @@ export class PackageFunctions {
356
390
  static async activityCliffs(
357
391
  @grok.decorators.param({options: {description: 'Input data table'}})table: DG.DataFrame,
358
392
  @grok.decorators.param({type: 'string', options: {semType: 'Macromolecule', description: 'Input data table'}}) molecules: DG.Column<string>,
359
- activities: DG.Column,
393
+ activities: DG.Column,
360
394
  @grok.decorators.param({options: {initialValue: '80', description: 'Similarity cutoff'}}) similarity: number,
361
395
  @grok.decorators.param({type: 'string', options: {choices: ['UMAP', 't-SNE']}}) methodName: DimReductionMethods,
362
396
  @grok.decorators.param({type: 'string', options: {choices: ['Hamming', 'Levenshtein', 'Monomer chemical distance']}}) similarityMetric: MmDistanceFunctionsNames | BitArrayMetrics,
@@ -410,30 +444,30 @@ export class PackageFunctions {
410
444
  return;
411
445
  }
412
446
 
413
- const pi = DG.TaskBarProgressIndicator.create(`Running sequence activity cliffs ...`);
414
- const scRes = (await new Promise<DG.Viewer | undefined>((resolve, reject) => {
415
- if (table.rowCount > fastRowCount && !options?.[BYPASS_LARGE_DATA_WARNING]) {
416
- ui.dialog().add(ui.divText(`Activity cliffs analysis might take several minutes.
447
+ const pi = DG.TaskBarProgressIndicator.create(`Running sequence activity cliffs ...`);
448
+ const scRes = (await new Promise<DG.Viewer | undefined>((resolve, reject) => {
449
+ if (table.rowCount > fastRowCount && !options?.[BYPASS_LARGE_DATA_WARNING]) {
450
+ ui.dialog().add(ui.divText(`Activity cliffs analysis might take several minutes.
417
451
  Do you want to continue?`))
418
- .onOK(async () => {
419
- runCliffs().then((res) => resolve(res)).catch((err) => reject(err));
420
- })
421
- .onCancel(() => { resolve(undefined); })
422
- .show();
423
- } else
424
- runCliffs().then((res) => resolve(res)).catch((err) => reject(err));
425
- }).catch((err: any) => {
426
- const [errMsg, errStack] = errInfo(err);
427
- _package.logger.error(errMsg, undefined, errStack);
428
- throw err;
429
- }).finally(() => { pi.close(); })) as DG.ScatterPlotViewer | undefined;
430
- if (scRes?.props?.xColumnName && scRes?.props?.yColumnName && table.col(scRes.props.xColumnName) && table.col(scRes.props.yColumnName)) {
452
+ .onOK(async () => {
453
+ runCliffs().then((res) => resolve(res)).catch((err) => reject(err));
454
+ })
455
+ .onCancel(() => { resolve(undefined); })
456
+ .show();
457
+ } else
458
+ runCliffs().then((res) => resolve(res)).catch((err) => reject(err));
459
+ }).catch((err: any) => {
460
+ const [errMsg, errStack] = errInfo(err);
461
+ _package.logger.error(errMsg, undefined, errStack);
462
+ throw err;
463
+ }).finally(() => { pi.close(); })) as DG.ScatterPlotViewer | undefined;
464
+ if (scRes?.props?.xColumnName && scRes?.props?.yColumnName && table.col(scRes.props.xColumnName) && table.col(scRes.props.yColumnName)) {
431
465
  table.col(scRes.props.xColumnName)!.set(0, table.col(scRes.props.xColumnName)!.get(0)); // to trigger rendering
432
466
  table.col(scRes.props.yColumnName)!.set(0, table.col(scRes.props.yColumnName)!.get(0)); // to trigger rendering
433
- }
467
+ }
434
468
 
435
- return scRes;
436
- }
469
+ return scRes;
470
+ }
437
471
 
438
472
  @grok.decorators.func({
439
473
  name: 'Encode Sequences',
@@ -969,8 +1003,8 @@ export class PackageFunctions {
969
1003
  return await showManageLibrariesView(false);
970
1004
  }
971
1005
 
972
- @grok.decorators.func({name: 'Monomer Manager Tree Browser'})
973
- static async manageMonomerLibrariesViewTreeBrowser(treeNode: DG.TreeViewGroup, browsePanel: DG.BrowsePanel) {
1006
+ @grok.decorators.func({name: 'Monomer Manager Tree Browser', meta: {role: 'appTreeBrowser'}})
1007
+ static async manageMonomerLibrariesViewTreeBrowser(treeNode: DG.TreeViewGroup) {
974
1008
  const libraries = (await (await MonomerLibManager.getInstance()).getFileManager()).getValidLibraryPaths();
975
1009
  libraries.forEach((libName) => {
976
1010
  const nodeName = libName.endsWith('.json') ? libName.substring(0, libName.length - 5) : libName;
@@ -49,14 +49,29 @@ export const MONOMER_DF_COLUMNS = {
49
49
  [MONOMER_DF_COLUMN_NAMES.SOURCE]: DG.COLUMN_TYPE.STRING,
50
50
  } as const;
51
51
 
52
- export function getMonomersDataFrame(activeMonomerLib: IMonomerLib) {
52
+ export async function standardiseMonomers(monomers: Monomer[]) {
53
+ const df = getMonomersDataFrame(monomers);
54
+ if (monomers.length !== df.rowCount)
55
+ throw new Error(`Monomers length ${monomers.length} does not match dataframe row count ${df.rowCount}`);
56
+ const fixedMonomers = await Promise.all(new Array(monomers.length).fill(null).map(async (_, i) => monomerFromDfRow(df.rows.get(i))));
57
+ return fixedMonomers;
58
+ }
59
+
60
+ /** Standardizes the monomer library
61
+ * warning: throws error if the library is not valid or has invalid monomers
62
+ */
63
+ export async function standardizeMonomerLibrary(libraryString: string) {
64
+ const library: Monomer[] = JSON.parse(libraryString);
65
+ if (!library || !Array.isArray(library) || library.length === 0)
66
+ throw new Error('Invalid library format, expected an array of monomers');
67
+ const fixedMonomers = await standardiseMonomers(library);
68
+ const fixedLibrary = fixedMonomers.map((m) => ({...m, lib: undefined, wem: undefined}));
69
+ const libraryStringFixed = JSON.stringify(fixedLibrary, null, 2);
70
+ return libraryStringFixed;
71
+ }
72
+
73
+ export function getMonomersDataFrame(monomers: Monomer[]) {
53
74
  try {
54
- const ploymerTypes = activeMonomerLib.getPolymerTypes();
55
- const monomers = ploymerTypes.flatMap((polymerType) => {
56
- return activeMonomerLib!.getMonomerSymbolsByType(polymerType).map((symbol) => {
57
- return activeMonomerLib!.getMonomer(polymerType, symbol)!;
58
- });
59
- });
60
75
  const df = DG.DataFrame.create(monomers.length);
61
76
 
62
77
  const uniqueRgroupNamesSet = new Set<string>();
@@ -437,7 +452,14 @@ export class MonomerManager implements IMonomerManager {
437
452
  grok.shell.error(`Library ${fileName} not found`);
438
453
  return DG.DataFrame.create();
439
454
  }
440
- const df = getMonomersDataFrame(this.activeMonomerLib);
455
+
456
+ const ploymerTypes = this.activeMonomerLib.getPolymerTypes();
457
+ const monomers = ploymerTypes.flatMap((polymerType) => {
458
+ return this.activeMonomerLib!.getMonomerSymbolsByType(polymerType).map((symbol) => {
459
+ return this.activeMonomerLib!.getMonomer(polymerType, symbol)!;
460
+ });
461
+ });
462
+ const df = getMonomersDataFrame(monomers);
441
463
  return df;
442
464
  } catch (e) {
443
465
  grok.shell.error('Error creating monomers dataframe');