@datagrok/sequence-translator 1.10.10 → 1.10.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/dist/455.js +1 -1
- package/dist/455.js.map +1 -1
- 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/package.json +6 -5
- package/src/apps/common/view/components/colored-input/style.css +3 -1
- package/src/apps/structure/view/style.css +15 -3
- package/src/apps/structure/view/ui.ts +2 -8
- package/src/apps/translator/view/ui.ts +7 -5
- package/src/polytool/pt-enumerate-seq-dialog.ts +93 -34
- package/test-console-output-1.log +87 -85
- package/test-record-1.mp4 +0 -0
- package/webpack.config.js +1 -22
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datagrok/sequence-translator",
|
|
3
3
|
"friendlyName": "Sequence Translator",
|
|
4
|
-
"version": "1.10.
|
|
4
|
+
"version": "1.10.12",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Davit Rizhinashvili",
|
|
7
7
|
"email": "drizhinashvili@datagrok.ai"
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
}
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@datagrok-libraries/bio": "^5.
|
|
25
|
+
"@datagrok-libraries/bio": "^5.63.6",
|
|
26
26
|
"@datagrok-libraries/chem-meta": "^1.2.8",
|
|
27
27
|
"@datagrok-libraries/tutorials": "^1.6.1",
|
|
28
28
|
"@datagrok-libraries/utils": "^4.6.5",
|
|
@@ -42,9 +42,9 @@
|
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@datagrok-libraries/helm-web-editor": "^1.1.16",
|
|
44
44
|
"@datagrok-libraries/js-draw-lite": "^0.0.10",
|
|
45
|
-
"@datagrok/bio": "^2.
|
|
46
|
-
"@datagrok/chem": "^1.
|
|
47
|
-
"@datagrok/helm": "^2.
|
|
45
|
+
"@datagrok/bio": "^2.26.0",
|
|
46
|
+
"@datagrok/chem": "^1.17.0",
|
|
47
|
+
"@datagrok/helm": "^2.13.0",
|
|
48
48
|
"@types/jquery": "^3.5.32",
|
|
49
49
|
"@types/js-yaml": "^4.0.5",
|
|
50
50
|
"@types/lodash": "^4.14.202",
|
|
@@ -55,6 +55,7 @@
|
|
|
55
55
|
"@typescript-eslint/eslint-plugin": "^7.2.0",
|
|
56
56
|
"@typescript-eslint/parser": "^7.2.0",
|
|
57
57
|
"css-loader": "^6.7.3",
|
|
58
|
+
"datagrok-tools": "^5.0.0",
|
|
58
59
|
"eslint": "^8.57.0",
|
|
59
60
|
"eslint-config-google": "^0.14.0",
|
|
60
61
|
"style-loader": "^3.3.1",
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
.st-colored-text-input > textarea {
|
|
2
2
|
width: 100%;
|
|
3
|
-
|
|
3
|
+
color: transparent !important;
|
|
4
|
+
caret-color: var(--grey-6);
|
|
5
|
+
-webkit-text-fill-color: transparent !important;
|
|
4
6
|
background-color: transparent;
|
|
5
7
|
position: relative;
|
|
6
8
|
z-index: 1;
|
|
@@ -2,11 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
.st-structure-body {
|
|
4
4
|
padding-right: 20px;
|
|
5
|
+
height: 100%;
|
|
6
|
+
display: flex;
|
|
7
|
+
flex-direction: column;
|
|
5
8
|
}
|
|
6
9
|
|
|
7
10
|
.st-structure-mol-img {
|
|
8
|
-
|
|
9
|
-
|
|
11
|
+
flex: 1 1 0;
|
|
12
|
+
min-height: 100px;
|
|
13
|
+
min-width: 0;
|
|
14
|
+
transform: translateX(-50px);
|
|
15
|
+
overflow: hidden;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.st-structure-mol-img canvas {
|
|
19
|
+
max-width: 100% !important;
|
|
20
|
+
height: auto !important;
|
|
10
21
|
}
|
|
11
22
|
|
|
12
23
|
.st-structure-bool-button-block {
|
|
@@ -15,8 +26,9 @@
|
|
|
15
26
|
}
|
|
16
27
|
|
|
17
28
|
.st-structure-bottom {
|
|
18
|
-
flex
|
|
29
|
+
flex: 1 1 0;
|
|
19
30
|
padding-top: 20px;
|
|
31
|
+
min-height: 0;
|
|
20
32
|
}
|
|
21
33
|
|
|
22
34
|
.st-structure-clear-buttons {
|
|
@@ -52,7 +52,6 @@ class StructureAppLayout {
|
|
|
52
52
|
);
|
|
53
53
|
this.moleculeImgDiv = ui.block([]);
|
|
54
54
|
$(this.moleculeImgDiv).addClass('st-structure-mol-img');
|
|
55
|
-
|
|
56
55
|
DG.debounce<string>(this.onInput, 300).subscribe(async () => {
|
|
57
56
|
await this.updateMoleculeImg();
|
|
58
57
|
});
|
|
@@ -74,7 +73,7 @@ class StructureAppLayout {
|
|
|
74
73
|
const tableLayout = this.getTableInput(th);
|
|
75
74
|
const boolInputsAndButton = this.getBoolInputsAndButton();
|
|
76
75
|
await this.updateMoleculeImg();
|
|
77
|
-
const bottomDiv = ui.divH([
|
|
76
|
+
const bottomDiv = ui.divH([this.moleculeImgDiv, boolInputsAndButton]);
|
|
78
77
|
$(bottomDiv).addClass('st-structure-bottom');
|
|
79
78
|
|
|
80
79
|
const layout = ui.divV([tableLayout, bottomDiv]);
|
|
@@ -186,13 +185,8 @@ class StructureAppLayout {
|
|
|
186
185
|
const errStr = errorToConsole(err);
|
|
187
186
|
console.error(errStr);
|
|
188
187
|
}
|
|
189
|
-
// todo: compute relative numbers
|
|
190
|
-
const canvasWidth = 650;
|
|
191
|
-
const canvasHeight = 150;
|
|
192
188
|
const molImgObj = new MoleculeImage(molfile);
|
|
193
|
-
await molImgObj.drawMolecule(this.moleculeImgDiv,
|
|
194
|
-
// should the canvas be returned from the above function?
|
|
195
|
-
$(this.moleculeImgDiv).find('canvas').css('float', 'inherit');
|
|
189
|
+
await molImgObj.drawMolecule(this.moleculeImgDiv, 650, 150);
|
|
196
190
|
}
|
|
197
191
|
}
|
|
198
192
|
|
|
@@ -56,8 +56,6 @@ class TranslatorAppLayout {
|
|
|
56
56
|
}
|
|
57
57
|
});
|
|
58
58
|
|
|
59
|
-
$(this.formatChoiceInput.root.getElementsByTagName('select')[0]).css('width', '20%');
|
|
60
|
-
|
|
61
59
|
this.sequenceInputBase = ui.input.textArea(
|
|
62
60
|
'', {value: DEFAULT_AXOLABS_INPUT, onValueChanged: () => { this.onInput.next(); }}
|
|
63
61
|
);
|
|
@@ -235,9 +233,13 @@ class TranslatorAppLayout {
|
|
|
235
233
|
}
|
|
236
234
|
|
|
237
235
|
private saveMolfile(): void {
|
|
238
|
-
|
|
239
|
-
this.
|
|
240
|
-
|
|
236
|
+
try {
|
|
237
|
+
const result = (new SequenceToMolfileConverter(this.sequence, false,
|
|
238
|
+
this.formatChoiceInput.value!)).convert() + '\n$$$$';
|
|
239
|
+
download(this.sequence + '.sdf', encodeURIComponent(result));
|
|
240
|
+
} catch (e: any) {
|
|
241
|
+
grok.shell.warning('Unable to save SDF: ' + e.message);
|
|
242
|
+
}
|
|
241
243
|
}
|
|
242
244
|
|
|
243
245
|
private copySmiles(): void {
|
|
@@ -16,7 +16,6 @@ import {helmTypeToPolymerType} from '@datagrok-libraries/bio/src/monomer-works/m
|
|
|
16
16
|
import {getSeqHelper} from '@datagrok-libraries/bio/src/utils/seq-helper';
|
|
17
17
|
import '@datagrok-libraries/bio/src/types/input';
|
|
18
18
|
import {errInfo} from '@datagrok-libraries/bio/src/utils/err-info';
|
|
19
|
-
import {InputColumnBase} from '@datagrok-libraries/bio/src/types/input';
|
|
20
19
|
import {SeqValueBase} from '@datagrok-libraries/bio/src/utils/macromolecule/seq-handler';
|
|
21
20
|
import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
22
21
|
import {SeqTemps} from '@datagrok-libraries/bio/src/utils/macromolecule/seq-handler';
|
|
@@ -60,7 +59,8 @@ type PolyToolEnumerateInputs = {
|
|
|
60
59
|
placeholders: PolyToolPlaceholdersInput;
|
|
61
60
|
placeholdersBreadth: PolyToolPlaceholdersBreadthInput;
|
|
62
61
|
enumeratorType: DG.ChoiceInput<PolyToolEnumeratorType>
|
|
63
|
-
|
|
62
|
+
trivialName: DG.InputBase<string>,
|
|
63
|
+
appendToTable: DG.InputBase<DG.DataFrame | null>,
|
|
64
64
|
keepOriginal: DG.InputBase<boolean>;
|
|
65
65
|
toAtomicLevel: DG.InputBase<boolean>;
|
|
66
66
|
generateHelm: DG.InputBase<boolean>;
|
|
@@ -75,7 +75,7 @@ type PolyToolEnumerateHelmSerialized = {
|
|
|
75
75
|
placeholders: string;
|
|
76
76
|
placeholdersBreadth: string;
|
|
77
77
|
enumeratorType: PolyToolEnumeratorType;
|
|
78
|
-
|
|
78
|
+
trivialName: string;
|
|
79
79
|
keepOriginal: boolean;
|
|
80
80
|
toAtomicLevel: boolean;
|
|
81
81
|
generateHelm: boolean;
|
|
@@ -170,7 +170,6 @@ async function getPolyToolEnumerateDialog(
|
|
|
170
170
|
const libHelper = await getMonomerLibHelper();
|
|
171
171
|
const monomerLib = libHelper.getMonomerLib();
|
|
172
172
|
const seqHelper = await getSeqHelper();
|
|
173
|
-
const emptyDf: DG.DataFrame = DG.DataFrame.fromColumns([]);
|
|
174
173
|
|
|
175
174
|
const helmHelper = await getHelmHelper();
|
|
176
175
|
const monomerLibFuncs = helmHelper.buildMonomersFuncsFromLib(monomerLib);
|
|
@@ -216,8 +215,10 @@ async function getPolyToolEnumerateDialog(
|
|
|
216
215
|
let srcId: { value: string, colName: string } | null = null;
|
|
217
216
|
let ruleFileList: string[];
|
|
218
217
|
let ruleInputs: RuleInputs;
|
|
219
|
-
const trivialNameSampleDiv = ui.divText('', {style: {marginLeft: '8px', marginTop: '2px'}});
|
|
220
218
|
const warningsTextDiv = ui.divText('', {style: {color: 'red'}});
|
|
219
|
+
const resultCountDiv = ui.divText('', {style: {
|
|
220
|
+
fontSize: '11px', color: 'var(--grey-4)', marginTop: '2px', marginLeft: '4px', whiteSpace: 'nowrap',
|
|
221
|
+
}});
|
|
221
222
|
|
|
222
223
|
// === INPUT DEFINITIONS ===
|
|
223
224
|
inputs = {
|
|
@@ -288,22 +289,17 @@ async function getPolyToolEnumerateDialog(
|
|
|
288
289
|
onValueChanged: (value: string[]) => { ruleFileList = value; }
|
|
289
290
|
})).getForm()
|
|
290
291
|
},
|
|
291
|
-
|
|
292
|
+
trivialName: ui.input.string(
|
|
292
293
|
'Trivial name', {
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
onValueChanged: (): void => {
|
|
298
|
-
const valueCol = inputs.trivialNameCol.value;
|
|
299
|
-
let newSrcId: typeof srcId = null;
|
|
300
|
-
if (cell && valueCol) {
|
|
301
|
-
const originalId = valueCol.get(cell.rowIndex)!;
|
|
302
|
-
newSrcId = {value: originalId, colName: valueCol.name};
|
|
303
|
-
}
|
|
304
|
-
srcId = newSrcId;
|
|
305
|
-
trivialNameSampleDiv.textContent = srcId ? `Original ID: ${srcId.value}` : '';
|
|
294
|
+
value: '',
|
|
295
|
+
onValueChanged: (value: string): void => {
|
|
296
|
+
const trimmed = value?.trim();
|
|
297
|
+
srcId = trimmed ? {value: trimmed, colName: 'Trivial name'} : null;
|
|
306
298
|
},
|
|
299
|
+
}),
|
|
300
|
+
appendToTable: ui.input.table(
|
|
301
|
+
'Append to table', {
|
|
302
|
+
items: grok.shell.tables,
|
|
307
303
|
nullable: true,
|
|
308
304
|
}),
|
|
309
305
|
};
|
|
@@ -316,7 +312,22 @@ async function getPolyToolEnumerateDialog(
|
|
|
316
312
|
};
|
|
317
313
|
updateEnumTypeTooltip();
|
|
318
314
|
|
|
319
|
-
|
|
315
|
+
// Attach a "pick from column" icon button to the trivial name input
|
|
316
|
+
if (cell?.dataFrame) {
|
|
317
|
+
const colIcon = ui.iconFA('columns', (e: MouseEvent) => {
|
|
318
|
+
DG.Menu.popup()
|
|
319
|
+
.singleColumnSelector(cell.dataFrame, {
|
|
320
|
+
columnFilter: (col: DG.Column) => col.type === DG.COLUMN_TYPE.STRING && col !== cell.column,
|
|
321
|
+
onChange: (_grid, col: DG.Column, currentRowChanged: boolean) => {
|
|
322
|
+
if (currentRowChanged)
|
|
323
|
+
inputs.trivialName.value = col.get(cell.rowIndex) ?? '';
|
|
324
|
+
},
|
|
325
|
+
})
|
|
326
|
+
.show({x: e.clientX, y: e.clientY});
|
|
327
|
+
}, 'Pick trivial name from a column');
|
|
328
|
+
inputs.trivialName.addOptions(colIcon);
|
|
329
|
+
}
|
|
330
|
+
inputs.trivialName.root.style.maxWidth = '450px';
|
|
320
331
|
|
|
321
332
|
// Wire up monomer cell double-click to open selection dialog
|
|
322
333
|
inputs.placeholders.onMonomerCellEdit = async (position: number, currentMonomers: string[]) => {
|
|
@@ -511,7 +522,9 @@ async function getPolyToolEnumerateDialog(
|
|
|
511
522
|
defaultErrorHandler(err);
|
|
512
523
|
}
|
|
513
524
|
}));
|
|
514
|
-
subs.push(inputs.placeholders.onChanged.subscribe(() => { updateViewMol(); }));
|
|
525
|
+
subs.push(inputs.placeholders.onChanged.subscribe(() => { updateViewMol(); updateResultCount(); }));
|
|
526
|
+
subs.push(inputs.placeholdersBreadth.onChanged.subscribe(() => { updateResultCount(); }));
|
|
527
|
+
subs.push(inputs.keepOriginal.onChanged.subscribe(() => { updateResultCount(); }));
|
|
515
528
|
|
|
516
529
|
// TODO: suspect
|
|
517
530
|
subs.push(ui.onSizeChanged(inputs.placeholders.root).subscribe(() => {
|
|
@@ -587,14 +600,49 @@ async function getPolyToolEnumerateDialog(
|
|
|
587
600
|
//resizeInputs();
|
|
588
601
|
};
|
|
589
602
|
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
inputs.
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
603
|
+
// Computes expected result count from current placeholders, breadth, and enumeration type
|
|
604
|
+
const updateResultCount = () => {
|
|
605
|
+
try {
|
|
606
|
+
const phs = inputs.placeholders.placeholdersValue.filter((ph) => ph.monomers.length > 0);
|
|
607
|
+
const bphs = inputs.placeholdersBreadth.placeholdersBreadthValue
|
|
608
|
+
.filter((ph) => ph.monomers.length > 0 && ph.start != null && ph.end != null);
|
|
609
|
+
|
|
610
|
+
let regularCount = 0;
|
|
611
|
+
switch (inputs.enumeratorType.value) {
|
|
612
|
+
case PolyToolEnumeratorTypes.Single:
|
|
613
|
+
regularCount = phs.reduce((sum, ph) => sum + ph.monomers.length, 0);
|
|
614
|
+
break;
|
|
615
|
+
case PolyToolEnumeratorTypes.Parallel: {
|
|
616
|
+
if (phs.length > 0) {
|
|
617
|
+
const allEqual = phs.every((ph) => ph.monomers.length === phs[0].monomers.length);
|
|
618
|
+
regularCount = allEqual ? phs[0].monomers.length : 0;
|
|
619
|
+
}
|
|
620
|
+
break;
|
|
621
|
+
}
|
|
622
|
+
case PolyToolEnumeratorTypes.Matrix:
|
|
623
|
+
regularCount = phs.length > 0 ? phs.reduce((prod, ph) => prod * ph.monomers.length, 1) : 0;
|
|
624
|
+
break;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
let breadthCount = 0;
|
|
628
|
+
if (bphs.length > 0) {
|
|
629
|
+
breadthCount = bphs.reduce((prod, ph) => {
|
|
630
|
+
const rangeSize = Math.abs(ph.end - ph.start) + 1;
|
|
631
|
+
return prod * (ph.monomers.length * rangeSize);
|
|
632
|
+
}, 1);
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
let total = regularCount + breadthCount;
|
|
636
|
+
if (inputs.keepOriginal.value && total > 0)
|
|
637
|
+
total += 1;
|
|
638
|
+
|
|
639
|
+
resultCountDiv.textContent = total > 0 ? `${total} sequence${total !== 1 ? 's' : ''} will be generated` : '';
|
|
640
|
+
} catch (_) {
|
|
641
|
+
resultCountDiv.textContent = '';
|
|
597
642
|
}
|
|
643
|
+
};
|
|
644
|
+
|
|
645
|
+
const fillTrivialNameList = (_table?: DG.DataFrame) => {
|
|
598
646
|
if (resizeInputs)
|
|
599
647
|
resizeInputs();
|
|
600
648
|
};
|
|
@@ -607,6 +655,7 @@ async function getPolyToolEnumerateDialog(
|
|
|
607
655
|
|
|
608
656
|
fillForCurrentCell(seqValue, dataRole, cell);
|
|
609
657
|
updateViewRules();
|
|
658
|
+
updateResultCount();
|
|
610
659
|
|
|
611
660
|
// === EXECUTION (OK button handler) ===
|
|
612
661
|
// Pre-flight validates inputs, builds params, and runs enumeration.
|
|
@@ -663,7 +712,13 @@ async function getPolyToolEnumerateDialog(
|
|
|
663
712
|
rules: await ruleInputs.getActive()
|
|
664
713
|
} : false,
|
|
665
714
|
helmHelper);
|
|
666
|
-
|
|
715
|
+
const appendTarget = inputs.appendToTable.value;
|
|
716
|
+
if (appendTarget) {
|
|
717
|
+
appendTarget.append(enumeratorResDf, true);
|
|
718
|
+
appendTarget.meta.detectSemanticTypes();
|
|
719
|
+
} else {
|
|
720
|
+
grok.shell.addTableView(enumeratorResDf);
|
|
721
|
+
}
|
|
667
722
|
}
|
|
668
723
|
} catch (err: any) {
|
|
669
724
|
defaultErrorHandler(err);
|
|
@@ -677,7 +732,8 @@ async function getPolyToolEnumerateDialog(
|
|
|
677
732
|
.add(ui.divH([
|
|
678
733
|
ui.divV([
|
|
679
734
|
inputs.placeholders.root,
|
|
680
|
-
inputs.enumeratorType.root],
|
|
735
|
+
ui.divH([inputs.enumeratorType.root, resultCountDiv],
|
|
736
|
+
{style: {alignItems: 'center'}})],
|
|
681
737
|
{style: {width: '50%'}}
|
|
682
738
|
),
|
|
683
739
|
ui.divV([
|
|
@@ -686,8 +742,9 @@ async function getPolyToolEnumerateDialog(
|
|
|
686
742
|
{style: {width: '100%'}}))
|
|
687
743
|
.add(ui.divH([
|
|
688
744
|
ui.divV([
|
|
689
|
-
inputs.
|
|
690
|
-
inputs.keepOriginal.root
|
|
745
|
+
inputs.trivialName.root,
|
|
746
|
+
inputs.keepOriginal.root,
|
|
747
|
+
inputs.appendToTable.root],
|
|
691
748
|
{style: {width: '50%'}}),
|
|
692
749
|
ui.divV([
|
|
693
750
|
ui.divH([inputs.toAtomicLevel.root, inputs.generateHelm.root]),
|
|
@@ -718,7 +775,7 @@ async function getPolyToolEnumerateDialog(
|
|
|
718
775
|
placeholders: inputs.placeholders.stringValue,
|
|
719
776
|
enumeratorType: inputs.enumeratorType.value,
|
|
720
777
|
placeholdersBreadth: inputs.placeholdersBreadth.stringValue,
|
|
721
|
-
|
|
778
|
+
trivialName: inputs.trivialName.value,
|
|
722
779
|
keepOriginal: inputs.keepOriginal.value,
|
|
723
780
|
toAtomicLevel: inputs.toAtomicLevel.value,
|
|
724
781
|
generateHelm: inputs.generateHelm.value,
|
|
@@ -732,7 +789,8 @@ async function getPolyToolEnumerateDialog(
|
|
|
732
789
|
inputs.enumeratorType.value = x.enumeratorType ?? PolyToolEnumeratorTypes.Single;
|
|
733
790
|
inputs.placeholders.stringValue = x.placeholders;
|
|
734
791
|
inputs.placeholdersBreadth.stringValue = x.placeholdersBreadth;
|
|
735
|
-
|
|
792
|
+
if (x.trivialName)
|
|
793
|
+
inputs.trivialName.value = x.trivialName;
|
|
736
794
|
inputs.keepOriginal.value = x.keepOriginal ?? false;
|
|
737
795
|
inputs.toAtomicLevel.value = x.toAtomicLevel ?? true;
|
|
738
796
|
inputs.generateHelm.value = x.generateHelm ?? true;
|
|
@@ -742,6 +800,7 @@ async function getPolyToolEnumerateDialog(
|
|
|
742
800
|
setTimeout(() => {
|
|
743
801
|
inputs.placeholders.invalidateGrid();
|
|
744
802
|
inputs.placeholdersBreadth.invalidateGrid();
|
|
803
|
+
updateResultCount();
|
|
745
804
|
}, 100);
|
|
746
805
|
});
|
|
747
806
|
return dialog;
|