@datagrok/sequence-translator 1.6.3 → 1.7.0
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 +16 -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/package.json +5 -5
- package/src/package.ts +9 -9
- package/src/polytool/const.ts +2 -0
- package/src/polytool/conversion/pt-atomic.ts +70 -0
- package/src/polytool/conversion/pt-chain.ts +22 -2
- package/src/polytool/conversion/pt-conversion.ts +7 -2
- package/src/polytool/conversion/pt-rule-cards.ts +160 -0
- package/src/polytool/conversion/pt-rules.ts +40 -1
- package/src/polytool/conversion/pt-tools-parse.ts +11 -21
- package/src/polytool/conversion/rule-manager.ts +74 -22
- package/src/polytool/conversion/style.css +32 -0
- package/src/polytool/pt-dialog.ts +38 -31
- package/src/polytool/pt-enumerate-seq-dialog.ts +134 -46
- package/src/polytool/pt-placeholders-breadth-input.ts +9 -0
- package/src/polytool/pt-placeholders-input.ts +18 -5
- package/src/polytool/types.ts +1 -0
- package/src/polytool/utils.ts +1 -1
- package/src/tests/polytool-convert-tests.ts +2 -2
- package/test-console-output-1.log +1662 -0
- package/test-record-1.mp4 +0 -0
- package/src/global.d.ts +0 -13
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
|
+
"version": "1.7.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Leonid Stolbov",
|
|
7
7
|
"email": "lstolbov@datagrok.ai"
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@datagrok-libraries/bio": "^5.46.0",
|
|
26
|
-
"@datagrok-libraries/chem-meta": "^1.2.
|
|
26
|
+
"@datagrok-libraries/chem-meta": "^1.2.8",
|
|
27
27
|
"@datagrok-libraries/tutorials": "^1.4.3",
|
|
28
28
|
"@datagrok-libraries/utils": "^4.3.7",
|
|
29
29
|
"@types/react": "^18.0.15",
|
|
@@ -41,9 +41,9 @@
|
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@datagrok-libraries/helm-web-editor": "^1.1.13",
|
|
43
43
|
"@datagrok-libraries/js-draw-lite": "^0.0.10",
|
|
44
|
-
"@datagrok/bio": "^2.
|
|
45
|
-
"@datagrok/helm": "^2.
|
|
46
|
-
"@datagrok/chem": "^1.
|
|
44
|
+
"@datagrok/bio": "^2.18.0",
|
|
45
|
+
"@datagrok/helm": "^2.7.0",
|
|
46
|
+
"@datagrok/chem": "^1.13.0",
|
|
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.ts
CHANGED
|
@@ -49,7 +49,7 @@ async function initSequenceTranslatorInt(): Promise<void> {
|
|
|
49
49
|
|
|
50
50
|
//name: Oligo Toolkit
|
|
51
51
|
//meta.icon: img/icons/toolkit.png
|
|
52
|
-
//meta.browsePath: Oligo
|
|
52
|
+
//meta.browsePath: Peptides | Oligo Toolkit
|
|
53
53
|
//tags: app
|
|
54
54
|
//output: view v
|
|
55
55
|
export async function oligoToolkitApp(): Promise<DG.ViewBase> {
|
|
@@ -64,7 +64,7 @@ export async function oligoToolkitApp(): Promise<DG.ViewBase> {
|
|
|
64
64
|
|
|
65
65
|
//name: Oligo Translator
|
|
66
66
|
//meta.icon: img/icons/translator.png
|
|
67
|
-
//meta.browsePath: Oligo
|
|
67
|
+
//meta.browsePath: Peptides | Oligo Toolkit
|
|
68
68
|
//tags: app
|
|
69
69
|
//output: view v
|
|
70
70
|
export async function oligoTranslatorApp(): Promise<DG.ViewBase> {
|
|
@@ -74,7 +74,7 @@ export async function oligoTranslatorApp(): Promise<DG.ViewBase> {
|
|
|
74
74
|
|
|
75
75
|
//name: Oligo Pattern
|
|
76
76
|
//meta.icon: img/icons/pattern.png
|
|
77
|
-
//meta.browsePath: Oligo
|
|
77
|
+
//meta.browsePath: Peptides | Oligo Toolkit
|
|
78
78
|
//tags: app
|
|
79
79
|
//output: view v
|
|
80
80
|
export async function oligoPatternApp(): Promise<DG.ViewBase> {
|
|
@@ -84,7 +84,7 @@ export async function oligoPatternApp(): Promise<DG.ViewBase> {
|
|
|
84
84
|
|
|
85
85
|
//name: Oligo Structure
|
|
86
86
|
//meta.icon: img/icons/structure.png
|
|
87
|
-
//meta.browsePath: Oligo
|
|
87
|
+
//meta.browsePath: Peptides | Oligo Toolkit
|
|
88
88
|
//tags: app
|
|
89
89
|
//output: view v
|
|
90
90
|
export async function oligoStructureApp(): Promise<DG.ViewBase> {
|
|
@@ -209,7 +209,7 @@ export async function getPolyToolConvertEditor(call: DG.FuncCall): Promise<DG.Co
|
|
|
209
209
|
export async function polyToolConvert2(table: DG.DataFrame,
|
|
210
210
|
seqCol: DG.Column, generateHelm: boolean, chiralityEngine: boolean, rules: string[]
|
|
211
211
|
): Promise<DG.Column<string>> {
|
|
212
|
-
const ptConvertRes = await polyToolConvert(seqCol, generateHelm, chiralityEngine, rules);
|
|
212
|
+
const ptConvertRes = await polyToolConvert(seqCol, generateHelm, false, chiralityEngine, false, rules);
|
|
213
213
|
return ptConvertRes[0];
|
|
214
214
|
}
|
|
215
215
|
|
|
@@ -273,17 +273,17 @@ export async function createMonomerLibraryForPolyTool(file: DG.FileInfo) {
|
|
|
273
273
|
// }
|
|
274
274
|
// }
|
|
275
275
|
|
|
276
|
-
//name:
|
|
276
|
+
//name: HELM Enumerator
|
|
277
277
|
//meta.icon: img/icons/structure.png
|
|
278
|
-
//meta.browsePath: PolyTool
|
|
278
|
+
//meta.browsePath: Peptides | PolyTool
|
|
279
279
|
//tags: app
|
|
280
280
|
export async function ptEnumeratorHelmApp(): Promise<void> {
|
|
281
281
|
await polyToolEnumerateHelmUI();
|
|
282
282
|
}
|
|
283
283
|
|
|
284
|
-
//name:
|
|
284
|
+
//name: Chem Enumerator
|
|
285
285
|
//meta.icon: img/icons/structure.png
|
|
286
|
-
//meta.browsePath: PolyTool
|
|
286
|
+
//meta.browsePath: Peptides | PolyTool
|
|
287
287
|
//tags: app
|
|
288
288
|
export async function ptEnumeratorChemApp(): Promise<void> {
|
|
289
289
|
polyToolEnumerateChemUI();
|
package/src/polytool/const.ts
CHANGED
|
@@ -32,6 +32,8 @@ export const PT_WARNING_COLUMN = 'No marcomolecule column chosen!';
|
|
|
32
32
|
|
|
33
33
|
export const PT_UI_GET_HELM = 'Get HELM';
|
|
34
34
|
export const PT_UI_ADD_HELM = 'Add HELM column';
|
|
35
|
+
export const PT_UI_LINEARIZE = 'Linearize';
|
|
36
|
+
export const PT_UI_LINEARIZE_TT = 'Make representation linear if possible';
|
|
35
37
|
export const PT_UI_USE_CHIRALITY = 'Chirality engine';
|
|
36
38
|
export const PT_UI_HIGHLIGHT_MONOMERS = 'Highlight monomers';
|
|
37
39
|
export const PT_UI_DIALOG_CONVERSION = 'Poly Tool Conversion';
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import * as DG from 'datagrok-api/dg';
|
|
2
|
+
import * as grok from 'datagrok-api/grok';
|
|
3
|
+
|
|
4
|
+
import {getMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
|
|
5
|
+
import {getSeqHelper, ISeqHelper} from '@datagrok-libraries/bio/src/utils/seq-helper';
|
|
6
|
+
import {_toAtomicLevel} from '@datagrok-libraries/bio/src/monomer-works/to-atomic-level';
|
|
7
|
+
import {ALPHABET, NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
8
|
+
import {IMonomerLibBase} from '@datagrok-libraries/bio/src/types';
|
|
9
|
+
import {RDModule} from '@datagrok-libraries/chem-meta/src/rdkit-api';
|
|
10
|
+
|
|
11
|
+
export function dealGroups(col: DG.Column<string>): void {
|
|
12
|
+
for (let i = 0; i < col.length; i++) {
|
|
13
|
+
col.set(i, col.get(i)!.replaceAll('undefined', 'H'));
|
|
14
|
+
col.set(i, col.get(i)!.replaceAll('Oh', 'O'));
|
|
15
|
+
col.set(i, col.get(i)!.replaceAll('0.000000 3', '0.000000 0'));
|
|
16
|
+
col.set(i, col.get(i)!.replaceAll('?', 'O'));
|
|
17
|
+
col.set(i, col.get(i)!.replaceAll('0 3\n', '0 0\n'));
|
|
18
|
+
col.set(i, col.get(i)!.replaceAll('RGROUPS=(1 1)', ''));
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export async function helmToMol(resHelmCol: DG.Column, resList: string[],
|
|
23
|
+
isLinear: boolean[], chiralityEngine: boolean, highlight: boolean, linearize: boolean,
|
|
24
|
+
lib: IMonomerLibBase, rdkit: RDModule, seqHelper: ISeqHelper) {
|
|
25
|
+
const getUnusedName = (df: DG.DataFrame | undefined, colName: string): string => {
|
|
26
|
+
if (!df) return colName;
|
|
27
|
+
return df.columns.getUnusedName(colName);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const toAtomicLevelRes =
|
|
31
|
+
await seqHelper.helmToAtomicLevel(resHelmCol, chiralityEngine, highlight, lib);
|
|
32
|
+
|
|
33
|
+
const resMolCol = toAtomicLevelRes.molCol!;
|
|
34
|
+
|
|
35
|
+
const allLinear = isLinear.filter((l) => l).length;
|
|
36
|
+
if (linearize && allLinear > 0) {
|
|
37
|
+
const lin = new Array<string>(allLinear);
|
|
38
|
+
let counter = 0;
|
|
39
|
+
for (let i = 0; i < isLinear.length; i++) {
|
|
40
|
+
if (isLinear[i]) {
|
|
41
|
+
lin[counter] = resList[i];
|
|
42
|
+
counter++;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const linCol = DG.Column.fromStrings('helm', lin);
|
|
47
|
+
linCol.semType = DG.SEMTYPE.MACROMOLECULE;
|
|
48
|
+
linCol.meta.units = NOTATION.HELM;
|
|
49
|
+
linCol.setTag(DG.TAGS.CELL_RENDERER, 'helm');
|
|
50
|
+
|
|
51
|
+
const monomerLibHelper = await getMonomerLibHelper();
|
|
52
|
+
const systemMonomerLib = monomerLibHelper.getMonomerLib();
|
|
53
|
+
try {
|
|
54
|
+
const linear = await _toAtomicLevel(DG.DataFrame.create(0), linCol, systemMonomerLib, seqHelper, rdkit);
|
|
55
|
+
counter = 0;
|
|
56
|
+
for (let i = 0; i < isLinear.length; i++) {
|
|
57
|
+
if (isLinear[i]) {
|
|
58
|
+
resMolCol.set(i, linear!.molCol!.get(counter));
|
|
59
|
+
counter++;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
} catch (e: any) {
|
|
63
|
+
grok.shell.warning('PolyTool was not able to linearize sequences');
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
dealGroups(resMolCol);
|
|
68
|
+
|
|
69
|
+
return resMolCol;
|
|
70
|
+
}
|
|
@@ -16,6 +16,7 @@ export class Chain {
|
|
|
16
16
|
linkagesUnderRules: Linkage[];
|
|
17
17
|
monomersUnderRules: string[][];
|
|
18
18
|
molUnderRules: HelmMol;
|
|
19
|
+
posToPosUnderRules: number[][] = [];
|
|
19
20
|
|
|
20
21
|
constructor(monomers: string[][], linkages: Linkage[], protected helmHelper: IHelmHelper) {
|
|
21
22
|
this.linkages = linkages;
|
|
@@ -52,9 +53,28 @@ export class Chain {
|
|
|
52
53
|
applyRules(rules: Rules): void {
|
|
53
54
|
const sequence = this.getNotation();
|
|
54
55
|
|
|
55
|
-
const [linkages, mainFragments] = handleDuplicated(sequence, rules);
|
|
56
|
+
const [linkages, mainFragments, isDuplicated] = handleDuplicated(sequence, rules);
|
|
56
57
|
const monomers = new Array<Array<string>>(mainFragments.length);
|
|
57
|
-
|
|
58
|
+
|
|
59
|
+
let counter = 0;
|
|
60
|
+
for (let i = 0; i < mainFragments.length; i++) {
|
|
61
|
+
monomers[i] = mainFragments[i].split('-');
|
|
62
|
+
if (!isDuplicated[i]) {
|
|
63
|
+
for (let j = 0; j < monomers[i].length; j++) {
|
|
64
|
+
this.posToPosUnderRules.push([counter]);
|
|
65
|
+
counter++;
|
|
66
|
+
}
|
|
67
|
+
} else {
|
|
68
|
+
const start = this.posToPosUnderRules.length - monomers[i].length;
|
|
69
|
+
for (let j = 0; j < monomers[i].length; j++) {
|
|
70
|
+
this.posToPosUnderRules[start + j].push(counter);
|
|
71
|
+
counter++;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
//his.posToPosUnderRules
|
|
77
|
+
handleLinkRules(monomers, linkages, rules);
|
|
58
78
|
handleReactionRules(monomers, linkages, rules);
|
|
59
79
|
|
|
60
80
|
this.underRules = true;
|
|
@@ -6,14 +6,19 @@ import {Chain} from './pt-chain';
|
|
|
6
6
|
import {_package} from '../../package';
|
|
7
7
|
|
|
8
8
|
/** The main PolyTool convert engine. Returns list of Helms. Covered with tests. */
|
|
9
|
-
export function doPolyToolConvert(sequences: string[], rules: Rules, helmHelper: IHelmHelper):
|
|
9
|
+
export function doPolyToolConvert(sequences: string[], rules: Rules, helmHelper: IHelmHelper):
|
|
10
|
+
[string[], boolean[], number[][][]] {
|
|
10
11
|
const helms = new Array<string>(sequences.length);
|
|
12
|
+
const isLinear = new Array<boolean>(sequences.length);
|
|
13
|
+
const positionMaps = new Array<number[][]>(sequences.length);
|
|
11
14
|
for (let i = 0; i < sequences.length; i++) {
|
|
12
15
|
try {
|
|
13
16
|
if (sequences[i] == null) { helms[i] = ''; } else {
|
|
14
17
|
const chain = Chain.fromSeparator(sequences[i], helmHelper);
|
|
15
18
|
chain.applyRules(rules);
|
|
19
|
+
isLinear[i] = chain.monomersUnderRules.length > 1 || chain.linkagesUnderRules.length > 0 ? false : true;
|
|
16
20
|
helms[i] = chain.getHelm();
|
|
21
|
+
positionMaps[i] = chain.posToPosUnderRules;
|
|
17
22
|
}
|
|
18
23
|
} catch (err: any) {
|
|
19
24
|
const [errMsg, errStack] = errInfo(err);
|
|
@@ -21,5 +26,5 @@ export function doPolyToolConvert(sequences: string[], rules: Rules, helmHelper:
|
|
|
21
26
|
helms[i] = '';
|
|
22
27
|
}
|
|
23
28
|
}
|
|
24
|
-
return helms;
|
|
29
|
+
return [helms, isLinear, positionMaps];
|
|
25
30
|
}
|
|
@@ -0,0 +1,160 @@
|
|
|
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
|
+
import './style.css';
|
|
5
|
+
|
|
6
|
+
import {IMonomerLib, Monomer} from '@datagrok-libraries/bio/src/types';
|
|
7
|
+
import {Rules} from './pt-rules';
|
|
8
|
+
import {getHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
|
|
9
|
+
import {doPolyToolConvert} from './pt-conversion';
|
|
10
|
+
import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
11
|
+
import {getRdKitModule} from '@datagrok-libraries/bio/src/chem/rdkit-module';
|
|
12
|
+
import {getSeqHelper, ISeqHelper} from '@datagrok-libraries/bio/src/utils/seq-helper';
|
|
13
|
+
import {RDModule} from '@datagrok-libraries/chem-meta/src/rdkit-api';
|
|
14
|
+
import {getOverriddenLibrary} from './pt-synthetic';
|
|
15
|
+
import {helmToMol} from './pt-atomic';
|
|
16
|
+
|
|
17
|
+
class MonomerCard {
|
|
18
|
+
root: HTMLElement = ui.divV([], {classes: 'monomer-card-rule-root'});
|
|
19
|
+
|
|
20
|
+
private _selected: boolean = false;
|
|
21
|
+
get selected(): boolean { return this._selected; }
|
|
22
|
+
set selected(value: boolean) {
|
|
23
|
+
this._selected = value;
|
|
24
|
+
this.root.style.border = value ? '2px solid var(--green-2)' : '2px solid var(--grey-2)';
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
constructor(public monomer: Monomer | null) {}
|
|
28
|
+
|
|
29
|
+
render() {
|
|
30
|
+
if (this.monomer) {
|
|
31
|
+
ui.empty(this.root);
|
|
32
|
+
const monomerMolSvg = this.monomer.smiles && grok.chem.checkSmiles(this.monomer.smiles) ?
|
|
33
|
+
grok.chem.drawMolecule(this.monomer.smiles, 150, 120) :
|
|
34
|
+
grok.chem.drawMolecule(this.monomer.molfile ?? '', 150, 120);
|
|
35
|
+
this.root.appendChild(monomerMolSvg);
|
|
36
|
+
const monomerName =
|
|
37
|
+
ui.divH([ui.divText('Monomer Name: '), ui.divText(this.monomer.name)], {classes: 'monomer-card-info-rules'});
|
|
38
|
+
|
|
39
|
+
this.root.appendChild(monomerName);
|
|
40
|
+
ui.tooltip.bind(monomerName, this.monomer.name);
|
|
41
|
+
if (this.monomer.lib?.source) {
|
|
42
|
+
const monomerSource =
|
|
43
|
+
ui.divH([ui.divText('Source: '), ui.divText(this.monomer.lib.source)], {classes: 'monomer-card-info-rules'});
|
|
44
|
+
this.root.appendChild(monomerSource);
|
|
45
|
+
ui.tooltip.bind(monomerSource, this.monomer.lib.source);
|
|
46
|
+
}
|
|
47
|
+
const monomerType = ui.divH([
|
|
48
|
+
ui.divText('Polymer Type: '),
|
|
49
|
+
ui.divText(this.monomer.polymerType)
|
|
50
|
+
], {classes: 'monomer-card-info-rules'});
|
|
51
|
+
this.root.appendChild(monomerType);
|
|
52
|
+
ui.tooltip.bind(monomerType, this.monomer.polymerType);
|
|
53
|
+
|
|
54
|
+
ui.tooltip.bind(this.root, 'Select Monomer');
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export class RuleCards {
|
|
60
|
+
root: HTMLElement = ui.divH([],
|
|
61
|
+
{style: {
|
|
62
|
+
alignItems: 'center',
|
|
63
|
+
width: '100%',
|
|
64
|
+
overflow: 'hidden',
|
|
65
|
+
visibility: 'visible',
|
|
66
|
+
}, classes: 'monomer-cards'}
|
|
67
|
+
);
|
|
68
|
+
cardsFirst: MonomerCard[];
|
|
69
|
+
cardsSecond: MonomerCard[];
|
|
70
|
+
firstCard: MonomerCard;
|
|
71
|
+
secondCard: MonomerCard;
|
|
72
|
+
resulting: HTMLElement;
|
|
73
|
+
actionable: boolean;
|
|
74
|
+
|
|
75
|
+
constructor(public firstMonomers: string[], public secondMonomers: string[],
|
|
76
|
+
lib: IMonomerLib, public code: number, public rules: Rules) {
|
|
77
|
+
if (firstMonomers.length > 0) {
|
|
78
|
+
this.actionable = true;
|
|
79
|
+
const monomerGalleryFirst = ui.divH([], {style: {overflowX: 'auto', width: '100%'}});
|
|
80
|
+
const monomerGallerySecond = ui.divH([], {style: {overflowX: 'auto', width: '100%'}});
|
|
81
|
+
this.resulting = ui.divH([], {style: {overflowX: 'auto', width: '100%', minHeight: '150px'}});
|
|
82
|
+
const galleries = ui.divV([monomerGalleryFirst, monomerGallerySecond, this.resulting]);
|
|
83
|
+
this.cardsFirst = firstMonomers.map((symbol) => new MonomerCard(lib.getMonomer('PEPTIDE', symbol)));
|
|
84
|
+
this.cardsSecond = secondMonomers.map((symbol) => new MonomerCard(lib.getMonomer('PEPTIDE', symbol)));
|
|
85
|
+
|
|
86
|
+
this.cardsFirst.forEach((card) => {
|
|
87
|
+
card.root.onclick = () => {
|
|
88
|
+
this.cardsFirst.forEach((c) => c.selected = false);
|
|
89
|
+
card.selected = true;
|
|
90
|
+
this.firstCard = card;
|
|
91
|
+
this.reset();
|
|
92
|
+
//onMonomerSelected(card.monomer);
|
|
93
|
+
};
|
|
94
|
+
monomerGalleryFirst.appendChild(card.root);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
this.cardsSecond.forEach((card) => {
|
|
98
|
+
card.root.onclick = () => {
|
|
99
|
+
this.cardsSecond.forEach((c) => c.selected = false);
|
|
100
|
+
card.selected = true;
|
|
101
|
+
this.secondCard = card;
|
|
102
|
+
this.reset();
|
|
103
|
+
//onMonomerSelected(card.monomer);
|
|
104
|
+
};
|
|
105
|
+
monomerGallerySecond.appendChild(card.root);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
this.cardsFirst[0].selected = true;
|
|
109
|
+
this.cardsSecond[0].selected = true;
|
|
110
|
+
this.firstCard = this.cardsFirst[0];
|
|
111
|
+
this.secondCard = this.cardsSecond[0];
|
|
112
|
+
this.root.appendChild(galleries);
|
|
113
|
+
} else {
|
|
114
|
+
const es = ui.divV(['Rule is active for all monomers, no examples to show']);
|
|
115
|
+
this.root.appendChild(es);
|
|
116
|
+
this.actionable = false;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async reset() {
|
|
121
|
+
if (this.actionable) {
|
|
122
|
+
const seqs: string[] = [
|
|
123
|
+
`${this.firstCard.monomer?.symbol}(${this.code})-A-A-A-A-${this.secondCard.monomer?.symbol}(${this.code})`
|
|
124
|
+
];
|
|
125
|
+
|
|
126
|
+
const helmHelper = await getHelmHelper();
|
|
127
|
+
const [helms, isLinear, positionMaps] = doPolyToolConvert(seqs, this.rules, helmHelper);
|
|
128
|
+
|
|
129
|
+
const resHelmCol = DG.Column.fromType(DG.COLUMN_TYPE.STRING, 'helm', helms.length)
|
|
130
|
+
.init((rowIdx: number) => { return helms[rowIdx]; });
|
|
131
|
+
resHelmCol.semType = DG.SEMTYPE.MACROMOLECULE;
|
|
132
|
+
resHelmCol.meta.units = NOTATION.HELM;
|
|
133
|
+
resHelmCol.setTag(DG.TAGS.CELL_RENDERER, 'helm');
|
|
134
|
+
|
|
135
|
+
const rdKitModule: RDModule = await getRdKitModule();
|
|
136
|
+
const seqHelper: ISeqHelper = await getSeqHelper();
|
|
137
|
+
|
|
138
|
+
const lib = await getOverriddenLibrary(this.rules);
|
|
139
|
+
const resHelmColTemp = resHelmCol.temp;
|
|
140
|
+
resHelmCol.temp = resHelmColTemp;
|
|
141
|
+
const resMolCol = await helmToMol(resHelmCol, helms,
|
|
142
|
+
isLinear, true, false, false, lib, rdKitModule, seqHelper);
|
|
143
|
+
|
|
144
|
+
const mol = resMolCol.get(0);
|
|
145
|
+
const monomerMolSvg = mol && grok.chem.checkSmiles(mol) ?
|
|
146
|
+
grok.chem.drawMolecule(mol, 150, 120) :
|
|
147
|
+
grok.chem.drawMolecule(mol ?? '', 150, 120);
|
|
148
|
+
|
|
149
|
+
ui.empty(this.resulting);
|
|
150
|
+
this.resulting.append(ui.divH([monomerMolSvg], {style: {overflowX: 'auto', width: '100%', minHeight: '150px'}}));
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
render() {
|
|
155
|
+
if (this.actionable) {
|
|
156
|
+
this.cardsFirst.forEach((card) => card.render());
|
|
157
|
+
this.cardsSecond.forEach((card) => card.render());
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import * as DG from 'datagrok-api/dg';
|
|
2
2
|
import * as grok from 'datagrok-api/grok';
|
|
3
|
+
import * as ui from 'datagrok-api/ui';
|
|
3
4
|
import {ActiveFiles} from '@datagrok-libraries/utils/src/settings/active-files-base';
|
|
4
5
|
import {RulesManager} from './rule-manager';
|
|
6
|
+
import {RuleCards} from './pt-rule-cards';
|
|
7
|
+
import {getMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
|
|
8
|
+
import {applyNotationProviderForCyclized} from '../../package';
|
|
5
9
|
|
|
6
10
|
export const RULES_PATH = 'System:AppData/SequenceTranslator/polytool-rules/';
|
|
7
11
|
export const RULES_STORAGE_NAME = 'Polytool';
|
|
@@ -93,10 +97,22 @@ export class Rules {
|
|
|
93
97
|
getLinkRulesDf(): DG.DataFrame {
|
|
94
98
|
const length = this.linkRules.length;
|
|
95
99
|
const codeCol = DG.Column.int(NAME_CODE, length);
|
|
100
|
+
codeCol.setTag('friendlyName', 'Code');
|
|
101
|
+
//ui.tooltip.bind(codeCol.root, 'Click to zoom');
|
|
96
102
|
const firstMonomerCol = DG.Column.string(NAME_FIRST_MONOMERS, length);
|
|
103
|
+
firstMonomerCol.setTag('friendlyName', 'First monomers');
|
|
104
|
+
firstMonomerCol.semType = DG.SEMTYPE.MACROMOLECULE;
|
|
105
|
+
applyNotationProviderForCyclized(firstMonomerCol, ',');
|
|
106
|
+
|
|
97
107
|
const secondMonomerCol = DG.Column.string(NAME_SECOND_MONOMERS, length);
|
|
108
|
+
secondMonomerCol.setTag('friendlyName', 'Second monomers');
|
|
109
|
+
secondMonomerCol.semType = DG.SEMTYPE.MACROMOLECULE;
|
|
110
|
+
applyNotationProviderForCyclized(secondMonomerCol, ',');
|
|
111
|
+
|
|
98
112
|
const firstLinkingGroup = DG.Column.int(NAME_FIRST_LINK, length);
|
|
113
|
+
firstLinkingGroup.setTag('friendlyName', 'First group');
|
|
99
114
|
const secondLinkingGroup = DG.Column.int(NAME_SECOND_LINK, length);
|
|
115
|
+
secondLinkingGroup.setTag('friendlyName', 'Second group');
|
|
100
116
|
|
|
101
117
|
for (let i = 0; i < length; i++) {
|
|
102
118
|
codeCol.set(i, this.linkRules[i].code);
|
|
@@ -106,20 +122,43 @@ export class Rules {
|
|
|
106
122
|
secondLinkingGroup.set(i, this.linkRules[i].secondLinkingGroup);
|
|
107
123
|
}
|
|
108
124
|
|
|
109
|
-
|
|
125
|
+
const res = DG.DataFrame.fromColumns([
|
|
110
126
|
codeCol, firstMonomerCol, secondMonomerCol, firstLinkingGroup, secondLinkingGroup
|
|
111
127
|
]);
|
|
128
|
+
|
|
129
|
+
return res;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async getLinkCards(): Promise<RuleCards[]> {
|
|
133
|
+
const length = this.linkRules.length;
|
|
134
|
+
const cards: RuleCards[] = new Array<RuleCards>(length);
|
|
135
|
+
const monomerLibHelper = await getMonomerLibHelper();
|
|
136
|
+
const systemMonomerLib = monomerLibHelper.getMonomerLib();
|
|
137
|
+
|
|
138
|
+
for (let i = 0; i < length; i++) {
|
|
139
|
+
cards[i] = new RuleCards(this.linkRules[i].firstMonomers, this.linkRules[i].secondMonomers,
|
|
140
|
+
systemMonomerLib, this.linkRules[i].code, this);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return cards;
|
|
112
144
|
}
|
|
113
145
|
|
|
114
146
|
getSynthesisRulesDf(): DG.DataFrame {
|
|
115
147
|
const length = this.reactionRules.length;
|
|
116
148
|
const codeCol = DG.Column.int(NAME_CODE, length);
|
|
149
|
+
codeCol.setTag('friendlyName', 'Code');
|
|
117
150
|
const firstMonomerCol = DG.Column.string(NAME_FIRST_MONOMERS, length);
|
|
151
|
+
firstMonomerCol.setTag('friendlyName', 'First monomers');
|
|
118
152
|
const secondMonomerCol = DG.Column.string(NAME_SECOND_MONOMERS, length);
|
|
153
|
+
secondMonomerCol.setTag('friendlyName', 'Second monomers');
|
|
119
154
|
const name = DG.Column.string(NAME_REACTION_NAME, length);
|
|
155
|
+
name.setTag('friendlyName', 'Name');
|
|
120
156
|
const firstReactant = DG.Column.string('firstReactant', length);
|
|
157
|
+
firstReactant.setTag('friendlyName', 'First reactant');
|
|
121
158
|
const secondReactant = DG.Column.string('secondReactant', length);
|
|
159
|
+
secondReactant.setTag('friendlyName', 'Second reactant');
|
|
122
160
|
const product = DG.Column.string('product', length);
|
|
161
|
+
product.setTag('friendlyName', 'Product');
|
|
123
162
|
|
|
124
163
|
for (let i = 0; i < length; i++) {
|
|
125
164
|
codeCol.set(i, this.reactionRules[i].code);
|
|
@@ -121,9 +121,10 @@ export function fromObjectsToHelm(linkages: Linkage[], monomers: string[][]): st
|
|
|
121
121
|
return helm;
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
-
//homo and hetero dimers
|
|
125
|
-
export function handleDuplicated(sequence: string, rules: Rules): [Linkage[], string[]] {
|
|
124
|
+
//homo and hetero dimers/ also fills map from initial positions to positions arrays
|
|
125
|
+
export function handleDuplicated(sequence: string, rules: Rules): [Linkage[], string[], boolean[]] {
|
|
126
126
|
const mainFragments: string[] = [];
|
|
127
|
+
const isDuplicated: boolean[] = [];
|
|
127
128
|
const linkages: Linkage[] = [];
|
|
128
129
|
const heterodimerCode = rules.heterodimerCode;
|
|
129
130
|
const homodimerCode = rules.homodimerCode;
|
|
@@ -134,8 +135,11 @@ export function handleDuplicated(sequence: string, rules: Rules): [Linkage[], st
|
|
|
134
135
|
linkages.push({fChain: 0, sChain: 1, fMonomer: 1, sMonomer: 1, fR: 1, sR: 1});
|
|
135
136
|
mainFragments.push(heterodimeric[1].replaceAll('{', '').replaceAll('}', ''));
|
|
136
137
|
mainFragments.push(heterodimeric[2].replaceAll('{', '').replaceAll('}', ''));
|
|
138
|
+
isDuplicated.push(false);
|
|
139
|
+
isDuplicated.push(false);
|
|
137
140
|
} else {
|
|
138
141
|
mainFragments.push(sequence);
|
|
142
|
+
isDuplicated.push(false);
|
|
139
143
|
}
|
|
140
144
|
|
|
141
145
|
//NOTICE: this works only with simple single dimers
|
|
@@ -151,30 +155,16 @@ export function handleDuplicated(sequence: string, rules: Rules): [Linkage[], st
|
|
|
151
155
|
|
|
152
156
|
mainFragments[i] = linker + body;
|
|
153
157
|
mainFragments.push(body);
|
|
158
|
+
isDuplicated.push(true);
|
|
154
159
|
}
|
|
155
160
|
}
|
|
156
161
|
|
|
157
|
-
|
|
158
|
-
if (homodimerCode !== null && mainFragments[i].includes(`(${homodimerCode!})`)) {
|
|
159
|
-
const idxSequence = mainFragments.length;
|
|
160
|
-
|
|
161
|
-
linkages.push({fChain: i, sChain: idxSequence, fMonomer: 1, sMonomer: 1, fR: 1, sR: 1});
|
|
162
|
-
const rawDimer = mainFragments[i].replace(`(${homodimerCode!})`, '');
|
|
163
|
-
const idx = rawDimer.indexOf('{');
|
|
164
|
-
const linker = rawDimer.slice(0, idx);
|
|
165
|
-
const body = rawDimer.replace(linker, '').replaceAll('{', '').replaceAll('}', '');
|
|
166
|
-
|
|
167
|
-
mainFragments[i] = linker + body;
|
|
168
|
-
mainFragments.push(body);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
return [linkages, mainFragments];
|
|
162
|
+
return [linkages, mainFragments, isDuplicated];
|
|
173
163
|
}
|
|
174
164
|
|
|
175
|
-
export function handleLinkRules(
|
|
176
|
-
for (let i = 0; i <
|
|
177
|
-
const rawMonomers =
|
|
165
|
+
export function handleLinkRules(monomers: string[][], linkages: Linkage[], rules: Rules): void {
|
|
166
|
+
for (let i = 0; i < monomers.length; i++) {
|
|
167
|
+
const rawMonomers = monomers[i];
|
|
178
168
|
const linkedPositions = getLinkedPositions(rawMonomers, rules.linkRules);
|
|
179
169
|
const [allPos1, allPos2, allAttaches1, allAttaches2] =
|
|
180
170
|
getAllCycles(rules.linkRules, rawMonomers, linkedPositions);
|