@datagrok/sequence-translator 1.4.2 → 1.4.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.
- package/.eslintrc.json +1 -1
- package/CHANGELOG.md +14 -0
- package/dist/package-test.js +1 -1
- package/dist/package-test.js.map +1 -1
- package/dist/package.js +1 -1
- package/dist/package.js.map +1 -1
- package/files/polytool-rules/rules_example.json +10 -0
- package/files/samples/cyclized.csv +1 -0
- package/files/tests/polytool-reaction-lib.json +40 -0
- package/package.json +6 -6
- package/src/package-test.ts +3 -1
- package/src/package.ts +8 -0
- package/src/polytool/const.ts +1 -0
- package/src/polytool/pt-conversion.ts +147 -43
- package/src/polytool/pt-dialog.ts +51 -19
- package/src/polytool/pt-placeholders-breadth-input.ts +2 -2
- package/src/polytool/pt-placeholders-input.ts +1 -1
- package/src/polytool/pt-rules.ts +24 -4
- package/src/polytool/pt-unrule-dialog.ts +106 -0
- package/src/polytool/pt-unrule.ts +37 -0
- package/src/tests/polytool-convert-tests.ts +8 -9
- package/src/tests/polytool-enumerate-breadth-tests.ts +3 -5
- package/src/tests/polytool-enumerate-tests.ts +2 -4
- package/src/tests/polytool-unrule-tests.ts +10 -0
- package/src/tests/toAtomicLevel-tests.ts +72 -0
|
@@ -23,6 +23,16 @@
|
|
|
23
23
|
"secondSubstitution": "D"
|
|
24
24
|
}
|
|
25
25
|
},
|
|
26
|
+
{
|
|
27
|
+
"type": "reaction",
|
|
28
|
+
"code": "3",
|
|
29
|
+
"monomericSubstitution": {
|
|
30
|
+
"firstMonomer": "aG",
|
|
31
|
+
"secondMonomer": "azG",
|
|
32
|
+
"reaction": "[H:1]NC(C([OH:2])=O)c1cn(C(N[H:3])C([OH:4])=O)nn1",
|
|
33
|
+
"name": "GGaz"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
26
36
|
{
|
|
27
37
|
"type": "fragmentDuplication",
|
|
28
38
|
"code": "#3"
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"monomerType": "Backbone",
|
|
4
|
+
"smiles": "[H:1]NC(C([OH:2])=O)c1cn(C(N[H:3])C([OH:4])=O)nn1",
|
|
5
|
+
"name": "GGaz",
|
|
6
|
+
"author": "Datagrok",
|
|
7
|
+
"molfile": "\n MJ201900 \n\n 17 17 0 0 0 0 0 0 0 0999 V2000\n 18.8168 -12.6760 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n 19.5312 -13.0885 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 20.2457 -12.6760 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 20.9602 -13.0885 0.0000 R# 0 0 0 0 0 0 0 0 0 0 0 0\n 20.2457 -11.8510 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n 19.1403 -15.8019 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n 19.8547 -16.2144 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 20.5692 -15.8019 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 21.2837 -16.2144 0.0000 R# 0 0 0 0 0 0 0 0 0 0 0 0\n 20.5692 -14.9769 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0\n 19.5083 -13.8885 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n 18.8409 -14.3735 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n 19.0958 -15.1581 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0\n 19.9208 -15.1581 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 20.1757 -14.3735 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0\n 18.4258 -16.2144 0.0000 R# 0 0 0 0 0 0 0 0 0 0 0 0\n 18.1023 -13.0885 0.0000 R# 0 0 0 0 0 0 0 0 0 0 0 0\n 2 3 1 0 0 0 0\n 3 5 2 0 0 0 0\n 7 8 1 0 0 0 0\n 8 10 2 0 0 0 0\n 3 4 1 0 0 0 0\n 8 9 1 0 0 0 0\n 14 15 2 0 0 0 0\n 11 15 1 0 0 0 0\n 11 12 1 0 0 0 0\n 13 14 1 0 0 0 0\n 12 13 2 0 0 0 0\n 2 11 1 0 0 0 0\n 7 14 1 0 0 0 0\n 1 2 1 0 0 0 0\n 1 17 1 0 0 0 0\n 6 7 1 0 0 0 0\n 6 16 1 0 0 0 0\nM RGP 4 4 2 9 4 16 3 17 1\nM END\n",
|
|
8
|
+
"naturalAnalog": "G",
|
|
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
|
+
"capGroupSMILES": "[*:3][H]",
|
|
24
|
+
"alternateId": "R3-H",
|
|
25
|
+
"capGroupName": "H",
|
|
26
|
+
"label": "R3"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"capGroupSMILES": "O[*:4]",
|
|
30
|
+
"alternateId": "R4-OH",
|
|
31
|
+
"capGroupName": "OH",
|
|
32
|
+
"label": "R4"
|
|
33
|
+
}
|
|
34
|
+
],
|
|
35
|
+
"createDate": null,
|
|
36
|
+
"id": 0,
|
|
37
|
+
"polymerType": "PEPTIDE",
|
|
38
|
+
"symbol": "GGaz"
|
|
39
|
+
}
|
|
40
|
+
]
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datagrok/sequence-translator",
|
|
3
3
|
"friendlyName": "Sequence Translator",
|
|
4
|
-
"version": "1.4.
|
|
4
|
+
"version": "1.4.3",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Alexey Choposky",
|
|
7
7
|
"email": "achopovsky@datagrok.ai"
|
|
@@ -22,10 +22,10 @@
|
|
|
22
22
|
}
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@datagrok-libraries/bio": "^5.44.
|
|
25
|
+
"@datagrok-libraries/bio": "^5.44.2",
|
|
26
26
|
"@datagrok-libraries/chem-meta": "^1.2.7",
|
|
27
27
|
"@datagrok-libraries/tutorials": "^1.4.0",
|
|
28
|
-
"@datagrok-libraries/utils": "^4.3.
|
|
28
|
+
"@datagrok-libraries/utils": "^4.3.5",
|
|
29
29
|
"@types/react": "^18.0.15",
|
|
30
30
|
"cash-dom": "^8.1.0",
|
|
31
31
|
"datagrok-api": "^1.21.1",
|
|
@@ -41,9 +41,9 @@
|
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@datagrok-libraries/helm-web-editor": "^1.1.11",
|
|
43
43
|
"@datagrok-libraries/js-draw-lite": "^0.0.8",
|
|
44
|
-
"@datagrok/bio": "^2.15.
|
|
45
|
-
"@datagrok/helm": "^2.5.
|
|
46
|
-
"@datagrok/chem": "^1.12.
|
|
44
|
+
"@datagrok/bio": "^2.15.6",
|
|
45
|
+
"@datagrok/helm": "^2.5.3",
|
|
46
|
+
"@datagrok/chem": "^1.12.1",
|
|
47
47
|
"@types/jquery": "^3.5.14",
|
|
48
48
|
"@types/js-yaml": "^4.0.5",
|
|
49
49
|
"@types/lodash": "^4.14.202",
|
package/src/package-test.ts
CHANGED
|
@@ -2,15 +2,17 @@ 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 {runTests, tests, TestContext, initAutoTests as initTests
|
|
5
|
+
import {runTests, tests, TestContext, initAutoTests as initTests} from '@datagrok-libraries/utils/src/test';
|
|
6
6
|
|
|
7
7
|
import './tests/formats-to-helm';
|
|
8
8
|
import './tests/helm-to-nucleotides';
|
|
9
9
|
import './tests/formats-support';
|
|
10
10
|
import './tests/files-tests';
|
|
11
11
|
import './tests/polytool-convert-tests';
|
|
12
|
+
import './tests/polytool-unrule-tests';
|
|
12
13
|
import './tests/polytool-enumerate-tests';
|
|
13
14
|
import './tests/polytool-enumerate-breadth-tests';
|
|
15
|
+
import './tests/toAtomicLevel-tests';
|
|
14
16
|
|
|
15
17
|
import {OligoToolkitTestPackage} from './tests/utils';
|
|
16
18
|
|
package/src/package.ts
CHANGED
|
@@ -25,6 +25,7 @@ import {PolyToolCsvLibHandler} from './polytool/csv-to-json-monomer-lib-converte
|
|
|
25
25
|
import {ITranslationHelper} from './types';
|
|
26
26
|
import {addContextMenuUI} from './utils/context-menu';
|
|
27
27
|
import {PolyToolConvertFuncEditor} from './polytool/pt-convert-editor';
|
|
28
|
+
import {polyToolUnruleUI} from './polytool/pt-unrule';
|
|
28
29
|
|
|
29
30
|
export const _package: OligoToolkitPackage = new OligoToolkitPackage({debug: true}/**/);
|
|
30
31
|
|
|
@@ -162,6 +163,13 @@ export async function polyToolConvertTopMenu(): Promise<void> {
|
|
|
162
163
|
await polyToolConvertUI();
|
|
163
164
|
}
|
|
164
165
|
|
|
166
|
+
// //top-menu: Bio | PolyTool | Unrule...
|
|
167
|
+
// //name: polyToolUnrule
|
|
168
|
+
// //description: Perform uncyclization of polymers by rules
|
|
169
|
+
// export async function polyToolUnruleTopMenu(): Promise<void> {
|
|
170
|
+
// await polyToolUnruleUI();
|
|
171
|
+
// }
|
|
172
|
+
|
|
165
173
|
//name: getPolyToolConvertEditor
|
|
166
174
|
//tags: editor
|
|
167
175
|
//input: funccall call
|
package/src/polytool/const.ts
CHANGED
|
@@ -34,5 +34,6 @@ export const PT_UI_GET_HELM = 'Get HELM';
|
|
|
34
34
|
export const PT_UI_ADD_HELM = 'Add HELM column';
|
|
35
35
|
export const PT_UI_USE_CHIRALITY = 'Chirality engine';
|
|
36
36
|
export const PT_UI_DIALOG_CONVERSION = 'Poly Tool Conversion';
|
|
37
|
+
export const PT_UI_DIALOG_UNRULE = 'Poly Tool Unrule';
|
|
37
38
|
export const PT_UI_DIALOG_ENUMERATION = 'Poly Tool Enumeration';
|
|
38
39
|
export const PT_UI_RULES_USED = 'Rules used';
|
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
import * as grok from 'datagrok-api/grok';
|
|
2
|
-
import * as DG from 'datagrok-api/dg';
|
|
1
|
+
// import * as grok from 'datagrok-api/grok';
|
|
2
|
+
// import * as DG from 'datagrok-api/dg';
|
|
3
3
|
|
|
4
|
-
import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
5
|
-
import {ALIGNMENT, ALPHABET} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
6
4
|
|
|
7
|
-
import {
|
|
5
|
+
//import {ALIGNMENT, ALPHABET} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
6
|
+
|
|
7
|
+
import {Rules, RuleLink, RuleReaction} from './pt-rules';
|
|
8
8
|
|
|
9
9
|
export const RULES_DIMER = '(#2)';
|
|
10
10
|
export const RULES_HETERODIMER = '($2)';
|
|
11
11
|
|
|
12
|
-
function addCommonTags(col: DG.Column): void {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
12
|
+
// function addCommonTags(col: DG.Column): void {
|
|
13
|
+
// col.semType = DG.SEMTYPE.MACROMOLECULE;
|
|
14
|
+
// col.setTag('aligned', ALIGNMENT.SEQ);
|
|
15
|
+
// col.setTag('alphabet', ALPHABET.PT);
|
|
16
|
+
// }
|
|
17
17
|
|
|
18
18
|
export class Chain {
|
|
19
|
-
linkages: {fChain: number, sChain: number, fMonomer:number, sMonomer:number, fR:number, sR:number}[];
|
|
19
|
+
linkages: { fChain: number, sChain: number, fMonomer: number, sMonomer: number, fR: number, sR: number }[];
|
|
20
20
|
monomers: string[][];
|
|
21
21
|
|
|
22
22
|
constructor(
|
|
23
23
|
monomers: string[][],
|
|
24
|
-
linkages: {fChain: number, sChain: number, fMonomer:number, sMonomer:number, fR:number, sR:number}[]) {
|
|
24
|
+
linkages: { fChain: number, sChain: number, fMonomer: number, sMonomer: number, fR: number, sR: number }[]) {
|
|
25
25
|
this.linkages = linkages;
|
|
26
26
|
this.monomers = monomers;
|
|
27
27
|
}
|
|
@@ -32,7 +32,7 @@ export class Chain {
|
|
|
32
32
|
const rawLinkages = fragmentation[1].split('|');
|
|
33
33
|
|
|
34
34
|
const monomers = new Array<Array<string>>(rawFragments.length);
|
|
35
|
-
const linkages: {fChain: number, sChain: number, fMonomer:number, sMonomer:number, fR:number, sR:number}[] = [];
|
|
35
|
+
const linkages: { fChain: number, sChain: number, fMonomer: number, sMonomer: number, fR: number, sR: number }[] = [];
|
|
36
36
|
|
|
37
37
|
//HELM parsing
|
|
38
38
|
for (let i = 0; i < rawFragments.length; i++) {
|
|
@@ -66,15 +66,15 @@ export class Chain {
|
|
|
66
66
|
return new Chain(monomers, linkages);
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
static fromNotation(sequence: string, rules: Rules) {
|
|
69
|
+
static fromNotation(sequence: string, rules: Rules): Chain {
|
|
70
70
|
const heterodimerCode = rules.heterodimerCode;
|
|
71
71
|
const homodimerCode = rules.homodimerCode;
|
|
72
72
|
const mainFragments: string[] = [];
|
|
73
73
|
|
|
74
|
-
const linkages: {fChain: number, sChain: number, fMonomer:number, sMonomer:number, fR:number, sR:number}[] = [];
|
|
74
|
+
const linkages: { fChain: number, sChain: number, fMonomer: number, sMonomer: number, fR: number, sR: number }[] = [];
|
|
75
75
|
|
|
76
76
|
//NOTICE: this works only with simple single heterodimers
|
|
77
|
-
const heterodimeric = heterodimerCode !== null? sequence.split(`(${rules.heterodimerCode!})`) : '';
|
|
77
|
+
const heterodimeric = heterodimerCode !== null ? sequence.split(`(${rules.heterodimerCode!})`) : '';
|
|
78
78
|
if (heterodimerCode !== null && heterodimeric.length > 1) {
|
|
79
79
|
linkages.push({fChain: 0, sChain: 1, fMonomer: 1, sMonomer: 1, fR: 1, sR: 1});
|
|
80
80
|
mainFragments.push(heterodimeric[1].replaceAll('{', '').replaceAll('}', ''));
|
|
@@ -99,17 +99,32 @@ export class Chain {
|
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
+
for (let i = 0; i < mainFragments.length; i++) {
|
|
103
|
+
if (homodimerCode !== null && mainFragments[i].includes(`(${homodimerCode!})`)) {
|
|
104
|
+
const idxSequence = mainFragments.length;
|
|
105
|
+
|
|
106
|
+
linkages.push({fChain: i, sChain: idxSequence, fMonomer: 1, sMonomer: 1, fR: 1, sR: 1});
|
|
107
|
+
const rawDimer = mainFragments[i].replace(`(${homodimerCode!})`, '');
|
|
108
|
+
const idx = rawDimer.indexOf('{');
|
|
109
|
+
const linker = rawDimer.slice(0, idx);
|
|
110
|
+
const body = rawDimer.replace(linker, '').replaceAll('{', '').replaceAll('}', '');
|
|
111
|
+
|
|
112
|
+
mainFragments[i] = linker + body;
|
|
113
|
+
mainFragments.push(body);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
102
117
|
const monomers = new Array<Array<string>>(mainFragments.length);
|
|
103
118
|
|
|
104
119
|
for (let i = 0; i < mainFragments.length; i++) {
|
|
105
120
|
const rawMonomers = mainFragments[i].split('-');
|
|
106
121
|
const linkedPositions = this.getLinkedPositions(rawMonomers, rules.linkRules);
|
|
107
122
|
const [monomersCycled, allPos1, allPos2, allAttaches1, allAttaches2] =
|
|
108
|
-
|
|
123
|
+
this.getAllCycles(rules.linkRules, rawMonomers, linkedPositions);
|
|
109
124
|
|
|
110
125
|
const monomersReady = new Array<string>(monomersCycled.length);
|
|
111
|
-
for (let j = 0; j < monomersCycled.length; j++)
|
|
112
|
-
|
|
126
|
+
// for (let j = 0; j < monomersCycled.length; j++)
|
|
127
|
+
// monomersReady[j] = `[${monomersCycled[j]}]`;
|
|
113
128
|
|
|
114
129
|
for (let j = 0; j < allPos1.length; j++) {
|
|
115
130
|
linkages.push({
|
|
@@ -122,10 +137,72 @@ export class Chain {
|
|
|
122
137
|
});
|
|
123
138
|
}
|
|
124
139
|
|
|
125
|
-
monomers[i] =
|
|
140
|
+
monomers[i] = monomersCycled;
|
|
126
141
|
}
|
|
127
142
|
|
|
128
|
-
|
|
143
|
+
const monomersAll: string[][] = [];
|
|
144
|
+
|
|
145
|
+
for (let i = 0; i < monomers.length; i++) {
|
|
146
|
+
const linkedPositions = this.getLinkedPositions(monomers[i], rules.reactionRules);
|
|
147
|
+
const [monomersCycled, allPos1, allPos2, ruleN] =
|
|
148
|
+
this.getAllReactants(rules.reactionRules, monomers[i], linkedPositions);
|
|
149
|
+
|
|
150
|
+
if (allPos1.length >= 1) {
|
|
151
|
+
const ch1 = new Array<string>(allPos2[0] - 1);
|
|
152
|
+
const ch2 = new Array<string>(monomersCycled.length - allPos2[0]);
|
|
153
|
+
for (let j = 0; j < allPos2[0] - 1; j++)
|
|
154
|
+
ch1[j] = monomersCycled[j];
|
|
155
|
+
|
|
156
|
+
for (let j = allPos2[0]; j < monomersCycled.length; j++)
|
|
157
|
+
ch2[j - allPos2[0]] = monomersCycled[j];
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
ch1[allPos1[0] - 1] = rules.reactionRules[ruleN[0]].name;
|
|
161
|
+
|
|
162
|
+
for (let j = 0; j < linkages.length; j++) {
|
|
163
|
+
if (linkages[j].fMonomer > allPos2[0]) {
|
|
164
|
+
linkages[j].fMonomer -= allPos2[0];
|
|
165
|
+
linkages[j].fChain++;
|
|
166
|
+
}
|
|
167
|
+
if (linkages[j].sMonomer > allPos2[0]) {
|
|
168
|
+
linkages[j].sMonomer -= allPos2[0];
|
|
169
|
+
linkages[j].sChain++;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
linkages.push({
|
|
173
|
+
fChain: 0,
|
|
174
|
+
sChain: 0,
|
|
175
|
+
fMonomer: allPos1[0],
|
|
176
|
+
sMonomer: allPos2[0] - 1,
|
|
177
|
+
fR: 3,
|
|
178
|
+
sR: 2,
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
linkages.push({
|
|
182
|
+
fChain: 0,
|
|
183
|
+
sChain: 1,
|
|
184
|
+
fMonomer: allPos1[0],
|
|
185
|
+
sMonomer: 1,
|
|
186
|
+
fR: 4,
|
|
187
|
+
sR: 1,
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
const monomersReady1 = new Array<string>(ch1.length);
|
|
191
|
+
for (let j = 0; j < ch1.length; j++)
|
|
192
|
+
monomersReady1[j] = `[${ch1[j]}]`;
|
|
193
|
+
const monomersReady2 = new Array<string>(ch2.length);
|
|
194
|
+
for (let j = 0; j < ch2.length; j++)
|
|
195
|
+
monomersReady2[j] = `[${ch2[j]}]`;
|
|
196
|
+
|
|
197
|
+
monomersAll.push(ch1);
|
|
198
|
+
monomersAll.push(ch2);
|
|
199
|
+
} else {
|
|
200
|
+
monomersAll.push(monomers[i]);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const chain = new Chain(monomersAll, linkages);
|
|
205
|
+
return chain;
|
|
129
206
|
}
|
|
130
207
|
|
|
131
208
|
getHelmChanged(changeNumber: number, monomer: string): string {
|
|
@@ -134,17 +211,17 @@ export class Chain {
|
|
|
134
211
|
let idx1 = 0;
|
|
135
212
|
let idx2 = 0;
|
|
136
213
|
loop1:
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
214
|
+
for (let i = 0; i < this.monomers.length; i++) {
|
|
215
|
+
loop2:
|
|
216
|
+
for (let j = 0; j < this.monomers[i].length; j++) {
|
|
217
|
+
if (counter == changeNumber) {
|
|
218
|
+
idx1 = i;
|
|
219
|
+
idx2 = j;
|
|
220
|
+
break loop1;
|
|
221
|
+
}
|
|
222
|
+
counter++;
|
|
223
|
+
}
|
|
146
224
|
}
|
|
147
|
-
}
|
|
148
225
|
|
|
149
226
|
const previous = this.monomers[idx1][idx2];
|
|
150
227
|
|
|
@@ -166,7 +243,8 @@ export class Chain {
|
|
|
166
243
|
for (let j = 0; j < this.monomers[i].length; j++) {
|
|
167
244
|
if (j > 0)
|
|
168
245
|
helm += '.';
|
|
169
|
-
|
|
246
|
+
const symbol = this.monomers[i][j];
|
|
247
|
+
helm += symbol.length > 1 ? `[${symbol}]` : symbol;
|
|
170
248
|
}
|
|
171
249
|
helm += `}`;
|
|
172
250
|
}
|
|
@@ -185,8 +263,13 @@ export class Chain {
|
|
|
185
263
|
return helm;
|
|
186
264
|
}
|
|
187
265
|
|
|
188
|
-
|
|
189
|
-
|
|
266
|
+
getNotation(rules: Rules): string {
|
|
267
|
+
return 'not implemented';
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
protected static getLinkedPositions(monomers: string[], rules: RuleLink[] | RuleReaction []):
|
|
271
|
+
[number, number, number][] {
|
|
272
|
+
const result: [number, number, number][] = new Array<[number, number, number]>(rules.length);
|
|
190
273
|
|
|
191
274
|
for (let i = 0; i < rules.length; i++) {
|
|
192
275
|
let firstFound = false;
|
|
@@ -226,19 +309,18 @@ export class Chain {
|
|
|
226
309
|
}
|
|
227
310
|
|
|
228
311
|
if (!(firstFound && secondFound))
|
|
229
|
-
result[i] = [-1, -1];
|
|
312
|
+
result[i] = [-1, -1, -1];
|
|
230
313
|
else if (firstIsFirst)
|
|
231
|
-
result[i] = [firstEntryIndex, secondEntryIndex];
|
|
314
|
+
result[i] = [firstEntryIndex, secondEntryIndex, i];
|
|
232
315
|
else
|
|
233
|
-
result[i] = [secondEntryIndex, firstEntryIndex];
|
|
316
|
+
result[i] = [secondEntryIndex, firstEntryIndex, i];
|
|
234
317
|
}
|
|
235
318
|
|
|
236
|
-
|
|
237
319
|
return result;
|
|
238
320
|
}
|
|
239
321
|
|
|
240
|
-
protected static getAllCycles(rules: RuleLink[], monomers: string [], positions: [number, number][])
|
|
241
|
-
|
|
322
|
+
protected static getAllCycles(rules: RuleLink[], monomers: string [], positions: [number, number, number][]):
|
|
323
|
+
[string [], number [], number [], number [], number []] {
|
|
242
324
|
const allPos1: number [] = [];
|
|
243
325
|
const allPos2: number [] = [];
|
|
244
326
|
const allAttaches1: number [] = [];
|
|
@@ -251,7 +333,6 @@ export class Chain {
|
|
|
251
333
|
|
|
252
334
|
const firstMonomer = monomers[positions[i][0]];
|
|
253
335
|
const secondMonomer = monomers[positions[i][1]];
|
|
254
|
-
|
|
255
336
|
monomers[positions[i][0]] = monomers[positions[i][0]].replace(firstMonomer, rules[i].firstSubstitution);
|
|
256
337
|
monomers[positions[i][1]] = monomers[positions[i][1]].replace(secondMonomer, rules[i].secondSubstitution);
|
|
257
338
|
|
|
@@ -263,17 +344,40 @@ export class Chain {
|
|
|
263
344
|
|
|
264
345
|
return [monomers, allPos1, allPos2, allAttaches1, allAttaches2];
|
|
265
346
|
}
|
|
347
|
+
|
|
348
|
+
protected static getAllReactants(rules: RuleReaction[], monomers: string [], positions: [number, number, number][]):
|
|
349
|
+
[string [], number [], number [], number []] {
|
|
350
|
+
const allPos1: number [] = [];
|
|
351
|
+
const allPos2: number [] = [];
|
|
352
|
+
const rule: number [] = [];
|
|
353
|
+
const ruleCount = rules.length;
|
|
354
|
+
|
|
355
|
+
for (let i = 0; i < ruleCount; i++) {
|
|
356
|
+
if (positions[i][0] == -1)
|
|
357
|
+
continue;
|
|
358
|
+
|
|
359
|
+
const firstMonomer = monomers[positions[i][0]];
|
|
360
|
+
const secondMonomer = monomers[positions[i][1]];
|
|
361
|
+
monomers[positions[i][0]] = monomers[positions[i][0]].replace(firstMonomer, rules[i].firstMonomer);
|
|
362
|
+
monomers[positions[i][1]] = monomers[positions[i][1]].replace(secondMonomer, rules[i].secondMonomer);
|
|
363
|
+
|
|
364
|
+
allPos1.push(positions[i][0] + 1);
|
|
365
|
+
allPos2.push(positions[i][1] + 1);
|
|
366
|
+
rule.push(positions[i][2]);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
return [monomers, allPos1, allPos2, rule];
|
|
370
|
+
}
|
|
266
371
|
}
|
|
267
372
|
|
|
268
373
|
/** The main PolyTool convert engine. Returns list of Helms. Covered with tests. */
|
|
269
374
|
export function doPolyToolConvert(sequences: string[], rules: Rules): string[] {
|
|
270
375
|
const helms = new Array<string>(sequences.length);
|
|
271
376
|
for (let i = 0; i < sequences.length; i++) {
|
|
272
|
-
if (sequences[i]
|
|
377
|
+
if (sequences[i] == null) { helms[i] = ''; } else {
|
|
273
378
|
const chain = Chain.fromNotation(sequences[i], rules);
|
|
274
379
|
helms[i] = chain.getHelm();
|
|
275
380
|
}
|
|
276
381
|
}
|
|
277
|
-
|
|
278
382
|
return helms;
|
|
279
383
|
}
|
|
@@ -9,6 +9,7 @@ import {getHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
|
|
|
9
9
|
import {errInfo} from '@datagrok-libraries/bio/src/utils/err-info';
|
|
10
10
|
import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
11
11
|
import {getSeqHelper, ISeqHelper} from '@datagrok-libraries/bio/src/utils/seq-helper';
|
|
12
|
+
import {SeqHandler} from '@datagrok-libraries/bio/src/utils/seq-handler';
|
|
12
13
|
|
|
13
14
|
import {getRules, RuleInputs, RULES_PATH, RULES_STORAGE_NAME} from './pt-rules';
|
|
14
15
|
import {doPolyToolConvert} from './pt-conversion';
|
|
@@ -26,6 +27,7 @@ import {_package} from '../package';
|
|
|
26
27
|
type PolyToolConvertSerialized = {
|
|
27
28
|
generateHelm: boolean;
|
|
28
29
|
chiralityEngine: boolean;
|
|
30
|
+
rules: string[];
|
|
29
31
|
};
|
|
30
32
|
|
|
31
33
|
type PolyToolEnumerateChemSerialized = {
|
|
@@ -55,35 +57,43 @@ export async function polyToolConvertUI(): Promise<void> {
|
|
|
55
57
|
}
|
|
56
58
|
}
|
|
57
59
|
|
|
58
|
-
export async function getPolyToolConvertDialog(
|
|
60
|
+
export async function getPolyToolConvertDialog(srcCol?: DG.Column): Promise<DG.Dialog> {
|
|
59
61
|
const subs: Unsubscribable[] = [];
|
|
60
62
|
const destroy = () => {
|
|
61
63
|
for (const sub of subs) sub.unsubscribe();
|
|
62
64
|
};
|
|
63
65
|
try {
|
|
64
|
-
|
|
65
|
-
if (!
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
66
|
+
let srcColVal: DG.Column<string> | undefined = srcCol;
|
|
67
|
+
if (!srcColVal) {
|
|
68
|
+
const srcColList = grok.shell.t.columns.bySemTypeAll(DG.SEMTYPE.MACROMOLECULE);
|
|
69
|
+
if (srcColList.length < 1)
|
|
70
|
+
throw new Error(PT_ERROR_DATAFRAME);
|
|
71
|
+
srcColVal = srcColList[0];
|
|
72
|
+
}
|
|
73
|
+
const srcColInput = ui.input.column('Column', {
|
|
74
|
+
table: srcColVal.dataFrame, value: srcColVal,
|
|
75
|
+
filter: (col: DG.Column) => {
|
|
76
|
+
if (col.semType !== DG.SEMTYPE.MACROMOLECULE) return false;
|
|
77
|
+
const sh = SeqHandler.forColumn(col);
|
|
78
|
+
return sh.notation === NOTATION.CUSTOM;
|
|
79
|
+
}
|
|
71
80
|
});
|
|
72
81
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
const generateHelmChoiceInput = ui.input.bool(PT_UI_GET_HELM, {value: true});
|
|
76
|
-
ui.tooltip.bind(generateHelmChoiceInput.root, PT_UI_ADD_HELM);
|
|
82
|
+
const generateHelmInput = ui.input.bool(PT_UI_GET_HELM, {value: true});
|
|
83
|
+
ui.tooltip.bind(generateHelmInput.root, PT_UI_ADD_HELM);
|
|
77
84
|
|
|
78
85
|
const chiralityEngineInput = ui.input.bool(PT_UI_USE_CHIRALITY, {value: false});
|
|
79
|
-
|
|
86
|
+
let ruleFileList: string[];
|
|
87
|
+
const ruleInputs = new RuleInputs(RULES_PATH, RULES_STORAGE_NAME, '.json', {
|
|
88
|
+
onValueChanged: (value: string[]) => { ruleFileList = value;}
|
|
89
|
+
});
|
|
80
90
|
const rulesHeader = ui.inlineText([PT_UI_RULES_USED]);
|
|
81
91
|
ui.tooltip.bind(rulesHeader, 'Add or specify rules to use');
|
|
82
92
|
const rulesForm = await ruleInputs.getForm();
|
|
83
93
|
|
|
84
|
-
const div = ui.
|
|
85
|
-
|
|
86
|
-
|
|
94
|
+
const div = ui.divV([
|
|
95
|
+
srcColInput,
|
|
96
|
+
generateHelmInput,
|
|
87
97
|
chiralityEngineInput,
|
|
88
98
|
rulesHeader,
|
|
89
99
|
rulesForm
|
|
@@ -92,7 +102,7 @@ export async function getPolyToolConvertDialog(targetCol?: DG.Column): Promise<D
|
|
|
92
102
|
const exec = async (): Promise<void> => {
|
|
93
103
|
try {
|
|
94
104
|
const ruleFileList = await ruleInputs.getActive();
|
|
95
|
-
await polyToolConvert(
|
|
105
|
+
await polyToolConvert(srcColInput.value!, generateHelmInput.value!, chiralityEngineInput.value!, ruleFileList);
|
|
96
106
|
} catch (err: any) {
|
|
97
107
|
defaultErrorHandler(err);
|
|
98
108
|
}
|
|
@@ -107,13 +117,15 @@ export async function getPolyToolConvertDialog(targetCol?: DG.Column): Promise<D
|
|
|
107
117
|
dialog.history(
|
|
108
118
|
/* getInput */ (): PolyToolConvertSerialized => {
|
|
109
119
|
return {
|
|
110
|
-
generateHelm:
|
|
120
|
+
generateHelm: generateHelmInput.value,
|
|
111
121
|
chiralityEngine: chiralityEngineInput.value,
|
|
122
|
+
rules: ruleFileList,
|
|
112
123
|
};
|
|
113
124
|
},
|
|
114
125
|
/* applyInput */ (x: PolyToolConvertSerialized): void => {
|
|
115
|
-
|
|
126
|
+
generateHelmInput.value = x.generateHelm;
|
|
116
127
|
chiralityEngineInput.value = x.chiralityEngine;
|
|
128
|
+
ruleInputs.setActive(ruleFileList);
|
|
117
129
|
});
|
|
118
130
|
return dialog;
|
|
119
131
|
} catch (err: any) {
|
|
@@ -246,6 +258,26 @@ export async function polyToolConvert(
|
|
|
246
258
|
const seqHelper: ISeqHelper = await getSeqHelper();
|
|
247
259
|
const toAtomicLevelRes = await seqHelper.helmToAtomicLevel(resHelmCol, chiralityEngine, /* highlight */ generateHelm);
|
|
248
260
|
const resMolCol = toAtomicLevelRes.molCol!;
|
|
261
|
+
|
|
262
|
+
// const rdkit = await grok.functions.call('Chem:getRdKitModule');
|
|
263
|
+
// for (let i = 0; i < rules.reactionRules.length; i++) {
|
|
264
|
+
// const reacSmarts = rules.reactionRules[i].reaction;
|
|
265
|
+
// const rxn = rdkit.get_rxn(reacSmarts);
|
|
266
|
+
|
|
267
|
+
// for (let j = 0; j < resMolCol.length; j++) {
|
|
268
|
+
// const mols = new rdkit.MolList();
|
|
269
|
+
// const mol = rdkit.get_mol(resMolCol.get(j));
|
|
270
|
+
// mols.append(mol!);
|
|
271
|
+
// const rctns = rxn.run_reactants(mols, 1);
|
|
272
|
+
// const size = rctns.size();
|
|
273
|
+
// const element = rctns.get(0);
|
|
274
|
+
// let molP: RDMol | null = null;
|
|
275
|
+
// molP = element.next();
|
|
276
|
+
// const molBlock = molP?.get_v3Kmolblock();
|
|
277
|
+
// resMolCol.set(j, molBlock!);
|
|
278
|
+
// }
|
|
279
|
+
// }
|
|
280
|
+
|
|
249
281
|
resMolCol.name = getUnusedName(table, `molfile(${seqCol.name})`);
|
|
250
282
|
resMolCol.semType = DG.SEMTYPE.MOLECULE;
|
|
251
283
|
if (table) {
|
|
@@ -100,8 +100,8 @@ export class PolyToolPlaceholdersBreadthInput extends DG.JsInputBase<DG.DataFram
|
|
|
100
100
|
export function dfToPlaceholdersBreadth(df: DG.DataFrame): PolyToolPlaceholdersBreadth {
|
|
101
101
|
const res: PolyToolPlaceholdersBreadth = [];
|
|
102
102
|
for (let rowI = 0; rowI < df.rowCount; rowI++) {
|
|
103
|
-
const startPos = parseInt(df.get('Start', rowI));
|
|
104
|
-
const endPos = parseInt(df.get('End', rowI));
|
|
103
|
+
const startPos = parseInt(df.get('Start', rowI)) - 1;
|
|
104
|
+
const endPos = parseInt(df.get('End', rowI)) - 1;
|
|
105
105
|
if (!isNaN(startPos) && !isNaN(endPos)) {
|
|
106
106
|
const monomerSymbolList = parseMonomerSymbolList(df.get('Monomers', rowI));
|
|
107
107
|
res.push({start: startPos, end: endPos, monomers: monomerSymbolList});
|
|
@@ -111,7 +111,7 @@ export function getPlaceholdersFromText(src: string): PolyToolPlaceholders {
|
|
|
111
111
|
export function dfToPlaceholders(df: DG.DataFrame): PolyToolPlaceholders {
|
|
112
112
|
const res: PolyToolPlaceholders = [];
|
|
113
113
|
for (let rowI = 0; rowI < df.rowCount; rowI++) {
|
|
114
|
-
const pos = parseInt(df.get('Position', rowI));
|
|
114
|
+
const pos = parseInt(df.get('Position', rowI)) - 1;
|
|
115
115
|
if (!isNaN(pos)) {
|
|
116
116
|
const monomerSymbolList = parseMonomerSymbolList(df.get('Monomers', rowI));
|
|
117
117
|
res.push({position: pos, monomers: monomerSymbolList});
|
package/src/polytool/pt-rules.ts
CHANGED
|
@@ -5,19 +5,24 @@ import {ActiveFiles} from '@datagrok-libraries/utils/src/settings/active-files-b
|
|
|
5
5
|
export const RULES_PATH = 'System:AppData/SequenceTranslator/polytool-rules/';
|
|
6
6
|
export const RULES_STORAGE_NAME = 'Polytool';
|
|
7
7
|
export const RULES_TYPE_LINK = 'link';
|
|
8
|
+
export const RULES_TYPE_REACTION = 'reaction';
|
|
8
9
|
export const RULES_TYPE_HOMODIMER = 'fragmentDuplication';
|
|
9
10
|
export const RULES_TYPE_HETERODIMER = 'differentFragments';
|
|
10
11
|
|
|
11
12
|
export class RuleInputs extends ActiveFiles {
|
|
12
|
-
constructor(
|
|
13
|
-
|
|
13
|
+
constructor(
|
|
14
|
+
path: string, userStorageName: string, ext: string,
|
|
15
|
+
options?: { onValueChanged: (value: string[]) => void }
|
|
16
|
+
) {
|
|
17
|
+
super(path, userStorageName, ext, options);
|
|
14
18
|
}
|
|
15
19
|
}
|
|
16
20
|
|
|
17
21
|
export type Rules = {
|
|
18
22
|
homodimerCode: string | null,
|
|
19
23
|
heterodimerCode: string | null,
|
|
20
|
-
linkRules: RuleLink[]
|
|
24
|
+
linkRules: RuleLink[],
|
|
25
|
+
reactionRules: RuleReaction[]
|
|
21
26
|
}
|
|
22
27
|
|
|
23
28
|
export type RuleLink = {
|
|
@@ -30,10 +35,19 @@ export type RuleLink = {
|
|
|
30
35
|
secondLinkingGroup: number
|
|
31
36
|
}
|
|
32
37
|
|
|
38
|
+
export type RuleReaction = {
|
|
39
|
+
code: number,
|
|
40
|
+
firstMonomer: string,
|
|
41
|
+
secondMonomer: string,
|
|
42
|
+
reaction: string,
|
|
43
|
+
name: string
|
|
44
|
+
}
|
|
45
|
+
|
|
33
46
|
export async function getRules(ruleFiles: string[]): Promise<Rules> {
|
|
34
47
|
const fileSource = new DG.FileSource(RULES_PATH);
|
|
35
48
|
const linkRules: RuleLink[] = [];
|
|
36
|
-
const
|
|
49
|
+
const reactionRules: RuleReaction[] = [];
|
|
50
|
+
const rules: Rules = {homodimerCode: null, heterodimerCode: null, linkRules: linkRules, reactionRules: reactionRules};
|
|
37
51
|
|
|
38
52
|
for (let i = 0; i < ruleFiles.length; i++) {
|
|
39
53
|
const rulesRaw = await fileSource.readAsText(ruleFiles[i].replace(RULES_PATH, ''));
|
|
@@ -47,6 +61,12 @@ export async function getRules(ruleFiles: string[]): Promise<Rules> {
|
|
|
47
61
|
linkRules.push(rule);
|
|
48
62
|
break;
|
|
49
63
|
}
|
|
64
|
+
case RULES_TYPE_REACTION: {
|
|
65
|
+
const rule = ruleSingle[j].monomericSubstitution;
|
|
66
|
+
rule['code'] = ruleSingle[j].code;
|
|
67
|
+
reactionRules.push(rule);
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
50
70
|
case RULES_TYPE_HOMODIMER: {
|
|
51
71
|
if (rules.homodimerCode)
|
|
52
72
|
grok.shell.warning(`PolyTool: homodimer code is duplicated in rules.`);
|