@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.
- package/CHANGELOG.md +32 -0
- package/detectors.js +3 -1
- package/dist/284.js +1 -1
- package/dist/284.js.map +1 -1
- package/dist/455.js +2 -0
- package/dist/455.js.map +1 -0
- package/dist/980.js +1 -1
- package/dist/980.js.map +1 -1
- package/dist/package-test.js +3 -3
- package/dist/package-test.js.map +1 -1
- package/dist/package.js +2 -2
- package/dist/package.js.map +1 -1
- package/files/tests/to-atomic-level-msa-fasta-output.csv +683 -683
- package/files/tests/to-atomic-level-msa-separator-output.csv +104 -104
- package/package.json +9 -9
- package/src/analysis/sequence-activity-cliffs.ts +3 -1
- package/src/calculations/monomerLevelMols.ts +2 -1
- package/src/demo/bio03-atomic-level.ts +1 -1
- package/src/package-test.ts +6 -1
- package/src/package.ts +151 -38
- package/src/tests/WebLogo-positions-test.ts +1 -1
- package/src/tests/bio-tests.ts +1 -1
- package/src/tests/detectors-tests.ts +10 -10
- package/src/tests/monomer-libraries-tests.ts +1 -1
- package/src/tests/seq-handler-splitted-tests.ts +6 -2
- package/src/tests/splitters-test.ts +6 -6
- package/src/tests/to-atomic-level-tests.ts +21 -14
- package/src/tests/to-atomic-level-ui-tests.ts +75 -35
- package/src/tests/utils.ts +2 -2
- package/src/utils/cell-renderer-custom.ts +62 -0
- package/src/utils/cell-renderer.ts +58 -126
- package/src/utils/cyclized.ts +28 -14
- package/src/utils/dimerized.ts +0 -2
- package/src/utils/helm-to-molfile/converter/converter.ts +75 -54
- package/src/utils/helm-to-molfile/converter/monomer-wrapper.ts +2 -2
- package/src/utils/helm-to-molfile/converter/polymer.ts +23 -16
- package/src/utils/helm-to-molfile/converter/types.ts +0 -10
- package/src/utils/helm-to-molfile/utils.ts +10 -7
- package/src/utils/monomer-cell-renderer.ts +8 -4
- package/src/utils/monomer-lib/lib-manager.ts +2 -2
- package/src/utils/monomer-lib/monomer-colors.ts +68 -0
- package/src/utils/monomer-lib/monomer-lib-base.ts +165 -0
- package/src/utils/monomer-lib/monomer-lib.ts +19 -68
- package/src/utils/monomer-lib/web-editor-monomer-dummy.ts +121 -0
- package/src/utils/monomer-lib/web-editor-monomer-of-library.ts +102 -0
- package/src/utils/save-as-fasta.ts +1 -1
- package/src/utils/seq-helper/seq-helper.ts +20 -49
- package/src/utils/sequence-to-mol.ts +24 -28
- package/src/viewers/web-logo-viewer.ts +2 -1
- package/src/widgets/composition-analysis-widget.ts +4 -3
- package/src/widgets/representations.ts +8 -10
- package/dist/248.js +0 -2
- package/dist/248.js.map +0 -1
- 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:
|
|
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 {
|
|
4
|
-
|
|
5
|
-
import
|
|
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:
|
|
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
|
-
|
|
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,
|
|
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
|
|
73
|
+
const monomers: MonomerMap = new MonomerMap();
|
|
68
74
|
for (const [mw, mwI] of wu.enumerate(this.monomerWrappers)) {
|
|
69
|
-
const
|
|
70
|
-
const
|
|
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
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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(
|
|
80
|
-
bonds: wu.count(
|
|
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 {
|
|
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(
|
|
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
|
-
|
|
23
|
+
helmCol: DG.Column<string>
|
|
22
24
|
): Promise<DG.Column<string>> {
|
|
23
25
|
const seqHelper = await SeqHelper.getInstance();
|
|
24
|
-
const
|
|
25
|
-
const
|
|
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 =
|
|
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
|
|
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 {
|
|
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
|
-
|
|
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:
|
|
45
|
+
monomers: MonomerLibDataType,
|
|
40
46
|
public readonly source: string | undefined = undefined,
|
|
41
47
|
public readonly error: string | undefined = undefined,
|
|
42
48
|
) {
|
|
43
|
-
|
|
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(
|
|
289
|
-
|
|
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) {
|