@datagrok/sequence-translator 1.4.1 → 1.4.2

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.
@@ -1,5 +1,5 @@
1
1
  n,seqs
2
- 1,R-F-C(1)-T-G-H-F-Y-P-C(1)-meI
2
+ 1,R-F-C(1)-T-G-H-F-Y-G-H-F-Y-G-H-F-Y-P-C(1)-meI
3
3
  2,C(1)-T-G-H-F-Y-P-C(1)-meI
4
4
  3,R-F-C(1)-T-G-H-F-Y-P-C(1)
5
5
  4,C(1)-T-G-H-F-H-P-C(1)
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.1",
4
+ "version": "1.4.2",
5
5
  "author": {
6
6
  "name": "Alexey Choposky",
7
7
  "email": "achopovsky@datagrok.ai"
@@ -22,8 +22,8 @@
22
22
  }
23
23
  ],
24
24
  "dependencies": {
25
- "@datagrok-libraries/bio": "^5.42.15",
26
- "@datagrok-libraries/chem-meta": "^1.2.5",
25
+ "@datagrok-libraries/bio": "^5.44.0",
26
+ "@datagrok-libraries/chem-meta": "^1.2.7",
27
27
  "@datagrok-libraries/tutorials": "^1.4.0",
28
28
  "@datagrok-libraries/utils": "^4.3.0",
29
29
  "@types/react": "^18.0.15",
@@ -41,7 +41,7 @@
41
41
  "devDependencies": {
42
42
  "@datagrok-libraries/helm-web-editor": "^1.1.11",
43
43
  "@datagrok-libraries/js-draw-lite": "^0.0.8",
44
- "@datagrok/bio": "^2.15.1",
44
+ "@datagrok/bio": "^2.15.3",
45
45
  "@datagrok/helm": "^2.5.0",
46
46
  "@datagrok/chem": "^1.12.0",
47
47
  "@types/jquery": "^3.5.14",
@@ -2,7 +2,7 @@ import * as grok from 'datagrok-api/grok';
2
2
  import * as ui from 'datagrok-api/ui';
3
3
  import * as DG from 'datagrok-api/dg';
4
4
 
5
- import {runTests, tests, TestContext} from '@datagrok-libraries/utils/src/test';
5
+ import {runTests, tests, TestContext, initAutoTests as initTests } from '@datagrok-libraries/utils/src/test';
6
6
 
7
7
  import './tests/formats-to-helm';
8
8
  import './tests/helm-to-nucleotides';
@@ -10,6 +10,7 @@ import './tests/formats-support';
10
10
  import './tests/files-tests';
11
11
  import './tests/polytool-convert-tests';
12
12
  import './tests/polytool-enumerate-tests';
13
+ import './tests/polytool-enumerate-breadth-tests';
13
14
 
14
15
  import {OligoToolkitTestPackage} from './tests/utils';
15
16
 
@@ -25,3 +26,8 @@ export async function test(category: string, test: string, testContext: TestCont
25
26
  const data = await runTests({category, test, testContext, verbose: true});
26
27
  return DG.DataFrame.fromObjects(data)!;
27
28
  }
29
+
30
+ //name: initAutoTests
31
+ export async function initAutoTests() {
32
+ await initTests(_package, _package.getModule('package-test.js'));
33
+ }
@@ -23,6 +23,16 @@ import {
23
23
 
24
24
  import {_package} from '../package';
25
25
 
26
+ type PolyToolConvertSerialized = {
27
+ generateHelm: boolean;
28
+ chiralityEngine: boolean;
29
+ };
30
+
31
+ type PolyToolEnumerateChemSerialized = {
32
+ mol: string;
33
+ screenLibrary: string | null;
34
+ }
35
+
26
36
  export function polyToolEnumerateChemUI(cell?: DG.Cell): void {
27
37
  getPolyToolEnumerationChemDialog(cell)
28
38
  .then((dialog) => {
@@ -79,7 +89,6 @@ export async function getPolyToolConvertDialog(targetCol?: DG.Column): Promise<D
79
89
  rulesForm
80
90
  ]);
81
91
 
82
-
83
92
  const exec = async (): Promise<void> => {
84
93
  try {
85
94
  const ruleFileList = await ruleInputs.getActive();
@@ -95,7 +104,17 @@ export async function getPolyToolConvertDialog(targetCol?: DG.Column): Promise<D
95
104
  subs.push(dialog.onClose.subscribe(() => {
96
105
  destroy();
97
106
  }));
98
-
107
+ dialog.history(
108
+ /* getInput */ (): PolyToolConvertSerialized => {
109
+ return {
110
+ generateHelm: generateHelmChoiceInput.value,
111
+ chiralityEngine: chiralityEngineInput.value,
112
+ };
113
+ },
114
+ /* applyInput */ (x: PolyToolConvertSerialized): void => {
115
+ generateHelmChoiceInput.value = x.generateHelm;
116
+ chiralityEngineInput.value = x.chiralityEngine;
117
+ });
99
118
  return dialog;
100
119
  } catch (err: any) {
101
120
  destroy(); // on failing to build a dialog
@@ -133,15 +152,15 @@ async function getPolyToolEnumerationChemDialog(cell?: DG.Cell): Promise<DG.Dial
133
152
  molInput.setMolFile(molfileValue);
134
153
 
135
154
  //const helmInput = helmHelper.createHelmInput('Macromolecule', {value: helmValue});
136
- const screenLibrary = ui.input.choice('Library to use', {value: null, items: libList});
155
+ const screenLibraryInput = ui.input.choice('Library to use', {value: null, items: libList});
137
156
 
138
157
  molInput.root.setAttribute('style', `min-width:250px!important;`);
139
158
  molInput.root.setAttribute('style', `max-width:250px!important;`);
140
- screenLibrary.input.setAttribute('style', `min-width:250px!important;`);
159
+ screenLibraryInput.input.setAttribute('style', `min-width:250px!important;`);
141
160
 
142
161
  const div = ui.div([
143
162
  molInput.root,
144
- screenLibrary.root
163
+ screenLibraryInput.root
145
164
  ]);
146
165
 
147
166
  subs.push(grok.events.onCurrentCellChanged.subscribe(() => {
@@ -160,7 +179,7 @@ async function getPolyToolEnumerationChemDialog(cell?: DG.Cell): Promise<DG.Dial
160
179
  } else if (!molString.includes('R#')) {
161
180
  grok.shell.warning('PolyTool: no R group was provided');
162
181
  } else {
163
- const molecules = await getEnumerationChem(molString, screenLibrary.value!);
182
+ const molecules = await getEnumerationChem(molString, screenLibraryInput.value!);
164
183
  const molCol = DG.Column.fromStrings('Enumerated', molecules);
165
184
  const df = DG.DataFrame.fromColumns([molCol]);
166
185
  grok.shell.addTableView(df);
@@ -182,6 +201,17 @@ async function getPolyToolEnumerationChemDialog(cell?: DG.Cell): Promise<DG.Dial
182
201
  subs.push(dialog.onClose.subscribe(() => {
183
202
  destroy();
184
203
  }));
204
+ dialog.history(
205
+ /* getInput */ (): PolyToolEnumerateChemSerialized => {
206
+ return {
207
+ mol: molInput.getMolFile(),
208
+ screenLibrary: screenLibraryInput.value,
209
+ };
210
+ },
211
+ /* applyInput */ (x: PolyToolEnumerateChemSerialized): void => {
212
+ molInput.setMolFile(x.mol);
213
+ screenLibraryInput.value = x.screenLibrary;
214
+ });
185
215
  return dialog;
186
216
  } catch (err: any) {
187
217
  destroy();
@@ -215,7 +245,7 @@ export async function polyToolConvert(
215
245
 
216
246
  const seqHelper: ISeqHelper = await getSeqHelper();
217
247
  const toAtomicLevelRes = await seqHelper.helmToAtomicLevel(resHelmCol, chiralityEngine, /* highlight */ generateHelm);
218
- const resMolCol = toAtomicLevelRes.molCol;
248
+ const resMolCol = toAtomicLevelRes.molCol!;
219
249
  resMolCol.name = getUnusedName(table, `molfile(${seqCol.name})`);
220
250
  resMolCol.semType = DG.SEMTYPE.MOLECULE;
221
251
  if (table) {
@@ -10,7 +10,7 @@ import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
10
10
  import {HelmAtom, HelmMol} from '@datagrok-libraries/helm-web-editor/src/types/org-helm';
11
11
  import {getHelmHelper, HelmInputBase} from '@datagrok-libraries/bio/src/helm/helm-helper';
12
12
  import {getMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
13
- import {HelmType, ISeqMonomer} from '@datagrok-libraries/bio/src/helm/types';
13
+ import {HelmType, PolymerType} from '@datagrok-libraries/bio/src/helm/types';
14
14
  import {helmTypeToPolymerType} from '@datagrok-libraries/bio/src/monomer-works/monomer-works';
15
15
  import {getSeqHelper, ISeqHelper} from '@datagrok-libraries/bio/src/utils/seq-helper';
16
16
  import '@datagrok-libraries/bio/src/types/input';
@@ -25,6 +25,7 @@ import {getLibrariesList} from './utils';
25
25
  import {doPolyToolEnumerateHelm, PT_HELM_EXAMPLE} from './pt-enumeration-helm';
26
26
  import {PolyToolPlaceholdersInput} from './pt-placeholders-input';
27
27
  import {defaultErrorHandler} from '../utils/err-info';
28
+ import {PolyToolPlaceholdersBreadthInput} from './pt-placeholders-breadth-input';
28
29
  import {PT_UI_DIALOG_ENUMERATION} from './const';
29
30
 
30
31
  import {_package} from '../package';
@@ -32,15 +33,17 @@ import {_package} from '../package';
32
33
  type PolyToolEnumerateInputs = {
33
34
  macromolecule: HelmInputBase;
34
35
  placeholders: PolyToolPlaceholdersInput;
36
+ placeholdersBreadth: PolyToolPlaceholdersBreadthInput;
35
37
  enumeratorType: DG.ChoiceInput<PolyToolEnumeratorType>
36
38
  trivialNameCol: InputColumnBase,
37
39
  toAtomicLevel: DG.InputBase<boolean>;
38
40
  keepOriginal: DG.InputBase<boolean>;
39
41
  };
40
42
 
41
- type PolyToolEnumerateSerialized = {
43
+ type PolyToolEnumerateHelmSerialized = {
42
44
  macromolecule: string;
43
45
  placeholders: string;
46
+ placeholdersBreadth: string;
44
47
  enumeratorType: PolyToolEnumeratorType;
45
48
  trivialNameCol: string;
46
49
  toAtomicLevel: boolean;
@@ -136,20 +139,27 @@ async function getPolyToolEnumerateDialog(
136
139
  const trivialNameSampleDiv = ui.divText('', {style: {marginLeft: '8px', marginTop: '2px'}});
137
140
  const warningsTextDiv = ui.divText('', {style: {color: 'red'}});
138
141
  inputs = {
142
+ macromolecule: helmHelper.createHelmInput(
143
+ 'Macromolecule', {editable: false}),
144
+ placeholders: await PolyToolPlaceholdersInput.create(
145
+ 'Placeholders', {
146
+ showAddNewRowIcon: true,
147
+ showRemoveRowIcon: true,
148
+ showRowHeader: false,
149
+ showCellTooltip: false,
150
+ }),
139
151
  enumeratorType: ui.input.choice<PolyToolEnumeratorType>(
140
152
  'Enumerator type', {
141
153
  value: PolyToolEnumeratorTypes.Single,
142
154
  items: Object.values(PolyToolEnumeratorTypes)
143
155
  }) as DG.ChoiceInput<PolyToolEnumeratorType>,
144
- macromolecule: helmHelper.createHelmInput(
145
- 'Macromolecule', {editable: false}),
146
- placeholders: await PolyToolPlaceholdersInput.create(
147
- 'Placeholders', {
156
+ placeholdersBreadth: await PolyToolPlaceholdersBreadthInput.create(
157
+ 'Breadth', {
148
158
  showAddNewRowIcon: true,
149
159
  showRemoveRowIcon: true,
150
160
  showRowHeader: false,
151
161
  showCellTooltip: false,
152
- }/*, 2/**/),
162
+ }),
153
163
  toAtomicLevel: ui.input.bool(
154
164
  'To atomic level', {value: false}),
155
165
  keepOriginal: ui.input.bool(
@@ -180,9 +190,9 @@ async function getPolyToolEnumerateDialog(
180
190
  inputs.placeholders.addValidator((value: string): string | null => {
181
191
  const errors: string[] = [];
182
192
  try {
183
- const missedMonomerList: ISeqMonomer[] = [];
184
- for (const [posVal, monomerSymbolList] of Object.entries(inputs.placeholders.placeholdersValue)) {
185
- const pos = parseInt(posVal);
193
+ const missedMonomerList: { polymerType: PolymerType, symbol: string }[] = [];
194
+ for (const ph of inputs.placeholders.placeholdersValue) {
195
+ const pos = ph.position;
186
196
  if (pos >= inputs.macromolecule.molValue.atoms.length) {
187
197
  errors.push(`There is no monomer at position ${pos + 1}.`);
188
198
  continue;
@@ -190,7 +200,7 @@ async function getPolyToolEnumerateDialog(
190
200
  const a = inputs.macromolecule.molValue.atoms[pos];
191
201
  const helmType: HelmType = a.biotype()!;
192
202
  const polymerType = helmTypeToPolymerType(helmType);
193
- for (const symbol of monomerSymbolList) {
203
+ for (const symbol of ph.monomers) {
194
204
  const substituteMonomer = monomerLib.getMonomer(polymerType, symbol)!;
195
205
  // TODO: Check substitution monomer is presented in the library
196
206
  if (!substituteMonomer || !substituteMonomer.lib)
@@ -228,8 +238,8 @@ async function getPolyToolEnumerateDialog(
228
238
  const hoveredAtom = helmHelper.getHoveredAtom(argsX, argsY, mol, inputs.macromolecule.root.clientHeight);
229
239
  if (hoveredAtom) {
230
240
  const hoveredAtomContIdx = hoveredAtom._parent.atoms.indexOf(hoveredAtom);
231
- const hoveredAtomContIdxStr = (hoveredAtomContIdx + 1).toString();
232
- const substitutingMonomers = inputs.placeholders.placeholdersValue[hoveredAtomContIdx];
241
+ const substitutingMonomers = inputs.placeholders.placeholdersValue
242
+ .find((ph) => ph.position === hoveredAtomContIdx)?.monomers;
233
243
 
234
244
  if (substitutingMonomers) {
235
245
  const cnt = ui.divText(substitutingMonomers.join(', '));
@@ -377,14 +387,17 @@ async function getPolyToolEnumerateDialog(
377
387
  } else /* if (helmSelections === undefined || helmSelections.length < 1) {
378
388
  grok.shell.warning('PolyTool: no selection was provided');
379
389
  } else /**/ {
380
- if (Object.keys(inputs.placeholders.placeholdersValue).length === 0) {
390
+ if (Object.keys(inputs.placeholders.placeholdersValue).length === 0 &&
391
+ Object.keys(inputs.placeholdersBreadth.placeholdersBreadthValue).length === 0
392
+ ) {
381
393
  grok.shell.warning(`${PT_UI_DIALOG_ENUMERATION}: placeholders are empty`);
382
394
  return;
383
395
  }
384
396
  await getHelmHelper(); // initializes JSDraw and org
385
397
  const params: PolyToolEnumeratorParams = {
386
- type: inputs.enumeratorType.value!,
387
398
  placeholders: inputs.placeholders.placeholdersValue,
399
+ type: inputs.enumeratorType.value!,
400
+ placeholdersBreadth: inputs.placeholdersBreadth.placeholdersBreadthValue,
388
401
  keepOriginal: inputs.keepOriginal.value,
389
402
  };
390
403
  const enumeratorResDf = await polyToolEnumerateHelm(srcHelm, srcId, params, inputs.toAtomicLevel.value, seqHelper);
@@ -399,6 +412,7 @@ async function getPolyToolEnumerateDialog(
399
412
  .add(inputs.macromolecule)
400
413
  .add(inputs.placeholders)
401
414
  .add(inputs.enumeratorType)
415
+ .add(inputs.placeholdersBreadth)
402
416
  .add(inputs.trivialNameCol)
403
417
  .add(inputs.toAtomicLevel)
404
418
  .add(inputs.keepOriginal)
@@ -412,20 +426,22 @@ async function getPolyToolEnumerateDialog(
412
426
  destroy();
413
427
  }));
414
428
  dialog.history(
415
- /* getInput */ (): PolyToolEnumerateSerialized => {
429
+ /* getInput */ (): PolyToolEnumerateHelmSerialized => {
416
430
  return {
417
431
  macromolecule: inputs.macromolecule.stringValue,
418
432
  placeholders: inputs.placeholders.stringValue,
419
433
  enumeratorType: inputs.enumeratorType.value,
434
+ placeholdersBreadth: inputs.placeholdersBreadth.stringValue,
420
435
  trivialNameCol: inputs.trivialNameCol.stringValue,
421
436
  toAtomicLevel: inputs.toAtomicLevel.value,
422
437
  keepOriginal: inputs.keepOriginal.value,
423
438
  };
424
439
  },
425
- /* applyInput */ (x: PolyToolEnumerateSerialized): void => {
440
+ /* applyInput */ (x: PolyToolEnumerateHelmSerialized): void => {
426
441
  inputs.macromolecule.stringValue = x.macromolecule;
427
442
  inputs.placeholders.stringValue = x.placeholders;
428
443
  inputs.enumeratorType.value = x.enumeratorType;
444
+ inputs.placeholdersBreadth.stringValue = x.placeholdersBreadth;
429
445
  inputs.trivialNameCol.stringValue = x.trivialNameCol;
430
446
  inputs.toAtomicLevel.value = x.toAtomicLevel;
431
447
  inputs.keepOriginal.value = x.keepOriginal;
@@ -453,9 +469,8 @@ async function polyToolEnumerateHelm(
453
469
  if (toAtomicLevel) {
454
470
  const seqHelper: ISeqHelper = await getSeqHelper();
455
471
  const toAtomicLevelRes = await seqHelper.helmToAtomicLevel(enumHelmCol, true, true);
456
- toAtomicLevelRes.molCol.semType = DG.SEMTYPE.MOLECULE;
457
- enumeratorResDf.columns.add(toAtomicLevelRes.molCol, false);
458
- enumeratorResDf.columns.add(toAtomicLevelRes.molHighlightCol, false);
472
+ toAtomicLevelRes.molCol!.semType = DG.SEMTYPE.MOLECULE;
473
+ enumeratorResDf.columns.add(toAtomicLevelRes.molCol!, false);
459
474
  }
460
475
 
461
476
  if (srcId) {
@@ -10,7 +10,7 @@ import {
10
10
 
11
11
  import {Chain} from './pt-conversion';
12
12
  import {getAvailableMonomers} from './utils';
13
- import {PolyToolEnumeratorParams, PolyToolEnumeratorTypes, PolyToolPlaceholders} from './types';
13
+ import {PolyToolEnumeratorParams, PolyToolEnumeratorTypes, PolyToolPlaceholders, PolyToolPlaceholdersBreadth} from './types';
14
14
 
15
15
  // For example keep monomers presented in HELMCoreLibrary.json only (not [NH2])
16
16
  export const PT_HELM_EXAMPLE = 'PEPTIDE1{R.[Aca].T.G.H.F.G.A.A.Y.P.E.[meI]}$$$$';
@@ -19,17 +19,21 @@ export const PT_HELM_EXAMPLE = 'PEPTIDE1{R.[Aca].T.G.H.F.G.A.A.Y.P.E.[meI]}$$$$'
19
19
  declare const JSDraw2: JSDraw2ModuleType;
20
20
  declare const org: OrgType;
21
21
 
22
- function polyToolEnumeratorCore(m: HelmMol, position: number, monomerList: string[]): HelmMol[] {
23
- const resMolList: HelmMol[] = new Array<HelmMol>(monomerList.length);
24
- for (let i = 0; i < monomerList.length; i++) {
25
- const newSymbol = monomerList[i];
26
- const resM = resMolList[i] = m.clone() as HelmMol;
27
- const oldSymbol = resM.atoms[position].elem;
28
- resM.atoms[position].elem = newSymbol;
22
+ function polyToolEnumeratorCore(m: HelmMol, start: number, end: number, monomerList: string[]): HelmMol[] {
23
+ const resMolList: HelmMol[] = new Array<HelmMol>(monomerList.length * (end - start + 1));
24
+ for (let monI: number = 0; monI < monomerList.length; ++monI) {
25
+ const posCount = end - start + 1;
26
+ for (let posI: number = 0; posI < posCount; ++posI) {
27
+ const pos = start + posI;
28
+ const newSymbol = monomerList[monI];
29
+ const resM = resMolList[monI * posCount + posI] = m.clone() as HelmMol;
30
+ const oldSymbol = resM.atoms[pos].elem;
31
+ resM.atoms[pos].elem = newSymbol;
29
32
 
30
- const idOldSymbol = oldSymbol?.length > 1 ? `[${oldSymbol}]` : oldSymbol;
31
- const idNewSymbol = newSymbol?.length > 1 ? `[${newSymbol}]` : newSymbol;
32
- resM.name = `${m.name}-${idOldSymbol}${position + 1}${idNewSymbol}`;
33
+ const idOldSymbol = oldSymbol?.length > 1 ? `[${oldSymbol}]` : oldSymbol;
34
+ const idNewSymbol = newSymbol?.length > 1 ? `[${newSymbol}]` : newSymbol;
35
+ resM.name = `${m.name}-${idOldSymbol}${pos + 1}${idNewSymbol}`;
36
+ }
33
37
  }
34
38
  return resMolList;
35
39
  }
@@ -40,18 +44,26 @@ function polyToolEnumeratorCore(m: HelmMol, position: number, monomerList: strin
40
44
  * @returns {string[]} List of enumerated molecules in Helm format
41
45
  */
42
46
  function getPtEnumeratorSingle(m: HelmMol, placeholders: PolyToolPlaceholders): HelmMol[] {
43
- const coreResList: HelmMol[][] = Object.entries(placeholders)
44
- .map(([p, monomerList]: [string, string[]]) => polyToolEnumeratorCore(m, parseInt(p), monomerList));
47
+ const coreResList: HelmMol[][] = placeholders
48
+ .map((ph) => polyToolEnumeratorCore(m, ph.position, ph.position, ph.monomers));
45
49
  const resMolList = coreResList.reduce((acc, posList) => acc.concat(posList), []);
46
50
  return resMolList;
47
51
  }
48
52
 
49
53
  function getPtEnumeratorMatrix(m: HelmMol, placeholders: PolyToolPlaceholders): HelmMol[] {
50
54
  let resMolList = [m];
51
- for (const [p, monomerList] of Object.entries(placeholders)) {
52
- const pos: number = parseInt(p);
53
- const posResMolList: HelmMol[][] = resMolList.map((m: HelmMol) => polyToolEnumeratorCore(m, pos, monomerList));
54
- resMolList = posResMolList.reduce((acc, l) => acc.concat(l), []);
55
+ for (const ph of placeholders) {
56
+ const phResMolList: HelmMol[][] = resMolList.map((m: HelmMol) => polyToolEnumeratorCore(m, ph.position, ph.position, ph.monomers));
57
+ resMolList = phResMolList.reduce((acc, l) => acc.concat(l), []);
58
+ }
59
+ return resMolList;
60
+ }
61
+
62
+ function getPtEnumeratorBreadth(m: HelmMol, placeholdersBreadth: PolyToolPlaceholdersBreadth): HelmMol[] {
63
+ let resMolList = [m];
64
+ for (const phb of placeholdersBreadth) {
65
+ const phResMolList: HelmMol[][] = resMolList.map((m: HelmMol) => polyToolEnumeratorCore(m, phb.start, phb.end, phb.monomers));
66
+ resMolList = phResMolList.reduce((acc, l) => acc.concat(l), []);
55
67
  }
56
68
  return resMolList;
57
69
  }
@@ -66,17 +78,25 @@ export function doPolyToolEnumerateHelm(
66
78
  const m = molHandler.m;
67
79
  m.name = id;
68
80
 
69
- let resMolList: HelmMol[];
70
- switch (params.type) {
71
- case PolyToolEnumeratorTypes.Single: {
72
- resMolList = getPtEnumeratorSingle(molHandler.m, params.placeholders);
73
- break;
74
- }
75
- case PolyToolEnumeratorTypes.Matrix: {
76
- resMolList = getPtEnumeratorMatrix(molHandler.m, params.placeholders);
77
- break;
81
+ let resMolList: HelmMol[] = [];
82
+ if (params.placeholders) {
83
+ switch (params.type) {
84
+ case PolyToolEnumeratorTypes.Single: {
85
+ resMolList = getPtEnumeratorSingle(molHandler.m, params.placeholders);
86
+ break;
87
+ }
88
+ case PolyToolEnumeratorTypes.Matrix: {
89
+ resMolList = getPtEnumeratorMatrix(molHandler.m, params.placeholders);
90
+ break;
91
+ }
92
+ }
78
93
  }
94
+
95
+ let resBreadthMolList: HelmMol[] = [];
96
+ if (params.placeholdersBreadth) {
97
+ resBreadthMolList = getPtEnumeratorBreadth(molHandler.m, params.placeholdersBreadth);
79
98
  }
99
+ resMolList = resMolList.concat(resBreadthMolList);
80
100
 
81
101
  if (params.keepOriginal)
82
102
  resMolList = [m, ...resMolList];
@@ -0,0 +1,111 @@
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 {Unsubscribable} from 'rxjs';
6
+ import {PolyToolPlaceholders, PolyToolPlaceholdersBreadth} from './types';
7
+ import {parseMonomerSymbolList} from './pt-placeholders-input';
8
+
9
+ export class PolyToolPlaceholdersBreadthInput extends DG.JsInputBase<DG.DataFrame> {
10
+ get inputType(): string { return 'Breadth'; }
11
+
12
+ get dataType(): string { return DG.TYPE.DATA_FRAME; }
13
+
14
+ getInput(): HTMLElement { return this.gridHost; }
15
+
16
+ getValue(): DG.DataFrame { return this.grid.dataFrame; }
17
+
18
+ setValue(value: DG.DataFrame): void { this.grid.dataFrame = value; }
19
+
20
+ getStringValue(): string { return this.grid.dataFrame.toCsv(); }
21
+
22
+ setStringValue(str: string): void { this.grid.dataFrame = DG.DataFrame.fromCsv(str); }
23
+
24
+ get placeholdersBreadthValue(): PolyToolPlaceholdersBreadth {
25
+ return dfToPlaceholdersBreadth(this.grid.dataFrame);
26
+ }
27
+
28
+ private readonly gridHost: HTMLDivElement;
29
+ public readonly grid: DG.Grid;
30
+
31
+ private subs: Unsubscribable[] = [];
32
+
33
+ protected constructor(name: string | undefined, grid: DG.Grid, heightRowCount?: number) {
34
+ super();
35
+
36
+ if (name) this.captionLabel.innerText = name;
37
+
38
+ this.gridHost = ui.div([], {
39
+ classes: 'ui-input-editor',
40
+ style: {width: '100%', height: '100%', marginTop: '-8px', marginBottom: '8px', paddingBottom: '4px'},
41
+ });
42
+
43
+ this.grid = grid;
44
+ this.gridHost.append(this.grid.root);
45
+
46
+ if (heightRowCount != null) {
47
+ this.updateGridHeight(heightRowCount + 0.7);
48
+ } else {
49
+ this.updateGridHeight(this.grid.dataFrame.rowCount + 0.6);
50
+ this.subs.push(this.grid.dataFrame.onRowsAdded
51
+ .subscribe(() => { this.updateGridHeight(this.grid.dataFrame.rowCount + 0.6); }));
52
+ }
53
+ this.grid.root.style.width = `100%`;
54
+
55
+ this.subs.push(this.grid.dataFrame.onDataChanged.subscribe(() => {
56
+ this.fireChanged();
57
+ }));
58
+
59
+ this.subs.push(ui.onSizeChanged(this.grid.root).subscribe(() => {
60
+ this.grid.columns.byIndex(3)!.width = this.grid.root.clientWidth - this.grid.horzScroll.root.offsetWidth -
61
+ this.grid.columns.byIndex(0)!.width - this.grid.columns.byIndex(1)!.width - this.grid.columns.byIndex(2)!.width - 10;
62
+ }));
63
+
64
+ this.root.classList.add('ui-input-polytool-pos-grid');
65
+ this.root.append(this.gridHost);
66
+ }
67
+
68
+ detach(): void {
69
+ for (const sub of this.subs) sub.unsubscribe();
70
+ }
71
+
72
+ public static async create(
73
+ name?: string, options?: {}, heightRowCount?: number
74
+ ): Promise<PolyToolPlaceholdersBreadthInput> {
75
+ const df: DG.DataFrame = DG.DataFrame.fromColumns([
76
+ DG.Column.fromType(DG.COLUMN_TYPE.INT, 'Start', 0),
77
+ DG.Column.fromType(DG.COLUMN_TYPE.INT, 'End', 0),
78
+ DG.Column.fromType(DG.COLUMN_TYPE.STRING, 'Monomers', 0),
79
+ ])!;
80
+ const grid = (await df.plot.fromType(DG.VIEWER.GRID, options)) as DG.Grid;
81
+ grid.sort(['Start', 'End']);
82
+ return new PolyToolPlaceholdersBreadthInput(name, grid, heightRowCount);
83
+ }
84
+
85
+ // -- Update view --
86
+
87
+ private updateGridHeight(visibleRowCount: number): void {
88
+ const gridHeight = this.grid.colHeaderHeight + visibleRowCount * this.grid.props.rowHeight + 6 + 2;
89
+ this.grid.root.style.height = `${gridHeight}px`;
90
+ }
91
+
92
+ // -- Handle events --
93
+
94
+ private gridRootOnSizeChanged(): void {
95
+ this.grid.columns.byIndex(3)!.width = this.grid.root.clientWidth - this.grid.horzScroll.root.offsetWidth -
96
+ this.grid.columns.byIndex(0)!.width - this.grid.columns.byIndex(1)!.width - this.grid.columns.byIndex(2)!.width - 10;
97
+ }
98
+ }
99
+
100
+ export function dfToPlaceholdersBreadth(df: DG.DataFrame): PolyToolPlaceholdersBreadth {
101
+ const res: PolyToolPlaceholdersBreadth = [];
102
+ for (let rowI = 0; rowI < df.rowCount; rowI++) {
103
+ const startPos = parseInt(df.get('Start', rowI));
104
+ const endPos = parseInt(df.get('End', rowI));
105
+ if (!isNaN(startPos) && !isNaN(endPos)) {
106
+ const monomerSymbolList = parseMonomerSymbolList(df.get('Monomers', rowI));
107
+ res.push({start: startPos, end: endPos, monomers: monomerSymbolList});
108
+ }
109
+ }
110
+ return res;
111
+ }
@@ -13,23 +13,15 @@ export class PolyToolPlaceholdersInput extends DG.JsInputBase<DG.DataFrame> {
13
13
 
14
14
  getInput(): HTMLElement { return this.gridHost; }
15
15
 
16
- getValue(): DG.DataFrame {
17
- return this.grid.dataFrame;
18
- }
16
+ getValue(): DG.DataFrame { return this.grid.dataFrame; }
19
17
 
20
- setValue(value: DG.DataFrame): void {
21
- this.grid.dataFrame = value;
22
- }
18
+ setValue(value: DG.DataFrame): void { this.grid.dataFrame = value; }
23
19
 
24
- getStringValue(): string {
25
- return this.grid.dataFrame.toCsv();
26
- }
20
+ getStringValue(): string { return this.grid.dataFrame.toCsv(); }
27
21
 
28
- setStringValue(str: string): void {
29
- this.grid.dataFrame = DG.DataFrame.fromCsv(str);
30
- }
22
+ setStringValue(str: string): void { this.grid.dataFrame = DG.DataFrame.fromCsv(str); }
31
23
 
32
- get placeholdersValue() {
24
+ get placeholdersValue(): PolyToolPlaceholders {
33
25
  return dfToPlaceholders(this.grid.dataFrame);
34
26
  }
35
27
 
@@ -80,7 +72,9 @@ export class PolyToolPlaceholdersInput extends DG.JsInputBase<DG.DataFrame> {
80
72
  public static async create(
81
73
  name?: string, options?: {}, heightRowCount?: number
82
74
  ): Promise<PolyToolPlaceholdersInput> {
83
- const df: DG.DataFrame = DG.DataFrame.fromObjects([{Position: '', Monomers: ''}])!;
75
+ const df: DG.DataFrame = DG.DataFrame.fromColumns([
76
+ DG.Column.fromType(DG.COLUMN_TYPE.INT, 'Position', 0),
77
+ DG.Column.fromType(DG.COLUMN_TYPE.STRING, 'Monomers', 0),])!;
84
78
  const grid = (await df.plot.fromType(DG.VIEWER.GRID, options)) as DG.Grid;
85
79
  grid.sort(['Position']);
86
80
  return new PolyToolPlaceholdersInput(name, grid, heightRowCount);
@@ -102,26 +96,25 @@ export class PolyToolPlaceholdersInput extends DG.JsInputBase<DG.DataFrame> {
102
96
  }
103
97
 
104
98
  export function getPlaceholdersFromText(src: string): PolyToolPlaceholders {
105
- const res: PolyToolPlaceholders = {};
99
+ const res: PolyToolPlaceholders = [];
106
100
  for (const line of src.split('\n')) {
107
101
  const lineM = /^\s*(?<pos>\d+)\s*:\s*(?<monomers>.+)$/.exec(line);
108
102
  if (lineM) {
109
103
  const pos: number = parseInt(lineM.groups!['pos']) - 1;
110
104
  const monomerList: string[] = lineM.groups!['monomers'].split(',').map((m) => m.trim());
111
- if (!(pos in res)) res[pos] = [];
112
- res[pos].push(...monomerList);
105
+ res.push({position: pos, monomers: monomerList});
113
106
  }
114
107
  }
115
108
  return res;
116
109
  }
117
110
 
118
111
  export function dfToPlaceholders(df: DG.DataFrame): PolyToolPlaceholders {
119
- const res: PolyToolPlaceholders = {};
112
+ const res: PolyToolPlaceholders = [];
120
113
  for (let rowI = 0; rowI < df.rowCount; rowI++) {
121
114
  const pos = parseInt(df.get('Position', rowI));
122
115
  if (!isNaN(pos)) {
123
116
  const monomerSymbolList = parseMonomerSymbolList(df.get('Monomers', rowI));
124
- res[pos - 1] = monomerSymbolList;
117
+ res.push({position: pos, monomers: monomerSymbolList});
125
118
  }
126
119
  }
127
120
  return res;
@@ -9,12 +9,15 @@ export enum PolyToolEnumeratorTypes {
9
9
 
10
10
  export type PolyToolEnumeratorType = typeof PolyToolEnumeratorTypes[keyof typeof PolyToolEnumeratorTypes];
11
11
 
12
- export type PolyToolPlaceholders = { [position: number]: string[] };
12
+ export type PolyToolPlaceholders = { position: number, monomers: string[] } [];
13
+
14
+ export type PolyToolPlaceholdersBreadth = { start: number, end: number, monomers: string[] }[];
13
15
 
14
16
  export type PolyToolEnumeratorParams = {
15
17
  type: PolyToolEnumeratorType;
16
18
  /** position key is zero-based */
17
- placeholders: PolyToolPlaceholders;
19
+ placeholders?: PolyToolPlaceholders;
20
+ placeholdersBreadth?: PolyToolPlaceholdersBreadth;
18
21
  keepOriginal?: boolean;
19
22
  trivialName?: boolean;
20
23
  }