@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/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "name": "Leonid Stolbov",
6
6
  "email": "lstolbov@datagrok.ai"
7
7
  },
8
- "version": "2.11.33",
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": "^5.39.25",
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.13",
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
- const libFnList = libFileManager.getValidLibraryPaths();
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
- expect(currentMonomerLib.getPolymerTypes().length === 0, true);
64
- const monomerOfTypesList = currentMonomerLib.getMonomerMolsByPolymerType('PEPTIDE');
65
- }, {skipReason: '#2690'});
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
- const filteredLibFnList = libFileNameList
60
- .filter((libFileName) => !settings.exclude.includes(libFileName))
61
- .filter((libFileName) => settings.explicit.length > 0 ? settings.explicit.includes(libFileName) : true);
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 instance: MonomerLibFileManager | undefined;
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.instance === undefined) {
37
- const helmSchemaRaw = await grok.dapi.files.readAsText(HELM_JSON_SCHEMA_PATH);
38
- const helmSchema = JSON.parse(helmSchemaRaw) as JSONSchemaType<any>;
39
-
40
- const fileValidator = new MonomerLibFileValidator(helmSchema);
41
- MonomerLibFileManager.instance = new MonomerLibFileManager(fileValidator, libraryEventManager);
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.instance;
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('Manage monomer libraries');
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 {addCommonTags} from './utils';
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
- abstract class TransformationBase {
14
- constructor(helmColumn: DG.Column<string>, meta: MetaData) {
15
- this.helmColumn = helmColumn;
16
- this.leftTerminal = meta.leftTerminal;
17
- this.rightTerminal = meta.rightTerminal;
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
- class TransformationNCys extends TransformationBase {
39
- constructor(helmColumn: DG.Column<string>, meta: MetaData) {
40
- super(helmColumn, meta);
41
- }
42
-
43
- protected hasTerminals(helm: string): boolean {
44
- // if (! helm.includes(this.rightTerminal + HELM_WRAPPER.RIGHT))
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
- class TransformationNO extends TransformationBase {
70
- constructor(helmColumn: DG.Column<string>, meta: MetaData) {
71
- super(helmColumn, meta);
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 TransformationR3 extends TransformationBase {
94
- constructor(helmColumn: DG.Column<string>, meta: MetaData) {
95
- super(helmColumn, meta);
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
- if (this.leftTerminal === ALL_MONOMERS || this.rightTerminal === ALL_MONOMERS)
100
- return true;
101
- const positions = this.getLinkedPositions(helm);
102
- return positions.every((el) => el > 0);
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 start = monomers.findIndex((el) => el === this.leftTerminal);
109
- const end = monomers.findIndex((el, idx) => el === this.rightTerminal && idx > start);
110
- return [start + 1, end + 1];
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
- protected getTransformedHelm(helm: string): string {
114
- const positions = this.getLinkedPositions(helm);
115
- const source = {monomerPosition: positions[0], attachmentPoint: 3};
116
- const target = {monomerPosition: positions[1], attachmentPoint: 3};
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>, meta: MetaData): TransformationBase {
125
- const cyclizationType = meta.cyclizationType;
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 getNumberOfMonomers(helm: string): number {
133
- const seq = helm.replace(HELM_WRAPPER.LEFT, '').replace(HELM_WRAPPER.RIGHT, '');
134
- return seq.split('.').length;
135
- }
136
-
137
- function getHelmCycle(helm: string, source: ConnectionData, target: ConnectionData): string {
138
- return helm.replace(HELM_WRAPPER.RIGHT,
139
- `}$PEPTIDE1,PEPTIDE1,${
140
- source.monomerPosition
141
- }:R${
142
- source.attachmentPoint
143
- }-${
144
- target.monomerPosition
145
- }:R${
146
- target.attachmentPoint
147
- }${'$'.repeat(6)}`
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>, meta: MetaData, addHelm: boolean
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, meta);
158
- const targetList = pt.transform();
159
- const helmColName = df.columns.getUnusedName(`${meta.transformationType}(` + molColumn.name + ')');
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(`${meta.transformationType}_molfile(` + molColumn.name + ')');
220
+ molCol.name = df.columns.getUnusedName('molfile(' + molColumn.name + ')');
167
221
 
168
222
  if (addHelm) {
169
223
  targetHelmCol.setTag('cell.renderer', 'helm');