@datagrok/bio 2.15.3 → 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 +28 -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.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-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
|
}
|
|
@@ -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) {
|
|
@@ -0,0 +1,121 @@
|
|
|
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 {
|
|
6
|
+
HelmType, PolymerType, MonomerType,
|
|
7
|
+
IWebEditorMonomer, WebEditorRGroups
|
|
8
|
+
} from '@datagrok-libraries/bio/src/helm/types';
|
|
9
|
+
|
|
10
|
+
/* eslint-disable camelcase */
|
|
11
|
+
export abstract class WebEditorMonomerDummy implements IWebEditorMonomer {
|
|
12
|
+
//@formatter:off
|
|
13
|
+
public abstract get backgroundcolor(): string | undefined;
|
|
14
|
+
public abstract get linecolor(): string | undefined;
|
|
15
|
+
public abstract get textcolor(): string | undefined;
|
|
16
|
+
//@formatter:on
|
|
17
|
+
|
|
18
|
+
get issmiles(): boolean { return !!this.smiles; }
|
|
19
|
+
|
|
20
|
+
/** R-Group index os single digit only is allowed in Pistoia code */
|
|
21
|
+
public readonly at: WebEditorRGroups = {
|
|
22
|
+
R1: 'H', R2: 'H', R3: 'H', R4: 'H', R5: 'H', R6: 'H', R7: 'H', R8: 'H', R9: 'H'
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
public get rs(): number { return Object.keys(this.at).length; }
|
|
26
|
+
|
|
27
|
+
protected constructor(
|
|
28
|
+
public readonly biotype: string,
|
|
29
|
+
/** symbol */ public readonly id: string,
|
|
30
|
+
/** name */ public readonly n: string | undefined = 'missing',
|
|
31
|
+
/** molfile */ public readonly m: string | undefined = undefined,
|
|
32
|
+
/* Pistoia.HELM deletes .type and .mt in Monomers.addOneMonomer() */
|
|
33
|
+
/** polymer type */ public readonly type: PolymerType | undefined = undefined,
|
|
34
|
+
/** monomer type */ public readonly mt: MonomerType | undefined = undefined,
|
|
35
|
+
public readonly smiles?: string,
|
|
36
|
+
) {
|
|
37
|
+
if (!this.id)
|
|
38
|
+
throw new Error('Invalid arg undefined [id].');
|
|
39
|
+
|
|
40
|
+
// return new Proxy(this, {
|
|
41
|
+
// get: (target: any, prop: string | symbol, _receiver: any) => {
|
|
42
|
+
// const logPrefix = `${this.toLog()}.proxy.get( '${String(prop)}' )`;
|
|
43
|
+
// switch (prop) {
|
|
44
|
+
// case 'id':
|
|
45
|
+
// case 'at':
|
|
46
|
+
// case 'na':
|
|
47
|
+
// case 'nature':
|
|
48
|
+
// case 'backgroundcolor':
|
|
49
|
+
// case 'linecolor':
|
|
50
|
+
// case 'textcolor': {
|
|
51
|
+
// // these attributes are known and handled
|
|
52
|
+
// return target[prop];
|
|
53
|
+
// }
|
|
54
|
+
// case 'rs': {
|
|
55
|
+
// /* R-Group count (?), 2 is default for monomer "?" */
|
|
56
|
+
// throw new Error('Not supported get "rs" attribute.');
|
|
57
|
+
// }
|
|
58
|
+
// default:
|
|
59
|
+
// // Unexpected attribute requested
|
|
60
|
+
// _package.logger.warning(`${logPrefix}`);
|
|
61
|
+
// return target[prop];
|
|
62
|
+
// }
|
|
63
|
+
// },
|
|
64
|
+
// set: (target, prop, value: any, _receiver: any): boolean => {
|
|
65
|
+
// throw new Error(`Not supported set '${String(prop)}' attribute, any.`);
|
|
66
|
+
// },
|
|
67
|
+
// apply: (target: any, thisArg: any, argArray: any[]): any | undefined => {
|
|
68
|
+
// throw new Error(`Not supported call (apply) '${thisArg.toString()}' method, any.`);
|
|
69
|
+
// }
|
|
70
|
+
// });
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
private static objCounter: number = -1;
|
|
74
|
+
private readonly objId: number = ++WebEditorMonomerDummy.objCounter;
|
|
75
|
+
|
|
76
|
+
private readonly className: string = 'WebEditorMonomerDummy';
|
|
77
|
+
|
|
78
|
+
protected toLog(): string {
|
|
79
|
+
return `Helm: ${this.className}<${this.objId}>`;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export class GapWebEditorMonomer extends WebEditorMonomerDummy {
|
|
84
|
+
public readonly backgroundcolor: string = '#FFFFFF';
|
|
85
|
+
public readonly linecolor: string = '#808080';
|
|
86
|
+
public readonly textcolor: string = '#808080';
|
|
87
|
+
|
|
88
|
+
constructor(biotype: string, id: string) {
|
|
89
|
+
super(biotype, id, 'gap');
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export class AmbiguousWebEditorMonomer extends WebEditorMonomerDummy {
|
|
94
|
+
public readonly backgroundcolor: string = '#808080';
|
|
95
|
+
public readonly linecolor: string = '#000000';
|
|
96
|
+
public readonly textcolor: string = '#000000';
|
|
97
|
+
|
|
98
|
+
constructor(biotype: string, id: string) {
|
|
99
|
+
super(biotype, id, 'ambiguous');
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export class MissingWebEditorMonomer extends WebEditorMonomerDummy {
|
|
104
|
+
public readonly backgroundcolor: string = '#FF4444';
|
|
105
|
+
public readonly linecolor: string = '#800000';
|
|
106
|
+
public readonly textcolor: string = '#FFFFFF';
|
|
107
|
+
|
|
108
|
+
constructor(biotype: string, id: string) {
|
|
109
|
+
super(biotype, id, 'missing');
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export class BrokenWebEditorMonomer extends WebEditorMonomerDummy {
|
|
114
|
+
public readonly backgroundcolor: string = '#FFFF44';
|
|
115
|
+
public readonly linecolor: string = '#800000';
|
|
116
|
+
public readonly textcolor: string = '#000000';
|
|
117
|
+
|
|
118
|
+
constructor(biotype: string, id: string) {
|
|
119
|
+
super(biotype, id, 'broken');
|
|
120
|
+
}
|
|
121
|
+
}
|