@datagrok/bio 2.11.33 → 2.11.35
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 +12 -0
- package/dist/package-test.js +3 -3
- package/dist/package-test.js.map +1 -1
- package/dist/package.js +6 -6
- package/dist/package.js.map +1 -1
- package/package.json +3 -3
- package/src/package.ts +12 -0
- package/src/tests/monomer-libraries-tests.ts +8 -4
- package/src/utils/monomer-lib/lib-manager.ts +8 -3
- package/src/utils/monomer-lib/library-file-manager/custom-monomer-lib-handlers.ts +0 -39
- package/src/utils/monomer-lib/library-file-manager/event-manager.ts +13 -1
- package/src/utils/monomer-lib/library-file-manager/file-manager.ts +18 -9
- package/src/utils/monomer-lib/library-file-manager/file-validator.ts +1 -1
- package/src/utils/monomer-lib/library-file-manager/ui.ts +6 -1
- package/src/utils/poly-tool/csv-to-json-monomer-lib-converter.ts +40 -0
- package/src/utils/poly-tool/transformation.ts +175 -121
- package/src/utils/poly-tool/ui.ts +41 -84
- package/src/utils/poly-tool/utils.ts +7 -7
- package/src/widgets/bio-substructure-filter-helm.ts +1 -1
- package/src/utils/poly-tool/types.ts +0 -20
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"name": "Leonid Stolbov",
|
|
6
6
|
"email": "lstolbov@datagrok.ai"
|
|
7
7
|
},
|
|
8
|
-
"version": "2.11.
|
|
8
|
+
"version": "2.11.35",
|
|
9
9
|
"description": "Bioinformatics support (import/export of sequences, conversion, visualization, analysis). [See more](https://github.com/datagrok-ai/public/blob/master/packages/Bio/README.md) for details.",
|
|
10
10
|
"repository": {
|
|
11
11
|
"type": "git",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
],
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@biowasm/aioli": "^3.1.0",
|
|
37
|
-
"@datagrok-libraries/bio": "
|
|
37
|
+
"@datagrok-libraries/bio": "5.39.26",
|
|
38
38
|
"@datagrok-libraries/chem-meta": "^1.2.1",
|
|
39
39
|
"@datagrok-libraries/ml": "^6.4.10",
|
|
40
40
|
"@datagrok-libraries/tutorials": "^1.3.11",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"@datagrok-libraries/math": "^1.0.7",
|
|
45
45
|
"cash-dom": "^8.0.0",
|
|
46
46
|
"css-loader": "^6.7.3",
|
|
47
|
-
"datagrok-api": "^1.17.
|
|
47
|
+
"datagrok-api": "^1.17.4",
|
|
48
48
|
"dayjs": "^1.11.4",
|
|
49
49
|
"fastest-levenshtein": "^1.0.16",
|
|
50
50
|
"openchemlib": "6.0.1",
|
package/src/package.ts
CHANGED
|
@@ -60,6 +60,7 @@ import {getCompositionAnalysisWidget} from './widgets/composition-analysis-widge
|
|
|
60
60
|
import {MacromoleculeColumnWidget} from './utils/macromolecule-column-widget';
|
|
61
61
|
import {addCopyMenuUI} from './utils/context-menu';
|
|
62
62
|
import {getPolyToolDialog} from './utils/poly-tool/ui';
|
|
63
|
+
import {PolyToolCsvLibHandler} from './utils/poly-tool/csv-to-json-monomer-lib-converter';
|
|
63
64
|
import {_setPeptideColumn} from './utils/poly-tool/utils';
|
|
64
65
|
import {getRegionDo} from './utils/get-region';
|
|
65
66
|
import {GetRegionApp} from './apps/get-region-app';
|
|
@@ -1018,6 +1019,17 @@ export async function polyToolColumnChoice(df: DG.DataFrame, macroMolecule: DG.C
|
|
|
1018
1019
|
await grok.data.detectSemanticTypes(df);
|
|
1019
1020
|
}
|
|
1020
1021
|
|
|
1022
|
+
//name: createMonomerLibraryForPolyTool
|
|
1023
|
+
//input: file file
|
|
1024
|
+
export async function createMonomerLibraryForPolyTool(file: DG.FileInfo) {
|
|
1025
|
+
const fileContent = await file.readAsString();
|
|
1026
|
+
const libHandler = new PolyToolCsvLibHandler(file.fileName, fileContent);
|
|
1027
|
+
const libObject = await libHandler.getJson();
|
|
1028
|
+
const jsonFileName = file.fileName.replace(/\.csv$/, '.json');
|
|
1029
|
+
const jsonFileContent = JSON.stringify(libObject, null, 2);
|
|
1030
|
+
DG.Utils.download(jsonFileName, jsonFileContent);
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1021
1033
|
//name: SDF to JSON Library
|
|
1022
1034
|
//input: dataframe table
|
|
1023
1035
|
export async function sdfToJsonLib(table: DG.DataFrame) {
|
|
@@ -53,14 +53,18 @@ category('monomerLibraries', () => {
|
|
|
53
53
|
const libSettings = await getUserLibSettings();
|
|
54
54
|
const libFileEventManager = MonomerLibFileEventManager.getInstance();
|
|
55
55
|
const libFileManager = await MonomerLibFileManager.getInstance(libFileEventManager);
|
|
56
|
-
|
|
56
|
+
|
|
57
|
+
let libFnList = libFileManager.getValidLibraryPaths();
|
|
58
|
+
if (libFnList.length === 0)
|
|
59
|
+
libFnList = await libFileManager.getValidLibraryPathsAsynchronously();
|
|
60
|
+
|
|
57
61
|
libSettings.exclude = libFnList;
|
|
58
62
|
libSettings.explicit = [];
|
|
59
63
|
await setUserLibSettings(libSettings);
|
|
60
64
|
|
|
61
65
|
await monomerLibHelper.loadLibraries(true);
|
|
62
66
|
const currentMonomerLib = monomerLibHelper.getBioLib();
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
67
|
+
const polymerTypes = currentMonomerLib.getPolymerTypes();
|
|
68
|
+
expect(polymerTypes.length === 0, true);
|
|
69
|
+
});
|
|
66
70
|
});
|
|
@@ -56,9 +56,14 @@ export class MonomerLibManager implements IMonomerLibHelper {
|
|
|
56
56
|
getLibFileNameList(),
|
|
57
57
|
getUserLibSettings(),
|
|
58
58
|
]);
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
|
|
60
|
+
const filteredLibFnList = libFileNameList.filter((libFileName) => {
|
|
61
|
+
const isFileIncluded = !settings.exclude.includes(libFileName);
|
|
62
|
+
const isExplicit = settings.explicit.length === 0 || settings.explicit.includes(libFileName);
|
|
63
|
+
|
|
64
|
+
return isFileIncluded && isExplicit;
|
|
65
|
+
});
|
|
66
|
+
|
|
62
67
|
const libs: IMonomerLib[] = await Promise.all(filteredLibFnList
|
|
63
68
|
.map((libFileName) => {
|
|
64
69
|
//TODO handle whether files are in place
|
|
@@ -4,7 +4,6 @@ import * as ui from 'datagrok-api/ui';
|
|
|
4
4
|
import * as DG from 'datagrok-api/dg';
|
|
5
5
|
|
|
6
6
|
import {createJsonMonomerLibFromSdf} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
|
|
7
|
-
import {PolyToolMonomerLibHandler} from '../../poly-tool/monomer-lib-handler';
|
|
8
7
|
|
|
9
8
|
interface CustomMonomerLibHandler {
|
|
10
9
|
getHelmLibContent(): Promise<string>;
|
|
@@ -40,41 +39,3 @@ export class SdfMonomerLibHandler implements CustomMonomerLibHandler {
|
|
|
40
39
|
throw new Error(`File ${this.fileName} is not an SDF file`);
|
|
41
40
|
}
|
|
42
41
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
/** Handler of custom monomer libs for PolyTool */
|
|
46
|
-
export class PolyToolCsvLibHandler implements CustomMonomerLibHandler {
|
|
47
|
-
constructor(private fileName: string, private fileContent: string) {
|
|
48
|
-
this.validateFileType();
|
|
49
|
-
const df = DG.DataFrame.fromCsv(this.fileContent);
|
|
50
|
-
const json = this.toJson(df);
|
|
51
|
-
this.polyToolMonomerLib = new PolyToolMonomerLibHandler(json);
|
|
52
|
-
this.validateContent();
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
private polyToolMonomerLib: PolyToolMonomerLibHandler;
|
|
56
|
-
|
|
57
|
-
async getHelmLibContent(): Promise<string> {
|
|
58
|
-
const rawLibData = this.polyToolMonomerLib.getJsonMonomerLib();
|
|
59
|
-
return JSON.stringify(rawLibData);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
private toJson(df: DG.DataFrame): any[] {
|
|
63
|
-
return Array.from({length: df.rowCount}, (_, idx) =>
|
|
64
|
-
df.columns.names().reduce((entry: { [key: string]: any }, colName) => {
|
|
65
|
-
entry[colName] = df.get(colName, idx);
|
|
66
|
-
return entry;
|
|
67
|
-
}, {})
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
private validateFileType(): void {
|
|
72
|
-
if (!this.fileName.endsWith('.csv'))
|
|
73
|
-
throw new Error(`File ${this.fileName} is not an CSV file`);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
private validateContent(): void {
|
|
77
|
-
if (!this.polyToolMonomerLib.isValid())
|
|
78
|
-
throw new Error('Invalid format of CSV monomer lib');
|
|
79
|
-
}
|
|
80
|
-
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as rxjs from 'rxjs';
|
|
2
|
-
import {debounceTime, tap} from 'rxjs/operators';
|
|
2
|
+
import {debounceTime, tap, skip} from 'rxjs/operators';
|
|
3
3
|
|
|
4
4
|
export class MonomerLibFileEventManager {
|
|
5
5
|
// WARNING: this must be a singleton because it manages the unique state
|
|
@@ -22,6 +22,18 @@ export class MonomerLibFileEventManager {
|
|
|
22
22
|
return this._libraryFilesUpdateSubject$.getValue();
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
// TODO: remove after adding init from user data storage
|
|
26
|
+
// WARNING: a temporary solution
|
|
27
|
+
async getValidLibraryPathsAsynchronously(): Promise<string[]> {
|
|
28
|
+
return new Promise((resolve) => {
|
|
29
|
+
this._libraryFilesUpdateSubject$.pipe(
|
|
30
|
+
skip(1)
|
|
31
|
+
).subscribe((fileNames) => {
|
|
32
|
+
resolve(fileNames);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
25
37
|
changeValidFilesPathList(newList: string[]): void {
|
|
26
38
|
this._libraryFilesUpdateSubject$.next(newList);
|
|
27
39
|
}
|
|
@@ -28,20 +28,22 @@ export class MonomerLibFileManager {
|
|
|
28
28
|
});
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
private static
|
|
31
|
+
private static instancePromise: Promise<MonomerLibFileManager> | undefined;
|
|
32
32
|
|
|
33
33
|
static async getInstance(
|
|
34
34
|
libraryEventManager: MonomerLibFileEventManager,
|
|
35
35
|
): Promise<MonomerLibFileManager> {
|
|
36
|
-
if (MonomerLibFileManager.
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
36
|
+
if (!MonomerLibFileManager.instancePromise) {
|
|
37
|
+
MonomerLibFileManager.instancePromise = (async () => {
|
|
38
|
+
const helmSchemaRaw = await grok.dapi.files.readAsText(HELM_JSON_SCHEMA_PATH);
|
|
39
|
+
const helmSchema = JSON.parse(helmSchemaRaw) as JSONSchemaType<any>;
|
|
40
|
+
|
|
41
|
+
const fileValidator = new MonomerLibFileValidator(helmSchema);
|
|
42
|
+
return new MonomerLibFileManager(fileValidator, libraryEventManager);
|
|
43
|
+
})();
|
|
42
44
|
}
|
|
43
45
|
|
|
44
|
-
return MonomerLibFileManager.
|
|
46
|
+
return MonomerLibFileManager.instancePromise;
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
/** Add standard .json monomer library */
|
|
@@ -103,6 +105,13 @@ export class MonomerLibFileManager {
|
|
|
103
105
|
return this.libraryEventManager.getValidFilesPathList();
|
|
104
106
|
}
|
|
105
107
|
|
|
108
|
+
// TODO: remove after adding init from user data storage
|
|
109
|
+
// WARNING: a temporary solution
|
|
110
|
+
async getValidLibraryPathsAsynchronously(): Promise<string[]> {
|
|
111
|
+
return await this.libraryEventManager.getValidLibraryPathsAsynchronously();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
|
|
106
115
|
private async libraryFileExists(fileName: string): Promise<boolean> {
|
|
107
116
|
return await grok.dapi.files.exists(LIB_PATH + `${fileName}`);
|
|
108
117
|
}
|
|
@@ -142,7 +151,7 @@ export class MonomerLibFileManager {
|
|
|
142
151
|
`, consider fixing or removing them: ${invalidFiles.join(', ')}`;
|
|
143
152
|
|
|
144
153
|
console.warn(message);
|
|
145
|
-
grok.shell.warning(message);
|
|
154
|
+
// grok.shell.warning(message);
|
|
146
155
|
}
|
|
147
156
|
}
|
|
148
157
|
|
|
@@ -41,7 +41,7 @@ export class MonomerLibFileValidator {
|
|
|
41
41
|
isValid = this.validateMonomerSchema(monomer);
|
|
42
42
|
if (!isValid) {
|
|
43
43
|
console.warn(
|
|
44
|
-
`Bio: Monomer Library File Validator:\nfile${fileName}\n monomer violating JSON schema:`,
|
|
44
|
+
`Bio: Monomer Library File Validator:\nfile ${fileName}\n monomer violating JSON schema:`,
|
|
45
45
|
monomer,
|
|
46
46
|
'\nError reason: ',
|
|
47
47
|
this.validateMonomerSchema.errors,
|
|
@@ -208,7 +208,12 @@ class DialogWrapper {
|
|
|
208
208
|
private async getDialog(): Promise<DG.Dialog> {
|
|
209
209
|
const eventManager = MonomerLibFileEventManager.getInstance();
|
|
210
210
|
const widget = await MonomerLibraryManagerWidget.getContent(eventManager);
|
|
211
|
-
const dialog = ui.dialog(
|
|
211
|
+
const dialog = ui.dialog(
|
|
212
|
+
{
|
|
213
|
+
title: 'Manage monomer libraries',
|
|
214
|
+
helpUrl: '/help/datagrok/solutions/domains/bio/bio.md#manage-monomer-libraries'
|
|
215
|
+
}
|
|
216
|
+
);
|
|
212
217
|
$(dialog.root).css('width', '350px');
|
|
213
218
|
dialog.clear();
|
|
214
219
|
dialog.addButton(
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as DG from 'datagrok-api/dg';
|
|
2
|
+
|
|
3
|
+
import {PolyToolMonomerLibHandler} from './monomer-lib-handler';
|
|
4
|
+
|
|
5
|
+
/** Handler of custom monomer libs for PolyTool */
|
|
6
|
+
export class PolyToolCsvLibHandler {
|
|
7
|
+
constructor(private fileName: string, private fileContent: string) {
|
|
8
|
+
this.validateFileType();
|
|
9
|
+
const df = DG.DataFrame.fromCsv(this.fileContent);
|
|
10
|
+
const json = this.toJson(df);
|
|
11
|
+
this.polyToolMonomerLib = new PolyToolMonomerLibHandler(json);
|
|
12
|
+
this.validateContent();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
private polyToolMonomerLib: PolyToolMonomerLibHandler;
|
|
16
|
+
|
|
17
|
+
async getJson(): Promise<any> {
|
|
18
|
+
const rawLibData = this.polyToolMonomerLib.getJsonMonomerLib();
|
|
19
|
+
return rawLibData;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
private toJson(df: DG.DataFrame): any[] {
|
|
23
|
+
return Array.from({length: df.rowCount}, (_, idx) =>
|
|
24
|
+
df.columns.names().reduce((entry: { [key: string]: any }, colName) => {
|
|
25
|
+
entry[colName] = df.get(colName, idx);
|
|
26
|
+
return entry;
|
|
27
|
+
}, {})
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
private validateFileType(): void {
|
|
32
|
+
if (!this.fileName.endsWith('.csv'))
|
|
33
|
+
throw new Error(`File ${this.fileName} is not an CSV file`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
private validateContent(): void {
|
|
37
|
+
if (!this.polyToolMonomerLib.isValid())
|
|
38
|
+
throw new Error('Invalid format of CSV monomer lib');
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -5,165 +5,219 @@ import * as DG from 'datagrok-api/dg';
|
|
|
5
5
|
import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
6
6
|
import {UnitsHandler} from '@datagrok-libraries/bio/src/utils/units-handler';
|
|
7
7
|
import {_package} from '../../package';
|
|
8
|
-
import {
|
|
9
|
-
import {HELM_WRAPPER, ALL_MONOMERS, CYCLIZATION_TYPE} from './const';
|
|
10
|
-
import {MetaData, ConnectionData} from './types';
|
|
8
|
+
import {HELM_WRAPPER} from './const';
|
|
11
9
|
import {getMolColumnFromHelm} from '../helm-to-molfile';
|
|
10
|
+
import {ALIGNMENT, ALPHABET} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
protected helmColumn: DG.Column<string>;
|
|
21
|
-
protected leftTerminal?: string;
|
|
22
|
-
protected rightTerminal?: string;
|
|
23
|
-
|
|
24
|
-
protected abstract hasTerminals(helm: string): boolean;
|
|
25
|
-
protected abstract getTransformedHelm(helm: string): string;
|
|
26
|
-
protected abstract getLinkedPositions(helm: string): [number, number];
|
|
27
|
-
|
|
28
|
-
transform(): string[] {
|
|
29
|
-
const resultList = this.helmColumn.toList().map((helm: string) => {
|
|
30
|
-
if (this.hasTerminals(helm))
|
|
31
|
-
return this.getTransformedHelm(helm);
|
|
32
|
-
return helm;
|
|
33
|
-
});
|
|
34
|
-
return resultList;
|
|
35
|
-
}
|
|
12
|
+
type ConnectionData = {
|
|
13
|
+
allPos1: number[],
|
|
14
|
+
allPos2: number[],
|
|
15
|
+
allAttaches1: number[],
|
|
16
|
+
allAttaches2: number[],
|
|
36
17
|
}
|
|
37
18
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
// return false;
|
|
46
|
-
// if (this.leftTerminal === ALL_MONOMERS)
|
|
47
|
-
// return true;
|
|
48
|
-
// return helm.includes(HELM_WRAPPER.LEFT + this.leftTerminal);
|
|
49
|
-
const positions = this.getLinkedPositions(helm);
|
|
50
|
-
return positions.every((el) => el > 0);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
protected getLinkedPositions(helm: string): [number, number] {
|
|
54
|
-
const seq = helm.replace(HELM_WRAPPER.LEFT, '').replace(HELM_WRAPPER.RIGHT, '');
|
|
55
|
-
const monomers = seq.split('.');
|
|
56
|
-
const start = 0;
|
|
57
|
-
const end = monomers.findIndex((el, idx) => el === this.rightTerminal && idx > start);
|
|
58
|
-
return [start + 1, end + 1];
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
protected getTransformedHelm(helm: string): string {
|
|
62
|
-
const positions = this.getLinkedPositions(helm);
|
|
63
|
-
const source = {monomerPosition: positions[0], attachmentPoint: 1};
|
|
64
|
-
const target = {monomerPosition: positions[1], attachmentPoint: 3};
|
|
65
|
-
return getHelmCycle(helm, source, target);
|
|
66
|
-
}
|
|
19
|
+
type Rule = {
|
|
20
|
+
firstMonomer: string,
|
|
21
|
+
secondMonomer: string,
|
|
22
|
+
firstModification: string,
|
|
23
|
+
secondModification: string,
|
|
24
|
+
firstR: number,
|
|
25
|
+
secondR: number
|
|
67
26
|
}
|
|
68
27
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
protected hasTerminals(helm: string): boolean {
|
|
75
|
-
if (this.leftTerminal === ALL_MONOMERS || this.rightTerminal === ALL_MONOMERS)
|
|
76
|
-
return true;
|
|
77
|
-
return helm.includes(HELM_WRAPPER.LEFT + this.leftTerminal) &&
|
|
78
|
-
helm.includes(this.rightTerminal + HELM_WRAPPER.RIGHT);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
protected getLinkedPositions(helm: string): [number, number] {
|
|
82
|
-
return [1, getNumberOfMonomers(helm)];
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
protected getTransformedHelm(helm: string): string {
|
|
86
|
-
const positions = this.getLinkedPositions(helm);
|
|
87
|
-
const source = {monomerPosition: positions[0], attachmentPoint: 1};
|
|
88
|
-
const target = {monomerPosition: positions[1], attachmentPoint: 2};
|
|
89
|
-
return getHelmCycle(helm, source, target);
|
|
90
|
-
}
|
|
28
|
+
function addCommonTags(col: DG.Column):void {
|
|
29
|
+
col.setTag('quality', DG.SEMTYPE.MACROMOLECULE);
|
|
30
|
+
col.setTag('aligned', ALIGNMENT.SEQ);
|
|
31
|
+
col.setTag('alphabet', ALPHABET.PT);
|
|
91
32
|
}
|
|
92
33
|
|
|
93
|
-
class
|
|
94
|
-
|
|
95
|
-
|
|
34
|
+
class TransformationCommon {
|
|
35
|
+
helmColumn: DG.Column;
|
|
36
|
+
|
|
37
|
+
constructor(helmColumn: DG.Column<string>) {
|
|
38
|
+
this.helmColumn = helmColumn;
|
|
96
39
|
}
|
|
97
40
|
|
|
98
41
|
protected hasTerminals(helm: string): boolean {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
42
|
+
let isLinkable = false;
|
|
43
|
+
if (helm.includes('(1)'))
|
|
44
|
+
isLinkable = true;
|
|
45
|
+
if (helm.includes('(2)'))
|
|
46
|
+
isLinkable = true;
|
|
47
|
+
|
|
48
|
+
return isLinkable;
|
|
103
49
|
}
|
|
104
50
|
|
|
105
|
-
protected getLinkedPositions(helm: string): [number, number] {
|
|
51
|
+
protected getLinkedPositions(helm: string, ruleCount: number): [number, number][] {
|
|
106
52
|
const seq = helm.replace(HELM_WRAPPER.LEFT, '').replace(HELM_WRAPPER.RIGHT, '');
|
|
107
53
|
const monomers = seq.split('.');
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
54
|
+
const result:[number, number][] = new Array<[number, number]>(ruleCount);
|
|
55
|
+
|
|
56
|
+
for (let i = 0; i < ruleCount; i++) {
|
|
57
|
+
let firstFound = false;
|
|
58
|
+
for (let j = 0; j < monomers.length; j++) {
|
|
59
|
+
if (monomers[j].includes(`(${i + 1})`)) {
|
|
60
|
+
if (firstFound) {
|
|
61
|
+
result[i][1] = j;
|
|
62
|
+
break;
|
|
63
|
+
} else {
|
|
64
|
+
firstFound = true;
|
|
65
|
+
result[i] = [j, 0];
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (!firstFound)
|
|
71
|
+
result[i] = [-1, -1];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
return result;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
protected getRules(rulesTable: DG.DataFrame): Rule[] {
|
|
79
|
+
const ruleCount = rulesTable.rowCount;
|
|
80
|
+
const rules: Rule[] = new Array<Rule>(ruleCount);
|
|
81
|
+
const codeCol = rulesTable.columns.byName('code');
|
|
82
|
+
const monomer1Col = rulesTable.columns.byName('monomer1');
|
|
83
|
+
const monomer2Col = rulesTable.columns.byName('monomer2');
|
|
84
|
+
const modification1Col = rulesTable.columns.byName('modification1');
|
|
85
|
+
const modification2Col = rulesTable.columns.byName('modification2');
|
|
86
|
+
const r1Col = rulesTable.columns.byName('R1');
|
|
87
|
+
const r2Col = rulesTable.columns.byName('R2');
|
|
88
|
+
|
|
89
|
+
for (let i = 0; i < ruleCount; i++) {
|
|
90
|
+
rules[i] = {
|
|
91
|
+
firstMonomer: monomer1Col.get(i),
|
|
92
|
+
secondMonomer: monomer2Col.get(i),
|
|
93
|
+
firstModification: modification1Col.get(i),
|
|
94
|
+
secondModification: modification2Col.get(i),
|
|
95
|
+
firstR: r1Col.get(i),
|
|
96
|
+
secondR: r2Col.get(i),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return rules;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
protected getTransformedHelm(helm: string, rules: Rule[]): string {
|
|
104
|
+
const ruleCount = rules.length;
|
|
105
|
+
const positions = this.getLinkedPositions(helm, ruleCount);
|
|
106
|
+
|
|
107
|
+
const allPos1: number [] = [];
|
|
108
|
+
const allPos2: number [] = [];
|
|
109
|
+
const allAttaches1: number [] = [];
|
|
110
|
+
const allAttaches2: number [] = [];
|
|
111
|
+
|
|
112
|
+
for (let i = 0; i < ruleCount; i++) {
|
|
113
|
+
if (positions[i][0] == -1)
|
|
114
|
+
continue;
|
|
115
|
+
|
|
116
|
+
helm = helm.replaceAll(`(${i + 1})`, '');
|
|
117
|
+
const seq = helm.replace(HELM_WRAPPER.LEFT, '').replace(HELM_WRAPPER.RIGHT, '');
|
|
118
|
+
const monomers = seq.split('.');
|
|
119
|
+
const firstMonomer = monomers[positions[i][0]].replace('[', '').replace(']', '');
|
|
120
|
+
const secondMonomer = monomers[positions[i][1]].replace('[', '').replace(']', '');
|
|
121
|
+
let attach1 = 0;
|
|
122
|
+
let attach2 = 0;
|
|
123
|
+
if (firstMonomer === rules[i].firstMonomer && secondMonomer === rules[i].secondMonomer) {
|
|
124
|
+
monomers[positions[i][0]] = monomers[positions[i][0]].replace(firstMonomer, rules[i].firstModification);
|
|
125
|
+
monomers[positions[i][1]] = monomers[positions[i][1]].replace(secondMonomer, rules[i].secondModification);
|
|
126
|
+
attach1 = rules[i].firstR;
|
|
127
|
+
attach2 = rules[i].secondR;
|
|
128
|
+
} else if (secondMonomer === rules[i].firstModification && firstMonomer === rules[i].secondModification) {
|
|
129
|
+
monomers[positions[i][0]] = monomers[positions[i][1]].replace(secondMonomer, rules[i].secondModification);
|
|
130
|
+
monomers[positions[i][1]] = rules[i].firstModification.replace(firstMonomer, rules[i].firstModification);
|
|
131
|
+
attach1 = rules[i].secondR;
|
|
132
|
+
attach2 = rules[i].firstR;
|
|
133
|
+
} else {
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
allPos1.push(positions[i][0] + 1);
|
|
138
|
+
allPos2.push(positions[i][1] + 1);
|
|
139
|
+
allAttaches1.push(attach1);
|
|
140
|
+
allAttaches2.push(attach2);
|
|
141
|
+
|
|
142
|
+
helm = HELM_WRAPPER.LEFT;
|
|
143
|
+
for (let i = 0; i < monomers.length; i ++) {
|
|
144
|
+
if (i != monomers.length - 1)
|
|
145
|
+
helm = helm + monomers[i] + '.';
|
|
146
|
+
else
|
|
147
|
+
helm = helm + monomers[i];
|
|
148
|
+
}
|
|
149
|
+
helm = helm + HELM_WRAPPER.RIGHT;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
const cycledHelm = getHelmCycle(helm, {allPos1, allPos2, allAttaches1, allAttaches2});
|
|
154
|
+
|
|
155
|
+
return cycledHelm;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
transform(rulesTable: DG.DataFrame): string[] {
|
|
159
|
+
const rules = this.getRules(rulesTable);
|
|
160
|
+
const resultList = this.helmColumn.toList().map((helm: string) => {
|
|
161
|
+
if (this.hasTerminals(helm))
|
|
162
|
+
return this.getTransformedHelm(helm, rules);
|
|
112
163
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
return getHelmCycle(helm, source, target);
|
|
164
|
+
console.log(helm);
|
|
165
|
+
return helm;
|
|
166
|
+
});
|
|
167
|
+
return resultList;
|
|
118
168
|
}
|
|
119
169
|
}
|
|
120
170
|
|
|
121
171
|
class PolymerTransformation {
|
|
122
172
|
private constructor() {}
|
|
123
173
|
|
|
124
|
-
static getInstance(molColumn: DG.Column<string
|
|
125
|
-
|
|
126
|
-
return (cyclizationType === CYCLIZATION_TYPE.R3) ? new TransformationR3(molColumn, meta) :
|
|
127
|
-
(cyclizationType === CYCLIZATION_TYPE.NCys) ? new TransformationNCys(molColumn, meta) :
|
|
128
|
-
new TransformationNO(molColumn, meta);
|
|
174
|
+
static getInstance(molColumn: DG.Column<string>) {
|
|
175
|
+
return new TransformationCommon(molColumn);
|
|
129
176
|
}
|
|
130
177
|
}
|
|
131
178
|
|
|
132
|
-
function
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
179
|
+
function getHelmCycle(helm: string, source: ConnectionData): string {
|
|
180
|
+
let cycled = helm.replace(HELM_WRAPPER.RIGHT, '}$');
|
|
181
|
+
|
|
182
|
+
for (let i = 0; i < source.allPos1.length; i++) {
|
|
183
|
+
if (i == 0)
|
|
184
|
+
cycled += 'PEPTIDE1,PEPTIDE1,';
|
|
185
|
+
else
|
|
186
|
+
cycled += '|PEPTIDE1,PEPTIDE1,';
|
|
187
|
+
cycled += `${source.allPos1[i]}:R${source.allAttaches1[i]}-${source.allPos2[i]}:R${source.allAttaches2[i]}`;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
cycled += '$$$';
|
|
191
|
+
return cycled;
|
|
192
|
+
// return helm.replace(HELM_WRAPPER.RIGHT,
|
|
193
|
+
// `}$PEPTIDE1,PEPTIDE1,${
|
|
194
|
+
// source.monomerPosition
|
|
195
|
+
// }:R${
|
|
196
|
+
// source.attachmentPoint
|
|
197
|
+
// }-${
|
|
198
|
+
// target.monomerPosition
|
|
199
|
+
// }:R${
|
|
200
|
+
// target.attachmentPoint
|
|
201
|
+
// }${'$'.repeat(6)}`
|
|
202
|
+
// );
|
|
149
203
|
}
|
|
150
204
|
|
|
151
205
|
export async function addTransformedColumn(
|
|
152
|
-
molColumn: DG.Column<string>,
|
|
206
|
+
molColumn: DG.Column<string>, rulesTable: DG.DataFrame, addHelm: boolean
|
|
153
207
|
): Promise<void> {
|
|
154
208
|
const df = molColumn.dataFrame;
|
|
155
209
|
const uh = UnitsHandler.getOrCreate(molColumn);
|
|
156
210
|
const sourceHelmCol = uh.convert(NOTATION.HELM);
|
|
157
|
-
const pt = PolymerTransformation.getInstance(sourceHelmCol
|
|
158
|
-
const targetList = pt.transform();
|
|
159
|
-
const helmColName = df.columns.getUnusedName(
|
|
211
|
+
const pt = PolymerTransformation.getInstance(sourceHelmCol);
|
|
212
|
+
const targetList = pt.transform(rulesTable);
|
|
213
|
+
const helmColName = df.columns.getUnusedName('transformed(' + molColumn.name + ')');
|
|
160
214
|
const targetHelmCol = DG.Column.fromList('string', helmColName, targetList);
|
|
161
215
|
|
|
162
216
|
addCommonTags(targetHelmCol);
|
|
163
217
|
targetHelmCol.setTag('units', NOTATION.HELM);
|
|
164
218
|
|
|
165
219
|
const molCol = await getMolColumnFromHelm(df, targetHelmCol);
|
|
166
|
-
molCol.name = df.columns.getUnusedName(
|
|
220
|
+
molCol.name = df.columns.getUnusedName('molfile(' + molColumn.name + ')');
|
|
167
221
|
|
|
168
222
|
if (addHelm) {
|
|
169
223
|
targetHelmCol.setTag('cell.renderer', 'helm');
|