@datagrok/bio 2.17.3 → 2.17.5

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/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "name": "Leonid Stolbov",
6
6
  "email": "lstolbov@datagrok.ai"
7
7
  },
8
- "version": "2.17.3",
8
+ "version": "2.17.5",
9
9
  "description": "Bioinformatics support (import/export of sequences, conversion, visualization, analysis). [See more](https://github.com/datagrok-ai/public/blob/master/packages/Bio/README.md) for details.",
10
10
  "repository": {
11
11
  "type": "git",
@@ -46,8 +46,8 @@
46
46
  "@biowasm/aioli": "^3.1.0",
47
47
  "@datagrok-libraries/bio": "^5.46.0",
48
48
  "@datagrok-libraries/chem-meta": "^1.2.7",
49
- "@datagrok-libraries/math": "^1.2.2",
50
- "@datagrok-libraries/ml": "^6.7.4",
49
+ "@datagrok-libraries/math": "^1.2.3",
50
+ "@datagrok-libraries/ml": "^6.7.5",
51
51
  "@datagrok-libraries/tutorials": "^1.4.3",
52
52
  "@datagrok-libraries/utils": "^4.3.7",
53
53
  "@webgpu/types": "^0.1.40",
package/src/package.ts CHANGED
@@ -85,7 +85,7 @@ export async function getMonomerLibHelper(): Promise<IMonomerLibHelper> {
85
85
  return await MonomerLibManager.getInstance();
86
86
  }
87
87
 
88
- export let hydrophobPalette: SeqPaletteCustom | null = null;
88
+ //export let hydrophobPalette: SeqPaletteCustom | null = null;
89
89
 
90
90
  export class SeqPaletteCustom implements SeqPalette {
91
91
  private readonly _palette: { [m: string]: string };
@@ -128,39 +128,42 @@ async function initBioInt() {
128
128
  libSettings.explicit = [];
129
129
  await setUserLibSettings(libSettings);
130
130
  }
131
- libHelper.awaitLoaded(Infinity).then(() => {
132
- // Do not wait for monomers and sets loaded
133
- return Promise.all([libHelper.loadMonomerLib(), libHelper.loadMonomerSets()]);
134
- });
131
+ await libHelper.awaitLoaded(Infinity);
132
+ if (!libHelper.initialLoadCompleted)
133
+ await libHelper.loadMonomerLib();
134
+ // Do not wait for monomers and sets loaded
135
+ libHelper.loadMonomerSets();
135
136
  const monomerLib = libHelper.getMonomerLib();
136
137
  const monomerSets = libHelper.getMonomerSets();
137
138
  // finally log
138
139
  const t2: number = window.performance.now();
139
140
  _package.logger.debug(`${logPrefix}, loading ET: ${t2 - t1} ms`);
140
141
 
141
- const monomers: string[] = [];
142
- const logPs: number[] = [];
142
+ // const monomers: string[] = [];
143
+ // const logPs: number[] = [];
143
144
 
144
145
  const seqHelper = new SeqHelper(libHelper, rdKitModule);
145
146
  _package.completeInit(seqHelper, monomerLib, monomerSets, rdKitModule);
146
- const series = monomerLib!.getMonomerMolsByPolymerType('PEPTIDE')!;
147
- Object.keys(series).forEach((symbol) => {
148
- monomers.push(symbol);
149
- const block = series[symbol].replaceAll('#R', 'O ');
150
- const mol = rdKitModule.get_mol(block);
151
- const logP = JSON.parse(mol.get_descriptors()).CrippenClogP;
152
- logPs.push(logP);
153
- mol?.delete();
154
- });
155
-
156
- const sum = logPs.reduce((a, b) => a + b, 0);
157
- const avg = (sum / logPs.length) || 0;
158
-
159
- const palette: { [monomer: string]: string } = {};
160
- for (let i = 0; i < monomers.length; i++)
161
- palette[monomers[i]] = logPs[i] < avg ? '#4682B4' : '#DC143C';
162
147
 
163
- hydrophobPalette = new SeqPaletteCustom(palette);
148
+ // NB! do not delete the code below. not used now but in future we might use hydrophobicity palette
149
+ // const series = monomerLib!.getMonomerMolsByPolymerType('PEPTIDE')!;
150
+ // Object.keys(series).forEach((symbol) => {
151
+ // monomers.push(symbol);
152
+ // const block = series[symbol].replaceAll('#R', 'O ');
153
+ // const mol = rdKitModule.get_mol(block);
154
+ // const logP = JSON.parse(mol.get_descriptors()).CrippenClogP;
155
+ // logPs.push(logP);
156
+ // mol?.delete();
157
+ // });
158
+
159
+ // const sum = logPs.reduce((a, b) => a + b, 0);
160
+ // const avg = (sum / logPs.length) || 0;
161
+
162
+ // const palette: { [monomer: string]: string } = {};
163
+ // for (let i = 0; i < monomers.length; i++)
164
+ // palette[monomers[i]] = logPs[i] < avg ? '#4682B4' : '#DC143C';
165
+
166
+ // hydrophobPalette = new SeqPaletteCustom(palette);
164
167
 
165
168
  _package.logger.debug(`${logPrefix}, end`);
166
169
  }
@@ -1,3 +1,4 @@
1
+ /* eslint-disable max-lines-per-function */
1
2
  import * as grok from 'datagrok-api/grok';
2
3
  import * as ui from 'datagrok-api/ui';
3
4
  import * as DG from 'datagrok-api/dg';
@@ -26,7 +27,7 @@ category('detectorsBenchmark', () => {
26
27
  // -- fasta --
27
28
 
28
29
  test('fastaDnaShorts50Few50', async () => {
29
- await detectMacromoleculeBenchmark(10, NOTATION.FASTA, ALPHABET.DNA, 50, 50);
30
+ await detectMacromoleculeBenchmark(20, NOTATION.FASTA, ALPHABET.DNA, 50, 50);
30
31
  });
31
32
 
32
33
  test('fastaDnaShorts50Many1E6', async () => {
@@ -40,7 +41,7 @@ category('detectorsBenchmark', () => {
40
41
  // -- separator --
41
42
 
42
43
  test('separatorDnaShorts50Few50', async () => {
43
- await detectMacromoleculeBenchmark(10, NOTATION.SEPARATOR, ALPHABET.DNA, 50, 50, '/');
44
+ await detectMacromoleculeBenchmark(20, NOTATION.SEPARATOR, ALPHABET.DNA, 50, 50, '/');
44
45
  });
45
46
 
46
47
  test('separatorDnaShorts50Many1E6', async () => {
@@ -88,11 +88,11 @@ MWRSWYCKHPMWRSWYCKHPMWRSWYCKHPMWRSWYCKHPMWRSWYCKHPMWRSWYCKHPMWRSWYCKHPMWRSWYCKHP
88
88
 
89
89
  test('isCorrectHelm', async () => {
90
90
  await _testMSAOnColumn(helmFromCsv, helmToCsv, NOTATION.HELM, NOTATION.SEPARATOR, undefined, 'mafft');
91
- }, {timeout: 80000 /* docker */});
91
+ }, {timeout: 80000 /* docker */, skipReason: 'Fails in docker'});
92
92
 
93
93
  test('isCorrectHelmLong', async () => {
94
94
  await _testMSAOnColumn(longHelmFromCsv, longHelmToCsv, NOTATION.HELM, NOTATION.SEPARATOR, undefined, 'mafft');
95
- }, {timeout: 80000 /* docker */});
95
+ }, {timeout: 80000 /* docker */, skipReason: 'Fails in docker'});
96
96
 
97
97
  test('isCorrectSeparator', async () => {
98
98
  await _testMSAOnColumn(
@@ -35,7 +35,7 @@ category('PepSeA', () => {
35
35
  const tgtMsaCol = df.getCol('MSA');
36
36
  for (let i = 0; i < resMsaCol!.length; ++i)
37
37
  expect(resMsaCol!.get(i) == tgtMsaCol.get(i), true);
38
- }, {timeout: 60000 /* docker */, stressTest: true});
38
+ }, {timeout: 60000 /* docker */, stressTest: true, skipReason: 'Fails in docker'});
39
39
 
40
40
  test('stderr', async () => {
41
41
  const logger = new TestLogger();
@@ -45,7 +45,7 @@ category('PepSeA', () => {
45
45
  const tgtMsaCol = df.getCol('MSA');
46
46
  expectArray(resMsaCol!.toList(), tgtMsaCol.toList());
47
47
  expect(logger.warningList[0].message, pepseaStderrWarningList);
48
- }, {timeout: 60000 /* docker */, stressTest: true});
48
+ }, {timeout: 60000 /* docker */, stressTest: true, skipReason: 'Fails in docker'});
49
49
 
50
50
  test('error', async () => {
51
51
  const logger = new TestLogger();
@@ -58,5 +58,5 @@ category('PepSeA', () => {
58
58
  logger.error(errMsg, undefined, errStack);
59
59
  }
60
60
  expect(logger.errorList[0].message, pepseaErrorError);
61
- });
61
+ }, {skipReason: 'Fails in docker'});
62
62
  });
@@ -30,7 +30,8 @@ declare const window: MonomerLibWindowType;
30
30
  export class MonomerLibManager implements IMonomerLibHelper {
31
31
  private readonly _monomerLib = new MonomerLib({}, 'MAIN');
32
32
  private readonly _monomerSets = new MonomerSet('MAIN', []);
33
-
33
+ private _initialLoadCompleted: boolean = false;
34
+ public get initialLoadCompleted(): boolean { return this._initialLoadCompleted; }
34
35
  private _eventManager: MonomerLibFileEventManager;
35
36
 
36
37
  public get eventManager(): IMonomerLibFileEventManager { return this._eventManager; }
@@ -85,7 +86,8 @@ export class MonomerLibManager implements IMonomerLibHelper {
85
86
  return this._monomerSets;
86
87
  }
87
88
 
88
- /** Object containing symbols for each type of polymer where duplicate monomers are found in different libs (based on symbol as key) */
89
+ /** Object containing symbols for each type of polymer where duplicate monomers
90
+ * are found in different libs (based on symbol as key) */
89
91
  get duplicateMonomers() {
90
92
  return this._monomerLib.duplicateMonomers;
91
93
  }
@@ -107,6 +109,7 @@ export class MonomerLibManager implements IMonomerLibHelper {
107
109
  this._fileManagerPromise = (async () => {
108
110
  const fileManager: MonomerLibFileManager =
109
111
  await MonomerLibFileManager.create(this, this._eventManager, this.logger);
112
+ await fileManager.initializedPromise;
110
113
  return fileManager;
111
114
  })();
112
115
  }
@@ -158,6 +161,7 @@ export class MonomerLibManager implements IMonomerLibHelper {
158
161
  });
159
162
  })),]);
160
163
  this._monomerLib.updateLibs(libs, reload);
164
+ this._initialLoadCompleted = true;
161
165
  } catch (err: any) {
162
166
  // WARNING: This function is not allowed to throw any exception,
163
167
  // because it will prevent further handling monomer library settings
@@ -28,6 +28,7 @@ import {_package} from '../../../package';
28
28
  * All files **must** be aligned to the HELM standard before adding. */
29
29
  export class MonomerLibFileManager implements IMonomerLibFileManager {
30
30
  public filesPromise: Promise<void> = Promise.resolve();
31
+ public initializedPromise: Promise<void> = Promise.resolve();
31
32
 
32
33
  private constructor(
33
34
  private readonly fileValidator: MonomerLibFileValidator,
@@ -35,8 +36,19 @@ export class MonomerLibFileManager implements IMonomerLibFileManager {
35
36
  public readonly eventManager: MonomerLibFileEventManager,
36
37
  private readonly logger: ILogger,
37
38
  ) {
39
+ // these both are behavioral subjects, i.e. they emit their value when subscribed.
40
+ // initial creation/request from bio package on awaiting files promise makes no sense,
41
+ // until the subscription fires first time
42
+ let resolveFilesPromise: () => void;
43
+ let initialized = false;
44
+ this.initializedPromise =
45
+ Promise.race([DG.delay(1000), new Promise<void>((resolve) => resolveFilesPromise = resolve)]);
38
46
  const _libSub = this.eventManager.updateValidLibraryFileListRequested$.subscribe(() => {
39
47
  this.updateValidLibList().then(() => {});
48
+ if (!initialized) {
49
+ initialized = true;
50
+ resolveFilesPromise();
51
+ }
40
52
  });
41
53
  const _setSub = this.eventManager.updateValidSetFileListRequested$.subscribe(() => {
42
54
  this.updateValidSetList().then(() => {});
@@ -181,7 +193,7 @@ export class MonomerLibFileManager implements IMonomerLibFileManager {
181
193
 
182
194
  if (this.libListHasChanged(validLibPathList)) {
183
195
  this.eventManager.changeValidLibPathList(validLibPathList);
184
- this.libHelper.loadMonomerLib(true);
196
+ await this.libHelper.loadMonomerLib(true);
185
197
  }
186
198
  // console.log(`files after validation:`, this.libraryEventManager.getValidFilesPathList());
187
199
 
@@ -474,7 +474,7 @@ function getCaseInvariantValue<T>(obj: { [key: string]: T }, key: string): T | u
474
474
 
475
475
  // some r groups for some monomers can lack smiles, or something else :D this function will try to fix that
476
476
  function resolveRGroupInfo(rgps: RGroup[]): RGroup[] {
477
- return rgps.map((rg) => {
477
+ return (rgps.map((rg) => {
478
478
  const cp = assignObjectCaseInvariant(RGROUP_FIELDS, rg);
479
479
  const smi = getCaseInvariantValue(cp, HELM_RGROUP_FIELDS.CAP_GROUP_SMILES_UPPERCASE);
480
480
  const altId = getCaseInvariantValue(cp, HELM_RGROUP_FIELDS.ALTERNATE_ID);
@@ -498,7 +498,7 @@ function resolveRGroupInfo(rgps: RGroup[]): RGroup[] {
498
498
  cp[HELM_RGROUP_FIELDS.ALTERNATE_ID] = `${label}-${capName}`;
499
499
  }
500
500
  return cp;
501
- }) as RGroup[];
501
+ }) as RGroup[]).sort((a, b) => a.label?.localeCompare(b.label ?? '') ?? 0);
502
502
  }
503
503
 
504
504
 
@@ -607,7 +607,7 @@ class MonomerForm implements INewMonomerForm {
607
607
  } as unknown as RGroup;
608
608
  });
609
609
  // if (this.rgroupsGrid.items.length !== rGroupItems.length)
610
- this.rgroupsGrid.items = rGroupItems.sort((a, b) => a.label.localeCompare(b.label));
610
+ this.rgroupsGrid.items = rGroupItems.sort((a, b) => a.label?.localeCompare(b.label ?? '') ?? 0);
611
611
  this.rgroupsGrid.render();
612
612
  this.rgroupsGridRoot.style.display = 'flex';
613
613
  const mostSimilar = await mostSimilarNaturalAnalog(capSmiles(smiles, rGroupItems), this.polymerTypeInput.value ?? '');