@datagrok/bio 2.12.22 → 2.13.2

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.
@@ -0,0 +1,37 @@
1
+ [
2
+ {
3
+ "monomerType": "Backbone",
4
+ "smiles": "CCCCCCCC[C@H](N[H:1])C([OH:2])=O",
5
+ "name": "2-Aminocapric acid",
6
+ "author": "Pistoia Alliance HELM project",
7
+ "molfile": "HELM Core Monomer library\n RDKit 2D\n\n 14 13 0 0 1 0 0 0 0 0999 V2000\n 0.6430 -4.4293 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 1.2375 -5.0013 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 2.0301 -4.7725 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 2.6246 -5.3445 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 3.4172 -5.1157 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 4.0117 -5.6877 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 4.8044 -5.4589 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 5.3988 -6.0310 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 6.1915 -5.8021 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 6.7859 -6.3742 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n 7.5786 -6.1454 0.0000 R# 0 0 0 0 0 0 0 0 0 0 0 0\n 6.3896 -5.0013 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 5.7951 -4.4293 0.0000 R# 0 0 0 0 0 0 0 0 0 0 0 0\n 7.1823 -4.7725 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n 1 2 1 0\n 2 3 1 0\n 3 4 1 0\n 4 5 1 0\n 5 6 1 0\n 6 7 1 0\n 7 8 1 0\n 9 8 1 0\n 9 10 1 1\n 10 11 1 0\n 9 12 1 0\n 12 13 1 0\n 12 14 2 0\nM RGP 2 11 1 13 2\nM END\n",
8
+ "naturalAnalog": "X",
9
+ "rgroups": [
10
+ {
11
+ "capGroupSMILES": "[*:1][H]",
12
+ "alternateId": "R1-H",
13
+ "capGroupName": "H",
14
+ "label": "R1"
15
+ },
16
+ {
17
+ "capGroupSMILES": "O[*:2]",
18
+ "alternateId": "R2-OH",
19
+ "capGroupName": "OH",
20
+ "label": "R2"
21
+ }
22
+ ],
23
+ "meta": {
24
+ "colors": {
25
+ "default": {
26
+ "line": "#202020",
27
+ "text": "#202020",
28
+ "background": "#60FF40"
29
+ }
30
+ }
31
+ },
32
+ "createDate": null,
33
+ "id": 0,
34
+ "polymerType": "PEPTIDE",
35
+ "symbol": "Aca"
36
+ }
37
+ ]
@@ -0,0 +1,4 @@
1
+ seq
2
+ [meI][hHis][Aca]NT[dE][Thr_PO3H2][Aca]D[meI][hHis][Aca]NT[dE][Thr_PO3H2][Aca]D[meI]
3
+ [meI][hHis][Aca][Cys_SEt]T[dK][Thr_PO3H2][Aca][Tyr_PO3H2][meI][hHis][Aca][Cys_SEt]T[dK][Thr_PO3H2][Aca][Tyr_PO3H2]
4
+ [Lys_Boc][hHis][Aca][Cys_SEt]T[dK][Thr_PO3H2][Aca][Tyr_PO3H2][Lys_Boc][hHis][Aca][Cys_SEt]T[dK][Thr_PO3H2][Aca][Tyr_PO3H2]
@@ -0,0 +1,4 @@
1
+ seq
2
+ [meI][hHis][Aca]NT[dE][Thr_PO3H2][Aca]D[meI][hHis][Aca]NT[dE][Thr_PO3H2][Aca]D
3
+ [meI][hHis][Aca][Cys_SEt]T[dK][Thr_PO3H2][Aca][Tyr_PO3H2][meI][hHis][Aca][Cys_SEt]T[dK][Thr_PO3H2][Aca][Tyr_PO3H2]
4
+ [Lys_Boc][hHis][Aca][Cys_SEt]T[dK][Thr_PO3H2][Aca][Tyr_PO3H2][Lys_Boc][hHis][Aca][Cys_SEt]T[dK][Thr_PO3H2][Aca][Tyr_PO3H2]
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "name": "Aleksandr Tanas",
6
6
  "email": "atanas@datagrok.ai"
7
7
  },
8
- "version": "2.12.22",
8
+ "version": "2.13.2",
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",
@@ -13,6 +13,16 @@
13
13
  "directory": "packages/Bio"
14
14
  },
15
15
  "properties": [
16
+ {
17
+ "name": "MonomerWidthMode",
18
+ "propertyType": "string",
19
+ "choices": [
20
+ "short",
21
+ "long"
22
+ ],
23
+ "defaultValue": "short",
24
+ "nullable": false
25
+ },
16
26
  {
17
27
  "name": "MaxMonomerLength",
18
28
  "propertyType": "int",
@@ -34,18 +44,18 @@
34
44
  ],
35
45
  "dependencies": {
36
46
  "@biowasm/aioli": "^3.1.0",
37
- "@datagrok-libraries/bio": "^5.41.8",
47
+ "@datagrok-libraries/bio": "^5.42.3",
38
48
  "@datagrok-libraries/chem-meta": "^1.2.5",
39
49
  "@datagrok-libraries/math": "^1.1.5",
40
- "@datagrok-libraries/ml": "^6.6.5",
50
+ "@datagrok-libraries/ml": "^6.6.12",
41
51
  "@datagrok-libraries/tutorials": "^1.3.12",
42
- "@datagrok-libraries/utils": "^4.2.5",
52
+ "@datagrok-libraries/utils": "^4.2.11",
43
53
  "@webgpu/types": "^0.1.40",
44
54
  "ajv": "^8.12.0",
45
55
  "ajv-errors": "^3.0.0",
46
56
  "cash-dom": "^8.0.0",
47
57
  "css-loader": "^6.7.3",
48
- "datagrok-api": "^1.17.4",
58
+ "datagrok-api": "^1.18.6",
49
59
  "dayjs": "^1.11.4",
50
60
  "fastest-levenshtein": "^1.0.16",
51
61
  "openchemlib": "^7.2.3",
@@ -55,6 +65,8 @@
55
65
  "wu": "latest"
56
66
  },
57
67
  "devDependencies": {
68
+ "@datagrok-libraries/helm-web-editor": "^1.1.5",
69
+ "@datagrok-libraries/js-draw-lite": "^0.0.3",
58
70
  "@datagrok/chem": "^1.9.2",
59
71
  "@datagrok/dendrogram": "^1.2.29",
60
72
  "@datagrok/helm": "^2.2.1",
@@ -4,9 +4,11 @@ import * as ui from 'datagrok-api/ui';
4
4
 
5
5
  import {Observable, Subject} from 'rxjs';
6
6
  import {errInfo} from '@datagrok-libraries/bio/src/utils/err-info';
7
+ import {MonomerWidthMode} from './utils/cell-renderer-consts';
7
8
 
8
9
  /** Names of package properties/settings declared in properties section of {@link './package.json'} */
9
10
  export const enum BioPackagePropertiesNames {
11
+ MonomerWidthMode = 'MonomerWidthMode',
10
12
  MaxMonomerLength = 'MaxMonomerLength',
11
13
  TooltipWebLogo = 'TooltipWebLogo',
12
14
  DefaultSeparator = 'DefaultSeparator',
@@ -17,6 +19,15 @@ export class BioPackageProperties extends Map<string, any> {
17
19
  private _onPropertyChanged: Subject<string> = new Subject<string>();
18
20
  public get onPropertyChanged(): Observable<string> { return this._onPropertyChanged; }
19
21
 
22
+ public get MonomerWidthMode(): MonomerWidthMode {
23
+ return super.get(BioPackagePropertiesNames.MonomerWidthMode) as MonomerWidthMode;
24
+ }
25
+
26
+ public set MonomerWidthMode(value: MonomerWidthMode) {
27
+ super.set(BioPackagePropertiesNames.MonomerWidthMode, value);
28
+ this._onPropertyChanged.next(BioPackagePropertiesNames.MonomerWidthMode);
29
+ }
30
+
20
31
  /** Monomer name maximum length displayed in short mode. */
21
32
  public get MaxMonomerLength(): number {
22
33
  return super.get(BioPackagePropertiesNames.MaxMonomerLength) as number;
package/src/package.ts CHANGED
@@ -3,8 +3,6 @@ import * as grok from 'datagrok-api/grok';
3
3
  import * as ui from 'datagrok-api/ui';
4
4
  import * as DG from 'datagrok-api/dg';
5
5
 
6
- import '@datagrok-libraries/bio/src/types/helm';
7
-
8
6
  import {Options} from '@datagrok-libraries/utils/src/type-declarations';
9
7
  import {DimReductionBaseEditor, PreprocessFunctionReturnType}
10
8
  from '@datagrok-libraries/ml/src/functionEditors/dimensionality-reduction-editor';
@@ -78,6 +76,7 @@ import {generateLongSequence, generateLongSequence2} from '@datagrok-libraries/b
78
76
 
79
77
  import {CyclizedNotationProvider} from './utils/cyclized';
80
78
  import {getMolColumnFromHelm} from './utils/helm-to-molfile/utils';
79
+ import {PackageSettingsEditorWidget} from './widgets/package-settings-editor-widget';
81
80
 
82
81
  export const _package = new BioPackage();
83
82
 
@@ -109,7 +108,7 @@ let monomerLib: IMonomerLib | null = null;
109
108
 
110
109
  //tags: init
111
110
  export async function initBio() {
112
- const logPrefix = 'Bio: initBio()';
111
+ const logPrefix = 'Bio: _package.initBio()';
113
112
  _package.logger.debug(`${logPrefix}, start`);
114
113
  const module = await grok.functions.call('Chem:getRdKitModule');
115
114
  const t1: number = window.performance.now();
@@ -152,7 +151,7 @@ export async function initBio() {
152
151
 
153
152
  hydrophobPalette = new SeqPaletteCustom(palette);
154
153
 
155
- _package.logger.debug('Bio: initBio(), completed');
154
+ _package.logger.debug(`${logPrefix}, end`);
156
155
  }
157
156
 
158
157
  //name: sequenceTooltip
@@ -292,16 +291,16 @@ export function SeqActivityCliffsEditor(call: DG.FuncCall) {
292
291
 
293
292
  // -- Package settings editor --
294
293
 
295
- // //name: packageSettingsEditor
296
- // //description: The database connection
297
- // //tags: packageSettingsEditor
298
- // //input: object propList
299
- // //output: widget result
300
- // export function packageSettingsEditor(propList: DG.Property[]): DG.Widget {
301
- // const widget = new PackageSettingsEditorWidget(propList);
302
- // widget.init().then(); // Ignore promise returned
303
- // return widget as DG.Widget;
304
- // }
294
+ //name: packageSettingsEditor
295
+ //description: The database connection
296
+ //tags: packageSettingsEditor
297
+ //input: object propList
298
+ //output: widget result
299
+ export function packageSettingsEditor(propList: DG.Property[]): DG.Widget {
300
+ const widget = new PackageSettingsEditorWidget(propList);
301
+ widget.init().then(); // Ignore promise returned
302
+ return widget as DG.Widget;
303
+ }
305
304
 
306
305
  // -- Cell renderers --
307
306
 
@@ -108,8 +108,6 @@ id3,QHIRE--LT
108
108
 
109
109
  for (const [testName, testData] of Object.entries(tests)) {
110
110
  test(`getPosition-${testName}`, async () => {
111
- const libHelper = await getMonomerLibHelper();
112
- const monomerLib = libHelper.getBioLib();
113
111
  const df: DG.DataFrame = DG.DataFrame.fromCsv(testData.csv);
114
112
  await grok.data.detectSemanticTypes(df);
115
113
  const seqCol: DG.Column = df.getCol('seq');
@@ -117,16 +115,16 @@ id3,QHIRE--LT
117
115
  const monLength: number = 3;
118
116
  const charWidth: number = 7;
119
117
  const sepWidth: number = 12;
120
- const colTemp: MonomerPlacer = new MonomerPlacer(null, seqCol, _package.logger, () => {
121
- const sh = SeqHandler.forColumn(seqCol);
122
- return {
123
- seqHandler: sh,
124
- monomerCharWidth: charWidth,
125
- separatorWidth: sepWidth,
126
- monomerToShort: monomerToShort,
127
- monomerLengthLimit: monLength,
128
- };
129
- });
118
+ const colTemp: MonomerPlacer = new MonomerPlacer(null, seqCol, _package.logger, monLength,
119
+ () => {
120
+ const sh = SeqHandler.forColumn(seqCol);
121
+ return {
122
+ seqHandler: sh,
123
+ monomerCharWidth: charWidth,
124
+ separatorWidth: sepWidth,
125
+ monomerToShort: monomerToShort,
126
+ };
127
+ });
130
128
 
131
129
  const width: number = 10000;
132
130
  const testList = testData.testList;
@@ -28,7 +28,7 @@ export const enum Temps {
28
28
  export const enum tempTAGS {
29
29
  referenceSequence = 'reference-sequence',
30
30
  currentWord = 'current-word',
31
- monomerWidth = 'monomer-width',
31
+ monomerWidthMode = 'monomer-width-mode',
32
32
  }
33
33
 
34
34
  // export const MacromoleculeCellRendererDefaults = new class {
@@ -26,7 +26,7 @@ import {getGridCellRendererBack} from '@datagrok-libraries/bio/src/utils/cell-re
26
26
 
27
27
  import {
28
28
  Temps as mmcrTemps, Tags as mmcrTags,
29
- tempTAGS, rendererSettingsChangedState
29
+ tempTAGS, rendererSettingsChangedState, MonomerWidthMode
30
30
  } from '../utils/cell-renderer-consts';
31
31
  import * as C from './constants';
32
32
 
@@ -155,8 +155,9 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
155
155
  let maxLengthOfMonomer = 50; // in case of long monomer representation, do not limit max length
156
156
 
157
157
  // Cell renderer settings
158
- const tempMonomerWidth: string | null = tableColTemp[tempTAGS.monomerWidth];
159
- const monomerWidth: string = (tempMonomerWidth != null) ? tempMonomerWidth : 'short';
158
+ const tempMonomerWidth: string | null = tableColTemp[tempTAGS.monomerWidthMode];
159
+ const monomerWidth: string = (tempMonomerWidth != null) ? tempMonomerWidth :
160
+ (_package.properties?.MonomerWidthMode ?? MonomerWidthMode.short);
160
161
  if (monomerWidth === 'short') {
161
162
  // Renderer can start to work before Bio package initialized, in that time _package.properties is null.
162
163
  // TODO: Render function is available but package init method is not completed
@@ -169,20 +170,23 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
169
170
  getGridCellRendererBack<string, MonomerPlacer>(gridCell);
170
171
  let seqColTemp: MonomerPlacer = temp.rendererBack;
171
172
  if (!seqColTemp) {
172
- seqColTemp = temp.rendererBack = new MonomerPlacer(gridCol, tableCol, _package.logger,
173
+ seqColTemp = temp.rendererBack = new MonomerPlacer(gridCol, tableCol, _package.logger, maxLengthOfMonomer,
173
174
  () => {
174
175
  const sh = SeqHandler.forColumn(tableCol);
175
176
  return {
176
177
  seqHandler: sh,
177
178
  monomerCharWidth: 7, separatorWidth: !sh.isMsa() ? gapLength : msaGapLength,
178
- monomerToShort: monomerToShortFunction, monomerLengthLimit: maxLengthOfMonomer,
179
+ monomerToShort: monomerToShortFunction,
179
180
  };
180
181
  });
181
182
  }
182
183
 
183
184
  g.save();
184
185
  try {
185
- if (tableCol.tags[mmcrTags.RendererSettingsChanged] === rendererSettingsChangedState.true) {
186
+ if (
187
+ tableCol.tags[mmcrTags.RendererSettingsChanged] === rendererSettingsChangedState.true ||
188
+ seqColTemp.monomerLengthLimit != maxLengthOfMonomer
189
+ ) {
186
190
  gapLength = tableColTemp[mmcrTemps.gapLength] as number ?? gapLength;
187
191
  // this event means that the mm renderer settings have changed,
188
192
  // particularly monomer representation and max width.
@@ -245,9 +249,13 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
245
249
  g.fillStyle = undefinedColor;
246
250
  const last = posIdx === subParts.length - 1;
247
251
  /*x1 = */
248
- printLeftOrCentered(x + this.padding, y, w, h,
249
- g, amino, color, 0, true, 1.0, separator, last, drawStyle,
250
- maxLengthWordsSum, posIdx, gridCell, referenceSequence, maxLengthOfMonomer, seqColTemp._monomerLengthMap);
252
+ const opts = {
253
+ color: color, pivot: 0, left: true, transparencyRate: 1.0, separator: separator, last: last,
254
+ drawStyle: drawStyle, maxWord: maxLengthWordsSum, wordIdx: posIdx, gridCell: gridCell,
255
+ referenceSequence: referenceSequence, maxLengthOfMonomer: maxLengthOfMonomer,
256
+ monomerTextSizeMap: seqColTemp._monomerLengthMap, logger: _package.logger
257
+ };
258
+ printLeftOrCentered(g, amino, x + this.padding, y, w, h, opts);
251
259
  if (minDistanceRenderer > w) break;
252
260
  }
253
261
  } catch (err: any) {
@@ -350,14 +358,17 @@ export function drawMoleculeDifferenceOnCanvas(
350
358
 
351
359
  if (amino1 != amino2) {
352
360
  const color2 = palette.get(amino2);
353
- const subX0 = printLeftOrCentered(updatedX, updatedY - vShift, w, h, g, amino1, color1, 0, true);
354
- const subX1 = printLeftOrCentered(updatedX, updatedY + vShift, w, h, g, amino2, color2, 0, true);
361
+ const subX0 = printLeftOrCentered(g, amino1, updatedX, updatedY - vShift, w, h,
362
+ {color: color1, pivot: 0, left: true});
363
+ const subX1 = printLeftOrCentered(g, amino2, updatedX, updatedY + vShift, w, h,
364
+ {color: color2, pivot: 0, left: true});
355
365
  updatedX = Math.max(subX1, subX0);
356
366
  if (molDifferences)
357
367
  molDifferences[i] = createDifferenceCanvas(amino1, amino2, color1, color2, updatedY, vShift, h);
358
368
  } else {
359
369
  //
360
- updatedX = printLeftOrCentered(updatedX, updatedY, w, h, g, amino1, color1, 0, true, 0.5);
370
+ updatedX = printLeftOrCentered(g, amino1, updatedX, updatedY, w, h,
371
+ {color: color1, pivot: 0, left: true, transparencyRate: 0.5});
361
372
  }
362
373
  updatedX += 4;
363
374
  }
@@ -382,8 +393,8 @@ function createDifferenceCanvas(amino1: string, amino2: string, color1: string,
382
393
  canvas.width = width + 4;
383
394
  context.font = '12px monospace';
384
395
  context.textBaseline = 'top';
385
- printLeftOrCentered(0, y - shift, width, h, context, amino1, color1, 0, true);
386
- printLeftOrCentered(0, y + shift, width, h, context, amino2, color2, 0, true);
396
+ printLeftOrCentered(context, amino1, 0, y - shift, width, h, {color: color1, pivot: 0, left: true});
397
+ printLeftOrCentered(context, amino2, 0, y + shift, width, h, {color: color2, pivot: 0, left: true});
387
398
  return canvas;
388
399
  }
389
400
 
@@ -34,5 +34,14 @@ export class MolfileAtomsV3K extends MolfileAtoms {
34
34
  }).replace(rGroupsRegex, '');
35
35
  });
36
36
  }
37
+
38
+ replaceRGroupSymbolByElement(atomIdx: number, newElementSymbol: string): void {
39
+ super.replaceRGroupSymbolByElement(atomIdx, newElementSymbol);
40
+ // rdkit can generate (out of thin air) masses for r groups, so we need to remove them as well.
41
+ //they are at the end of the line after coordinates and other data
42
+ const lineInfo = this.rawAtomLines[atomIdx].substring(3).split(' ');
43
+ if (lineInfo.length > 7)
44
+ this.rawAtomLines[atomIdx] = `M ${lineInfo.slice(0, 7).join(' ')}`;
45
+ }
37
46
  }
38
47
 
@@ -2,10 +2,10 @@ import * as grok from 'datagrok-api/grok';
2
2
  import * as DG from 'datagrok-api/dg';
3
3
  import * as ui from 'datagrok-api/ui';
4
4
 
5
+ import {PolymerType} from '@datagrok-libraries/bio/src/helm/types';
5
6
  import {ALPHABET, getPaletteByType, monomerToShort} from '@datagrok-libraries/bio/src/utils/macromolecule';
6
7
  import {TAGS as bioTAGS} from '@datagrok-libraries/bio/src/utils/macromolecule/consts';
7
8
  import {MonomerWorks} from '@datagrok-libraries/bio/src/monomer-works/monomer-works';
8
- import {PolymerType} from '@datagrok-libraries/bio/src/types';
9
9
 
10
10
  import * as C from './constants';
11
11
  import {getMonomerLib} from '../package';
@@ -2,6 +2,12 @@ import {JSONSchemaType, ValidateFunction} from 'ajv';
2
2
  import Ajv2020 from 'ajv/dist/2020';
3
3
  import addErrors from 'ajv-errors';
4
4
 
5
+ const NA_CODE: string = '#N/A';
6
+
7
+ import {
8
+ HELM_REQUIRED_FIELD as REQ,
9
+ } from '@datagrok-libraries/bio/src/utils/const';
10
+
5
11
  export class MonomerLibFileValidator {
6
12
  private validateMonomerSchema: ValidateFunction<any>;
7
13
 
@@ -14,25 +20,24 @@ export class MonomerLibFileValidator {
14
20
  }
15
21
 
16
22
  validateFile(fileContent: string, fileName: string): boolean {
17
- const jsonContent = this.parseJson(fileContent);
23
+ const jsonContent = this.parseJson(fileContent, fileName);
18
24
  if (jsonContent === null)
19
25
  return false;
20
26
 
21
27
  if (!Array.isArray(jsonContent)) {
22
- console.warn(
23
- 'Bio: Monomer Library File Validator: Invalid JSON format: The file must contain an array of monomers.'
24
- );
28
+ console.warn(`Bio: Monomer Library File Validator file '${fileName}': Invalid JSON format: ` +
29
+ 'The file must contain an array of monomers.');
25
30
  return false;
26
31
  }
27
32
 
28
33
  return this.validateJsonContent(jsonContent, fileName);
29
34
  }
30
35
 
31
- private parseJson(fileContent: string): any[] | null {
36
+ private parseJson(fileContent: string, fileName: string): any[] | null {
32
37
  try {
33
38
  return JSON.parse(fileContent);
34
39
  } catch (e) {
35
- console.error('Bio: Monomer Library File Validator: Invalid JSON format:', e);
40
+ console.error(`Bio: Monomer Library File Validator file '${fileName}': Invalid JSON format:`, e);
36
41
  return null;
37
42
  }
38
43
  }
@@ -40,10 +45,11 @@ export class MonomerLibFileValidator {
40
45
  private validateJsonContent(jsonContent: any[], fileName: string): boolean {
41
46
  let isValid = true;
42
47
  for (const monomer of jsonContent) {
48
+ const name = monomer[REQ.SYMBOL] ?? monomer[REQ.ID] ?? monomer[REQ.NAME] ?? NA_CODE;
43
49
  isValid = this.validateMonomerSchema(monomer);
44
50
  if (!isValid) {
45
51
  console.warn(
46
- `Bio: Monomer Library File Validator:\nfile ${fileName}\n monomer violating JSON schema:`,
52
+ `Bio: Monomer Library File Validator file ${fileName}, monomer '${name}' violating JSON schema:`,
47
53
  monomer,
48
54
  '\nError reason: ',
49
55
  this.validateMonomerSchema.errors,
@@ -14,6 +14,7 @@ import {UserLibSettings} from '@datagrok-libraries/bio/src/monomer-works/types';
14
14
  import {getMonomerLibHelper, IMonomerLibFileManager} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
15
15
 
16
16
  import {MonomerLibFileEventManager} from './event-manager';
17
+ import {_package} from '../../../package';
17
18
 
18
19
  export async function showManageLibrariesDialog(): Promise<void> {
19
20
  await DialogWrapper.showDialog();
@@ -89,7 +90,8 @@ class MonomerLibraryManagerWidget {
89
90
 
90
91
  class LibraryControlsManager {
91
92
  private constructor(
92
- private fileManager: IMonomerLibFileManager
93
+ private fileManager: IMonomerLibFileManager,
94
+ private readonly userLibSettings: UserLibSettings,
93
95
  ) {
94
96
  this.fileManager.eventManager.updateUIControlsRequested$.subscribe(() => {
95
97
  this.updateControlsForm();
@@ -99,13 +101,18 @@ class LibraryControlsManager {
99
101
  });
100
102
  }
101
103
 
102
- private userLibSettings: UserLibSettings;
104
+ private toLog(): string {
105
+ return `LibraryControlsManager<#>`;
106
+ }
103
107
 
104
108
  static async createControlsForm(): Promise<HTMLElement> {
105
- const libHelper = await getMonomerLibHelper();
106
- const fileManager = await libHelper.getFileManager();
107
- const manager = new LibraryControlsManager(fileManager);
108
- await manager.initialize();
109
+ const logPrefix = 'LibraryControlsForm.createControlsForm()';
110
+ _package.logger.debug(`${logPrefix}, start`);
111
+ const [fileManager, userLibSettings] = await Promise.all([
112
+ getMonomerLibHelper().then((libHelper) => libHelper.getFileManager()),
113
+ await getUserLibSettings(),
114
+ ]);
115
+ const manager = new LibraryControlsManager(fileManager, userLibSettings);
109
116
 
110
117
  return manager._createControlsForm();
111
118
  }
@@ -118,10 +125,6 @@ class LibraryControlsManager {
118
125
  return inputsForm;
119
126
  }
120
127
 
121
- private async initialize(): Promise<void> {
122
- this.userLibSettings = await getUserLibSettings();
123
- };
124
-
125
128
  private updateControlsForm(): void {
126
129
  const updatedForm = this._createControlsForm();
127
130
  $('.monomer-lib-controls-form').replaceWith(updatedForm);
@@ -133,6 +136,8 @@ class LibraryControlsManager {
133
136
  }
134
137
 
135
138
  private createLibInput(libFileName: string): DG.InputBase<boolean | null> {
139
+ const logPrefix = `${this.toLog()}.createLibInput()`;
140
+ _package.logger.debug(`${logPrefix}, libFileName = '${libFileName}', start`);
136
141
  const isMonomerLibrarySelected = !this.userLibSettings.exclude.includes(libFileName);
137
142
  const libInput = ui.boolInput(
138
143
  libFileName,
@@ -144,6 +149,7 @@ class LibraryControlsManager {
144
149
  const deleteIcon = ui.iconFA('trash-alt', () => this.promptForLibraryDeletion(libFileName));
145
150
  ui.tooltip.bind(deleteIcon, `Delete ${libFileName}`);
146
151
  libInput.addOptions(deleteIcon);
152
+ _package.logger.debug(`${logPrefix}, libFileName = '${libFileName}', end`);
147
153
  return libInput;
148
154
  }
149
155
 
@@ -6,17 +6,18 @@ import * as DG from 'datagrok-api/dg';
6
6
  import wu from 'wu';
7
7
  import {Observable, Subject} from 'rxjs';
8
8
 
9
- import {
10
- IMonomerLib, Monomer, MonomerLibSummaryType, MonomerType, PolymerType, RGroup
11
- } from '@datagrok-libraries/bio/src/types';
12
- import {PolymerTypes} from '@datagrok-libraries/bio/src/utils/const';
9
+ import {MonomerType, PolymerType} from '@datagrok-libraries/bio/src/helm/types';
10
+ import {IMonomerLib, Monomer, MonomerLibSummaryType, RGroup} from '@datagrok-libraries/bio/src/types';
13
11
  import {HELM_REQUIRED_FIELD as REQ, HELM_RGROUP_FIELDS as RGP} from '@datagrok-libraries/bio/src/utils/const';
14
12
  import {MolfileHandler} from '@datagrok-libraries/chem-meta/src/parsing-utils/molfile-handler';
15
13
  import {GapOriginals} from '@datagrok-libraries/bio/src/utils/seq-handler';
16
14
  import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
15
+ import {PolymerTypes} from '@datagrok-libraries/bio/src/helm/consts';
17
16
 
18
17
  import '../../../css/cell-renderer.css';
19
18
 
19
+ import {_package} from '../../package';
20
+
20
21
  /** Wrapper for monomers obtained from different sources. For managing monomere
21
22
  * libraries, use MolfileHandler class instead */
22
23
  export class MonomerLib implements IMonomerLib {
@@ -75,7 +76,8 @@ export class MonomerLib implements IMonomerLib {
75
76
  return m;
76
77
  }
77
78
 
78
- getMonomer(polymerType: PolymerType, argMonomerSymbol: string): Monomer | null {
79
+ getMonomer(polymerType: PolymerType | null, argMonomerSymbol: string): Monomer | null {
80
+ const logPrefix = `Bio: MonomerLib.getMonomer()`;
79
81
  // Adjust RNA's 'R' for ribose to 'r' and 'P' for phosphate to 'p' for case-sensitive monomer names.
80
82
  // There are uppercase 'R' and 'P' at RNA samples in test data 'helm2.csv' but lowercase in HELMCoreLibrary.json
81
83
  let monomerSymbol = argMonomerSymbol;
@@ -84,10 +86,20 @@ export class MonomerLib implements IMonomerLib {
84
86
  if (polymerType == 'RNA' && monomerSymbol == 'P')
85
87
  monomerSymbol = 'p';
86
88
 
87
- if (polymerType in this._monomers! && monomerSymbol in this._monomers![polymerType])
88
- return this._monomers![polymerType][monomerSymbol];
89
- else
90
- return null;
89
+ let res: Monomer | null = null;
90
+
91
+ if (!polymerType) {
92
+ _package.logger.warning(`${logPrefix} symbol '${argMonomerSymbol}', polymerType not specified.`);
93
+ // Assume any polymer type
94
+ for (const [polymerType, dict] of Object.entries(this._monomers)) {
95
+ res = dict[monomerSymbol];
96
+ if (res) break;
97
+ }
98
+ } else {
99
+ const dict = this._monomers[polymerType];
100
+ res = dict ? dict[monomerSymbol] : null;
101
+ }
102
+ return res;
91
103
  }
92
104
 
93
105
  getPolymerTypes(): PolymerType[] {
@@ -231,6 +243,7 @@ export class MonomerLib implements IMonomerLib {
231
243
  const chemOptions = {autoCrop: true, autoCropMargin: 0, suppressChiralText: true};
232
244
  let structureEl: HTMLElement;
233
245
  if (monomer.molfile) {
246
+ //
234
247
  structureEl = grok.chem.svgMol(monomer.molfile, undefined, undefined, chemOptions);
235
248
  } else if (monomer.smiles) {
236
249
  structureEl = ui.divV([
@@ -245,7 +258,7 @@ export class MonomerLib implements IMonomerLib {
245
258
  {style: {display: 'flex', flexDirection: 'row', justifyContent: 'center', margin: '6px'}}));
246
259
 
247
260
  // Source
248
- res.append(ui.divText(monomer.lib?.source ?? 'unknown'));
261
+ res.append(ui.divText(monomer.lib?.source ?? 'Missed in libraries'));
249
262
 
250
263
  // const label = (s: string) => {
251
264
  // return ui.label(s /* span ? */, {classes: 'ui-input-label'});
@@ -31,7 +31,7 @@ export async function splitToMonomersUI(table: DG.DataFrame, seqCol: DG.Column<s
31
31
  colNameRe.lastIndex = 0;
32
32
  const ma = srcName.match(colNameRe);
33
33
  if (!ma) return srcName;
34
- return `${ma[1]} (${parseInt(ma[2] ?? 0) + 1})`;
34
+ return `${ma[1]} (${parseInt(ma[2] ?? '0') + 1})`;
35
35
  };
36
36
 
37
37
  // if (tempDf.columns.length === 0) return;