@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.
@@ -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"
@@ -4,3 +4,4 @@ n,seqs
4
4
  3,R-F-C(1)-T-G-H-F-Y-P-C(1)
5
5
  4,C(1)-T-G-H-F-H-P-C(1)
6
6
  5,R-F-D(2)-T-G-H-F-Y-P-NH2(2)
7
+ 6,R-F-aG(3)-T-G-H-F-Y-P-azG(3)-meI
@@ -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.2",
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.0",
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.0",
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.3",
45
- "@datagrok/helm": "^2.5.0",
46
- "@datagrok/chem": "^1.12.0",
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",
@@ -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 } from '@datagrok-libraries/utils/src/test';
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
@@ -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 {Rules, RuleLink, getRules} from './pt-rules';
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
- col.semType = DG.SEMTYPE.MACROMOLECULE;
14
- col.setTag('aligned', ALIGNMENT.SEQ);
15
- col.setTag('alphabet', ALPHABET.PT);
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
- this.getAllCycles(rules.linkRules, rawMonomers, linkedPositions);
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
- monomersReady[j] = `[${monomersCycled[j]}]`;
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] = monomersReady;
140
+ monomers[i] = monomersCycled;
126
141
  }
127
142
 
128
- return new Chain(monomers, linkages);
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
- for (let i = 0; i < this.monomers.length; i++) {
138
- loop2:
139
- for (let j = 0; j < this.monomers[i].length; j++) {
140
- if (counter == changeNumber) {
141
- idx1 = i;
142
- idx2 = j;
143
- break loop1;
144
- }
145
- counter++;
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
- helm += this.monomers[i][j];
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
- protected static getLinkedPositions(monomers: string[], rules: RuleLink[]): [number, number][] {
189
- const result: [number, number][] = new Array<[number, number]>(rules.length);
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
- [string [], number [], number [], number [], number []] {
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] === undefined) { helms[i] = ''; } else {
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(targetCol?: DG.Column): Promise<DG.Dialog> {
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
- const targetColumns = grok.shell.t.columns.bySemTypeAll(DG.SEMTYPE.MACROMOLECULE);
65
- if (!targetColumns)
66
- throw new Error(PT_ERROR_DATAFRAME);
67
-
68
- const targetColumnInput = ui.input.column('Column', {
69
- table: grok.shell.t, value: targetColumns[0],
70
- filter: (col: DG.Column) => col.semType === DG.SEMTYPE.MACROMOLECULE
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
- targetColumnInput.value = targetCol ? targetCol : targetColumnInput.value;
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
- const ruleInputs = new RuleInputs(RULES_PATH, RULES_STORAGE_NAME, '.json');
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.div([
85
- targetColumnInput,
86
- generateHelmChoiceInput,
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(targetColumnInput.value!, generateHelmChoiceInput.value!, chiralityEngineInput.value!, ruleFileList);
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: generateHelmChoiceInput.value,
120
+ generateHelm: generateHelmInput.value,
111
121
  chiralityEngine: chiralityEngineInput.value,
122
+ rules: ruleFileList,
112
123
  };
113
124
  },
114
125
  /* applyInput */ (x: PolyToolConvertSerialized): void => {
115
- generateHelmChoiceInput.value = x.generateHelm;
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});
@@ -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(path: string, userStorageName: string, ext: string ) {
13
- super(path, userStorageName, ext);
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 rules: Rules = {homodimerCode: null, heterodimerCode: null, linkRules: linkRules};
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.`);