@datagrok/sequence-translator 1.3.11 → 1.3.12

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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@datagrok/sequence-translator",
3
3
  "friendlyName": "Sequence Translator",
4
- "version": "1.3.11",
4
+ "version": "1.3.12",
5
5
  "author": {
6
6
  "name": "Alexey Choposky",
7
7
  "email": "achopovsky@datagrok.ai"
@@ -22,9 +22,9 @@
22
22
  }
23
23
  ],
24
24
  "dependencies": {
25
- "@datagrok-libraries/bio": "5.42.5",
25
+ "@datagrok-libraries/bio": "5.42.9",
26
26
  "@datagrok-libraries/chem-meta": "^1.2.5",
27
- "@datagrok-libraries/tutorials": "^1.3.12",
27
+ "@datagrok-libraries/tutorials": "^1.3.13",
28
28
  "@datagrok-libraries/utils": "^4.2.13",
29
29
  "@types/react": "^18.0.15",
30
30
  "cash-dom": "^8.1.0",
@@ -39,10 +39,11 @@
39
39
  "wu": "latest"
40
40
  },
41
41
  "devDependencies": {
42
- "@datagrok-libraries/helm-web-editor": "^1.1.6",
43
- "@datagrok-libraries/js-draw-lite": "^0.0.4",
44
- "@datagrok/bio": "^2.13.3",
45
- "@datagrok/chem": "1.9.2",
42
+ "@datagrok-libraries/helm-web-editor": "^1.1.8",
43
+ "@datagrok-libraries/js-draw-lite": "^0.0.6",
44
+ "@datagrok/bio": "^2.14.2",
45
+ "@datagrok/helm": "^2.4.1",
46
+ "@datagrok/chem": "^1.11.3",
46
47
  "@types/jquery": "^3.5.14",
47
48
  "@types/js-yaml": "^4.0.5",
48
49
  "@types/lodash": "^4.14.202",
@@ -4,6 +4,7 @@ import * as DG from 'datagrok-api/dg';
4
4
 
5
5
  import {getMonomerLibHelper, IMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
6
6
  import {IMonomerLib, Monomer} from '@datagrok-libraries/bio/src/types';
7
+ import {LoggerWrapper} from '@datagrok-libraries/bio/src/utils/logger';
7
8
 
8
9
  import {APP_NAME} from '../view/const';
9
10
  import {DEFAULT_LIB_FILENAME, FALLBACK_LIB_PATH} from './data-loader/const';
@@ -12,7 +13,6 @@ import {ITranslationHelper} from '../../../types';
12
13
  import {SequenceValidator} from './parsing-validation/sequence-validator';
13
14
  import {JsonData, loadJsonData} from './data-loader/json-loader';
14
15
  import {MonomerLibWrapper} from './monomer-lib/lib-wrapper';
15
- import {_package} from '../../../package';
16
16
  import {FormatConverter} from '../../translator/model/format-converter';
17
17
  import {FormatDetector} from './parsing-validation/format-detector';
18
18
  import {highlightInvalidSubsequence} from '../view/components/colored-input/input-painters';
@@ -39,8 +39,10 @@ export class OligoToolkitPackage extends DG.Package implements ITranslationHelpe
39
39
  return this._monomerLibWrapper;
40
40
  }
41
41
 
42
- constructor() {
42
+ constructor(opts: { debug: boolean } = {debug: false}) {
43
43
  super();
44
+ // @ts-ignore
45
+ super._logger = new LoggerWrapper(super.logger, opts.debug);
44
46
  }
45
47
 
46
48
  private initPromise?: Promise<void>;
@@ -51,7 +53,7 @@ export class OligoToolkitPackage extends DG.Package implements ITranslationHelpe
51
53
  const packageSettings = await this.getSettings();
52
54
  let monomersPath: string = packageSettings['MonomersPath'];
53
55
  if (!monomersPath || !(await grok.dapi.files.exists(monomersPath))) {
54
- _package.logger.warning(`Monomers path '${monomersPath}' not found. ` +
56
+ this.logger.warning(`Monomers path '${monomersPath}' not found. ` +
55
57
  `Fallback to monomers sample path '${FALLBACK_LIB_PATH}'.`);
56
58
  monomersPath = FALLBACK_LIB_PATH;
57
59
  }
@@ -8,6 +8,7 @@ import './tests/formats-to-helm';
8
8
  import './tests/helm-to-nucleotides';
9
9
  import './tests/formats-support';
10
10
  import './tests/files-tests';
11
+ import './tests/polytool-enumerate-tests';
11
12
 
12
13
  import {OligoToolkitTestPackage} from './tests/utils';
13
14
 
package/src/package.ts CHANGED
@@ -21,9 +21,9 @@ import {_setPeptideColumn} from './polytool/utils';
21
21
  import {PolyToolCsvLibHandler} from './polytool/csv-to-json-monomer-lib-converter';
22
22
  import {ITranslationHelper} from './types';
23
23
  import {addContextMenuUI} from './utils/context-menu';
24
- import { NOTATION } from '@datagrok-libraries/bio/src/utils/macromolecule/consts';
24
+ import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule/consts';
25
25
 
26
- export const _package: OligoToolkitPackage = new OligoToolkitPackage();
26
+ export const _package: OligoToolkitPackage = new OligoToolkitPackage(/*{debug: true}/**/);
27
27
 
28
28
  //name: Oligo Toolkit
29
29
  //meta.icon: img/icons/toolkit.png
@@ -169,7 +169,7 @@ export async function polyToolConvert(): Promise<void> {
169
169
  //name: polyToolEnumerateHelm
170
170
  //description: Perform cyclization of polymers
171
171
  export async function polyToolEnumerateHelm(): Promise<void> {
172
- polyToolEnumerateHelmUI();
172
+ await polyToolEnumerateHelmUI();
173
173
  }
174
174
 
175
175
  //top-menu: Bio | Convert | PolyTool-Enumerate Chem
@@ -213,7 +213,7 @@ export function addContextMenu(event: DG.EventData): void {
213
213
  // export async function ptConverterApp(): Promise<void> {
214
214
  // const view = grok.shell.v as DG.TableView;
215
215
  // const table = view.dataFrame;
216
- // const colNames = table.columns.names();
216
+ // const colNames = table.columns.names();
217
217
  // let covertableName = '';
218
218
 
219
219
  // for (let i = 0; i < colNames.length; i++) {
@@ -229,7 +229,7 @@ export function addContextMenu(event: DG.EventData): void {
229
229
  // else {
230
230
  // const dialog = await getPolyToolConversionDialog();
231
231
  // dialog.show();
232
- // }
232
+ // }
233
233
  // }
234
234
 
235
235
  //name: PolyTool Enumerator Helm
@@ -237,7 +237,7 @@ export function addContextMenu(event: DG.EventData): void {
237
237
  //meta.browsePath: PolyTool
238
238
  //tags: app
239
239
  export async function ptEnumeratorHelmApp(): Promise<void> {
240
- polyToolEnumerateHelmUI();
240
+ await polyToolEnumerateHelmUI();
241
241
  }
242
242
 
243
243
  //name: PolyTool Enumerator Chem
@@ -246,4 +246,4 @@ export async function ptEnumeratorHelmApp(): Promise<void> {
246
246
  //tags: app
247
247
  export async function ptEnumeratorChemApp(): Promise<void> {
248
248
  polyToolEnumerateChemUI();
249
- }
249
+ }
@@ -26,3 +26,13 @@ export const R_GROUP_BLOCK_DUMMY = [
26
26
  'label': 'R3'
27
27
  }
28
28
  ];
29
+
30
+ export const PT_ERROR_DATAFRAME = 'No dataframe with macromolecule columns open';
31
+ export const PT_WARNING_COLUMN = 'No marcomolecule column chosen!';
32
+
33
+ export const PT_UI_GET_HELM = 'Get HELM';
34
+ export const PT_UI_ADD_HELM = 'Add HELM column';
35
+ export const PT_UI_USE_CHIRALITY = 'Chirality engine';
36
+ export const PT_UI_DIALOG_CONVERSION = 'Poly Tool Conversion';
37
+ export const PT_UI_DIALOG_ENUMERATION = 'Poly Tool Enumeration';
38
+ export const PT_UI_RULES_USED = 'Rules used';
@@ -297,6 +297,7 @@ export async function addTransformedColumn(
297
297
  df.columns.add(targetHelmCol);
298
298
  }
299
299
 
300
+ // toAtomicLevel
300
301
  const molCol = await grok.functions.call('Bio:getMolFromHelm', {
301
302
  'df': df,
302
303
  'helmCol': targetHelmCol,
@@ -3,11 +3,14 @@ import * as grok from 'datagrok-api/grok';
3
3
  import * as ui from 'datagrok-api/ui';
4
4
  import * as DG from 'datagrok-api/dg';
5
5
 
6
+ import $ from 'cash-dom';
6
7
  import wu from 'wu';
8
+ import {Unsubscribable} from 'rxjs';
7
9
 
8
10
  import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule/consts';
9
11
  import {getHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
10
- import {HelmAtom} from '@datagrok-libraries/bio/src/helm/types';
12
+ import {HelmAtom, HelmMol} from '@datagrok-libraries/bio/src/helm/types';
13
+ // import {FormsViewer} from '@datagrok-libraries/utils/src/viewers/forms-viewer';
11
14
 
12
15
  import {RuleInputs, RULES_PATH, RULES_STORAGE_NAME} from './pt-rules';
13
16
  import {addTransformedColumn} from './pt-conversion';
@@ -15,27 +18,74 @@ import {addTransformedColumn} from './pt-conversion';
15
18
  import {handleError} from './utils';
16
19
  import {defaultErrorHandler} from '../utils/err-info';
17
20
  import {getLibrariesList} from './utils';
18
- import {getEnumerationHelm, PT_HELM_EXAMPLE} from './pt-enumeration-helm';
21
+ import {getPtEnumeratorHelm, PT_HELM_EXAMPLE} from './pt-enumeration-helm';
19
22
  import {getEnumerationChem, PT_CHEM_EXAMPLE} from './pt-enumeration-chem';
23
+ import {
24
+ PolyToolEnumeratorParams, PolyToolEnumeratorType, PolyToolEnumeratorTypes, PolyToolPlaceholders
25
+ } from './types';
26
+
27
+ import {_package} from '../package';
28
+ import {PolyToolPlaceholdersInput} from './pt-placeholders-input';
29
+ import {InputBase} from 'datagrok-api/dg';
30
+ import {PT_ERROR_DATAFRAME, PT_UI_ADD_HELM, PT_UI_DIALOG_CONVERSION, PT_UI_DIALOG_ENUMERATION, PT_UI_GET_HELM, PT_UI_RULES_USED, PT_UI_USE_CHIRALITY, PT_WARNING_COLUMN} from './const';
31
+ import {PolyToolEnumerateDialog} from './pt-enumeration-helm-dialog';
32
+
33
+ export async function polyToolEnumerateHelmUI(cell?: DG.Cell): Promise<void> {
34
+ const maxWidth = window.innerWidth;
35
+ const maxHeight = window.innerHeight;
36
+
37
+ try {
38
+ const resizeInputs = () => {
39
+ const contentHeight = $(dialog.root).find('div.d4-dialog-contents').get(0)!.clientHeight;
40
+
41
+ const fitInputs: { [idx: number]: number } = {1: 1 /*, 3: 0.5*/};
42
+ const fitInputsSumHeight = Object.values(fitInputs).reduce((sum, h) => sum + h, 0);
43
+
44
+ const otherInputsHeight: number = dialog.inputs.filter((input, idx) => !(idx in fitInputs))
45
+ .map((input) => input.root.offsetHeight).reduce((sum, h) => sum + h, 0);
46
+ const remainFitHeight = contentHeight - otherInputsHeight - 38;
47
+ dialog.inputs.forEach((input, idx) => {
48
+ if (idx in fitInputs) {
49
+ const inputFitHeight = remainFitHeight * fitInputs[idx] / fitInputsSumHeight;
50
+ input.root.style.height = `${inputFitHeight}px`;
51
+ }
52
+ });
53
+ };
54
+ const [dialog, inputs] = await PolyToolEnumerateDialog.create2(cell, resizeInputs);
55
+
56
+ let isFirstShow = true;
57
+ ui.onSizeChanged(dialog.root).subscribe(() => {
58
+ if (isFirstShow) {
59
+ const dialogInputList = dialog.inputs;
60
+ const dialogRootCash = $(dialog.root);
61
+ const contentMaxHeight = maxHeight
62
+ - dialogRootCash.find('div.d4-dialog-header').get(0)!.offsetHeight
63
+ - dialogRootCash.find('div.d4-dialog-footer').get(0)!.offsetHeight;
64
+
65
+ // dialog.inputs2.macromolecule.root.style.backgroundColor = '#CCFFCC';
66
+
67
+ const dialogWidth = maxWidth * 0.7;
68
+ const dialogHeight = maxHeight * 0.7;
69
+
70
+ // Centered, but resizable dialog
71
+ dialog.root.style.width = `${Math.min(maxWidth, dialogWidth)}px`;
72
+ dialog.root.style.height = `${Math.min(maxHeight, dialogHeight)}px`;
73
+ dialog.root.style.left = `${Math.floor((maxWidth - dialog.root.offsetWidth) / 2)}px`;
74
+ dialog.root.style.top = `${Math.floor((maxHeight - dialog.root.offsetHeight) / 2)}px`;
75
+
76
+ isFirstShow = false;
77
+ }
20
78
 
21
- const PT_ERROR_DATAFRAME = 'No dataframe with macromolecule columns open';
22
- const PT_WARNING_COLUMN = 'No marcomolecule column chosen!';
23
-
24
- const PT_UI_GET_HELM = 'Get HELM';
25
- const PT_UI_ADD_HELM = 'Add HELM column';
26
- const PT_UI_USE_CHIRALITY = 'Chirality engine';
27
- const PT_UI_DIALOG_CONVERSION = 'Poly Tool Conversion';
28
- const PT_UI_DIALOG_ENUMERATION = 'Poly Tool Enumeration';
29
- const PT_UI_RULES_USED = 'Rules used';
30
-
31
- export function polyToolEnumerateHelmUI(cell?: DG.Cell): void {
32
- getPolyToolEnumerationHelmDialog(cell)
33
- .then((dialog) => {
34
- dialog.show({resizable: true});
35
- })
36
- .catch((_err: any) => {
37
- grok.shell.warning('To run PolyTool Enumeration, sketch the macromolecule and select monomers to vary');
79
+ resizeInputs();
38
80
  });
81
+
82
+ _package.logger.debug('PolyToolEnumerateHelmUI: dialog before show');
83
+ const res = dialog.show({width: Math.max(350, maxWidth * 0.7), /* center: true,*/ resizable: true});
84
+ _package.logger.debug('PolyToolEnumerateHelmUI: dialog after show');
85
+ const k = 42;
86
+ } catch (_err: any) {
87
+ grok.shell.warning('To run PolyTool Enumeration, sketch the macromolecule and select monomers to vary');
88
+ }
39
89
  }
40
90
 
41
91
  export function polyToolEnumerateChemUI(cell?: DG.Cell): void {
@@ -104,61 +154,6 @@ export async function getPolyToolConversionDialog(targetCol?: DG.Column): Promis
104
154
  return dialog;
105
155
  }
106
156
 
107
- async function getPolyToolEnumerationHelmDialog(cell?: DG.Cell): Promise<DG.Dialog> {
108
- const [libList, helmHelper] = await Promise.all([
109
- getLibrariesList(), getHelmHelper()]);
110
-
111
- const helmValue = cell ? cell.value : PT_HELM_EXAMPLE;
112
-
113
- const helmInput = helmHelper.createHelmInput('Macromolecule', {value: helmValue});
114
- const screenLibrary = ui.input.choice('Library to use', {value: null, items: libList});
115
-
116
- helmInput.input.setAttribute('style', `min-width:250px!important;`);
117
- screenLibrary.input.setAttribute('style', `min-width:250px!important;`);
118
-
119
- const div = ui.div([
120
- helmInput.root,
121
- screenLibrary.root
122
- ]);
123
-
124
- // Displays the molecule from a current cell (monitors changes)
125
- const cccSubs = grok.events.onCurrentCellChanged.subscribe(() => {
126
- const cell = grok.shell.tv.dataFrame.currentCell;
127
-
128
- if (cell.column.semType === DG.SEMTYPE.MACROMOLECULE && cell.column.meta.units === NOTATION.HELM)
129
- helmInput.stringValue = cell.value;
130
- });
131
-
132
- const dialog = ui.dialog(PT_UI_DIALOG_ENUMERATION)
133
- .add(div)
134
- .onOK(async () => {
135
- try {
136
- const helmString = helmInput.stringValue;
137
- const helmSelections: number[] = wu.enumerate<HelmAtom>(helmInput.value.atoms)
138
- .filter(([a, aI]) => a.highlighted)
139
- .map(([a, aI]) => aI).toArray();
140
- if (helmString === undefined || helmString === '') {
141
- grok.shell.warning('PolyTool: no molecule was provided');
142
- } else if (helmSelections === undefined || helmSelections.length < 1) {
143
- grok.shell.warning('PolyTool: no selection was provided');
144
- } else {
145
- const molecules = await getEnumerationHelm(helmString, helmSelections, screenLibrary.value!);
146
- const molCol = DG.Column.fromStrings('Enumerated', molecules);
147
- const df = DG.DataFrame.fromColumns([molCol]);
148
- grok.shell.addTableView(df);
149
- }
150
- } catch (err: any) {
151
- defaultErrorHandler(err);
152
- } finally {
153
- cccSubs.unsubscribe();
154
- }
155
- }).onCancel(() => {
156
- cccSubs.unsubscribe();
157
- });
158
-
159
- return dialog;
160
- }
161
-
162
157
  async function getPolyToolEnumerationChemDialog(cell?: DG.Cell): Promise<DG.Dialog> {
163
158
  const [libList, helmHelper] = await Promise.all([
164
159
  getLibrariesList(), getHelmHelper()]);
@@ -87,23 +87,8 @@ export async function getEnumerationChem(molString: string, screenLibrary: strin
87
87
  //TODO: use RDKit linking function when exposed
88
88
  const smiResRaw = `${smiScaffold}.${smilesSubsts[i]}`.replaceAll('[1*]C', 'C([1*])').replaceAll('[1*]c', 'c([1*])').replaceAll('[1*]O', 'O([1*])').replaceAll('[1*]N', 'N([1*])');
89
89
  const smiRes = `${smiResRaw}`.replaceAll('([1*])', '9').replaceAll('[1*]', '9');
90
- molRes = rdkitModule.get_mol(smiRes);
90
+ molRes = rdkitModule.get_mol(smiRes, JSON.stringify({mappedDummiesAreRGroups: true}))
91
91
  let molV3 = molRes.get_v3Kmolblock();
92
-
93
-
94
- //TODO: use RDKit when MASS problem is solved
95
- while(molV3.includes('MASS')) {
96
-
97
- //MASS=2 VAL=1
98
- //RGROUPS=(1 2)
99
- const idx = molV3.indexOf('MASS');
100
- const rNum = parseInt(molV3.slice(idx + 5, idx + 6));
101
- const replace = `RGROUPS=(1 ${rNum})`;
102
- molV3 = molV3.substring(0, idx) + replace + molV3.substring(idx + 12);
103
- }
104
-
105
- molV3 = molV3.replaceAll('R ', 'R# ')
106
-
107
92
  enumerations[i] = molV3;
108
93
  }
109
94
  catch(err:any) {
@@ -0,0 +1,218 @@
1
+ import * as ui from 'datagrok-api/ui';
2
+ import * as grok from 'datagrok-api/grok';
3
+ import * as DG from 'datagrok-api/dg';
4
+
5
+ import wu from 'wu';
6
+ import {Unsubscribable} from 'rxjs';
7
+
8
+ import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
9
+ import {HelmAtom, HelmMol} from '@datagrok-libraries/helm-web-editor/src/types/org-helm';
10
+ import {getHelmHelper, HelmInputBase} from '@datagrok-libraries/bio/src/helm/helm-helper';
11
+
12
+ import {
13
+ PolyToolEnumeratorParams, PolyToolEnumeratorType, PolyToolEnumeratorTypes, PolyToolPlaceholders
14
+ } from './types';
15
+
16
+ import {PT_UI_DIALOG_ENUMERATION} from './const';
17
+ import {getLibrariesList} from './utils';
18
+ import {getPtEnumeratorHelm, PT_HELM_EXAMPLE} from './pt-enumeration-helm';
19
+ import {PolyToolPlaceholdersInput} from './pt-placeholders-input';
20
+ import {Dialog} from 'datagrok-api/dg';
21
+ import {defaultErrorHandler} from '../utils/err-info';
22
+
23
+ import {_package} from '../package';
24
+
25
+ type PolyToolEnumerateInputs = {
26
+ enumeratorType: DG.ChoiceInput<PolyToolEnumeratorType>
27
+ macromolecule: HelmInputBase;
28
+ placeholders: PolyToolPlaceholdersInput;
29
+ toAtomicLevel: DG.InputBase<boolean>;
30
+ };
31
+
32
+
33
+ export class PolyToolEnumerateDialog extends DG.Dialog {
34
+ protected constructor(
35
+ // public readonly inputs2: PolyToolEnumerateInputs
36
+ ) {
37
+ const dlg = ui.dialog({title: PT_UI_DIALOG_ENUMERATION});
38
+ super(dlg.dart);
39
+
40
+ // for (const [key, value] of Object.entries(this.inputs2)) { this.add(value); }
41
+ }
42
+
43
+ public override show(options?: { modal?: boolean; resizable?: boolean; fullScreen?: boolean; center?: boolean; centerAt?: Element; x?: number; y?: number; width?: number; height?: number; backgroundColor?: string; showNextTo?: HTMLElement }): Dialog {
44
+ return super.show(options);
45
+ }
46
+
47
+ public static async create2(cell?: DG.Cell, resizeInputs?: () => void): Promise<[PolyToolEnumerateDialog, PolyToolEnumerateInputs]> {
48
+ const logPrefix = `ST: PT: HelmDialog()`;
49
+
50
+ const [libList, helmHelper] = await Promise.all([getLibrariesList(), getHelmHelper()]);
51
+
52
+ const helmValue = cell ? cell.value : PT_HELM_EXAMPLE;
53
+ const posDf = DG.DataFrame.fromObjects([{Position: '', Monomers: ''}, {Position: '', Monomers: ''}]);
54
+
55
+ const macromoleculeInput = helmHelper.createHelmInput(
56
+ 'Macromolecule', {value: helmValue, editable: false});
57
+
58
+ const inputs: PolyToolEnumerateInputs = {
59
+ enumeratorType: ui.input.choice<PolyToolEnumeratorType>(
60
+ 'Enumerator type', {
61
+ value: PolyToolEnumeratorTypes.Single,
62
+ items: Object.values(PolyToolEnumeratorTypes)
63
+ }) as DG.ChoiceInput<PolyToolEnumeratorType>,
64
+ macromolecule: macromoleculeInput,
65
+
66
+ placeholders: await PolyToolPlaceholdersInput.create(
67
+ 'Placeholders', posDf, {
68
+ showAddNewRowIcon: true,
69
+ showRemoveRowIcon: true,
70
+ showRowHeader: false,
71
+ showCellTooltip: false,
72
+ }/*, 2/**/),
73
+
74
+ toAtomicLevel: ui.input.bool(
75
+ 'To atomic level', {value: true}),
76
+ };
77
+
78
+ const subs: Unsubscribable[] = [];
79
+ const destroy = () => { for (const sub of subs) sub.unsubscribe(); };
80
+
81
+ subs.push(inputs.macromolecule.onMouseMove.subscribe((e: MouseEvent) => {
82
+ try {
83
+ _package.logger.debug(`${logPrefix}, placeholdersInput.onMouseMove()`);
84
+
85
+ const argsX = e.offsetX;
86
+ const argsY = e.offsetY;
87
+ const mol = inputs.macromolecule.molValue;
88
+ const hoveredAtom = helmHelper.getHoveredAtom(argsX, argsY, mol, inputs.macromolecule.root.clientHeight);
89
+ if (hoveredAtom) {
90
+ const hoveredAtomContIdx = hoveredAtom._parent.atoms.indexOf(hoveredAtom);
91
+ const hoveredAtomContIdxStr = (hoveredAtomContIdx + 1).toString();
92
+ const substitutingMonomers = inputs.placeholders.placeholdersValue[hoveredAtomContIdx];
93
+
94
+ if (substitutingMonomers) {
95
+ const cnt = ui.divText(substitutingMonomers.join(', '));
96
+ inputs.macromolecule.showTooltip(cnt, hoveredAtom);
97
+ e.preventDefault();
98
+ e.stopPropagation();
99
+ }
100
+ }
101
+ } catch (err: any) {
102
+ defaultErrorHandler(err, false);
103
+ }
104
+ }));
105
+ subs.push(inputs.macromolecule.onClick.subscribe((e: MouseEvent) => {
106
+ try {
107
+ _package.logger.debug(`${logPrefix}, placeholdersInput.onClick()`);
108
+
109
+ const argsX = e.offsetX;
110
+ const argsY = e.offsetY;
111
+ const mol = inputs.macromolecule.molValue;
112
+ const clickedAtom = helmHelper.getHoveredAtom(argsX, argsY, mol, inputs.macromolecule.root.clientHeight);
113
+ if (clickedAtom) {
114
+ const clickedAtomContIdx = clickedAtom._parent.atoms.indexOf(clickedAtom);
115
+ const clickedAtomContIdxStr = (clickedAtomContIdx + 1).toString();
116
+
117
+ const phDf = inputs.placeholders.grid.dataFrame;
118
+ const posList = phDf.columns.byName('Position').toList();
119
+ let rowIdx = posList.indexOf(clickedAtomContIdxStr);
120
+ if (rowIdx === -1) {
121
+ rowIdx = posList.findIndex((v) => isNaN(v));
122
+ if (rowIdx === -1)
123
+ rowIdx = phDf.rows.addNew([clickedAtomContIdxStr, '']).idx;
124
+ phDf.set('Position', rowIdx, clickedAtomContIdxStr);
125
+ // const tgtCell = inputs.placeholders.grid.cell('Monomers', rowIdx);
126
+ }
127
+ phDf.currentCell = phDf.cell(rowIdx, 'Monomers');
128
+ //const gridRowIdx = inputs.placeholders.grid.tableRowToGrid(rowIdx);
129
+ //const monomersGCell = inputs.placeholders.grid.cell('Monomers', gridRowIdx);
130
+ const k = 42;
131
+ }
132
+ } catch (err: any) {
133
+ defaultErrorHandler(err);
134
+ }
135
+ }));
136
+ subs.push(inputs.placeholders.grid.dataFrame.onDataChanged.subscribe(() => {
137
+ updateMolView();
138
+ }));
139
+
140
+
141
+ // TODO: suspect
142
+ subs.push(ui.onSizeChanged(inputs.placeholders.root).subscribe(() => {
143
+ if (resizeInputs) resizeInputs();
144
+ }));
145
+
146
+ // Displays the molecule from a current cell (monitors changes)
147
+ subs.push(grok.events.onCurrentCellChanged.subscribe(() => {
148
+ const cell = grok.shell.tv.dataFrame.currentCell;
149
+
150
+ if (cell.column.semType === DG.SEMTYPE.MACROMOLECULE && cell.column.meta.units === NOTATION.HELM)
151
+ inputs.macromolecule.stringValue = cell.value;
152
+ }));
153
+
154
+ inputs.macromolecule.root.style.setProperty('min-width', '250px', 'important');
155
+ // inputs.macromolecule.root.style.setProperty('max-height', '300px', 'important');
156
+
157
+ const updateMolView = () => {
158
+ const mol = inputs.macromolecule.molValue;
159
+ for (let aI = 0; aI < mol.atoms.length; aI++) {
160
+ const a = mol.atoms[aI];
161
+ a.highlighted = aI in inputs.placeholders.placeholdersValue;
162
+ inputs.macromolecule.redraw();
163
+ }
164
+ };
165
+
166
+ const dialog = new PolyToolEnumerateDialog()
167
+ .add(inputs.enumeratorType)
168
+ .add(inputs.macromolecule)
169
+ .add(inputs.placeholders)
170
+ .add(inputs.toAtomicLevel)
171
+ .onOK(async () => {
172
+ try {
173
+ const helmString = inputs.macromolecule.stringValue;
174
+ const helmSelections: number[] = wu.enumerate<HelmAtom>(inputs.macromolecule.molValue.atoms)
175
+ .filter(([a, aI]) => a.highlighted)
176
+ .map(([a, aI]) => aI).toArray();
177
+ if (helmString === undefined || helmString === '') {
178
+ grok.shell.warning('PolyTool: no molecule was provided');
179
+ } else /* if (helmSelections === undefined || helmSelections.length < 1) {
180
+ grok.shell.warning('PolyTool: no selection was provided');
181
+ } else /**/ {
182
+ await getHelmHelper(); // initializes JSDraw and org
183
+
184
+ const params: PolyToolEnumeratorParams = {
185
+ type: inputs.enumeratorType.value!,
186
+ placeholders: inputs.placeholders.placeholdersValue,
187
+ };
188
+ if (Object.keys(params.placeholders).length === 0) {
189
+ grok.shell.warning(`${PT_UI_DIALOG_ENUMERATION}: placeholders are empty`);
190
+ return;
191
+ }
192
+
193
+ const enumHelmList = getPtEnumeratorHelm(helmString, params);
194
+ const enumHelmCol = DG.Column.fromStrings('Enumerated', enumHelmList);
195
+ const enumeratorResDf = DG.DataFrame.fromColumns([enumHelmCol]);
196
+
197
+ if (inputs.toAtomicLevel.value) {
198
+ const enumMolCol = await grok.functions.call('Bio:getMolFromHelm', {
199
+ 'df': enumeratorResDf,
200
+ 'helmCol': enumHelmCol,
201
+ 'chiralityEngine': true,
202
+ });
203
+ enumMolCol.name = enumeratorResDf.columns.getUnusedName(`molfile(${enumHelmCol.name})`);
204
+ enumMolCol.semType = DG.SEMTYPE.MOLECULE;
205
+ enumeratorResDf.columns.add(enumMolCol, true);
206
+ }
207
+ grok.shell.addTableView(enumeratorResDf);
208
+ }
209
+ } catch (err: any) {
210
+ defaultErrorHandler(err);
211
+ } finally {
212
+ destroy();
213
+ }
214
+ })
215
+ .onCancel(() => { destroy(); }) as PolyToolEnumerateDialog;
216
+ return [dialog, inputs];
217
+ }
218
+ }
@@ -1,22 +1,74 @@
1
1
  import * as ui from 'datagrok-api/ui';
2
2
  import * as grok from 'datagrok-api/grok';
3
3
  import * as DG from 'datagrok-api/dg';
4
+
5
+ import {HelmType, JSDraw2ModuleType, OrgType, HelmAtom, HelmMol} from '@datagrok-libraries/bio/src/helm/types';
6
+
4
7
  import {Chain} from './pt-conversion';
5
- import {getAvailableMonomers} from './utils'
8
+ import {getAvailableMonomers} from './utils';
9
+ import {PolyToolEnumeratorParams, PolyToolEnumeratorTypes, PolyToolPlaceholders} from './types';
6
10
 
7
11
  export const PT_HELM_EXAMPLE = 'PEPTIDE1{[R].[F].[T].[G].[H].[F].[G].[A].[A].[Y].[P].[E].[NH2]}$$$$';
8
12
 
9
- export async function getEnumerationHelm(helmString: string, helmSelections: number[], screenLibrary: string):
10
- Promise<string[]> {
11
- const variableMonomers = await getAvailableMonomers(screenLibrary);
12
- const chain: Chain = Chain.fromHelm(helmString);
13
- const size = helmSelections.length * variableMonomers.length;
14
- const enumerations = new Array<string>(size);
13
+ /** Initialized by getHelmHelper via init Helm package */
14
+ declare const JSDraw2: JSDraw2ModuleType;
15
+ declare const org: OrgType;
15
16
 
16
- for (let i = 0; i < helmSelections.length; i++) {
17
- for (let j = 0; j < variableMonomers.length; j++)
18
- enumerations[i * variableMonomers.length + j] = chain.getHelmChanged(helmSelections[i], variableMonomers[j]);
17
+ function polyToolEnumeratorCore(m: HelmMol, position: number, monomerList: string[]): HelmMol[] {
18
+ const resMolList: HelmMol[] = new Array<HelmMol>(monomerList.length);
19
+ for (let i = 0; i < monomerList.length; i++) {
20
+ const symbolName = monomerList[i];
21
+ const resM = resMolList[i] = m.clone();
22
+ resM.atoms[position].elem = symbolName;
19
23
  }
24
+ return resMolList;
25
+ }
26
+
27
+ /**
28
+ * @param {string} helm Molecule string Helm format
29
+ * @param placeholders Placeholders by zero-based position key
30
+ * @returns {string[]} List of enumerated molecules in Helm format
31
+ */
32
+ function getPtEnumeratorSingle(helm: string, placeholders: PolyToolPlaceholders): string[] {
33
+ const molHandler = new JSDraw2.MolHandler<HelmType>();
34
+ const plugin = new org.helm.webeditor.Plugin(molHandler);
35
+ const io = org.helm.webeditor.IO;
36
+
37
+ const origin = new JSDraw2.Point(0, 0);
38
+ io.parseHelm(plugin, helm, origin, undefined);
39
+
40
+ const coreResList: HelmMol[][] = Object.entries(placeholders)
41
+ .map(([p, monomerList]: [string, string[]]) => polyToolEnumeratorCore(molHandler.m, parseInt(p), monomerList));
42
+ const resMolList = coreResList.reduce((acc, posList) => acc.concat(posList), []);
43
+
44
+ const resHelmList = resMolList.map((m: HelmMol) => org.helm.webeditor.IO.getHelm(m)!);
45
+ return resHelmList;
46
+ }
20
47
 
21
- return enumerations;
48
+ function getPtEnumeratorMatrix(helm: string, placeholders: PolyToolPlaceholders): string[] {
49
+ const molHandler = new JSDraw2.MolHandler<HelmType>();
50
+ const plugin = new org.helm.webeditor.Plugin(molHandler);
51
+ const io = org.helm.webeditor.IO;
52
+
53
+ const origin = new JSDraw2.Point(0, 0);
54
+ io.parseHelm(plugin, helm, origin, undefined);
55
+
56
+ let resMolList = [molHandler.m];
57
+ for (const [p, monomerList] of Object.entries(placeholders)) {
58
+ const pos: number = parseInt(p);
59
+ const posResMolList: HelmMol[][] = resMolList.map((m: HelmMol) => polyToolEnumeratorCore(m, pos, monomerList));
60
+ resMolList = posResMolList.reduce((acc, l) => acc.concat(l), []);
61
+ }
62
+
63
+ const resHelmList = resMolList.map((m: HelmMol) => org.helm.webeditor.IO.getHelm(m)!);
64
+ return resHelmList;
65
+ }
66
+
67
+ export function getPtEnumeratorHelm(helm: string, params: PolyToolEnumeratorParams): string[] {
68
+ switch (params.type) {
69
+ case PolyToolEnumeratorTypes.Single:
70
+ return getPtEnumeratorSingle(helm, params.placeholders);
71
+ case PolyToolEnumeratorTypes.Matrix:
72
+ return getPtEnumeratorMatrix(helm, params.placeholders);
73
+ }
22
74
  }