@datagrok/bio 2.12.23 → 2.13.3

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.23",
8
+ "version": "2.13.3",
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",
@@ -15,18 +15,21 @@
15
15
  "properties": [
16
16
  {
17
17
  "name": "MaxMonomerLength",
18
- "propertyType": "int",
19
- "defaultValue": 4,
18
+ "description": "The max length of monomer symbol displayed without shortening, 'long' to no limit",
19
+ "propertyType": "string",
20
+ "defaultValue": "4",
20
21
  "nullable": false
21
22
  },
22
23
  {
23
24
  "name": "TooltipWebLogo",
25
+ "description": "Display WebLogo in a Macromolecule column header tooltip",
24
26
  "propertyType": "bool",
25
27
  "defaultValue": "true",
26
28
  "nullable": false
27
29
  },
28
30
  {
29
31
  "name": "DefaultSeparator",
32
+ "description": "Default separator using to convert sequences into separator notation",
30
33
  "propertyType": "string",
31
34
  "defaultValue": ".",
32
35
  "nullable": false
@@ -34,18 +37,18 @@
34
37
  ],
35
38
  "dependencies": {
36
39
  "@biowasm/aioli": "^3.1.0",
37
- "@datagrok-libraries/bio": "^5.41.8",
40
+ "@datagrok-libraries/bio": "^5.42.3",
38
41
  "@datagrok-libraries/chem-meta": "^1.2.5",
39
42
  "@datagrok-libraries/math": "^1.1.5",
40
- "@datagrok-libraries/ml": "^6.6.5",
43
+ "@datagrok-libraries/ml": "^6.6.12",
41
44
  "@datagrok-libraries/tutorials": "^1.3.12",
42
- "@datagrok-libraries/utils": "^4.2.5",
45
+ "@datagrok-libraries/utils": "^4.2.11",
43
46
  "@webgpu/types": "^0.1.40",
44
47
  "ajv": "^8.12.0",
45
48
  "ajv-errors": "^3.0.0",
46
49
  "cash-dom": "^8.0.0",
47
50
  "css-loader": "^6.7.3",
48
- "datagrok-api": "^1.17.4",
51
+ "datagrok-api": "^1.18.6",
49
52
  "dayjs": "^1.11.4",
50
53
  "fastest-levenshtein": "^1.0.16",
51
54
  "openchemlib": "^7.2.3",
@@ -55,6 +58,8 @@
55
58
  "wu": "latest"
56
59
  },
57
60
  "devDependencies": {
61
+ "@datagrok-libraries/helm-web-editor": "^1.1.5",
62
+ "@datagrok-libraries/js-draw-lite": "^0.0.3",
58
63
  "@datagrok/chem": "^1.9.2",
59
64
  "@datagrok/dendrogram": "^1.2.29",
60
65
  "@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 {Group} from 'datagrok-api/dg';
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,13 +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
 
20
- /** Monomer name maximum length displayed in short mode. */
21
- public get MaxMonomerLength(): number {
22
- return super.get(BioPackagePropertiesNames.MaxMonomerLength) as number;
22
+ /** Monomer symbol maximum length displayed, null for unlimited. */
23
+ public get MaxMonomerLength(): number | null {
24
+ const vs = super.get(BioPackagePropertiesNames.MaxMonomerLength);
25
+ return vs === 'long' ? null : parseInt(vs);
23
26
  }
24
27
 
25
- public set MaxMonomerLength(value: number) {
26
- super.set(BioPackagePropertiesNames.MaxMonomerLength, value);
28
+ public set MaxMonomerLength(value: number | null) {
29
+ const vs = value === null ? 'long' : value.toString();
30
+ super.set(BioPackagePropertiesNames.MaxMonomerLength, vs);
27
31
  this._onPropertyChanged.next(BioPackagePropertiesNames.MaxMonomerLength);
28
32
  }
29
33
 
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,8 @@ 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';
80
+ import {getUserLibSettings, setUserLibSettings} from '@datagrok-libraries/bio/src/monomer-works/lib-settings';
81
81
 
82
82
  export const _package = new BioPackage();
83
83
 
@@ -109,13 +109,19 @@ let monomerLib: IMonomerLib | null = null;
109
109
 
110
110
  //tags: init
111
111
  export async function initBio() {
112
- const logPrefix = 'Bio: initBio()';
112
+ const logPrefix = 'Bio: _package.initBio()';
113
113
  _package.logger.debug(`${logPrefix}, start`);
114
114
  const module = await grok.functions.call('Chem:getRdKitModule');
115
115
  const t1: number = window.performance.now();
116
116
  await Promise.all([
117
117
  (async () => {
118
118
  const monomerLibManager = await MonomerLibManager.getInstance();
119
+ // Fix user lib settings for explicit stuck from a terminated test
120
+ const libSettings = await getUserLibSettings();
121
+ if (libSettings.explicit) {
122
+ libSettings.explicit = [];
123
+ await setUserLibSettings(libSettings);
124
+ }
119
125
  await monomerLibManager.loadLibraries();
120
126
  monomerLib = monomerLibManager.getBioLib();
121
127
  })(),
@@ -152,7 +158,7 @@ export async function initBio() {
152
158
 
153
159
  hydrophobPalette = new SeqPaletteCustom(palette);
154
160
 
155
- _package.logger.debug('Bio: initBio(), completed');
161
+ _package.logger.debug(`${logPrefix}, end`);
156
162
  }
157
163
 
158
164
  //name: sequenceTooltip
@@ -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;
@@ -2,33 +2,25 @@ import * as grok from 'datagrok-api/grok';
2
2
  import * as ui from 'datagrok-api/ui';
3
3
  import * as DG from 'datagrok-api/dg';
4
4
 
5
- export enum MonomerWidthMode {
6
- long = 'long',
7
- short = 'short',
8
- }
9
-
10
- export const enum Tags {
11
- RendererSettingsChanged = '.mm.cellRenderer.settingsChanged',
12
- }
13
-
14
5
  export const rendererSettingsChangedState = {
15
6
  true: '1',
16
7
  false: '0',
17
8
  };
18
9
 
19
10
  export const enum Temps {
20
- monomerWidth = '.mm.cellRenderer.monomerWidth',
11
+ maxMonomerLength = '.mm.cellRenderer.maxMonomerLength',
21
12
  colorCode = '.mm.cellRenderer.colorCode',
22
13
  compareWithCurrent = '.mm.cellRenderer.compareWithCurrent',
23
14
  highlightDifference = '.mm.cellRenderer.highlightDifference',
24
15
  gapLength = '.mm.cellRenderer.gapLength',
25
16
  monomerPlacer = '.mm.cellRenderer.monomerPlacer',
17
+
18
+ rendererSettingsChanged = '.mm.cellRenderer.settingsChanged',
26
19
  }
27
20
 
28
21
  export const enum tempTAGS {
29
22
  referenceSequence = 'reference-sequence',
30
23
  currentWord = 'current-word',
31
- monomerWidth = 'monomer-width',
32
24
  }
33
25
 
34
26
  // export const MacromoleculeCellRendererDefaults = new class {
@@ -25,8 +25,8 @@ import {alphabetPolymerTypes, IMonomerLib} from '@datagrok-libraries/bio/src/typ
25
25
  import {getGridCellRendererBack} from '@datagrok-libraries/bio/src/utils/cell-renderer-back-base';
26
26
 
27
27
  import {
28
- Temps as mmcrTemps, Tags as mmcrTags,
29
- tempTAGS, rendererSettingsChangedState
28
+ Temps as mmcrTemps,
29
+ tempTAGS, rendererSettingsChangedState, Temps
30
30
  } from '../utils/cell-renderer-consts';
31
31
  import * as C from './constants';
32
32
 
@@ -152,43 +152,45 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
152
152
 
153
153
  let gapLength = 0;
154
154
  const msaGapLength = 8;
155
- let maxLengthOfMonomer = 50; // in case of long monomer representation, do not limit max length
156
155
 
157
156
  // Cell renderer settings
158
- const tempMonomerWidth: string | null = tableColTemp[tempTAGS.monomerWidth];
159
- const monomerWidth: string = (tempMonomerWidth != null) ? tempMonomerWidth : 'short';
160
- if (monomerWidth === 'short') {
161
- // Renderer can start to work before Bio package initialized, in that time _package.properties is null.
162
- // TODO: Render function is available but package init method is not completed
163
- const tagMaxMonomerLength: number = parseInt(tableCol.getTag(mmcrTAGS.maxMonomerLength));
164
- maxLengthOfMonomer =
165
- (!isNaN(tagMaxMonomerLength) ? tagMaxMonomerLength : _package.properties?.MaxMonomerLength) ?? 4;
157
+ let maxLengthOfMonomer: number = (_package.properties ? _package.properties.MaxMonomerLength : 4) ?? 50;
158
+ if (mmcrTAGS.maxMonomerLength in tableCol.tags) {
159
+ const v = parseInt(tableCol.getTag(mmcrTAGS.maxMonomerLength));
160
+ maxLengthOfMonomer = !isNaN(v) && v ? v : 50;
161
+ }
162
+ if (Temps.maxMonomerLength in tableColTemp) {
163
+ const v = tableColTemp[Temps.maxMonomerLength];
164
+ maxLengthOfMonomer = !isNaN(v) && v ? v : 50;
166
165
  }
167
166
 
168
167
  const [_gc, _tc, temp] =
169
168
  getGridCellRendererBack<string, MonomerPlacer>(gridCell);
170
169
  let seqColTemp: MonomerPlacer = temp.rendererBack;
171
170
  if (!seqColTemp) {
172
- seqColTemp = temp.rendererBack = new MonomerPlacer(gridCol, tableCol, _package.logger,
171
+ seqColTemp = temp.rendererBack = new MonomerPlacer(gridCol, tableCol, _package.logger, maxLengthOfMonomer,
173
172
  () => {
174
173
  const sh = SeqHandler.forColumn(tableCol);
175
174
  return {
176
175
  seqHandler: sh,
177
176
  monomerCharWidth: 7, separatorWidth: !sh.isMsa() ? gapLength : msaGapLength,
178
- monomerToShort: monomerToShortFunction, monomerLengthLimit: maxLengthOfMonomer,
177
+ monomerToShort: monomerToShortFunction,
179
178
  };
180
179
  });
181
180
  }
182
181
 
183
182
  g.save();
184
183
  try {
185
- if (tableCol.tags[mmcrTags.RendererSettingsChanged] === rendererSettingsChangedState.true) {
184
+ if (
185
+ tableCol.temp[Temps.rendererSettingsChanged] === rendererSettingsChangedState.true ||
186
+ seqColTemp.monomerLengthLimit != maxLengthOfMonomer
187
+ ) {
186
188
  gapLength = tableColTemp[mmcrTemps.gapLength] as number ?? gapLength;
187
189
  // this event means that the mm renderer settings have changed,
188
190
  // particularly monomer representation and max width.
189
191
  seqColTemp.setMonomerLengthLimit(maxLengthOfMonomer);
190
192
  seqColTemp.setSeparatorWidth(seqColTemp.isMsa() ? msaGapLength : gapLength);
191
- tableCol.setTag(mmcrTags.RendererSettingsChanged, rendererSettingsChangedState.false);
193
+ tableCol.temp[Temps.rendererSettingsChanged] = rendererSettingsChangedState.false;
192
194
  }
193
195
 
194
196
  const [maxLengthWords, maxLengthWordsSum]: [number[], number[]] =
@@ -245,9 +247,13 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
245
247
  g.fillStyle = undefinedColor;
246
248
  const last = posIdx === subParts.length - 1;
247
249
  /*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);
250
+ const opts = {
251
+ color: color, pivot: 0, left: true, transparencyRate: 1.0, separator: separator, last: last,
252
+ drawStyle: drawStyle, maxWord: maxLengthWordsSum, wordIdx: posIdx, gridCell: gridCell,
253
+ referenceSequence: referenceSequence, maxLengthOfMonomer: maxLengthOfMonomer,
254
+ monomerTextSizeMap: seqColTemp._monomerLengthMap, logger: _package.logger
255
+ };
256
+ printLeftOrCentered(g, amino, x + this.padding, y, w, h, opts);
251
257
  if (minDistanceRenderer > w) break;
252
258
  }
253
259
  } catch (err: any) {
@@ -350,14 +356,17 @@ export function drawMoleculeDifferenceOnCanvas(
350
356
 
351
357
  if (amino1 != amino2) {
352
358
  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);
359
+ const subX0 = printLeftOrCentered(g, amino1, updatedX, updatedY - vShift, w, h,
360
+ {color: color1, pivot: 0, left: true});
361
+ const subX1 = printLeftOrCentered(g, amino2, updatedX, updatedY + vShift, w, h,
362
+ {color: color2, pivot: 0, left: true});
355
363
  updatedX = Math.max(subX1, subX0);
356
364
  if (molDifferences)
357
365
  molDifferences[i] = createDifferenceCanvas(amino1, amino2, color1, color2, updatedY, vShift, h);
358
366
  } else {
359
367
  //
360
- updatedX = printLeftOrCentered(updatedX, updatedY, w, h, g, amino1, color1, 0, true, 0.5);
368
+ updatedX = printLeftOrCentered(g, amino1, updatedX, updatedY, w, h,
369
+ {color: color1, pivot: 0, left: true, transparencyRate: 0.5});
361
370
  }
362
371
  updatedX += 4;
363
372
  }
@@ -382,8 +391,8 @@ function createDifferenceCanvas(amino1: string, amino2: string, color1: string,
382
391
  canvas.width = width + 4;
383
392
  context.font = '12px monospace';
384
393
  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);
394
+ printLeftOrCentered(context, amino1, 0, y - shift, width, h, {color: color1, pivot: 0, left: true});
395
+ printLeftOrCentered(context, amino2, 0, y + shift, width, h, {color: color2, pivot: 0, left: true});
387
396
  return canvas;
388
397
  }
389
398
 
@@ -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;