@datagrok/bio 2.22.6 → 2.22.7

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.
@@ -28,7 +28,7 @@ category('renderers', () => {
28
28
  });
29
29
 
30
30
  test('long sequence performance ', async () => {
31
- await performanceTest(generateLongSequence, 'Long sequences');
31
+ await performanceTest(() => generateLongSequence(10 ** 4), 'Long sequences');
32
32
  });
33
33
 
34
34
  test('many sequence performance', async () => {
@@ -59,6 +59,8 @@ export function processSequence(subParts: string[]): [string[], boolean] {
59
59
  type RendererGridCellTemp = {
60
60
  [MmcrTemps.monomerPlacer]: MonomerPlacer
61
61
  }
62
+
63
+ // @grok.decorators.cellRenderer({name: 'customSequenceCellRenderer', cellType: 'sequence', columnTags: 'quality=Macromolecule, units=custom'})
62
64
  export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
63
65
  private readonly seqHelper: ISeqHelper;
64
66
 
@@ -1,3 +1,4 @@
1
+ /* eslint-disable max-lines */
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';
@@ -6,11 +7,13 @@ import wu from 'wu';
6
7
  import {Observable, Subject} from 'rxjs';
7
8
 
8
9
  import {IMonomerLibBase, Monomer, RGroup} from '@datagrok-libraries/bio/src/types/index';
9
- import {HelmAtom, HelmType, IMonomerColors, IWebEditorMonomer, MonomerType, PolymerType} from '@datagrok-libraries/bio/src/helm/types';
10
+ import {HelmAtom, HelmType, IMonomerColors,
11
+ IWebEditorMonomer, MonomerType, PolymerType} from '@datagrok-libraries/bio/src/helm/types';
10
12
  import {getMonomerHandleArgs} from '@datagrok-libraries/bio/src/helm/helm-helper';
11
13
  import {helmTypeToPolymerType} from '@datagrok-libraries/bio/src/monomer-works/monomer-works';
12
14
  import {HelmTypes, PolymerTypes} from '@datagrok-libraries/bio/src/helm/consts';
13
- import {HELM_OPTIONAL_FIELDS as OPT, HELM_REQUIRED_FIELD as REQ, HELM_RGROUP_FIELDS as RGP} from '@datagrok-libraries/bio/src/utils/const';
15
+ import {HELM_OPTIONAL_FIELDS as OPT, HELM_REQUIRED_FIELD as REQ,
16
+ HELM_RGROUP_FIELDS as RGP} from '@datagrok-libraries/bio/src/utils/const';
14
17
  import {GAP_SYMBOL, GapOriginals, NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule/consts';
15
18
  import {Vector} from '@datagrok-libraries/utils/src/type-declarations';
16
19
  import {vectorAdd, vectorDotProduct, vectorLength} from '@datagrok-libraries/utils/src/vector-operations';
@@ -276,9 +279,19 @@ export class MonomerLibBase implements IMonomerLibBase {
276
279
  let res: any;
277
280
  if (monomer) {
278
281
  if (monomer.meta && monomer.meta.colors) {
282
+ // due to some weird formatting, meta.colors can be a string
283
+ if (typeof monomer.meta.colors === 'string') {
284
+ try {
285
+ monomer.meta.colors = JSON.parse(monomer.meta.colors);
286
+ } catch (e) {
287
+ _package.logger.error(`Bio: MonomerLib.getMonomerColors() failed to parse monomer.meta.colors: ${e}`);
288
+ }
289
+ }
279
290
  const monomerColors: { [colorSchemaName: string]: any } = monomer.meta.colors;
280
- if (!(currentMonomerSchema in monomerColors)) monomerSchema = 'default';
281
- res = monomerColors[monomerSchema];
291
+ if (monomerColors && typeof monomerColors != 'string' && !(currentMonomerSchema in monomerColors))
292
+ monomerSchema = 'default';
293
+ if (monomerColors && typeof monomerColors != 'string' && monomerSchema in monomerColors)
294
+ res = monomerColors[monomerSchema];
282
295
  }
283
296
 
284
297
  if (!res) {
@@ -5,17 +5,17 @@ import * as ui from 'datagrok-api/ui';
5
5
  import * as DG from 'datagrok-api/dg';
6
6
 
7
7
  import wu from 'wu';
8
- import {Observable, Subject} from 'rxjs';
8
+ import {Observable} from 'rxjs';
9
9
 
10
10
  import {
11
- HelmType, HelmAtom,
12
- MonomerSetType, MonomerType, PolymerType, IWebEditorMonomer,
11
+ HelmType,
12
+ MonomerSetType, PolymerType,
13
13
  } from '@datagrok-libraries/bio/src/helm/types';
14
- import {IMonomerLibBase, IMonomerLib, IMonomerSet, Monomer, MonomerLibData, MonomerLibSummaryType, RGroup} from '@datagrok-libraries/bio/src/types';
15
- import {HELM_OPTIONAL_FIELDS as OPT, HELM_REQUIRED_FIELD as REQ, HELM_RGROUP_FIELDS as RGP} from '@datagrok-libraries/bio/src/utils/const';
14
+ import {IMonomerLibBase, IMonomerLib, Monomer,
15
+ MonomerLibData, MonomerLibSummaryType} from '@datagrok-libraries/bio/src/types';
16
16
  import {MolfileHandler} from '@datagrok-libraries/chem-meta/src/parsing-utils/molfile-handler';
17
17
  import {helmTypeToPolymerType} from '@datagrok-libraries/bio/src/monomer-works/monomer-works';
18
- import {getUserLibSettings, setUserLibSettings} from '@datagrok-libraries/bio/src/monomer-works/lib-settings';
18
+ import {getUserLibSettings} from '@datagrok-libraries/bio/src/monomer-works/lib-settings';
19
19
  import {UserLibSettings} from '@datagrok-libraries/bio/src/monomer-works/types';
20
20
 
21
21
  import {MonomerLibBase, MonomerLibDataType} from './monomer-lib-base';
@@ -87,7 +87,7 @@ export class MonomerLib extends MonomerLibBase implements IMonomerLib {
87
87
  if (!this._monomerSets)
88
88
  this._monomerSets = {};
89
89
  if (!(biotype in this._monomerSets)) {
90
- for (const [monomerSymbol, monomer] of Object.entries(this._monomers[polymerType])) {
90
+ for (const [_monomerSymbol, _monomer] of Object.entries(this._monomers[polymerType])) {
91
91
 
92
92
  }
93
93
  }
@@ -126,18 +126,65 @@ export class DuplicateMonomerManager {
126
126
  this.settings.duplicateMonomerPreferences[polymerType] = this.settings.duplicateMonomerPreferences[polymerType] ?? {};
127
127
  this.settings.duplicateMonomerPreferences[polymerType][monomerSymbol] = monomer.lib.source;
128
128
  await setUserLibSettings(this.settings);
129
- grok.shell.info(`Monomer '${monomer.name}' from source '${monomer.lib.source}' selected for symbol '${monomerSymbol}'.`);
130
129
  libManager.assignDuplicatePreferances(this.settings);
130
+ grok.shell.info(`Monomer '${monomer.name}' from source '${monomer.lib.source}' selected for symbol '${monomerSymbol}'.`);
131
131
  });
132
132
  }));
133
133
  }
134
134
  }
135
+ const setAllMonomersToSourceButton = ui.divText('Set Default');
136
+ setAllMonomersToSourceButton.addEventListener('click', async () => {
137
+ if (Object.keys(this.monomers ?? {}).length === 0) {
138
+ grok.shell.info('No Duplicate Monomers found');
139
+ return;
140
+ }
141
+ const uniqueLibSet = new Set<string>();
142
+ for (const polymerType in this.monomers) {
143
+ for (const monomerSymbol in this.monomers[polymerType]) {
144
+ for (const monomer of this.monomers[polymerType][monomerSymbol]) {
145
+ if (monomer.lib?.source)
146
+ uniqueLibSet.add(monomer.lib.source);
147
+ }
148
+ }
149
+ }
150
+ if (uniqueLibSet.size === 0) {
151
+ grok.shell.info('No Duplicate Monomers found');
152
+ return;
153
+ }
154
+ const uniqueLibs = Array.from(uniqueLibSet);
155
+ const libSelector = ui.input.choice('Default Library', {items: uniqueLibs, nullable: true});
156
+ ui.dialog('Set Default Monomer Source for Duplicates')
157
+ .add(libSelector)
158
+ .onOK(async () => {
159
+ if (!libSelector.value) {
160
+ grok.shell.info('No library selected');
161
+ return;
162
+ }
163
+ for (const polymerType in this.monomers) {
164
+ for (const monomerSymbol in this.monomers[polymerType]) {
165
+ const monomers = this.monomers[polymerType][monomerSymbol];
166
+ if (!monomers?.some((mon) => mon.lib?.source === libSelector.value))
167
+ continue;
168
+ this.settings.duplicateMonomerPreferences = this.settings.duplicateMonomerPreferences ?? {};
169
+ this.settings.duplicateMonomerPreferences[polymerType] = this.settings.duplicateMonomerPreferences[polymerType] ?? {};
170
+ this.settings.duplicateMonomerPreferences[polymerType][monomerSymbol] = libSelector.value;
171
+ }
172
+ }
173
+ await setUserLibSettings(this.settings);
174
+ libManager.assignDuplicatePreferances(this.settings);
175
+ grok.shell.info(`Default Monomer Source for Duplicates set to '${libSelector.value}'.`);
176
+ setTimeout(() => this.refresh(), 100);
177
+ })
178
+ .show();
179
+ });
180
+
135
181
  this.filteredMonomerRows = this.monomerCardRows;
136
182
  if (!this.vv) {
137
183
  this.vv = ui.virtualView(this.monomerCardRows.length, (i) => { this.monomerCardRows[i].render(); return this.monomerCardRows[i].root; });
138
184
  this.vv.root.classList.add('duplicate-monomers-virtual-view');
139
185
  this.searchInput = ui.input.string('Search', {placeholder: 'Monomer Symbol', value: '', onValueChanged: () => search(this.searchInput.value)});
140
186
  this.searchInput.root.style.justifyContent = 'center';
187
+ this.searchInput.addOptions(setAllMonomersToSourceButton);
141
188
  this.searchInput.input.style.width = '200px';
142
189
  this._root = ui.divV([ui.h1('Manage Duplicate Monomer Symbols', {style: {textAlign: 'center'}}),
143
190
  this.searchInput.root, ui.divV([this.vv.root], {style: {overflowY: 'auto', height: '100%'}})], {style: {height: '100%'}});
@@ -49,6 +49,89 @@ 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) {
53
+ 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
+ const df = DG.DataFrame.create(monomers.length);
61
+
62
+ const uniqueRgroupNamesSet = new Set<string>();
63
+ for (const monomer of monomers) {
64
+ monomer.rgroups.forEach((rg) => {
65
+ rg.label && uniqueRgroupNamesSet.add(rg.label);
66
+ });
67
+ }
68
+ const uniqueRgroupNames = Array.from(uniqueRgroupNamesSet);
69
+ uniqueRgroupNames.sort();
70
+ for (const [k, v] of Object.entries(MONOMER_DF_COLUMNS)) {
71
+ df.columns.addNew(k, v);
72
+ if (k === MONOMER_DF_COLUMN_NAMES.R_GROUPS) {
73
+ for (const rgroupName of uniqueRgroupNames)
74
+ df.columns.addNew(rgroupName, DG.COLUMN_TYPE.STRING);
75
+ }
76
+ }
77
+ df.col(MONOMER_DF_COLUMN_NAMES.SYMBOL)!.semType = 'Monomer';
78
+ df.col(MONOMER_DF_COLUMN_NAMES.SYMBOL)!.setTag(MONOMER_RENDERER_TAGS.applyToBackground, 'true');
79
+
80
+
81
+ for (let i = 0; i < monomers.length; i++) {
82
+ let molSmiles = getCorrectedSmiles(monomers[i].rgroups, monomers[i].smiles, monomers[i].molfile);
83
+ molSmiles = fixRGroupsAsElementsSmiles(molSmiles);
84
+ // r-groups here might be broken, so need to make sure they are correct
85
+ monomers[i].rgroups = resolveRGroupInfo(monomers[i].rgroups);
86
+ const rgroupSmiles = uniqueRgroupNames.map((rgName) => {
87
+ const rgroup = monomers[i].rgroups.find((rg) => rg.label === rgName);
88
+ return rgroup ? getCaseInvariantValue(rgroup, HELM_RGROUP_FIELDS.CAP_GROUP_SMILES) : '';
89
+ });
90
+ let date: number | null = null;
91
+
92
+ if (monomers[i].createDate) {
93
+ try {
94
+ date = Date.parse(monomers[i].createDate!);
95
+ } catch (e) {
96
+ console.error(`Error parsing date ${monomers[i].createDate}`);
97
+ }
98
+ }
99
+
100
+
101
+ df.rows.setValues(i, [
102
+ molSmiles,
103
+ monomers[i].symbol,
104
+ monomers[i].name,
105
+ JSON.stringify(monomers[i].rgroups ?? []),
106
+ ...rgroupSmiles,
107
+ monomers[i].monomerType,
108
+ monomers[i].polymerType,
109
+ monomers[i].naturalAnalog,
110
+ monomers[i].author,
111
+ date,
112
+ monomers[i].id,
113
+ JSON.stringify(monomers[i].meta ?? {}),
114
+ monomers[i].lib?.source ?? '',
115
+ ]);
116
+ // something is wrong with setting dates, so setting it manually for now
117
+ try {
118
+ if (date)
119
+ df.col(MONOMER_DF_COLUMN_NAMES.CREATE_DATE)?.set(i, date, false);
120
+ } catch (e) {
121
+ console.error(`Error setting date ${monomers[i].createDate}`, e);
122
+ }
123
+ }
124
+ df.col(MONOMER_DF_COLUMN_NAMES.MONOMER)!.semType = DG.SEMTYPE.MOLECULE;
125
+ uniqueRgroupNames.forEach((rgName) => {
126
+ df.col(rgName)!.semType = DG.SEMTYPE.MOLECULE;
127
+ });
128
+ return df;
129
+ } catch (e) {
130
+ grok.shell.error('Error creating monomers dataframe');
131
+ console.error(e);
132
+ throw e;
133
+ }
134
+ }
52
135
 
53
136
  export class MonomerManager implements IMonomerManager {
54
137
  private adjustTable() {
@@ -354,91 +437,7 @@ export class MonomerManager implements IMonomerManager {
354
437
  grok.shell.error(`Library ${fileName} not found`);
355
438
  return DG.DataFrame.create();
356
439
  }
357
- const ploymerTypes = this.activeMonomerLib.getPolymerTypes();
358
- const monomers = ploymerTypes.flatMap((polymerType) => {
359
- return this.activeMonomerLib!.getMonomerSymbolsByType(polymerType).map((symbol) => {
360
- return this.activeMonomerLib!.getMonomer(polymerType, symbol)!;
361
- });
362
- });
363
- const df = DG.DataFrame.create(monomers.length);
364
-
365
- const uniqueRgroupNamesSet = new Set<string>();
366
- for (const monomer of monomers) {
367
- monomer.rgroups.forEach((rg) => {
368
- rg.label && uniqueRgroupNamesSet.add(rg.label);
369
- });
370
- }
371
- const uniqueRgroupNames = Array.from(uniqueRgroupNamesSet);
372
- uniqueRgroupNames.sort();
373
- for (const [k, v] of Object.entries(MONOMER_DF_COLUMNS)) {
374
- df.columns.addNew(k, v);
375
- if (k === MONOMER_DF_COLUMN_NAMES.R_GROUPS) {
376
- for (const rgroupName of uniqueRgroupNames)
377
- df.columns.addNew(rgroupName, DG.COLUMN_TYPE.STRING);
378
- }
379
- }
380
- df.col(MONOMER_DF_COLUMN_NAMES.SYMBOL)!.semType = 'Monomer';
381
- df.col(MONOMER_DF_COLUMN_NAMES.SYMBOL)!.setTag(MONOMER_RENDERER_TAGS.applyToBackground, 'true');
382
-
383
-
384
- for (let i = 0; i < monomers.length; i++) {
385
- let molSmiles = getCorrectedSmiles(monomers[i].rgroups, monomers[i].smiles, monomers[i].molfile);
386
- molSmiles = fixRGroupsAsElementsSmiles(molSmiles);
387
- // r-groups here might be broken, so need to make sure they are correct
388
- monomers[i].rgroups = resolveRGroupInfo(monomers[i].rgroups);
389
- const rgroupSmiles = uniqueRgroupNames.map((rgName) => {
390
- const rgroup = monomers[i].rgroups.find((rg) => rg.label === rgName);
391
- return rgroup ? getCaseInvariantValue(rgroup, HELM_RGROUP_FIELDS.CAP_GROUP_SMILES) : '';
392
- });
393
- let date: number | null = null;
394
-
395
- if (monomers[i].createDate) {
396
- try {
397
- date = Date.parse(monomers[i].createDate!);
398
- } catch (e) {
399
- console.error(`Error parsing date ${monomers[i].createDate}`);
400
- }
401
- }
402
-
403
-
404
- df.rows.setValues(i, [
405
- molSmiles,
406
- monomers[i].symbol,
407
- monomers[i].name,
408
- JSON.stringify(monomers[i].rgroups ?? []),
409
- ...rgroupSmiles,
410
- monomers[i].monomerType,
411
- monomers[i].polymerType,
412
- monomers[i].naturalAnalog,
413
- monomers[i].author,
414
- date,
415
- monomers[i].id,
416
- JSON.stringify(monomers[i].meta ?? {}),
417
- monomers[i].lib?.source ?? '',
418
- ]);
419
- // something is wrong with setting dates, so setting it manually for now
420
- try {
421
- if (date)
422
- df.col(MONOMER_DF_COLUMN_NAMES.CREATE_DATE)?.set(i, date, false);
423
- } catch (e) {
424
- console.error(`Error setting date ${monomers[i].createDate}`);
425
- }
426
- }
427
- df.col(MONOMER_DF_COLUMN_NAMES.MONOMER)!.semType = DG.SEMTYPE.MOLECULE;
428
- uniqueRgroupNames.forEach((rgName) => {
429
- df.col(rgName)!.semType = DG.SEMTYPE.MOLECULE;
430
- });
431
- df.currentRowIdx = -1;
432
- // eslint-disable-next-line rxjs/no-ignored-subscription, rxjs/no-async-subscribe
433
- df.onCurrentRowChanged.subscribe(async (_) => {
434
- try {
435
- if (df.currentRowIdx === -1 || this._newMonomerForm.molChanged)
436
- return;
437
- await this.editMonomer(df.rows.get(df.currentRowIdx));
438
- } catch (e) {
439
- console.error(e);
440
- }
441
- });
440
+ const df = getMonomersDataFrame(this.activeMonomerLib);
442
441
  return df;
443
442
  } catch (e) {
444
443
  grok.shell.error('Error creating monomers dataframe');
@@ -31,7 +31,7 @@ import {undefinedColor} from '@datagrok-libraries/bio/src/utils/cell-renderer-mo
31
31
 
32
32
  import {AggFunc, getAgg} from '../utils/agg';
33
33
 
34
- import {_package, getMonomerLibHelper} from '../package';
34
+ import {_package, PackageFunctions} from '../package';
35
35
  import {numbersWithinMaxDiff} from './utils';
36
36
  import {buildCompositionTable} from '@datagrok-libraries/bio/src/utils/composition-table';
37
37
 
@@ -463,7 +463,7 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
463
463
  this.canvas.classList.value = 'bio-wl-canvas';
464
464
  this.canvas.style.width = '100%';
465
465
 
466
- getMonomerLibHelper().then((libHelper) => {
466
+ PackageFunctions.getMonomerLibHelper().then((libHelper) => {
467
467
  this.monomerLib = libHelper.getMonomerLib();
468
468
  this.render(WlRenderLevel.Render, 'monomerLib');
469
469
  this.subs.push(this.monomerLib.onChanged.subscribe(() => {
@@ -3,7 +3,7 @@ import * as ui from 'datagrok-api/ui';
3
3
  import * as DG from 'datagrok-api/dg';
4
4
  import * as OCL from 'openchemlib/full';
5
5
  import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
6
- import {_package, getSeqHelper, toAtomicLevel} from '../package';
6
+ import {_package, PackageFunctions} from '../package';
7
7
 
8
8
 
9
9
  export async function toAtomicLevelSingle(sequence: DG.SemanticValue): Promise<{mol: string, errorText: string}> {
@@ -23,7 +23,7 @@ export async function toAtomicLevelSingle(sequence: DG.SemanticValue): Promise<{
23
23
  errorText = 'Unsupported sequence notation. please use Bio | Polytool | Convert';
24
24
  return {errorText, mol: ''};
25
25
  }
26
- const seqHelper = await getSeqHelper();
26
+ const seqHelper = await PackageFunctions.getSeqHelper();
27
27
  const seqSh = seqHelper.getSeqHandler(sequence.cell.column);
28
28
  if (!seqSh) {
29
29
  errorText = 'No sequence handler found';
@@ -39,7 +39,7 @@ export async function toAtomicLevelSingle(sequence: DG.SemanticValue): Promise<{
39
39
  Object.entries(sequence.cell.column.tags).forEach(([key, value]) => {
40
40
  singleValCol.setTag(key, value as string);
41
41
  });
42
- await toAtomicLevel(sDf, singleValCol, sequence.cell.column.meta.units === NOTATION.HELM, false);
42
+ await PackageFunctions.toAtomicLevel(sDf, singleValCol, sequence.cell.column.meta.units === NOTATION.HELM, false);
43
43
  if (sDf.columns.length < 2) {
44
44
  errorText = 'No structure generated';
45
45
  return {errorText, mol: ''};