@datagrok/bio 2.15.2 → 2.15.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.
Files changed (54) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/detectors.js +3 -1
  3. package/dist/284.js +1 -1
  4. package/dist/284.js.map +1 -1
  5. package/dist/455.js +2 -0
  6. package/dist/455.js.map +1 -0
  7. package/dist/980.js +1 -1
  8. package/dist/980.js.map +1 -1
  9. package/dist/package-test.js +3 -3
  10. package/dist/package-test.js.map +1 -1
  11. package/dist/package.js +2 -2
  12. package/dist/package.js.map +1 -1
  13. package/files/tests/to-atomic-level-msa-fasta-output.csv +683 -683
  14. package/files/tests/to-atomic-level-msa-separator-output.csv +104 -104
  15. package/package.json +9 -9
  16. package/src/analysis/sequence-activity-cliffs.ts +3 -1
  17. package/src/calculations/monomerLevelMols.ts +2 -1
  18. package/src/demo/bio03-atomic-level.ts +1 -1
  19. package/src/package-test.ts +6 -1
  20. package/src/package.ts +151 -38
  21. package/src/tests/WebLogo-positions-test.ts +1 -1
  22. package/src/tests/bio-tests.ts +1 -1
  23. package/src/tests/detectors-tests.ts +10 -10
  24. package/src/tests/monomer-libraries-tests.ts +1 -1
  25. package/src/tests/seq-handler-splitted-tests.ts +6 -2
  26. package/src/tests/splitters-test.ts +6 -6
  27. package/src/tests/to-atomic-level-tests.ts +21 -14
  28. package/src/tests/to-atomic-level-ui-tests.ts +75 -35
  29. package/src/tests/utils.ts +2 -2
  30. package/src/utils/cell-renderer-custom.ts +62 -0
  31. package/src/utils/cell-renderer.ts +58 -126
  32. package/src/utils/cyclized.ts +28 -14
  33. package/src/utils/dimerized.ts +0 -2
  34. package/src/utils/helm-to-molfile/converter/converter.ts +75 -54
  35. package/src/utils/helm-to-molfile/converter/monomer-wrapper.ts +2 -2
  36. package/src/utils/helm-to-molfile/converter/polymer.ts +23 -16
  37. package/src/utils/helm-to-molfile/converter/types.ts +0 -10
  38. package/src/utils/helm-to-molfile/utils.ts +10 -7
  39. package/src/utils/monomer-cell-renderer.ts +8 -4
  40. package/src/utils/monomer-lib/lib-manager.ts +2 -2
  41. package/src/utils/monomer-lib/monomer-colors.ts +68 -0
  42. package/src/utils/monomer-lib/monomer-lib-base.ts +165 -0
  43. package/src/utils/monomer-lib/monomer-lib.ts +19 -68
  44. package/src/utils/monomer-lib/web-editor-monomer-dummy.ts +121 -0
  45. package/src/utils/monomer-lib/web-editor-monomer-of-library.ts +102 -0
  46. package/src/utils/save-as-fasta.ts +1 -1
  47. package/src/utils/seq-helper/seq-helper.ts +20 -49
  48. package/src/utils/sequence-to-mol.ts +24 -28
  49. package/src/viewers/web-logo-viewer.ts +2 -1
  50. package/src/widgets/composition-analysis-widget.ts +4 -3
  51. package/src/widgets/representations.ts +8 -10
  52. package/dist/248.js +0 -2
  53. package/dist/248.js.map +0 -1
  54. package/src/utils/cell-renderer-consts.ts +0 -31
@@ -1,4 +1,4 @@
1
- import {IMonomerLib, Monomer} from '@datagrok-libraries/bio/src/types';
1
+ import {IMonomerLib, IMonomerLibBase, Monomer} from '@datagrok-libraries/bio/src/types';
2
2
  import {HELM_RGROUP_FIELDS} from '@datagrok-libraries/bio/src/utils/const';
3
3
  import {RDModule, RDMol} from '@datagrok-libraries/chem-meta/src/rdkit-api';
4
4
  import {MolfileHandler} from '@datagrok-libraries/chem-meta/src/parsing-utils/molfile-handler';
@@ -17,7 +17,7 @@ export class MonomerWrapper {
17
17
  private helm: Helm,
18
18
  shift: { x: number, y: number },
19
19
  rdKitModule: RDModule,
20
- private readonly monomerLib: IMonomerLib
20
+ private readonly monomerLib: IMonomerLibBase
21
21
  ) {
22
22
  const libraryMonomerObject = this.getLibraryMonomerObject();
23
23
 
@@ -1,18 +1,21 @@
1
+ import wu from 'wu';
2
+
1
3
  import {RDModule} from '@datagrok-libraries/chem-meta/src/rdkit-api';
2
4
  import {V3K_CONST} from '@datagrok-libraries/chem-meta/src/formats/molfile-const';
3
- import {IMonomerLib} from '@datagrok-libraries/bio/src/types/index';
4
-
5
- import wu from 'wu';
5
+ import {HelmTypes, PolymerTypes} from '@datagrok-libraries/bio/src/helm/consts';
6
+ import {IMonomerLib, IMonomerLibBase} from '@datagrok-libraries/bio/src/types/index';
7
+ import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
8
+ import {GapOriginals} from '@datagrok-libraries/bio/src/utils/macromolecule/consts';
9
+ import {MolfileWithMap, MonomerMap} from '@datagrok-libraries/bio/src/monomer-works/types';
6
10
 
7
11
  import {Helm} from './helm';
8
12
  import {MonomerWrapper} from './monomer-wrapper';
9
- import {MolfileWithMap, MonomerMap} from './types';
10
13
 
11
14
  export class Polymer {
12
15
  constructor(
13
16
  helmString: string,
14
17
  private readonly rdKitModule: RDModule,
15
- private readonly monomerLib: IMonomerLib
18
+ private readonly monomerLib: IMonomerLibBase
16
19
  ) {
17
20
  this.helm = new Helm(helmString);
18
21
  }
@@ -22,11 +25,14 @@ export class Polymer {
22
25
 
23
26
  addMonomer(
24
27
  monomerSymbol: string,
25
- monomerIdx: number,
28
+ helmMonomerIdx: number,
26
29
  shift: { x: number, y: number },
27
30
  ): void {
31
+ if (monomerSymbol === GapOriginals[NOTATION.HELM]) return;
32
+
33
+ const molMonomerIdx: number = this.monomerWrappers.length;
28
34
  const monomerWrapper = new MonomerWrapper(
29
- monomerSymbol, monomerIdx, this.helm, shift, this.rdKitModule, this.monomerLib);
35
+ monomerSymbol, molMonomerIdx, this.helm, shift, this.rdKitModule, this.monomerLib);
30
36
 
31
37
  this.monomerWrappers.push(monomerWrapper);
32
38
  }
@@ -64,21 +70,22 @@ export class Polymer {
64
70
 
65
71
  this.restoreBondsBetweenMonomers();
66
72
 
67
- const monomers: MonomerMap[] = new Array<MonomerMap>(this.monomerWrappers.length);
73
+ const monomers: MonomerMap = new MonomerMap();
68
74
  for (const [mw, mwI] of wu.enumerate(this.monomerWrappers)) {
69
- const mwAtomFirst = atomLines.length;
70
- const mwBondFirst = bondLines.length;
75
+ const mAtomFirst = atomLines.length;
76
+ const mBondFirst = bondLines.length;
71
77
 
72
78
  atomLines.push(...mw.getAtomLines());
73
79
  bondLines.push(...mw.getBondLines());
74
80
 
75
- monomers[mwI] = {
76
- position: mwI,
77
- // TODO: PolymerType
81
+ const polymerType = this.helm.getPolymerTypeByMonomerIdx(mwI);
82
+ const biotype = polymerType == PolymerTypes.RNA ? HelmTypes.NUCLEOTIDE : HelmTypes.AA;
83
+ monomers.set(mwI, {
84
+ biotype: biotype,
78
85
  symbol: mw.monomerSymbol,
79
- atoms: wu.count(mwAtomFirst).take(mw.atomCount).toArray(),
80
- bonds: wu.count(mwBondFirst).take(mw.bondCount).toArray(),
81
- };
86
+ atoms: wu.count(mAtomFirst).take(mw.atomCount).toArray(),
87
+ bonds: wu.count(mBondFirst).take(mw.bondCount).toArray(),
88
+ });
82
89
  }
83
90
 
84
91
  const atomCount = atomLines.length;
@@ -11,13 +11,3 @@ export type PositionInBonds = {
11
11
  nodeIdx: number,
12
12
  }
13
13
 
14
- export type MonomerMap = { position: number, symbol: string, atoms: number[], bonds: number[] };
15
-
16
- export class MolfileWithMap {
17
- constructor(
18
- public readonly molfile: string,
19
- public readonly monomers: MonomerMap[]
20
- ) {}
21
-
22
- static empty() { return new MolfileWithMap('', []); }
23
- }
@@ -2,27 +2,30 @@ 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
- import {_package} from '../../package';
5
+ import {IMonomerLibBase} from '@datagrok-libraries/bio/src/types';
6
+
6
7
  import {SeqHelper} from '../seq-helper';
7
8
 
9
+ import {_package, getMonomerLib} from '../../package';
8
10
 
9
11
  /** Translate HELM column into molfile column and append to the dataframe */
10
12
  export async function getMolColumnFromHelm(
11
- df: DG.DataFrame, helmCol: DG.Column<string>, chiralityEngine: boolean = true
13
+ df: DG.DataFrame, helmCol: DG.Column<string>, chiralityEngine: boolean = true, monomerLib: IMonomerLibBase
12
14
  ): Promise<DG.Column<string>> {
13
15
  const seqHelper = await SeqHelper.getInstance();
14
- const converter = seqHelper.getHelmToMolfileConverter(df, helmCol);
15
- const molCol = converter.convertToRdKitBeautifiedMolfileColumn(chiralityEngine, _package.rdKitModule);
16
+ const converter = seqHelper.getHelmToMolfileConverter(monomerLib);
17
+ const molCol = converter.convertToRdKitBeautifiedMolfileColumn(helmCol, chiralityEngine, _package.rdKitModule, monomerLib);
16
18
  molCol.semType = DG.SEMTYPE.MOLECULE;
17
19
  return molCol;
18
20
  }
19
21
 
20
22
  export async function getSmilesColumnFromHelm(
21
- df: DG.DataFrame, helmCol: DG.Column<string>
23
+ helmCol: DG.Column<string>
22
24
  ): Promise<DG.Column<string>> {
23
25
  const seqHelper = await SeqHelper.getInstance();
24
- const converter = seqHelper.getHelmToMolfileConverter(df, helmCol);
25
- const smilesCol = converter.convertToSmiles(_package.rdKitModule);
26
+ const monomerLib = getMonomerLib();
27
+ const converter = seqHelper.getHelmToMolfileConverter(monomerLib);
28
+ const smilesCol = converter.convertToSmiles(helmCol);
26
29
  smilesCol.semType = DG.SEMTYPE.MOLECULE;
27
30
  return smilesCol;
28
31
  }
@@ -4,7 +4,8 @@ import * as ui from 'datagrok-api/ui';
4
4
 
5
5
  import {PolymerType} from '@datagrok-libraries/bio/src/helm/types';
6
6
  import {ALPHABET, getPaletteByType, monomerToShort} from '@datagrok-libraries/bio/src/utils/macromolecule';
7
- import {TAGS as bioTAGS} from '@datagrok-libraries/bio/src/utils/macromolecule/consts';
7
+ import {TAGS as bioTAGS, } from '@datagrok-libraries/bio/src/utils/macromolecule/consts';
8
+ import {MONOMER_RENDERER_TAGS} from '@datagrok-libraries/bio/src/utils/cell-renderer';
8
9
  import {MonomerWorks} from '@datagrok-libraries/bio/src/monomer-works/monomer-works';
9
10
 
10
11
  import * as C from './constants';
@@ -92,7 +93,7 @@ export class MonomerCellRenderer extends DG.GridCellRenderer {
92
93
  ): void {
93
94
  if (gridCell.gridRow < 0) return;
94
95
  MonomerTooltipHandler.getOrCreate(gridCell.gridColumn);
95
-
96
+ const applyToBackground = gridCell.cell?.column && gridCell.cell.column.getTag(MONOMER_RENDERER_TAGS.applyToBackground) === 'true';
96
97
 
97
98
  g.font = `12px monospace`;
98
99
  g.textBaseline = 'middle';
@@ -103,11 +104,14 @@ export class MonomerCellRenderer extends DG.GridCellRenderer {
103
104
  if (!s)
104
105
  return;
105
106
  const color = palette.get(s);
106
-
107
- g.fillStyle = color;
108
107
  //cell width of monomer should dictate how many characters can be displayed
109
108
  // for width 40, 6 characters can be displayed (0.15 is 6 / 40)
110
109
  const maxChars = Math.max(2, Math.floor(w * 0.15));
110
+ g.fillStyle = color;
111
+ if (applyToBackground) {
112
+ g.fillRect(x, y, w, h);
113
+ g.fillStyle = DG.Color.toHtml(DG.Color.getContrastColor(DG.Color.fromHtml(color)));
114
+ }
111
115
  g.fillText(monomerToShort(s, maxChars), x + (w / 2), y + (h / 2), w);
112
116
  }
113
117
  }
@@ -34,7 +34,7 @@ export class MonomerLibManager implements IMonomerLibHelper {
34
34
 
35
35
  public get eventManager(): IMonomerLibFileEventManager { return this._eventManager; }
36
36
 
37
- public async awaitLoaded(timeout: number = 3000): Promise<void> {
37
+ public async awaitLoaded(timeout: number = 5000): Promise<void> {
38
38
  return await Promise.race([
39
39
  (async () => {
40
40
  const fileManager = await this.getFileManager();
@@ -47,7 +47,7 @@ export class MonomerLibManager implements IMonomerLibHelper {
47
47
  })(),
48
48
  ]).then((res) => {
49
49
  if (!res)
50
- throw new Error(`Loading monomer libraries is timeout ${timeout} ms.`);
50
+ throw new Error(`Loading monomer libraries timeout ${timeout} ms.`);
51
51
  });
52
52
  }
53
53
 
@@ -0,0 +1,68 @@
1
+ import {HelmTypes} from '@datagrok-libraries/bio/src/helm/consts';
2
+ import {Helm} from '../helm-to-molfile/converter/helm';
3
+ import {HelmType} from '@datagrok-libraries/bio/src/helm/types';
4
+
5
+ /**
6
+ * MonomerColors class from HelmWebEditor for natural monomers
7
+ */
8
+ export const naturalMonomerColors = {
9
+ [HelmTypes.BASE]: {
10
+ A: "#A0A0FF",
11
+ G: "#FF7070",
12
+ T: "#A0FFA0",
13
+ C: "#FF8C4B",
14
+ U: "#FF8080"
15
+ },
16
+
17
+ [HelmTypes.NUCLEOTIDE]: {
18
+ A: "#A0A0FF",
19
+ G: "#FF7070",
20
+ T: "#A0FFA0",
21
+ C: "#FF8C4B",
22
+ U: "#FF8080"
23
+ },
24
+
25
+ [HelmTypes.LINKER]: {
26
+ P: "#9aa5e1",
27
+ p: "#9aa5e1"
28
+ },
29
+
30
+ [HelmTypes.SUGAR]: {
31
+ R: "#7a85c1",
32
+ r: "#7a85c1",
33
+ // TODO: deoxyribose
34
+ },
35
+
36
+ [HelmTypes.AA]: {
37
+ A: "#C8C8C8",
38
+ R: "#145AFF",
39
+ N: "#00DCDC",
40
+ D: "#E60A0A",
41
+ C: "#E6E600",
42
+ E: "#00DCDC",
43
+ Q: "#E60A0A",
44
+ G: "#EBEBEB",
45
+ H: "#8282D2",
46
+ I: "#0F820F",
47
+ L: "#0F820F",
48
+ K: "#145AFF",
49
+ M: "#E6E600",
50
+ F: "#3232AA",
51
+ P: "#DC9682",
52
+ S: "#FA9600",
53
+ T: "#FA9600",
54
+ W: "#B45AB4",
55
+ Y: "#3232AA",
56
+ V: "#0F820F"
57
+ },
58
+
59
+ [HelmTypes.CHEM]: {
60
+ R: "#eeeeee",
61
+ },
62
+
63
+ [HelmTypes.BLOB]: {
64
+ B: "#999999",
65
+ G: "#e2e2e2"
66
+ }
67
+ };
68
+
@@ -0,0 +1,165 @@
1
+ import * as grok from 'datagrok-api/grok';
2
+ import * as ui from 'datagrok-api/ui';
3
+ import * as DG from 'datagrok-api/dg';
4
+
5
+ import wu from 'wu';
6
+
7
+ import {IMonomerLibBase, Monomer, RGroup} from '@datagrok-libraries/bio/src/types/index';
8
+ import {HelmAtom, HelmType, IWebEditorMonomer, MonomerType, PolymerType} from '@datagrok-libraries/bio/src/helm/types';
9
+ import {getMonomerHandleArgs} from '@datagrok-libraries/bio/src/helm/helm-helper';
10
+ import {helmTypeToPolymerType} from '@datagrok-libraries/bio/src/monomer-works/monomer-works';
11
+ import {HelmTypes, PolymerTypes} from '@datagrok-libraries/bio/src/helm/consts';
12
+ import {HELM_REQUIRED_FIELD as REQ, HELM_RGROUP_FIELDS as RGP} from '@datagrok-libraries/bio/src/utils/const';
13
+ import {GapOriginals, NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule/consts';
14
+
15
+ import {AmbiguousWebEditorMonomer, GapWebEditorMonomer, MissingWebEditorMonomer} from './web-editor-monomer-dummy';
16
+ import {LibraryWebEditorMonomer} from './web-editor-monomer-of-library';
17
+
18
+ import {_package} from '../../package';
19
+ import {Observable, Subject} from 'rxjs';
20
+
21
+ const monomerRe = /[\w()]+/;
22
+ //** Do not mess with monomer symbol with parenthesis enclosed in square brackets */
23
+ const ambMonomerRe = RegExp(String.raw`\(${monomerRe}(,${monomerRe})+\)`);
24
+
25
+ export type MonomerLibDataType = { [polymerType: string]: { [monomerSymbol: string]: Monomer } };
26
+
27
+ export class MonomerLibBase implements IMonomerLibBase {
28
+ protected _onChanged = new Subject<any>();
29
+
30
+ get onChanged(): Observable<any> { return this._onChanged; }
31
+
32
+ constructor(
33
+ protected _monomers: MonomerLibDataType,
34
+ ) {}
35
+
36
+ /** Creates missing {@link Monomer} */
37
+ addMissingMonomer(polymerType: PolymerType, monomerSymbol: string): Monomer {
38
+ let mSet = this._monomers[polymerType];
39
+ if (!mSet)
40
+ mSet = this._monomers[polymerType] = {};
41
+
42
+ let monomerName: string = monomerSymbol;
43
+ if (monomerSymbol === GapOriginals[NOTATION.HELM])
44
+ monomerName = 'Gap';
45
+ else if (polymerType === PolymerTypes.PEPTIDE && monomerSymbol === 'X')
46
+ monomerName = 'Any';
47
+ else if (polymerType === PolymerTypes.RNA && monomerSymbol === 'N')
48
+ monomerName = 'Any';
49
+
50
+ const m = mSet[monomerSymbol] = {
51
+ [REQ.SYMBOL]: monomerSymbol,
52
+ [REQ.NAME]: monomerName,
53
+ [REQ.MOLFILE]: '',
54
+ [REQ.AUTHOR]: 'MISSING',
55
+ [REQ.ID]: -1,
56
+ [REQ.RGROUPS]:
57
+ wu.count(1).take(9).map((i) => {
58
+ return {
59
+ /* eslint-disable no-multi-spaces */
60
+ // Samples // PEPTIDE RNA
61
+ [RGP.CAP_GROUP_SMILES]: '', // '[*:1][H]' '[*:1][H]'
62
+ [RGP.ALTERNATE_ID]: '', // 'R1-H' 'R1-H'
63
+ [RGP.CAP_GROUP_NAME]: '', // 'H' 'H'
64
+ [RGP.LABEL]: `R${i.toString()}`, // 'R1' 'R1'
65
+ /* eslint-enable no-multi-spaces */
66
+ } as RGroup;
67
+ }).toArray(),
68
+ [REQ.SMILES]: '',
69
+ [REQ.POLYMER_TYPE]: polymerType,
70
+ [REQ.MONOMER_TYPE]: undefined as unknown as MonomerType, // TODO: Can we get monomerType from atom of POM
71
+ [REQ.CREATE_DATE]: null,
72
+ } as Monomer;
73
+ return m;
74
+ }
75
+
76
+ getMonomer(polymerType: PolymerType | null, argMonomerSymbol: string): Monomer | null {
77
+ const logPrefix = `Bio: MonomerLib.getMonomer()`;
78
+ // Adjust RNA's 'R' for ribose to 'r' and 'P' for phosphate to 'p' for case-sensitive monomer names.
79
+ // There are uppercase 'R' and 'P' at RNA samples in test data 'helm2.csv' but lowercase in HELMCoreLibrary.json
80
+ let monomerSymbol = argMonomerSymbol;
81
+ if (polymerType == 'RNA' && monomerSymbol == 'R')
82
+ monomerSymbol = 'r';
83
+ if (polymerType == 'RNA' && monomerSymbol == 'P')
84
+ monomerSymbol = 'p';
85
+
86
+ let res: Monomer | null = null;
87
+
88
+ if (!polymerType) {
89
+ _package.logger.warning(`${logPrefix} symbol '${argMonomerSymbol}', polymerType not specified.`);
90
+ // Assume any polymer type
91
+ for (const [_polymerType, dict] of Object.entries(this._monomers)) {
92
+ res = dict[monomerSymbol];
93
+ if (res) break;
94
+ }
95
+ } else {
96
+ const dict = this._monomers[polymerType];
97
+ res = dict ? dict[monomerSymbol] : null;
98
+ }
99
+ return res;
100
+ }
101
+
102
+ /** Substitutes {@link org.helm.webeditor.Monomers.getMonomer()} */
103
+ getWebEditorMonomer(a: HelmAtom | HelmType, argName?: string): IWebEditorMonomer | null {
104
+ const [biotype, elem] = getMonomerHandleArgs(a, argName);
105
+ const pt = helmTypeToPolymerType(biotype);
106
+
107
+ /** Get or create {@link Monomer} object (in case it is missing in monomer library current config) */
108
+ let m: Monomer | null = this.getMonomer(pt, elem);
109
+ if (m && biotype == HelmTypes.LINKER && m[REQ.RGROUPS].length != 2) {
110
+ // Web Editor expects null
111
+ return null;
112
+ }
113
+ if (m && biotype == HelmTypes.SUGAR && m[REQ.RGROUPS].length != 3) {
114
+ // Web Editor expects null
115
+ return null;
116
+ }
117
+ if (!m /* && biotype != HelmTypes.LINKER*/)
118
+ m = this.addMissingMonomer(pt, elem);
119
+
120
+ /** Get or create {@link org,helm.WebEditorMonomer} */
121
+ let resWem: IWebEditorMonomer | null = m.wem ?? null;
122
+ if (!resWem) {
123
+ if (elem === '*')
124
+ resWem = m.wem = new GapWebEditorMonomer(biotype, elem);
125
+ else if (
126
+ (biotype === 'HELM_NUCLETIDE' && elem === 'N') ||
127
+ (biotype === 'HELM_AA' && elem === 'X') ||
128
+ (biotype === 'HELM_CHEM' && false) || // TODO: Ambiguous monomer for CHEM
129
+ ambMonomerRe.test(elem) // e.g. (A,R,_)
130
+ )
131
+ resWem = m.wem = new AmbiguousWebEditorMonomer(biotype, elem);
132
+ else if (!m.lib)
133
+ resWem = m.wem = new MissingWebEditorMonomer(biotype, elem);
134
+
135
+ if (!resWem)
136
+ resWem = m.wem = LibraryWebEditorMonomer.fromMonomer(biotype, m, this);
137
+ }
138
+
139
+ return resWem!;
140
+ }
141
+
142
+ getRS(smiles: string): { [r: string]: string } {
143
+ const newS = smiles.match(/(?<=\[)[^\][]*(?=])/gm);
144
+ const res: { [name: string]: string } = {};
145
+ let el = '';
146
+ let digit;
147
+ if (!!newS) {
148
+ for (let i = 0; i < newS.length; i++) {
149
+ if (newS[i] != null) {
150
+ if (/\d/.test(newS[i])) {
151
+ digit = newS[i][newS[i].length - 1];
152
+ newS[i] = newS[i].replace(/[0-9]/g, '');
153
+ for (let j = 0; j < newS[i].length; j++) {
154
+ if (newS[i][j] != ':')
155
+ el += newS[i][j];
156
+ }
157
+ res['R' + digit] = el;
158
+ el = '';
159
+ }
160
+ }
161
+ }
162
+ }
163
+ return res;
164
+ }
165
+ }
@@ -7,40 +7,46 @@ import * as DG from 'datagrok-api/dg';
7
7
  import wu from 'wu';
8
8
  import {Observable, Subject} from 'rxjs';
9
9
 
10
- import {HelmType, MonomerSetType, MonomerType, PolymerType} from '@datagrok-libraries/bio/src/helm/types';
10
+ import {
11
+ HelmType, HelmAtom,
12
+ MonomerSetType, MonomerType, PolymerType, IWebEditorMonomer,
13
+ } from '@datagrok-libraries/bio/src/helm/types';
14
+ import {HelmTypes, PolymerTypes} from '@datagrok-libraries/bio/src/helm/consts';
11
15
  import {IMonomerLib, IMonomerSet, Monomer, MonomerLibSummaryType, RGroup} from '@datagrok-libraries/bio/src/types';
12
- import {HELM_REQUIRED_FIELD as REQ, HELM_RGROUP_FIELDS as RGP} from '@datagrok-libraries/bio/src/utils/const';
16
+ import {HELM_OPTIONAL_FIELDS as OPT, HELM_REQUIRED_FIELD as REQ, HELM_RGROUP_FIELDS as RGP} from '@datagrok-libraries/bio/src/utils/const';
13
17
  import {MolfileHandler} from '@datagrok-libraries/chem-meta/src/parsing-utils/molfile-handler';
14
- import {GapOriginals} from '@datagrok-libraries/bio/src/utils/seq-handler';
15
18
  import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
16
- import {PolymerTypes} from '@datagrok-libraries/bio/src/helm/consts';
17
19
  import {helmTypeToPolymerType} from '@datagrok-libraries/bio/src/monomer-works/monomer-works';
20
+ import {getUserLibSettings} from '@datagrok-libraries/bio/src/monomer-works/lib-settings';
21
+ import {UserLibSettings} from '@datagrok-libraries/bio/src/monomer-works/types';
22
+ import {GapOriginals} from '@datagrok-libraries/bio/src/utils/macromolecule/consts';
23
+
24
+ import {MonomerLibBase, MonomerLibDataType} from './monomer-lib-base';
18
25
 
19
26
  import '../../../css/cell-renderer.css';
20
27
 
21
28
  import {_package} from '../../package';
22
- import {getUserLibSettings} from '@datagrok-libraries/bio/src/monomer-works/lib-settings';
23
- import {UserLibSettings} from '@datagrok-libraries/bio/src/monomer-works/types';
29
+
24
30
 
25
31
  /** Wrapper for monomers obtained from different sources. For managing monomere
26
32
  * libraries, use MolfileHandler class instead */
27
- export class MonomerLib implements IMonomerLib {
28
- private _monomers: { [polymerType: string]: { [monomerSymbol: string]: Monomer } } = {};
29
- private _onChanged = new Subject<any>();
33
+ export class MonomerLib extends MonomerLibBase implements IMonomerLib {
30
34
  private _duplicateMonomers: { [polymerType: string]: { [monomerSymbol: string]: Monomer[] } } = {};
31
35
  public get duplicateMonomers(): { [polymerType: string]: { [monomerSymbol: string]: Monomer[] } } {
32
36
  return this._duplicateMonomers;
33
37
  }
38
+
34
39
  private _duplicatesHandled = true;
35
40
  public get duplicatesHandled() { return this._duplicatesHandled; }
41
+
36
42
  private duplicatesNotified: boolean = false;
37
43
 
38
44
  constructor(
39
- monomers: { [polymerType: string]: { [monomerSymbol: string]: Monomer } },
45
+ monomers: MonomerLibDataType,
40
46
  public readonly source: string | undefined = undefined,
41
47
  public readonly error: string | undefined = undefined,
42
48
  ) {
43
- this._monomers = monomers;
49
+ super(monomers);
44
50
  for (const [_monomerType, monomersOfType] of Object.entries(this._monomers)) {
45
51
  for (const [_monomerSymbol, monomer] of Object.entries(monomersOfType))
46
52
  monomer.lib = this;
@@ -56,46 +62,6 @@ export class MonomerLib implements IMonomerLib {
56
62
  return resJSON;
57
63
  }
58
64
 
59
- /** Creates missing {@link Monomer} */
60
- addMissingMonomer(polymerType: PolymerType, monomerSymbol: string): Monomer {
61
- let mSet = this._monomers[polymerType];
62
- if (!mSet)
63
- mSet = this._monomers[polymerType] = {};
64
-
65
- let monomerName: string = monomerSymbol;
66
- if (monomerSymbol === GapOriginals[NOTATION.HELM])
67
- monomerName = 'Gap';
68
- else if (polymerType === PolymerTypes.PEPTIDE && monomerSymbol === 'X')
69
- monomerName = 'Any';
70
- else if (polymerType === PolymerTypes.RNA && monomerSymbol === 'N')
71
- monomerName = 'Any';
72
-
73
- const m = mSet[monomerSymbol] = {
74
- [REQ.SYMBOL]: monomerSymbol,
75
- [REQ.NAME]: monomerName,
76
- [REQ.MOLFILE]: '',
77
- [REQ.AUTHOR]: 'MISSING',
78
- [REQ.ID]: -1,
79
- [REQ.RGROUPS]:
80
- wu.count(1).take(9).map((i) => {
81
- return {
82
- /* eslint-disable no-multi-spaces */
83
- // Samples // PEPTIDE RNA
84
- [RGP.CAP_GROUP_SMILES]: '', // '[*:1][H]' '[*:1][H]'
85
- [RGP.ALTERNATE_ID]: '', // 'R1-H' 'R1-H'
86
- [RGP.CAP_GROUP_NAME]: '', // 'H' 'H'
87
- [RGP.LABEL]: `R${i.toString()}`, // 'R1' 'R1'
88
- /* eslint-enable no-multi-spaces */
89
- } as RGroup;
90
- }).toArray(),
91
- [REQ.SMILES]: '',
92
- [REQ.POLYMER_TYPE]: polymerType,
93
- [REQ.MONOMER_TYPE]: undefined as unknown as MonomerType, // TODO: Can we get monomerType from atom of POM
94
- [REQ.CREATE_DATE]: null,
95
- } as Monomer;
96
- return m;
97
- }
98
-
99
65
  getMonomer(polymerType: PolymerType | null, argMonomerSymbol: string): Monomer | null {
100
66
  const logPrefix = `Bio: MonomerLib.getMonomer()`;
101
67
  // Adjust RNA's 'R' for ribose to 'r' and 'P' for phosphate to 'p' for case-sensitive monomer names.
@@ -181,10 +147,6 @@ export class MonomerLib implements IMonomerLib {
181
147
  return monomers.map((monomer) => monomer?.symbol!);
182
148
  }
183
149
 
184
- get onChanged(): Observable<any> {
185
- return this._onChanged;
186
- }
187
-
188
150
  private _updateLibInt(lib: IMonomerLib): void {
189
151
  const typesNew = lib.getPolymerTypes();
190
152
  const types = this.getPolymerTypes();
@@ -285,19 +247,8 @@ export class MonomerLib implements IMonomerLib {
285
247
  return resStr;
286
248
  }
287
249
 
288
- getTooltip(polymerType: PolymerType, monomerSymbol: string): HTMLElement {
289
- // getTooltip(monomer: Monomer): HTMLElement;
290
- // getTooltip(monomerOrPolymerType: string | Monomer, symbol?: string): HTMLElement {
291
- // let polymerType: string;
292
- // let monomerSymbol: string;
293
- // if (typeof monomerOrPolymerType === 'string' || monomerOrPolymerType instanceof String) {
294
- // polymerType = monomerOrPolymerType as string;
295
- // monomerSymbol = symbol!;
296
- // } else {
297
- // const m = monomerOrPolymerType as Monomer;
298
- // polymerType = m[HELM_REQUIRED_FIELD.POLYMER_TYPE];
299
- // monomerSymbol = m[HELM_REQUIRED_FIELD.SYMBOL];
300
- // }
250
+ getTooltip(biotype: HelmType, monomerSymbol: string): HTMLElement {
251
+ const polymerType = helmTypeToPolymerType(biotype);
301
252
  const res = ui.div([], {classes: 'ui-form ui-tooltip'});
302
253
  const monomer = this.getMonomer(polymerType, monomerSymbol);
303
254
  if (monomer) {