@datagrok/sequence-translator 1.4.0 → 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.
- package/CHANGELOG.md +12 -0
- package/dist/package-test.js +1 -1
- package/dist/package-test.js.map +1 -1
- package/dist/package.js +1 -1
- package/dist/package.js.map +1 -1
- package/files/samples/cyclized.csv +1 -1
- package/package.json +4 -4
- package/src/apps/common/view/components/colored-input/colored-text-input.ts +1 -1
- package/src/apps/common/view/components/colored-input/style.css +2 -3
- package/src/apps/pattern/view/components/right-section.ts +6 -3
- package/src/apps/structure/view/ui.ts +9 -6
- package/src/apps/translator/view/style.css +0 -4
- package/src/apps/translator/view/ui.ts +10 -7
- package/src/demo/demo-st-ui.ts +1 -1
- package/src/package-test.ts +7 -1
- package/src/polytool/pt-conversion.ts +1 -3
- package/src/polytool/pt-convert-editor.ts +8 -8
- package/src/polytool/pt-dialog.ts +38 -10
- package/src/polytool/pt-enumeration-chem.ts +6 -10
- package/src/polytool/pt-enumeration-helm-dialog.ts +40 -25
- package/src/polytool/pt-enumeration-helm.ts +46 -26
- package/src/polytool/pt-placeholders-breadth-input.ts +111 -0
- package/src/polytool/pt-placeholders-input.ts +13 -20
- package/src/polytool/types.ts +5 -2
- package/src/tests/polytool-enumerate-breadth-tests.ts +118 -0
- package/src/tests/polytool-enumerate-tests.ts +39 -38
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.
|
|
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.
|
|
26
|
-
"@datagrok-libraries/chem-meta": "^1.2.
|
|
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.
|
|
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",
|
|
@@ -19,7 +19,7 @@ export class ColoredTextInput {
|
|
|
19
19
|
/** Resize, no scrolls */
|
|
20
20
|
resizeable: boolean = true
|
|
21
21
|
) {
|
|
22
|
-
$(this.root).addClass('colored-text-input');
|
|
22
|
+
$(this.root).addClass('st-colored-text-input');
|
|
23
23
|
if (resizeable) {
|
|
24
24
|
// make input field automatically resizeable
|
|
25
25
|
this.textInputBase.onChanged.subscribe(
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
.colored-text-input > textarea {
|
|
1
|
+
.st-colored-text-input > textarea {
|
|
2
2
|
width: 100%;
|
|
3
3
|
-webkit-text-fill-color: transparent;
|
|
4
4
|
background-color: transparent;
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
height: 22px; /* Fine tuned value to avoid "jumping" of the textarea upon autoresize */
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
.colored-text-input > div {
|
|
11
|
+
.st-colored-text-input > div {
|
|
12
12
|
/* The values here are fine tuned to those of the ui.input textarea in order
|
|
13
13
|
* to achieve precise overlap */
|
|
14
14
|
overflow: auto;
|
|
@@ -25,5 +25,4 @@
|
|
|
25
25
|
color: transparent;
|
|
26
26
|
white-space: pre-wrap;
|
|
27
27
|
word-wrap: break-word;
|
|
28
|
-
padding-left: 35px;
|
|
29
28
|
}
|
|
@@ -96,10 +96,10 @@ export class PatternAppRightSection {
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
const message = ui.divV([
|
|
99
|
-
ui.divText(`Author: ${author}`),
|
|
100
99
|
ui.divText(`Pattern Name: ${patternName}`),
|
|
101
|
-
ui.divText(`
|
|
102
|
-
ui.divText(`
|
|
100
|
+
ui.divText(`Author: ${author}`),
|
|
101
|
+
ui.divText(`Created: ${getInfoTimestamp(new Date(createDate))}`),
|
|
102
|
+
ui.divText(`Modified: ${getInfoTimestamp(new Date(modifyDate))}`),
|
|
103
103
|
]);
|
|
104
104
|
grok.shell.info(message);
|
|
105
105
|
}
|
|
@@ -195,3 +195,6 @@ class OverwritePatternDialog {
|
|
|
195
195
|
}
|
|
196
196
|
}
|
|
197
197
|
|
|
198
|
+
function getInfoTimestamp(date: Date): string {
|
|
199
|
+
return date.toLocaleString().split(':').slice(0, -1).join(':');
|
|
200
|
+
}
|
|
@@ -33,7 +33,15 @@ class StructureAppLayout {
|
|
|
33
33
|
this.onInvalidInput = new rxjs.Subject<string>();
|
|
34
34
|
this.inputBase = Object.fromEntries(
|
|
35
35
|
STRANDS.map(
|
|
36
|
-
(key) =>
|
|
36
|
+
(key) => {
|
|
37
|
+
const input = ui.input.textArea(key.toUpperCase(), {value: '', onValueChanged: () => {
|
|
38
|
+
this.onInput.next();
|
|
39
|
+
// WARNING: this fine tuning is necessary to fix layout within ui.form
|
|
40
|
+
// js-api version ^1.21
|
|
41
|
+
$(input.root.getElementsByTagName('div')).css('padding-left', '38px');
|
|
42
|
+
}});
|
|
43
|
+
return [key, input];
|
|
44
|
+
}
|
|
37
45
|
)
|
|
38
46
|
);
|
|
39
47
|
this.useChiralInput = ui.input.bool('Use chiral', {value: true});
|
|
@@ -165,11 +173,6 @@ class StructureAppLayout {
|
|
|
165
173
|
}
|
|
166
174
|
|
|
167
175
|
private getMolfile(ss: StrandData, as: StrandData, as2: StrandData): string {
|
|
168
|
-
// if (ss.strand === '' && (as.strand !== '' || as2.strand !== '')) {
|
|
169
|
-
// this.onInvalidInput.next();
|
|
170
|
-
// return '';
|
|
171
|
-
// }
|
|
172
|
-
|
|
173
176
|
return getLinkedMolfile(ss, as, as2, this.useChiralInput.value!, this.th);
|
|
174
177
|
}
|
|
175
178
|
|
|
@@ -10,8 +10,6 @@ import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
|
10
10
|
|
|
11
11
|
import {DEFAULT_FORMATS} from '../../common/model/const';
|
|
12
12
|
import {download} from '../../common/model/helpers';
|
|
13
|
-
import {FormatDetector} from '../../common/model/parsing-validation/format-detector';
|
|
14
|
-
import {SequenceValidator} from '../../common/model/parsing-validation/sequence-validator';
|
|
15
13
|
import {ColoredTextInput} from '../../common/view/components/colored-input/colored-text-input';
|
|
16
14
|
import {highlightInvalidSubsequence} from '../../common/view/components/colored-input/input-painters';
|
|
17
15
|
import {MoleculeImage} from '../../common/view/components/molecule-img';
|
|
@@ -20,11 +18,11 @@ import {IsolatedAppUIBase} from '../../common/view/isolated-app-ui';
|
|
|
20
18
|
import {MonomerLibViewer} from '../../common/view/monomer-lib-viewer';
|
|
21
19
|
import {SequenceToMolfileConverter} from '../../structure/model/sequence-to-molfile';
|
|
22
20
|
import {convert, getSupportedTargetFormats, getTranslatedSequences} from '../model/conversion-utils';
|
|
23
|
-
import {FormatConverter} from '../model/format-converter';
|
|
24
21
|
import {ITranslationHelper} from '../../../types';
|
|
25
22
|
|
|
26
23
|
import {NUCLEOTIDES_FORMAT, SEQUENCE_COPIED_MSG, SEQ_TOOLTIP_MSG} from './const';
|
|
27
24
|
import './style.css';
|
|
25
|
+
import $ from 'cash-dom';
|
|
28
26
|
import {_package} from '../../../package';
|
|
29
27
|
|
|
30
28
|
const enum REQUIRED_COLUMN_LABEL {
|
|
@@ -55,7 +53,12 @@ class TranslatorAppLayout {
|
|
|
55
53
|
await this.updateMolImg();
|
|
56
54
|
}
|
|
57
55
|
});
|
|
58
|
-
|
|
56
|
+
|
|
57
|
+
$(this.formatChoiceInput.root.getElementsByTagName('select')[0]).css('width', '20%');
|
|
58
|
+
|
|
59
|
+
this.sequenceInputBase = ui.input.textArea(
|
|
60
|
+
'', {value: DEFAULT_AXOLABS_INPUT, onValueChanged: () => { this.onInput.next(); }}
|
|
61
|
+
);
|
|
59
62
|
|
|
60
63
|
this.init();
|
|
61
64
|
|
|
@@ -457,9 +460,9 @@ class ColumnInputsManager {
|
|
|
457
460
|
this.selectColumnIfTableNotNull(selectedTable, selectedColumnName, columnLabel);
|
|
458
461
|
|
|
459
462
|
const input = ui.input.choice(`${columnLabel}`, {
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
+
value: selectedColumnName, items: columnNames,
|
|
464
|
+
onValueChanged: (value) => this.selectColumnIfTableNotNull(selectedTable, value, columnLabel)
|
|
465
|
+
}
|
|
463
466
|
);
|
|
464
467
|
|
|
465
468
|
return input;
|
package/src/demo/demo-st-ui.ts
CHANGED
|
@@ -24,7 +24,7 @@ export async function demoOligoStructureUI() {
|
|
|
24
24
|
await tryCatch(async () => {
|
|
25
25
|
async function setInputValue(idx: number, sequence: string): Promise<void> {
|
|
26
26
|
await delay(500);
|
|
27
|
-
const textInputs: NodeListOf<HTMLTextAreaElement> = document.querySelectorAll('.colored-text-input > textarea');
|
|
27
|
+
const textInputs: NodeListOf<HTMLTextAreaElement> = document.querySelectorAll('.st-colored-text-input > textarea');
|
|
28
28
|
const textarea = textInputs[idx];
|
|
29
29
|
textarea.value = sequence;
|
|
30
30
|
const event = new Event('input');
|
package/src/package-test.ts
CHANGED
|
@@ -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
|
+
}
|
|
@@ -269,9 +269,7 @@ export class Chain {
|
|
|
269
269
|
export function doPolyToolConvert(sequences: string[], rules: Rules): string[] {
|
|
270
270
|
const helms = new Array<string>(sequences.length);
|
|
271
271
|
for (let i = 0; i < sequences.length; i++) {
|
|
272
|
-
if (sequences[i] === undefined)
|
|
273
|
-
helms[i] = '';
|
|
274
|
-
else {
|
|
272
|
+
if (sequences[i] === undefined) { helms[i] = ''; } else {
|
|
275
273
|
const chain = Chain.fromNotation(sequences[i], rules);
|
|
276
274
|
helms[i] = chain.getHelm();
|
|
277
275
|
}
|
|
@@ -74,14 +74,14 @@ export class PolyToolConvertFuncEditor {
|
|
|
74
74
|
|
|
75
75
|
public async showDialog(): Promise<DG.Column<string>> {
|
|
76
76
|
const formDiv = ui.div([
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
77
|
+
this.inputs.table,
|
|
78
|
+
this.inputs.seqCol,
|
|
79
|
+
this.inputs.generateHelm,
|
|
80
|
+
this.inputs.chiralityEngine,
|
|
81
|
+
this.inputs.rules.header,
|
|
82
|
+
this.inputs.rules.form,
|
|
83
|
+
],
|
|
84
|
+
{style: {minWidth: '320px'}});
|
|
85
85
|
|
|
86
86
|
return new Promise((resolve, reject) => {
|
|
87
87
|
ui.dialog({title: PT_UI_DIALOG_CONVERSION})
|
|
@@ -3,7 +3,6 @@ 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';
|
|
7
6
|
import {Unsubscribable} from 'rxjs';
|
|
8
7
|
|
|
9
8
|
import {getHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
|
|
@@ -24,6 +23,16 @@ import {
|
|
|
24
23
|
|
|
25
24
|
import {_package} from '../package';
|
|
26
25
|
|
|
26
|
+
type PolyToolConvertSerialized = {
|
|
27
|
+
generateHelm: boolean;
|
|
28
|
+
chiralityEngine: boolean;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
type PolyToolEnumerateChemSerialized = {
|
|
32
|
+
mol: string;
|
|
33
|
+
screenLibrary: string | null;
|
|
34
|
+
}
|
|
35
|
+
|
|
27
36
|
export function polyToolEnumerateChemUI(cell?: DG.Cell): void {
|
|
28
37
|
getPolyToolEnumerationChemDialog(cell)
|
|
29
38
|
.then((dialog) => {
|
|
@@ -80,7 +89,6 @@ export async function getPolyToolConvertDialog(targetCol?: DG.Column): Promise<D
|
|
|
80
89
|
rulesForm
|
|
81
90
|
]);
|
|
82
91
|
|
|
83
|
-
|
|
84
92
|
const exec = async (): Promise<void> => {
|
|
85
93
|
try {
|
|
86
94
|
const ruleFileList = await ruleInputs.getActive();
|
|
@@ -96,7 +104,17 @@ export async function getPolyToolConvertDialog(targetCol?: DG.Column): Promise<D
|
|
|
96
104
|
subs.push(dialog.onClose.subscribe(() => {
|
|
97
105
|
destroy();
|
|
98
106
|
}));
|
|
99
|
-
|
|
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
|
+
});
|
|
100
118
|
return dialog;
|
|
101
119
|
} catch (err: any) {
|
|
102
120
|
destroy(); // on failing to build a dialog
|
|
@@ -110,7 +128,6 @@ async function getPolyToolEnumerationChemDialog(cell?: DG.Cell): Promise<DG.Dial
|
|
|
110
128
|
for (const sub of subs) sub.unsubscribe();
|
|
111
129
|
};
|
|
112
130
|
try {
|
|
113
|
-
|
|
114
131
|
const [libList, helmHelper] = await Promise.all([
|
|
115
132
|
getLibrariesList(), getHelmHelper()]);
|
|
116
133
|
|
|
@@ -135,15 +152,15 @@ async function getPolyToolEnumerationChemDialog(cell?: DG.Cell): Promise<DG.Dial
|
|
|
135
152
|
molInput.setMolFile(molfileValue);
|
|
136
153
|
|
|
137
154
|
//const helmInput = helmHelper.createHelmInput('Macromolecule', {value: helmValue});
|
|
138
|
-
const
|
|
155
|
+
const screenLibraryInput = ui.input.choice('Library to use', {value: null, items: libList});
|
|
139
156
|
|
|
140
157
|
molInput.root.setAttribute('style', `min-width:250px!important;`);
|
|
141
158
|
molInput.root.setAttribute('style', `max-width:250px!important;`);
|
|
142
|
-
|
|
159
|
+
screenLibraryInput.input.setAttribute('style', `min-width:250px!important;`);
|
|
143
160
|
|
|
144
161
|
const div = ui.div([
|
|
145
162
|
molInput.root,
|
|
146
|
-
|
|
163
|
+
screenLibraryInput.root
|
|
147
164
|
]);
|
|
148
165
|
|
|
149
166
|
subs.push(grok.events.onCurrentCellChanged.subscribe(() => {
|
|
@@ -162,7 +179,7 @@ async function getPolyToolEnumerationChemDialog(cell?: DG.Cell): Promise<DG.Dial
|
|
|
162
179
|
} else if (!molString.includes('R#')) {
|
|
163
180
|
grok.shell.warning('PolyTool: no R group was provided');
|
|
164
181
|
} else {
|
|
165
|
-
const molecules = await getEnumerationChem(molString,
|
|
182
|
+
const molecules = await getEnumerationChem(molString, screenLibraryInput.value!);
|
|
166
183
|
const molCol = DG.Column.fromStrings('Enumerated', molecules);
|
|
167
184
|
const df = DG.DataFrame.fromColumns([molCol]);
|
|
168
185
|
grok.shell.addTableView(df);
|
|
@@ -184,6 +201,17 @@ async function getPolyToolEnumerationChemDialog(cell?: DG.Cell): Promise<DG.Dial
|
|
|
184
201
|
subs.push(dialog.onClose.subscribe(() => {
|
|
185
202
|
destroy();
|
|
186
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
|
+
});
|
|
187
215
|
return dialog;
|
|
188
216
|
} catch (err: any) {
|
|
189
217
|
destroy();
|
|
@@ -209,7 +237,7 @@ export async function polyToolConvert(
|
|
|
209
237
|
|
|
210
238
|
const resHelmColName = getUnusedName(table, `transformed(${seqCol.name})`);
|
|
211
239
|
const resHelmCol = DG.Column.fromType(DG.COLUMN_TYPE.STRING, resHelmColName, resList.length)
|
|
212
|
-
.init((rowIdx: number) => { return resList[rowIdx];});
|
|
240
|
+
.init((rowIdx: number) => { return resList[rowIdx]; });
|
|
213
241
|
resHelmCol.semType = DG.SEMTYPE.MACROMOLECULE;
|
|
214
242
|
resHelmCol.meta.units = NOTATION.HELM;
|
|
215
243
|
resHelmCol.setTag(DG.TAGS.CELL_RENDERER, 'helm');
|
|
@@ -217,7 +245,7 @@ export async function polyToolConvert(
|
|
|
217
245
|
|
|
218
246
|
const seqHelper: ISeqHelper = await getSeqHelper();
|
|
219
247
|
const toAtomicLevelRes = await seqHelper.helmToAtomicLevel(resHelmCol, chiralityEngine, /* highlight */ generateHelm);
|
|
220
|
-
const resMolCol = toAtomicLevelRes.molCol
|
|
248
|
+
const resMolCol = toAtomicLevelRes.molCol!;
|
|
221
249
|
resMolCol.name = getUnusedName(table, `molfile(${seqCol.name})`);
|
|
222
250
|
resMolCol.semType = DG.SEMTYPE.MOLECULE;
|
|
223
251
|
if (table) {
|
|
@@ -60,12 +60,11 @@ M END`;
|
|
|
60
60
|
|
|
61
61
|
export async function getEnumerationChem(molString: string, screenLibrary: string):
|
|
62
62
|
Promise<string[]> {
|
|
63
|
-
|
|
64
63
|
const variableMonomers = await getAvailableMonomers(screenLibrary);
|
|
65
64
|
const variableMols = await getAvailableMonomerMols(screenLibrary);
|
|
66
65
|
const enumerations = new Array<string>(variableMonomers.length);
|
|
67
66
|
|
|
68
|
-
|
|
67
|
+
const rdkitModule: RDModule = await grok.functions.call('Chem:getRdKitModule');
|
|
69
68
|
const molScaffold: RDMol = rdkitModule.get_mol(molString);
|
|
70
69
|
const smiScaffold = molScaffold.get_smiles();
|
|
71
70
|
molScaffold.delete();
|
|
@@ -73,7 +72,6 @@ export async function getEnumerationChem(molString: string, screenLibrary: strin
|
|
|
73
72
|
const smilesSubsts = new Array<string>(variableMonomers.length);
|
|
74
73
|
|
|
75
74
|
for (let i = 0; i < variableMonomers.length; i++) {
|
|
76
|
-
|
|
77
75
|
const name = variableMonomers[i];
|
|
78
76
|
const molBlock = variableMols[name];
|
|
79
77
|
const molSubst: RDMol = rdkitModule.get_mol(molBlock);
|
|
@@ -87,18 +85,16 @@ export async function getEnumerationChem(molString: string, screenLibrary: strin
|
|
|
87
85
|
//TODO: use RDKit linking function when exposed
|
|
88
86
|
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
87
|
const smiRes = `${smiResRaw}`.replaceAll('([1*])', '9').replaceAll('[1*]', '9');
|
|
90
|
-
molRes = rdkitModule.get_mol(smiRes, JSON.stringify({mappedDummiesAreRGroups: true}))
|
|
91
|
-
|
|
88
|
+
molRes = rdkitModule.get_mol(smiRes, JSON.stringify({mappedDummiesAreRGroups: true}));
|
|
89
|
+
const molV3 = molRes.get_v3Kmolblock();
|
|
92
90
|
enumerations[i] = molV3;
|
|
93
|
-
}
|
|
94
|
-
catch(err:any) {
|
|
91
|
+
} catch (err:any) {
|
|
95
92
|
enumerations[i] = '';
|
|
96
|
-
}
|
|
97
|
-
finally {
|
|
93
|
+
} finally {
|
|
98
94
|
molRes?.delete();
|
|
99
95
|
}
|
|
100
96
|
}
|
|
101
|
-
|
|
97
|
+
|
|
102
98
|
|
|
103
99
|
return enumerations;
|
|
104
100
|
}
|
|
@@ -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,
|
|
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
|
|
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;
|
|
@@ -82,9 +85,9 @@ export async function polyToolEnumerateHelmUI(cell?: DG.Cell): Promise<void> {
|
|
|
82
85
|
if (isFirstShow) {
|
|
83
86
|
const dialogInputList = dialog.inputs;
|
|
84
87
|
const dialogRootCash = $(dialog.root);
|
|
85
|
-
const contentMaxHeight = maxHeight
|
|
86
|
-
|
|
87
|
-
|
|
88
|
+
const contentMaxHeight = maxHeight -
|
|
89
|
+
dialogRootCash.find('div.d4-dialog-header').get(0)!.offsetHeight -
|
|
90
|
+
dialogRootCash.find('div.d4-dialog-footer').get(0)!.offsetHeight;
|
|
88
91
|
|
|
89
92
|
// dialog.inputs2.macromolecule.root.style.backgroundColor = '#CCFFCC';
|
|
90
93
|
|
|
@@ -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
|
-
|
|
145
|
-
'
|
|
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
|
-
}
|
|
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:
|
|
184
|
-
for (const
|
|
185
|
-
const pos =
|
|
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
|
|
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
|
|
232
|
-
|
|
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(', '));
|
|
@@ -259,9 +269,9 @@ async function getPolyToolEnumerateDialog(
|
|
|
259
269
|
let rowIdx = posList.indexOf(clickedAtomContIdxStr);
|
|
260
270
|
if (rowIdx === -1) {
|
|
261
271
|
rowIdx = posList.findIndex((v) => isNaN(v));
|
|
262
|
-
if (rowIdx === -1)
|
|
272
|
+
if (rowIdx === -1)
|
|
263
273
|
rowIdx = phDf.rows.addNew([clickedAtomContIdxStr, '']).idx;
|
|
264
|
-
|
|
274
|
+
|
|
265
275
|
phDf.set('Position', rowIdx, clickedAtomContIdxStr);
|
|
266
276
|
// const tgtCell = inputs.placeholders.grid.cell('Monomers', rowIdx);
|
|
267
277
|
}
|
|
@@ -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 */ ():
|
|
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:
|
|
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
|
|
457
|
-
enumeratorResDf.columns.add(toAtomicLevelRes.molCol
|
|
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) {
|