@datagrok/sequence-translator 1.4.3 → 1.4.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 +24 -0
- package/detectors.js +24 -0
- package/dist/455.js +2 -0
- package/dist/455.js.map +1 -0
- package/dist/package-test.js +2 -1
- package/dist/package-test.js.LICENSE.txt +8 -0
- 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 +4 -4
- package/files/samples/cyclized.csv +3 -2
- package/package.json +14 -14
- package/src/apps/common/model/oligo-toolkit-package.ts +12 -0
- package/src/apps/common/view/components/molecule-img.ts +2 -2
- package/src/apps/pattern/model/data-manager.ts +9 -9
- package/src/apps/translator/view/ui.ts +8 -8
- package/src/package-test.ts +2 -0
- package/src/package.ts +30 -4
- package/src/polytool/pt-conversion.ts +361 -32
- package/src/polytool/pt-dialog.ts +18 -25
- package/src/polytool/pt-enumeration-helm-dialog.ts +18 -11
- package/src/polytool/pt-enumeration-helm.ts +3 -2
- package/src/polytool/pt-unrule-dialog.ts +2 -2
- package/src/polytool/pt-unrule.ts +1 -1
- package/src/polytool/types.ts +18 -0
- package/src/tests/polytool-chain-from-notation-tests.ts +45 -0
- package/src/tests/polytool-chain-parse-notation-tests.ts +59 -0
- package/src/tests/polytool-detectors-custom-notation-test.ts +43 -0
- package/src/tests/toAtomicLevel-tests.ts +26 -1
- package/src/tests/utils/detect-macromolecule-utils.ts +64 -0
- package/src/tests/{utils.ts → utils/index.ts} +2 -2
- package/src/utils/context-menu.ts +0 -3
- package/src/utils/cyclized.ts +90 -0
- package/src/utils/dimerized.ts +10 -0
|
@@ -1,29 +1,40 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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 {HelmTypes, PolymerTypes} from '@datagrok-libraries/bio/src/helm/consts';
|
|
8
|
+
import {getMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
|
|
9
|
+
import {IMonomerLib, IMonomerLibBase, Monomer, MonomerLibData, RGroup} from '@datagrok-libraries/bio/src/types';
|
|
10
|
+
import {RDModule, RDMol, RDReaction, MolList, RDReactionResult} from '@datagrok-libraries/chem-meta/src/rdkit-api';
|
|
11
|
+
import {HELM_REQUIRED_FIELD as REQ, HELM_OPTIONAL_FIELDS as OPT, HELM_RGROUP_FIELDS, HELM_OPTIONAL_FIELDS} from '@datagrok-libraries/bio/src/utils/const';
|
|
12
|
+
import {getRdKitModule} from '@datagrok-libraries/bio/src/chem/rdkit-module';
|
|
13
|
+
import {errInfo} from '@datagrok-libraries/bio/src/utils/err-info';
|
|
14
|
+
import {HelmMol, HelmType, JSDraw2ModuleType, OrgType} from '@datagrok-libraries/bio/src/helm/types';
|
|
15
|
+
import {getHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
|
|
6
16
|
|
|
7
17
|
import {Rules, RuleLink, RuleReaction} from './pt-rules';
|
|
18
|
+
import {InvalidReactionError, MonomerNotFoundError} from './types';
|
|
19
|
+
|
|
20
|
+
import {_package} from '../package';
|
|
8
21
|
|
|
9
|
-
|
|
10
|
-
|
|
22
|
+
declare const JSDraw2: JSDraw2ModuleType;
|
|
23
|
+
declare const org: OrgType;
|
|
11
24
|
|
|
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
25
|
|
|
18
26
|
export class Chain {
|
|
19
27
|
linkages: { fChain: number, sChain: number, fMonomer: number, sMonomer: number, fR: number, sR: number }[];
|
|
20
28
|
monomers: string[][];
|
|
29
|
+
mol: HelmMol | null;
|
|
21
30
|
|
|
22
31
|
constructor(
|
|
23
32
|
monomers: string[][],
|
|
24
|
-
linkages: { fChain: number, sChain: number, fMonomer: number, sMonomer: number, fR: number, sR: number }[]
|
|
33
|
+
linkages: { fChain: number, sChain: number, fMonomer: number, sMonomer: number, fR: number, sR: number }[],
|
|
34
|
+
mol: HelmMol | null) {
|
|
25
35
|
this.linkages = linkages;
|
|
26
36
|
this.monomers = monomers;
|
|
37
|
+
this.mol = mol;
|
|
27
38
|
}
|
|
28
39
|
|
|
29
40
|
static fromHelm(helm: string) {
|
|
@@ -32,7 +43,14 @@ export class Chain {
|
|
|
32
43
|
const rawLinkages = fragmentation[1].split('|');
|
|
33
44
|
|
|
34
45
|
const monomers = new Array<Array<string>>(rawFragments.length);
|
|
35
|
-
const linkages: {
|
|
46
|
+
const linkages: {
|
|
47
|
+
fChain: number,
|
|
48
|
+
sChain: number,
|
|
49
|
+
fMonomer: number,
|
|
50
|
+
sMonomer: number,
|
|
51
|
+
fR: number,
|
|
52
|
+
sR: number
|
|
53
|
+
}[] = [];
|
|
36
54
|
|
|
37
55
|
//HELM parsing
|
|
38
56
|
for (let i = 0; i < rawFragments.length; i++) {
|
|
@@ -63,7 +81,7 @@ export class Chain {
|
|
|
63
81
|
}
|
|
64
82
|
}
|
|
65
83
|
|
|
66
|
-
return new Chain(monomers, linkages);
|
|
84
|
+
return new Chain(monomers, linkages, null);
|
|
67
85
|
}
|
|
68
86
|
|
|
69
87
|
static fromNotation(sequence: string, rules: Rules): Chain {
|
|
@@ -71,7 +89,14 @@ export class Chain {
|
|
|
71
89
|
const homodimerCode = rules.homodimerCode;
|
|
72
90
|
const mainFragments: string[] = [];
|
|
73
91
|
|
|
74
|
-
const linkages: {
|
|
92
|
+
const linkages: {
|
|
93
|
+
fChain: number,
|
|
94
|
+
sChain: number,
|
|
95
|
+
fMonomer: number,
|
|
96
|
+
sMonomer: number,
|
|
97
|
+
fR: number,
|
|
98
|
+
sR: number
|
|
99
|
+
}[] = [];
|
|
75
100
|
|
|
76
101
|
//NOTICE: this works only with simple single heterodimers
|
|
77
102
|
const heterodimeric = heterodimerCode !== null ? sequence.split(`(${rules.heterodimerCode!})`) : '';
|
|
@@ -201,7 +226,97 @@ export class Chain {
|
|
|
201
226
|
}
|
|
202
227
|
}
|
|
203
228
|
|
|
204
|
-
const chain = new Chain(monomersAll, linkages);
|
|
229
|
+
const chain = new Chain(monomersAll, linkages, null);
|
|
230
|
+
return chain;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
static async parseNotation(sequence: string): Promise<Chain> {
|
|
234
|
+
const mainFragments: string[][] = [];
|
|
235
|
+
|
|
236
|
+
const linkages: {
|
|
237
|
+
fChain: number,
|
|
238
|
+
sChain: number,
|
|
239
|
+
fMonomer: number,
|
|
240
|
+
sMonomer: number,
|
|
241
|
+
fR: number,
|
|
242
|
+
sR: number
|
|
243
|
+
}[] = [];
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
const hh = await getHelmHelper();
|
|
247
|
+
// const sampleHwe = hh.createHelmWebEditor();
|
|
248
|
+
// sampleHwe.editor.setHelm('PEPTIDE1{R.P.D.[meI]}$$$$');
|
|
249
|
+
|
|
250
|
+
const resHwe = hh.createHelmWebEditor();
|
|
251
|
+
const resMol = resHwe.editor.m;
|
|
252
|
+
|
|
253
|
+
const rxp = /(\(.\d+\))?\{[^\}]*\}/g;
|
|
254
|
+
const seqs: string [] = [];
|
|
255
|
+
seqs.push(sequence.replaceAll(rxp, ''));
|
|
256
|
+
|
|
257
|
+
//const l = (rxpRes?.length) ?? -1;
|
|
258
|
+
|
|
259
|
+
const matches = sequence.matchAll(rxp);
|
|
260
|
+
//const rxpRes = rxp.exec(sequence);
|
|
261
|
+
for (const m of matches) {
|
|
262
|
+
const str = m![0];
|
|
263
|
+
if (str)
|
|
264
|
+
seqs.push(str);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
let counter = 0;
|
|
268
|
+
for (let i = 0; i < seqs.length; i++) {
|
|
269
|
+
const splMonomers = seqs[i].split('-');
|
|
270
|
+
const monomers: string [] = new Array<string>(splMonomers.length);
|
|
271
|
+
for (let j = 0; j < splMonomers.length; j++) {
|
|
272
|
+
const monomer = splMonomers[j].replace('{', '').replace('}', '');
|
|
273
|
+
if (monomer !== '') {
|
|
274
|
+
monomers[j] = monomer;
|
|
275
|
+
counter++;
|
|
276
|
+
} else {
|
|
277
|
+
linkages.push({fChain: i, sChain: i + 1, fMonomer: counter, sMonomer: counter + 1, fR: 1, sR: 1});
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
mainFragments.push(monomers);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
counter = 0;
|
|
285
|
+
const p = new JSDraw2.Point(0, 0);
|
|
286
|
+
for (let i = 0; i < mainFragments.length; i++) {
|
|
287
|
+
for (let j = 0; j < mainFragments[i].length; j++) {
|
|
288
|
+
if (!!mainFragments[i][j]) {
|
|
289
|
+
const elem = mainFragments[i][j];
|
|
290
|
+
const bio = {type: HelmTypes.AA, i: i, j: j};
|
|
291
|
+
const atom = new JSDraw2.Atom<HelmType>(p, elem, bio);
|
|
292
|
+
resMol.addAtom(atom);
|
|
293
|
+
|
|
294
|
+
if (j !== 0) {
|
|
295
|
+
const atom1 = resMol.atoms[counter - 1];
|
|
296
|
+
const atom2 = resMol.atoms[counter];
|
|
297
|
+
const bond = new JSDraw2.Bond<HelmType>(atom1, atom2);
|
|
298
|
+
bond.r1 = 2;
|
|
299
|
+
bond.r2 = 1;
|
|
300
|
+
resMol.addBond(bond);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
counter++;
|
|
304
|
+
p.x += JSDraw2.Editor.BONDLENGTH; // Inspired by HELMWebEditor
|
|
305
|
+
}
|
|
306
|
+
p.y += 4 * JSDraw2.Editor.BONDLENGTH; // Inspired by HELMWebEditor
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
for (let i = 0; i < linkages.length; i++) {
|
|
311
|
+
const atom1 = resMol.atoms[linkages[i].fMonomer - 1];
|
|
312
|
+
const atom2 = resMol.atoms[linkages[i].sMonomer - 1];
|
|
313
|
+
const bond = new JSDraw2.Bond<HelmType>(atom1, atom2);
|
|
314
|
+
bond.r1 = linkages[i].fR;
|
|
315
|
+
bond.r2 = linkages[i].sR;
|
|
316
|
+
resMol.addBond(bond);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const chain = new Chain(mainFragments, linkages, resMol);
|
|
205
320
|
return chain;
|
|
206
321
|
}
|
|
207
322
|
|
|
@@ -211,17 +326,17 @@ export class Chain {
|
|
|
211
326
|
let idx1 = 0;
|
|
212
327
|
let idx2 = 0;
|
|
213
328
|
loop1:
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
}
|
|
329
|
+
for (let i = 0; i < this.monomers.length; i++) {
|
|
330
|
+
loop2:
|
|
331
|
+
for (let j = 0; j < this.monomers[i].length; j++) {
|
|
332
|
+
if (counter == changeNumber) {
|
|
333
|
+
idx1 = i;
|
|
334
|
+
idx2 = j;
|
|
335
|
+
break loop1;
|
|
336
|
+
}
|
|
337
|
+
counter++;
|
|
224
338
|
}
|
|
339
|
+
}
|
|
225
340
|
|
|
226
341
|
const previous = this.monomers[idx1][idx2];
|
|
227
342
|
|
|
@@ -232,6 +347,10 @@ export class Chain {
|
|
|
232
347
|
return res;
|
|
233
348
|
}
|
|
234
349
|
|
|
350
|
+
getNotationHelm(): string {
|
|
351
|
+
return this.getHelm();
|
|
352
|
+
}
|
|
353
|
+
|
|
235
354
|
getHelm(): string {
|
|
236
355
|
let helm = '';
|
|
237
356
|
for (let i = 0; i < this.monomers.length; i++) {
|
|
@@ -263,8 +382,66 @@ export class Chain {
|
|
|
263
382
|
return helm;
|
|
264
383
|
}
|
|
265
384
|
|
|
266
|
-
getNotation(
|
|
267
|
-
|
|
385
|
+
getNotation(): string {
|
|
386
|
+
const atoms = this.mol!.atoms;
|
|
387
|
+
const bonds = this.mol!.bonds;
|
|
388
|
+
const chains: number[] = [];
|
|
389
|
+
const specialBonds: number[] = [];
|
|
390
|
+
for (let i = 0; i < bonds.length!; i++) {
|
|
391
|
+
//@ts-ignore
|
|
392
|
+
if (bonds[i].a1.bio.i !== bonds[i].a2.bio.i)
|
|
393
|
+
specialBonds.push(i);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
for (let i = 0; i < atoms.length!; i++) {
|
|
397
|
+
//@ts-ignore
|
|
398
|
+
const atomChain = atoms[i].bio?.i;
|
|
399
|
+
if (atomChain + 1 > chains.length)
|
|
400
|
+
chains.push(1);
|
|
401
|
+
else
|
|
402
|
+
chains[atomChain]++;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
const simpleChains: string[][] = new Array(chains.length);
|
|
406
|
+
let counter = 0;
|
|
407
|
+
for (let i = 0; i < chains.length!; i++) {
|
|
408
|
+
const simpleChain: string[] = new Array(chains[i]);
|
|
409
|
+
for (let j = 0; j < chains[i]; j++) {
|
|
410
|
+
simpleChain[j] = atoms[counter].elem;
|
|
411
|
+
counter++;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
simpleChains[i] = simpleChain;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
let res = '';
|
|
418
|
+
for (let i = 0; i < simpleChains.length; i++) {
|
|
419
|
+
let chainAdd = '';
|
|
420
|
+
|
|
421
|
+
for (let j = 0; j < simpleChains[i].length; j++)
|
|
422
|
+
chainAdd += `${j == 0 ? '' : '-'}${simpleChains[i][j]}`;
|
|
423
|
+
|
|
424
|
+
if (i !== 0) {
|
|
425
|
+
const rxp = /(\(.\d+\))/;
|
|
426
|
+
const match = chainAdd.match(rxp);
|
|
427
|
+
chainAdd = chainAdd.replace(match?.[0]!, '');
|
|
428
|
+
const group = match ? match?.[0]! : '';
|
|
429
|
+
chainAdd = `${group}{${chainAdd}}`;
|
|
430
|
+
} else {
|
|
431
|
+
if (simpleChains.length > 1) {
|
|
432
|
+
//@ts-ignore
|
|
433
|
+
const firstAtomLinks = bonds[specialBonds[0]].a1.bio.i == 0 && bonds[specialBonds[0]].a1.bio.j == 0;
|
|
434
|
+
//@ts-ignore
|
|
435
|
+
const secondAtomLinks = bonds[specialBonds[0]].a2.bio.i == 1 && bonds[specialBonds[0]].a1.bio.j == 0;
|
|
436
|
+
if (firstAtomLinks && secondAtomLinks)
|
|
437
|
+
chainAdd += '-';
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
res += chainAdd;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
return res;
|
|
268
445
|
}
|
|
269
446
|
|
|
270
447
|
protected static getLinkedPositions(monomers: string[], rules: RuleLink[] | RuleReaction []):
|
|
@@ -374,10 +551,162 @@ export class Chain {
|
|
|
374
551
|
export function doPolyToolConvert(sequences: string[], rules: Rules): string[] {
|
|
375
552
|
const helms = new Array<string>(sequences.length);
|
|
376
553
|
for (let i = 0; i < sequences.length; i++) {
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
554
|
+
try {
|
|
555
|
+
if (sequences[i] == null) { helms[i] = ''; } else {
|
|
556
|
+
const chain = Chain.fromNotation(sequences[i], rules);
|
|
557
|
+
helms[i] = chain.getHelm();
|
|
558
|
+
}
|
|
559
|
+
} catch (err: any) {
|
|
560
|
+
const [errMsg, errStack] = errInfo(err);
|
|
561
|
+
_package.logger.error(errMsg, undefined, errStack);
|
|
562
|
+
helms[i] = '';
|
|
380
563
|
}
|
|
381
564
|
}
|
|
382
565
|
return helms;
|
|
383
566
|
}
|
|
567
|
+
|
|
568
|
+
function getMonomersMolBlocks(monomer1: Monomer, monomer2: Monomer): [string, string] {
|
|
569
|
+
const mb1 = monomer1.molfile;
|
|
570
|
+
let mb2 = monomer2.molfile;
|
|
571
|
+
const addGroups = monomer1.rgroups.length;
|
|
572
|
+
|
|
573
|
+
//mol v2000 monomer
|
|
574
|
+
const rgpIdx = mb2.indexOf('M RGP');
|
|
575
|
+
if (rgpIdx !== -1) {
|
|
576
|
+
const groupsCountStr = mb2.substring(rgpIdx + 6, rgpIdx + 9);
|
|
577
|
+
const groupsCount = Number(groupsCountStr);
|
|
578
|
+
|
|
579
|
+
for (let i = 0; i < groupsCount; i++) {
|
|
580
|
+
const start = rgpIdx + 9 + 4 + i * 8;
|
|
581
|
+
const end = rgpIdx + 9 + 8 + i * 8;
|
|
582
|
+
const rGroupSpecifier = mb2.substring(start, end);
|
|
583
|
+
const groupPosition = Number(rGroupSpecifier) + addGroups;
|
|
584
|
+
const digits = Math.floor(Math.log10(groupPosition) + 1);
|
|
585
|
+
const newSpecifier = ' '.repeat(4 - digits) + String(groupPosition);
|
|
586
|
+
mb2 = mb2.substring(0, start) + newSpecifier + mb2.substring(end, mb2.length);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
//TODO: same for v3000 monomer
|
|
591
|
+
|
|
592
|
+
return [mb1, mb2];
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
function getSyntheticMolBlock(rdkit: RDModule, reaction: string,
|
|
596
|
+
mb1: string, mb2: string, monomerName: string): string {
|
|
597
|
+
let rxn: RDReaction | null = null;
|
|
598
|
+
let mols: MolList | null = null;
|
|
599
|
+
let mol1: RDMol | null = null;
|
|
600
|
+
let mol2: RDMol | null = null;
|
|
601
|
+
let rctns: RDReactionResult | null = null;
|
|
602
|
+
let molP: RDMol | null = null;
|
|
603
|
+
let molBlock = '';
|
|
604
|
+
|
|
605
|
+
try {
|
|
606
|
+
rxn = rdkit.get_rxn(reaction);
|
|
607
|
+
if (!rxn) throw new InvalidReactionError(reaction);
|
|
608
|
+
mols = new rdkit.MolList();
|
|
609
|
+
mol1 = rdkit.get_mol(mb1!);
|
|
610
|
+
mol2 = rdkit.get_mol(mb2!);
|
|
611
|
+
mols.append(mol1!);
|
|
612
|
+
mols.append(mol2!);
|
|
613
|
+
|
|
614
|
+
rctns = rxn.run_reactants(mols, 1);
|
|
615
|
+
//const size = rctns.size();
|
|
616
|
+
const element = rctns.get(0);
|
|
617
|
+
|
|
618
|
+
molP = element.next();
|
|
619
|
+
molBlock = molP?.get_molblock();//molP?.get_v3Kmolblock();//
|
|
620
|
+
} catch (err: any) {
|
|
621
|
+
const [errMsg, _errStack] = errInfo(err);
|
|
622
|
+
grok.shell.error(`Can not assemble monomer '${monomerName}': ${errMsg}.`);
|
|
623
|
+
throw err;
|
|
624
|
+
} finally {
|
|
625
|
+
rxn?.delete();
|
|
626
|
+
mols?.delete();
|
|
627
|
+
mol1?.delete();
|
|
628
|
+
mol2?.delete();
|
|
629
|
+
rctns?.delete();
|
|
630
|
+
molP?.delete();
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
return molBlock;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
function getNewGroups(monomer1: Monomer, monomer2: Monomer): RGroup[] {
|
|
637
|
+
const groups = new Array<RGroup>(monomer1?.rgroups.length! + monomer2?.rgroups.length!);
|
|
638
|
+
const length1 = monomer1?.rgroups.length!;
|
|
639
|
+
const length2 = monomer2?.rgroups.length!;
|
|
640
|
+
|
|
641
|
+
for (let i = 0; i < length1; i++)
|
|
642
|
+
groups[i] = monomer1?.rgroups[i]!;
|
|
643
|
+
|
|
644
|
+
for (let i = 0; i < length2; i++) {
|
|
645
|
+
const rGroupSpecifier = monomer2?.rgroups[i]!.label.replace('R', '');
|
|
646
|
+
const groupPosition = Number(rGroupSpecifier) + length1;
|
|
647
|
+
const group: RGroup = {
|
|
648
|
+
//@ts-ignore
|
|
649
|
+
[HELM_RGROUP_FIELDS.CAP_GROUP_SMILES_UPPERCASE]: monomer2?.rgroups[i].capGroupSMILES.replace(rGroupSpecifier, String(groupPosition)),
|
|
650
|
+
[HELM_RGROUP_FIELDS.ALTERNATE_ID]: monomer2?.rgroups[i].alternateId.replace(rGroupSpecifier, String(groupPosition)),
|
|
651
|
+
[HELM_RGROUP_FIELDS.CAP_GROUP_NAME]: monomer2?.rgroups[i].capGroupName,
|
|
652
|
+
[HELM_RGROUP_FIELDS.LABEL]: monomer2?.rgroups[i].label.replace(rGroupSpecifier, String(groupPosition)),
|
|
653
|
+
};
|
|
654
|
+
|
|
655
|
+
groups[i + length1] = group;
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
return groups;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
export function getNewMonomer(rdkit: RDModule, mLib: IMonomerLib, rule: RuleReaction): [string, Monomer] {
|
|
662
|
+
const reacSmarts = rule.reaction;
|
|
663
|
+
const monomerName = rule.name;
|
|
664
|
+
|
|
665
|
+
const monomer1 = mLib.getMonomer('PEPTIDE', rule.firstMonomer);
|
|
666
|
+
if (!monomer1) throw new MonomerNotFoundError('PEPTIDE', rule.firstMonomer);
|
|
667
|
+
const monomer2 = mLib.getMonomer('PEPTIDE', rule.secondMonomer);
|
|
668
|
+
if (!monomer2) throw new MonomerNotFoundError('PEPTIDE', rule.secondMonomer);
|
|
669
|
+
|
|
670
|
+
const [mb1, mb2] = getMonomersMolBlocks(monomer1!, monomer2!);
|
|
671
|
+
const molBlock = getSyntheticMolBlock(rdkit, reacSmarts, mb1, mb2, monomerName);
|
|
672
|
+
const groups: RGroup[] = getNewGroups(monomer1!, monomer2!);
|
|
673
|
+
|
|
674
|
+
const resMonomer: Monomer = {
|
|
675
|
+
[REQ.SYMBOL]: monomerName,
|
|
676
|
+
[REQ.NAME]: monomerName,
|
|
677
|
+
[REQ.MOLFILE]: molBlock,
|
|
678
|
+
[REQ.AUTHOR]: '',
|
|
679
|
+
[REQ.ID]: 0,
|
|
680
|
+
[REQ.RGROUPS]: groups,
|
|
681
|
+
[REQ.SMILES]: '',
|
|
682
|
+
[REQ.POLYMER_TYPE]: 'PEPTIDE',
|
|
683
|
+
[REQ.MONOMER_TYPE]: 'Backbone',
|
|
684
|
+
[REQ.CREATE_DATE]: null,
|
|
685
|
+
|
|
686
|
+
// // @ts-ignore
|
|
687
|
+
// lib: {source: 'Reaction'},
|
|
688
|
+
};
|
|
689
|
+
|
|
690
|
+
resMonomer[OPT.META] = Object.assign(resMonomer[OPT.META] ?? {},
|
|
691
|
+
{'colors': {'default': {line: '#2083D5', text: '#2083D5', background: '#F2F2F5'}}});
|
|
692
|
+
|
|
693
|
+
return [monomerName, resMonomer];
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
export async function getOverriddenLibrary(rules: Rules): Promise<IMonomerLibBase> {
|
|
697
|
+
const monomerLibHelper = await getMonomerLibHelper();
|
|
698
|
+
const systemMonomerLib = monomerLibHelper.getMonomerLib();
|
|
699
|
+
|
|
700
|
+
const rdkit = await getRdKitModule();
|
|
701
|
+
const argLib: { [symbol: string]: Monomer } = {};
|
|
702
|
+
|
|
703
|
+
for (let i = 0; i < rules.reactionRules.length; i++) {
|
|
704
|
+
const [name, monomer] = getNewMonomer(rdkit, systemMonomerLib, rules.reactionRules[i]);
|
|
705
|
+
argLib[name] = monomer;
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
const overrideMonomerLibData: MonomerLibData = {[PolymerTypes.PEPTIDE]: argLib};
|
|
709
|
+
const overriddenMonomerLib = systemMonomerLib.override(overrideMonomerLibData,
|
|
710
|
+
'ST-PT-reactions.' + wu.repeat(1).map(() => Math.floor((Math.random() * 36)).toString(36)).take(4).toArray().join(''));
|
|
711
|
+
return overriddenMonomerLib;
|
|
712
|
+
}
|
|
@@ -9,10 +9,13 @@ 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 {
|
|
12
|
+
import {MmcrTemps} from '@datagrok-libraries/bio/src/utils/cell-renderer-consts';
|
|
13
|
+
import {buildMonomerHoverLink} from '@datagrok-libraries/bio/src/monomer-works/monomer-hover';
|
|
14
|
+
import {getRdKitModule} from '@datagrok-libraries/bio/src/chem/rdkit-module';
|
|
15
|
+
import {RDModule} from '@datagrok-libraries/chem-meta/src/rdkit-api';
|
|
13
16
|
|
|
14
|
-
import {getRules, RuleInputs, RULES_PATH, RULES_STORAGE_NAME} from './pt-rules';
|
|
15
|
-
import {doPolyToolConvert} from './pt-conversion';
|
|
17
|
+
import {getRules, RuleInputs, Rules, RULES_PATH, RULES_STORAGE_NAME} from './pt-rules';
|
|
18
|
+
import {doPolyToolConvert, getOverriddenLibrary} from './pt-conversion';
|
|
16
19
|
import {defaultErrorHandler} from '../utils/err-info';
|
|
17
20
|
import {getLibrariesList} from './utils';
|
|
18
21
|
import {getEnumerationChem, PT_CHEM_EXAMPLE} from './pt-enumeration-chem';
|
|
@@ -74,7 +77,7 @@ export async function getPolyToolConvertDialog(srcCol?: DG.Column): Promise<DG.D
|
|
|
74
77
|
table: srcColVal.dataFrame, value: srcColVal,
|
|
75
78
|
filter: (col: DG.Column) => {
|
|
76
79
|
if (col.semType !== DG.SEMTYPE.MACROMOLECULE) return false;
|
|
77
|
-
const sh =
|
|
80
|
+
const sh = _package.seqHelper.getSeqHandler(col);
|
|
78
81
|
return sh.notation === NOTATION.CUSTOM;
|
|
79
82
|
}
|
|
80
83
|
});
|
|
@@ -85,7 +88,7 @@ export async function getPolyToolConvertDialog(srcCol?: DG.Column): Promise<DG.D
|
|
|
85
88
|
const chiralityEngineInput = ui.input.bool(PT_UI_USE_CHIRALITY, {value: false});
|
|
86
89
|
let ruleFileList: string[];
|
|
87
90
|
const ruleInputs = new RuleInputs(RULES_PATH, RULES_STORAGE_NAME, '.json', {
|
|
88
|
-
onValueChanged: (value: string[]) => { ruleFileList = value;}
|
|
91
|
+
onValueChanged: (value: string[]) => { ruleFileList = value; }
|
|
89
92
|
});
|
|
90
93
|
const rulesHeader = ui.inlineText([PT_UI_RULES_USED]);
|
|
91
94
|
ui.tooltip.bind(rulesHeader, 'Add or specify rules to use');
|
|
@@ -256,34 +259,24 @@ export async function polyToolConvert(
|
|
|
256
259
|
if (generateHelm && table) table.columns.add(resHelmCol, true);
|
|
257
260
|
|
|
258
261
|
const seqHelper: ISeqHelper = await getSeqHelper();
|
|
259
|
-
const
|
|
262
|
+
const rdKitModule: RDModule = await getRdKitModule();
|
|
263
|
+
const lib = await getOverriddenLibrary(rules);
|
|
264
|
+
const resHelmColTemp = resHelmCol.temp;
|
|
265
|
+
resHelmColTemp[MmcrTemps.overriddenLibrary] = lib;
|
|
266
|
+
resHelmCol.temp = resHelmColTemp;
|
|
267
|
+
const toAtomicLevelRes =
|
|
268
|
+
await seqHelper.helmToAtomicLevel(resHelmCol, chiralityEngine, /* highlight */ generateHelm, lib);
|
|
260
269
|
const resMolCol = toAtomicLevelRes.molCol!;
|
|
261
270
|
|
|
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
|
-
|
|
281
271
|
resMolCol.name = getUnusedName(table, `molfile(${seqCol.name})`);
|
|
282
272
|
resMolCol.semType = DG.SEMTYPE.MOLECULE;
|
|
283
273
|
if (table) {
|
|
284
274
|
table.columns.add(resMolCol, true);
|
|
285
275
|
await grok.data.detectSemanticTypes(table);
|
|
286
276
|
}
|
|
277
|
+
|
|
278
|
+
buildMonomerHoverLink(resHelmCol, resMolCol, lib, seqHelper, rdKitModule);
|
|
279
|
+
|
|
287
280
|
return [resHelmCol, resMolCol];
|
|
288
281
|
} finally {
|
|
289
282
|
pi.close();
|
|
@@ -16,7 +16,6 @@ import {getSeqHelper, ISeqHelper} from '@datagrok-libraries/bio/src/utils/seq-he
|
|
|
16
16
|
import '@datagrok-libraries/bio/src/types/input';
|
|
17
17
|
import {errInfo} from '@datagrok-libraries/bio/src/utils/err-info';
|
|
18
18
|
import {InputColumnBase} from '@datagrok-libraries/bio/src/types/input';
|
|
19
|
-
import {SeqHandler} from '@datagrok-libraries/bio/src/utils/seq-handler';
|
|
20
19
|
|
|
21
20
|
import {
|
|
22
21
|
PolyToolEnumeratorParams, PolyToolEnumeratorType, PolyToolEnumeratorTypes
|
|
@@ -36,8 +35,9 @@ type PolyToolEnumerateInputs = {
|
|
|
36
35
|
placeholdersBreadth: PolyToolPlaceholdersBreadthInput;
|
|
37
36
|
enumeratorType: DG.ChoiceInput<PolyToolEnumeratorType>
|
|
38
37
|
trivialNameCol: InputColumnBase,
|
|
39
|
-
toAtomicLevel: DG.InputBase<boolean>;
|
|
40
38
|
keepOriginal: DG.InputBase<boolean>;
|
|
39
|
+
toAtomicLevel: DG.InputBase<boolean>;
|
|
40
|
+
toHarmonizedSequence: DG.InputBase<boolean>;
|
|
41
41
|
};
|
|
42
42
|
|
|
43
43
|
type PolyToolEnumerateHelmSerialized = {
|
|
@@ -46,8 +46,9 @@ type PolyToolEnumerateHelmSerialized = {
|
|
|
46
46
|
placeholdersBreadth: string;
|
|
47
47
|
enumeratorType: PolyToolEnumeratorType;
|
|
48
48
|
trivialNameCol: string;
|
|
49
|
-
toAtomicLevel: boolean;
|
|
50
49
|
keepOriginal: boolean;
|
|
50
|
+
toAtomicLevel: boolean;
|
|
51
|
+
toHarmonizedSequence: boolean;
|
|
51
52
|
};
|
|
52
53
|
|
|
53
54
|
export async function polyToolEnumerateHelmUI(cell?: DG.Cell): Promise<void> {
|
|
@@ -160,10 +161,12 @@ async function getPolyToolEnumerateDialog(
|
|
|
160
161
|
showRowHeader: false,
|
|
161
162
|
showCellTooltip: false,
|
|
162
163
|
}),
|
|
163
|
-
toAtomicLevel: ui.input.bool(
|
|
164
|
-
'To atomic level', {value: false}),
|
|
165
164
|
keepOriginal: ui.input.bool(
|
|
166
165
|
'Keep original', {value: false}),
|
|
166
|
+
toAtomicLevel: ui.input.bool(
|
|
167
|
+
'To atomic level', {value: false}),
|
|
168
|
+
toHarmonizedSequence: ui.input.bool(
|
|
169
|
+
'To harmonized sequence', {value: false}),
|
|
167
170
|
trivialNameCol: ui.input.column2(
|
|
168
171
|
'Trivial name', {
|
|
169
172
|
table: cell?.dataFrame,
|
|
@@ -184,6 +187,7 @@ async function getPolyToolEnumerateDialog(
|
|
|
184
187
|
}),
|
|
185
188
|
};
|
|
186
189
|
|
|
190
|
+
inputs.toHarmonizedSequence.root.style.display = 'none';
|
|
187
191
|
inputs.trivialNameCol.addOptions(trivialNameSampleDiv);
|
|
188
192
|
|
|
189
193
|
let placeholdersValidity: string | null = null;
|
|
@@ -363,8 +367,9 @@ async function getPolyToolEnumerateDialog(
|
|
|
363
367
|
let helmValue: string;
|
|
364
368
|
let table: DG.DataFrame | undefined = undefined;
|
|
365
369
|
if (cell && cell.rowIndex >= 0 && cell?.column.semType == DG.SEMTYPE.MACROMOLECULE) {
|
|
366
|
-
const sh =
|
|
367
|
-
|
|
370
|
+
const sh = _package.seqHelper.getSeqHandler(cell.column);
|
|
371
|
+
const helmSemValue = await sh.getHelm(cell.rowIndex);
|
|
372
|
+
helmValue = helmSemValue.value;
|
|
368
373
|
table = cell.dataFrame;
|
|
369
374
|
} else {
|
|
370
375
|
helmValue = PT_HELM_EXAMPLE;
|
|
@@ -414,8 +419,8 @@ async function getPolyToolEnumerateDialog(
|
|
|
414
419
|
.add(inputs.enumeratorType)
|
|
415
420
|
.add(inputs.placeholdersBreadth)
|
|
416
421
|
.add(inputs.trivialNameCol)
|
|
417
|
-
.add(inputs.toAtomicLevel
|
|
418
|
-
|
|
422
|
+
.add(ui.divH([inputs.keepOriginal.root, inputs.toAtomicLevel.root, inputs.toHarmonizedSequence.root],
|
|
423
|
+
{style: {width: '100%'}}))
|
|
419
424
|
.add(warningsTextDiv)
|
|
420
425
|
// .addButton('Enumerate', () => {
|
|
421
426
|
// execDialog()
|
|
@@ -433,8 +438,9 @@ async function getPolyToolEnumerateDialog(
|
|
|
433
438
|
enumeratorType: inputs.enumeratorType.value,
|
|
434
439
|
placeholdersBreadth: inputs.placeholdersBreadth.stringValue,
|
|
435
440
|
trivialNameCol: inputs.trivialNameCol.stringValue,
|
|
436
|
-
toAtomicLevel: inputs.toAtomicLevel.value,
|
|
437
441
|
keepOriginal: inputs.keepOriginal.value,
|
|
442
|
+
toAtomicLevel: inputs.toAtomicLevel.value,
|
|
443
|
+
toHarmonizedSequence: inputs.toHarmonizedSequence.value,
|
|
438
444
|
};
|
|
439
445
|
},
|
|
440
446
|
/* applyInput */ (x: PolyToolEnumerateHelmSerialized): void => {
|
|
@@ -443,8 +449,9 @@ async function getPolyToolEnumerateDialog(
|
|
|
443
449
|
inputs.enumeratorType.value = x.enumeratorType;
|
|
444
450
|
inputs.placeholdersBreadth.stringValue = x.placeholdersBreadth;
|
|
445
451
|
inputs.trivialNameCol.stringValue = x.trivialNameCol;
|
|
446
|
-
inputs.toAtomicLevel.value = x.toAtomicLevel;
|
|
447
452
|
inputs.keepOriginal.value = x.keepOriginal;
|
|
453
|
+
inputs.toAtomicLevel.value = x.toAtomicLevel;
|
|
454
|
+
inputs.toHarmonizedSequence.value = x.toHarmonizedSequence;
|
|
448
455
|
});
|
|
449
456
|
return dialog;
|
|
450
457
|
} catch (err: any) {
|
|
@@ -4,7 +4,8 @@ import * as DG from 'datagrok-api/dg';
|
|
|
4
4
|
|
|
5
5
|
import {
|
|
6
6
|
HelmType, HelmMol,
|
|
7
|
-
JSDraw2ModuleType, OrgType
|
|
7
|
+
JSDraw2ModuleType, OrgType,
|
|
8
|
+
IHelmEditorOptions
|
|
8
9
|
} from '@datagrok-libraries/bio/src/helm/types';
|
|
9
10
|
|
|
10
11
|
|
|
@@ -72,7 +73,7 @@ function getPtEnumeratorBreadth(m: HelmMol, placeholdersBreadth: PolyToolPlaceho
|
|
|
72
73
|
export function doPolyToolEnumerateHelm(
|
|
73
74
|
helm: string, id: string, params: PolyToolEnumeratorParams
|
|
74
75
|
): [ /* helm */ string, /* id */ string][] {
|
|
75
|
-
const molHandler = new JSDraw2.MolHandler<HelmType>();
|
|
76
|
+
const molHandler = new JSDraw2.MolHandler<HelmType, IHelmEditorOptions>();
|
|
76
77
|
const plugin = new org.helm.webeditor.Plugin(molHandler);
|
|
77
78
|
org.helm.webeditor.IO.parseHelm(plugin, helm, new JSDraw2.Point(0, 0), undefined);
|
|
78
79
|
const m = molHandler.m;
|
|
@@ -4,7 +4,6 @@ import * as DG from 'datagrok-api/dg';
|
|
|
4
4
|
|
|
5
5
|
import {Unsubscribable} from 'rxjs';
|
|
6
6
|
|
|
7
|
-
import {SeqHandler} from '@datagrok-libraries/bio/src/utils/seq-handler';
|
|
8
7
|
import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
9
8
|
import {getUnusedColName} from '@datagrok-libraries/bio/src/monomer-works/utils';
|
|
10
9
|
|
|
@@ -12,6 +11,7 @@ import {defaultErrorHandler} from '../utils/err-info';
|
|
|
12
11
|
import {doPolyToolUnrule} from './pt-unrule';
|
|
13
12
|
import {getRules, RuleInputs, RULES_PATH, RULES_STORAGE_NAME} from './pt-rules';
|
|
14
13
|
import {PT_ERROR_DATAFRAME, PT_UI_DIALOG_UNRULE, PT_UI_RULES_USED} from './const';
|
|
14
|
+
import {_package} from '../package';
|
|
15
15
|
|
|
16
16
|
type PolyToolUnruleSerialized = {
|
|
17
17
|
rules: string[];
|
|
@@ -34,7 +34,7 @@ export async function getPolyToolUnruleDialog(srcCol?: DG.Column<string>): Promi
|
|
|
34
34
|
table: srcColVal.dataFrame, value: srcColVal,
|
|
35
35
|
filter: (col: DG.Column) => {
|
|
36
36
|
if (col.semType !== DG.SEMTYPE.MACROMOLECULE) return false;
|
|
37
|
-
const sh =
|
|
37
|
+
const sh = _package.seqHelper.getSeqHandler(col);
|
|
38
38
|
return sh.notation === NOTATION.HELM;
|
|
39
39
|
}
|
|
40
40
|
});
|