@datagrok/sequence-translator 0.0.9 → 1.0.1
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/README.md +19 -11
- package/css/style.css +18 -0
- package/dist/package-test.js +2454 -0
- package/dist/package.js +5234 -0
- package/package.json +19 -10
- package/src/defineAxolabsPattern.ts +58 -55
- package/src/package-test.ts +1 -1
- package/src/package.ts +53 -50
- package/src/salts.ts +2 -2
- package/src/structures-works/from-monomers.ts +20 -12
- package/src/structures-works/mol-transformations.ts +34 -18
- package/src/structures-works/save-sense-antisense.ts +5 -2
- package/src/structures-works/sequence-codes-tools.ts +192 -93
- package/src/tests/smiles-tests.ts +31 -27
- package/{test-SequenceTranslator-2e08c8e54bde-1367d435.html → test-SequenceTranslator-089b6516ed77-2280593f.html} +2 -2
package/package.json
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datagrok/sequence-translator",
|
|
3
3
|
"friendlyName": "Sequence Translator",
|
|
4
|
-
"version": "
|
|
5
|
-
"description": "",
|
|
4
|
+
"version": "1.0.1",
|
|
5
|
+
"description": "SequenceTranslator is a [package](https://datagrok.ai/help/develop/develop#packages) for the [Datagrok](https://datagrok.ai) platform, used to translate [oligonucleotide](https://en.wikipedia.org/wiki/Oligonucleotide) sequences between [different representations](https://github.com/datagrok-ai/public/tree/master/packages/SequenceTranslator#sequence-representations).",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/datagrok-ai/public.git",
|
|
9
|
+
"directory": "packages/SequenceTranslator"
|
|
10
|
+
},
|
|
6
11
|
"dependencies": {
|
|
7
12
|
"@datagrok-libraries/utils": "^0.1.0",
|
|
8
13
|
"@types/react": "latest",
|
|
9
|
-
"datagrok-api": "
|
|
14
|
+
"datagrok-api": "^1.1.7",
|
|
10
15
|
"datagrok-tools": "^4.1.2",
|
|
11
|
-
"npm": "^
|
|
16
|
+
"npm": "^8.11.0",
|
|
12
17
|
"save-svg-as-png": "^1.4.17",
|
|
13
18
|
"ts-loader": "latest",
|
|
14
19
|
"typescript": "latest",
|
|
@@ -28,6 +33,9 @@
|
|
|
28
33
|
"test-dev": "set HOST=dev && jest",
|
|
29
34
|
"test-local": "set HOST=localhost && jest"
|
|
30
35
|
},
|
|
36
|
+
"sources": [
|
|
37
|
+
"css/style.css"
|
|
38
|
+
],
|
|
31
39
|
"devDependencies": {
|
|
32
40
|
"@typescript-eslint/eslint-plugin": "^4.29.1",
|
|
33
41
|
"@typescript-eslint/parser": "^4.29.1",
|
|
@@ -36,10 +44,11 @@
|
|
|
36
44
|
"eslint-config-google": "^0.14.0",
|
|
37
45
|
"webpack": "^5.31.0",
|
|
38
46
|
"webpack-cli": "^4.6.0",
|
|
39
|
-
"
|
|
40
|
-
"jest": "
|
|
41
|
-
"jest
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
}
|
|
47
|
+
"jest-html-reporter": "^3.5.0",
|
|
48
|
+
"jest": "^27.0.0",
|
|
49
|
+
"@types/jest": "^27.0.0",
|
|
50
|
+
"ts-jest": "^27.0.0",
|
|
51
|
+
"puppeteer": "^13.7.0"
|
|
52
|
+
},
|
|
53
|
+
"category": "Bioinformatics"
|
|
45
54
|
}
|
|
@@ -114,7 +114,7 @@ export function defineAxolabsPattern() {
|
|
|
114
114
|
asPtoLinkages = asPtoLinkages.concat(Array(maximalAsLength - asBases.length).fill(fullyPto));
|
|
115
115
|
asBases = asBases.concat(Array(maximalAsLength - asBases.length).fill(sequenceBase));
|
|
116
116
|
let nucleotideCounter = 0;
|
|
117
|
-
for (let i = 0; i < asLength.value
|
|
117
|
+
for (let i = 0; i < asLength.value!; i++) {
|
|
118
118
|
asPtoLinkages[i] = ui.boolInput('', asPtoLinkages[i].value, () => {
|
|
119
119
|
updateSvgScheme();
|
|
120
120
|
updateOutputExamples();
|
|
@@ -157,7 +157,7 @@ export function defineAxolabsPattern() {
|
|
|
157
157
|
ssPtoLinkages = ssPtoLinkages.concat(Array(maximalSsLength - ssBases.length).fill(fullyPto));
|
|
158
158
|
ssBases = ssBases.concat(Array(maximalSsLength - ssBases.length).fill(sequenceBase));
|
|
159
159
|
let nucleotideCounter = 0;
|
|
160
|
-
for (let i = 0; i < ssLength.value
|
|
160
|
+
for (let i = 0; i < ssLength.value!; i++) {
|
|
161
161
|
ssPtoLinkages[i] = ui.boolInput('', ssPtoLinkages[i].value, () => {
|
|
162
162
|
updateSvgScheme();
|
|
163
163
|
updateOutputExamples();
|
|
@@ -196,11 +196,11 @@ export function defineAxolabsPattern() {
|
|
|
196
196
|
}
|
|
197
197
|
|
|
198
198
|
function updateUiForNewSequenceLength() {
|
|
199
|
-
if (ssLength.value < maximalValidSequenceLength && asLength.value < maximalValidSequenceLength) {
|
|
200
|
-
if (ssLength.value > maximalSsLength)
|
|
201
|
-
maximalSsLength = ssLength.value
|
|
202
|
-
if (asLength.value > maximalAsLength)
|
|
203
|
-
maximalAsLength = asLength.value
|
|
199
|
+
if (ssLength.value! < maximalValidSequenceLength && asLength.value! < maximalValidSequenceLength) {
|
|
200
|
+
if (ssLength.value! > maximalSsLength)
|
|
201
|
+
maximalSsLength = ssLength.value!;
|
|
202
|
+
if (asLength.value! > maximalAsLength)
|
|
203
|
+
maximalAsLength = asLength.value!;
|
|
204
204
|
updateSsModification();
|
|
205
205
|
updateAsModification();
|
|
206
206
|
updateSvgScheme();
|
|
@@ -236,17 +236,17 @@ export function defineAxolabsPattern() {
|
|
|
236
236
|
}
|
|
237
237
|
|
|
238
238
|
function updateInputExamples() {
|
|
239
|
-
ssInputExample.value = generateExample(ssLength.value
|
|
239
|
+
ssInputExample.value = generateExample(ssLength.value!, sequenceBase.value!);
|
|
240
240
|
if (createAsStrand.value)
|
|
241
|
-
asInputExample.value = generateExample(asLength.value
|
|
241
|
+
asInputExample.value = generateExample(asLength.value!, sequenceBase.value!);
|
|
242
242
|
}
|
|
243
243
|
|
|
244
244
|
function updateOutputExamples() {
|
|
245
245
|
ssOutputExample.value = translateSequence(
|
|
246
|
-
ssInputExample.value, ssBases, ssPtoLinkages, ssFiveModification, ssThreeModification, firstSsPto.value);
|
|
246
|
+
ssInputExample.value, ssBases, ssPtoLinkages, ssFiveModification, ssThreeModification, firstSsPto.value!);
|
|
247
247
|
if (createAsStrand.value) {
|
|
248
248
|
asOutputExample.value = translateSequence(
|
|
249
|
-
asInputExample.value, asBases, asPtoLinkages, asFiveModification, asThreeModification, firstAsPto.value);
|
|
249
|
+
asInputExample.value, asBases, asPtoLinkages, asFiveModification, asThreeModification, firstAsPto.value!);
|
|
250
250
|
}
|
|
251
251
|
}
|
|
252
252
|
|
|
@@ -256,11 +256,11 @@ export function defineAxolabsPattern() {
|
|
|
256
256
|
ui.span([
|
|
257
257
|
drawAxolabsPattern(
|
|
258
258
|
getShortName(saveAs.value),
|
|
259
|
-
createAsStrand.value
|
|
260
|
-
ssBases.slice(0, ssLength.value).map((e) => e.value),
|
|
261
|
-
asBases.slice(0, asLength.value).map((e) => e.value),
|
|
262
|
-
[firstSsPto.value].concat(ssPtoLinkages.slice(0, ssLength.value).map((e) => e.value)),
|
|
263
|
-
[firstAsPto.value].concat(asPtoLinkages.slice(0, asLength.value).map((e) => e.value)),
|
|
259
|
+
createAsStrand.value!,
|
|
260
|
+
ssBases.slice(0, ssLength.value!).map((e) => e.value),
|
|
261
|
+
asBases.slice(0, asLength.value!).map((e) => e.value),
|
|
262
|
+
[firstSsPto.value!].concat(ssPtoLinkages.slice(0, ssLength.value!).map((e) => e.value)),
|
|
263
|
+
[firstAsPto.value!].concat(asPtoLinkages.slice(0, asLength.value!).map((e) => e.value)),
|
|
264
264
|
ssThreeModification.value,
|
|
265
265
|
ssFiveModification.value,
|
|
266
266
|
asThreeModification.value,
|
|
@@ -329,7 +329,7 @@ export function defineAxolabsPattern() {
|
|
|
329
329
|
}
|
|
330
330
|
|
|
331
331
|
function checkWhetherAllValuesInColumnHaveTheSameLength(colName: string): boolean {
|
|
332
|
-
const col = tables.value
|
|
332
|
+
const col = tables.value!.columns.byName(colName);
|
|
333
333
|
let allLengthsAreTheSame = true;
|
|
334
334
|
for (let i = 1; i < col.length; i++) {
|
|
335
335
|
if (col.get(i - 1).length != col.get(i).length) {
|
|
@@ -344,10 +344,10 @@ export function defineAxolabsPattern() {
|
|
|
344
344
|
.add(ui.divText('The sequence length should match the number of Raw sequences in the input file'))
|
|
345
345
|
.add(ui.divText('\'ADD COLUMN\' to see sequences lengths'))
|
|
346
346
|
.addButton('ADD COLUMN', () => {
|
|
347
|
-
tables.value
|
|
348
|
-
grok.shell.info('Column with lengths added to \'' + tables.value
|
|
347
|
+
tables.value!.columns.addNewInt('Sequences lengths in ' + colName).init((j: number) => col.get(j).length);
|
|
348
|
+
grok.shell.info('Column with lengths added to \'' + tables.value!.name + '\'');
|
|
349
349
|
dialog.close();
|
|
350
|
-
grok.shell.v = grok.shell.getTableView(tables.value
|
|
350
|
+
grok.shell.v = grok.shell.getTableView(tables.value!.name);
|
|
351
351
|
})
|
|
352
352
|
.show();
|
|
353
353
|
}
|
|
@@ -368,10 +368,10 @@ export function defineAxolabsPattern() {
|
|
|
368
368
|
userStorageKey,
|
|
369
369
|
saveAs.stringValue,
|
|
370
370
|
JSON.stringify({
|
|
371
|
-
'ssBases': ssBases.slice(0, ssLength.value).map((e) => e.value),
|
|
372
|
-
'asBases': asBases.slice(0, asLength.value).map((e) => e.value),
|
|
373
|
-
'ssPtoLinkages': [firstSsPto.value].concat(ssPtoLinkages.slice(0, ssLength.value).map((e) => e.value)),
|
|
374
|
-
'asPtoLinkages': [firstAsPto.value].concat(asPtoLinkages.slice(0, asLength.value).map((e) => e.value)),
|
|
371
|
+
'ssBases': ssBases.slice(0, ssLength.value!).map((e) => e.value),
|
|
372
|
+
'asBases': asBases.slice(0, asLength.value!).map((e) => e.value),
|
|
373
|
+
'ssPtoLinkages': [firstSsPto.value].concat(ssPtoLinkages.slice(0, ssLength.value!).map((e) => e.value)),
|
|
374
|
+
'asPtoLinkages': [firstAsPto.value].concat(asPtoLinkages.slice(0, asLength.value!).map((e) => e.value)),
|
|
375
375
|
'ssThreeModification': ssThreeModification.value,
|
|
376
376
|
'ssFiveModification': ssFiveModification.value,
|
|
377
377
|
'asThreeModification': asThreeModification.value,
|
|
@@ -506,24 +506,24 @@ export function defineAxolabsPattern() {
|
|
|
506
506
|
|
|
507
507
|
function validateSsColumn(colName: string) {
|
|
508
508
|
const allLengthsAreTheSame: boolean = checkWhetherAllValuesInColumnHaveTheSameLength(colName);
|
|
509
|
-
const firstSequence = tables.value
|
|
509
|
+
const firstSequence = tables.value!.columns.byName(colName).get(0);
|
|
510
510
|
if (allLengthsAreTheSame && firstSequence.length != ssLength.value)
|
|
511
|
-
ssLength.value = tables.value
|
|
511
|
+
ssLength.value = tables.value!.columns.byName(colName).get(0).length;
|
|
512
512
|
ssInputExample.value = firstSequence;
|
|
513
513
|
}
|
|
514
514
|
|
|
515
515
|
function validateAsColumn(colName: string) {
|
|
516
516
|
const allLengthsAreTheSame: boolean = checkWhetherAllValuesInColumnHaveTheSameLength(colName);
|
|
517
|
-
const firstSequence = tables.value
|
|
517
|
+
const firstSequence = tables.value!.columns.byName(colName).get(0);
|
|
518
518
|
if (allLengthsAreTheSame && firstSequence.length != asLength.value)
|
|
519
|
-
asLength.value = tables.value
|
|
519
|
+
asLength.value = tables.value!.columns.byName(colName).get(0).length;
|
|
520
520
|
asLengthDiv.innerHTML = '';
|
|
521
521
|
asLengthDiv.append(asLength.root);
|
|
522
522
|
asInputExample.value = firstSequence;
|
|
523
523
|
}
|
|
524
524
|
|
|
525
525
|
function validateIdsColumn(colName: string) {
|
|
526
|
-
const col = tables.value
|
|
526
|
+
const col = tables.value!.columns.byName(colName);
|
|
527
527
|
if (col.type != DG.TYPE.INT)
|
|
528
528
|
grok.shell.error('Column should contain integers only');
|
|
529
529
|
else if (col.categories.length < col.length) {
|
|
@@ -531,32 +531,35 @@ export function defineAxolabsPattern() {
|
|
|
531
531
|
ui.dialog('Non-unique IDs')
|
|
532
532
|
.add(ui.divText('Press \'OK\' to select rows with non-unique values'))
|
|
533
533
|
.onOK(() => {
|
|
534
|
-
const selection = tables.value
|
|
534
|
+
const selection = tables.value!.selection;
|
|
535
535
|
selection.init((i: number) => duplicates.indexOf(col.get(i)) > -1);
|
|
536
|
-
grok.shell.v = grok.shell.getTableView(tables.value
|
|
537
|
-
grok.shell.info('Rows are selected in table \'' + tables.value
|
|
536
|
+
grok.shell.v = grok.shell.getTableView(tables.value!.name);
|
|
537
|
+
grok.shell.info('Rows are selected in table \'' + tables.value!.name + '\'');
|
|
538
538
|
})
|
|
539
539
|
.show();
|
|
540
540
|
}
|
|
541
541
|
}
|
|
542
542
|
|
|
543
543
|
const tables = ui.tableInput('Tables', grok.shell.tables[0], grok.shell.tables, (t: DG.DataFrame) => {
|
|
544
|
-
inputSsColumn =
|
|
544
|
+
const inputSsColumn =
|
|
545
|
+
ui.choiceInput('SS Column', '', t.columns.names(), (colName: string) => validateSsColumn(colName));
|
|
545
546
|
inputSsColumnDiv.innerHTML = '';
|
|
546
547
|
inputSsColumnDiv.append(inputSsColumn.root);
|
|
547
|
-
inputAsColumn =
|
|
548
|
+
const inputAsColumn =
|
|
549
|
+
ui.choiceInput('AS Column', '', t.columns.names(), (colName: string) => validateAsColumn(colName));
|
|
548
550
|
inputAsColumnDiv.innerHTML = '';
|
|
549
551
|
inputAsColumnDiv.append(inputAsColumn.root);
|
|
550
|
-
inputIdColumn =
|
|
552
|
+
const inputIdColumn =
|
|
553
|
+
ui.choiceInput('ID Column', '', t.columns.names(), (colName: string) => validateIdsColumn(colName));
|
|
551
554
|
inputIdColumnDiv.innerHTML = '';
|
|
552
555
|
inputIdColumnDiv.append(inputIdColumn.root);
|
|
553
556
|
});
|
|
554
557
|
|
|
555
|
-
|
|
558
|
+
const inputSsColumn = ui.choiceInput('SS Column', '', []);
|
|
556
559
|
inputSsColumnDiv.append(inputSsColumn.root);
|
|
557
|
-
|
|
560
|
+
const inputAsColumn = ui.choiceInput('AS Column', '', []);
|
|
558
561
|
inputAsColumnDiv.append(inputAsColumn.root);
|
|
559
|
-
|
|
562
|
+
const inputIdColumn = ui.choiceInput('ID Column', '', []);
|
|
560
563
|
inputIdColumnDiv.append(inputIdColumn.root);
|
|
561
564
|
|
|
562
565
|
updatePatternsList();
|
|
@@ -573,8 +576,8 @@ export function defineAxolabsPattern() {
|
|
|
573
576
|
updateOutputExamples();
|
|
574
577
|
});
|
|
575
578
|
|
|
576
|
-
const firstSsPto = ui.boolInput('First SS PTO', fullyPto.value
|
|
577
|
-
const firstAsPto = ui.boolInput('First AS PTO', fullyPto.value
|
|
579
|
+
const firstSsPto = ui.boolInput('First SS PTO', fullyPto.value!, () => updateSvgScheme());
|
|
580
|
+
const firstAsPto = ui.boolInput('First AS PTO', fullyPto.value!, () => updateSvgScheme());
|
|
578
581
|
firstAsPtoDiv.append(firstAsPto.root);
|
|
579
582
|
|
|
580
583
|
const createAsStrand = ui.boolInput('Create AS Strand', true, (v: boolean) => {
|
|
@@ -643,34 +646,34 @@ export function defineAxolabsPattern() {
|
|
|
643
646
|
dialog
|
|
644
647
|
.add(ui.divText('Length of sequences in columns doesn\'t match entered length. Update length value?'))
|
|
645
648
|
.addButton('YES', () => {
|
|
646
|
-
ssLength.value = tables.value
|
|
647
|
-
asLength.value = tables.value
|
|
649
|
+
ssLength.value = tables.value!.columns.byName(inputSsColumn.value!).getString(0).length;
|
|
650
|
+
asLength.value = tables.value!.columns.byName(inputAsColumn.value!).getString(0).length;
|
|
648
651
|
dialog.close();
|
|
649
652
|
})
|
|
650
653
|
.show();
|
|
651
654
|
} else {
|
|
652
655
|
if (inputIdColumn.value != null)
|
|
653
|
-
addColumnWithIds(tables.value
|
|
656
|
+
addColumnWithIds(tables.value!.name, inputIdColumn.value, getShortName(saveAs.value));
|
|
654
657
|
addColumnWithTranslatedSequences(
|
|
655
|
-
tables.value
|
|
656
|
-
ssFiveModification, ssThreeModification, firstSsPto.value);
|
|
658
|
+
tables.value!.name, inputSsColumn.value, ssBases, ssPtoLinkages,
|
|
659
|
+
ssFiveModification, ssThreeModification, firstSsPto.value!);
|
|
657
660
|
if (createAsStrand.value) {
|
|
658
661
|
addColumnWithTranslatedSequences(
|
|
659
|
-
tables.value
|
|
660
|
-
asFiveModification, asThreeModification, firstAsPto.value);
|
|
662
|
+
tables.value!.name, inputAsColumn.value!, asBases, asPtoLinkages,
|
|
663
|
+
asFiveModification, asThreeModification, firstAsPto.value!);
|
|
661
664
|
}
|
|
662
|
-
grok.shell.v = grok.shell.getTableView(tables.value
|
|
665
|
+
grok.shell.v = grok.shell.getTableView(tables.value!.name);
|
|
663
666
|
grok.shell.info(((createAsStrand.value) ? 'Columns were' : 'Column was') +
|
|
664
|
-
' added to table \'' + tables.value
|
|
667
|
+
' added to table \'' + tables.value!.name + '\'');
|
|
665
668
|
}
|
|
666
669
|
});
|
|
667
670
|
|
|
668
|
-
const ssInputExample = ui.textInput('Sense Strand', generateExample(ssLength.value
|
|
671
|
+
const ssInputExample = ui.textInput('Sense Strand', generateExample(ssLength.value!, sequenceBase.value!), () => {
|
|
669
672
|
ssOutputExample.value = translateSequence(ssInputExample.value, ssBases, ssPtoLinkages,
|
|
670
|
-
ssFiveModification, ssThreeModification, firstSsPto.value);
|
|
673
|
+
ssFiveModification, ssThreeModification, firstSsPto.value!);
|
|
671
674
|
});
|
|
672
675
|
const ssOutputExample = ui.textInput(' ', translateSequence(
|
|
673
|
-
ssInputExample.value, ssBases, ssPtoLinkages, ssThreeModification, ssFiveModification, firstSsPto.value));
|
|
676
|
+
ssInputExample.value, ssBases, ssPtoLinkages, ssThreeModification, ssFiveModification, firstSsPto.value!));
|
|
674
677
|
(ssInputExample.input as HTMLElement).style.resize = 'none';
|
|
675
678
|
(ssInputExample.input as HTMLElement).style.minWidth = exampleMinWidth;
|
|
676
679
|
(ssOutputExample.input as HTMLElement).style.resize = 'none';
|
|
@@ -686,12 +689,12 @@ export function defineAxolabsPattern() {
|
|
|
686
689
|
], 'ui-input-options'),
|
|
687
690
|
);
|
|
688
691
|
|
|
689
|
-
const asInputExample = ui.textInput('Antisense Strand', generateExample(asLength.value
|
|
692
|
+
const asInputExample = ui.textInput('Antisense Strand', generateExample(asLength.value!, sequenceBase.value!), () => {
|
|
690
693
|
asOutputExample.value = translateSequence(
|
|
691
|
-
asInputExample.value, asBases, asPtoLinkages, asFiveModification, asThreeModification, firstSsPto.value);
|
|
694
|
+
asInputExample.value, asBases, asPtoLinkages, asFiveModification, asThreeModification, firstSsPto.value!);
|
|
692
695
|
});
|
|
693
696
|
const asOutputExample = ui.textInput(' ', translateSequence(
|
|
694
|
-
asInputExample.value, asBases, asPtoLinkages, asFiveModification, asThreeModification, firstSsPto.value));
|
|
697
|
+
asInputExample.value, asBases, asPtoLinkages, asFiveModification, asThreeModification, firstSsPto.value!));
|
|
695
698
|
(asInputExample.input as HTMLElement).style.resize = 'none';
|
|
696
699
|
(asInputExample.input as HTMLElement).style.minWidth = exampleMinWidth;
|
|
697
700
|
(asOutputExample.input as HTMLElement).style.resize = 'none';
|
package/src/package-test.ts
CHANGED
package/src/package.ts
CHANGED
|
@@ -7,7 +7,8 @@ import $ from 'cash-dom';
|
|
|
7
7
|
import {defineAxolabsPattern} from './defineAxolabsPattern';
|
|
8
8
|
import {saveSenseAntiSense} from './structures-works/save-sense-antisense';
|
|
9
9
|
import {sequenceToSmiles, sequenceToMolV3000} from './structures-works/from-monomers';
|
|
10
|
-
import {convertSequence, undefinedInputSequence} from
|
|
10
|
+
import {convertSequence, undefinedInputSequence, isValidSequence, getFormat} from
|
|
11
|
+
'./structures-works/sequence-codes-tools';
|
|
11
12
|
import {map, COL_NAMES, MODIFICATIONS} from './structures-works/map';
|
|
12
13
|
import {SALTS_CSV} from './salts';
|
|
13
14
|
import {USERS_CSV} from './users';
|
|
@@ -17,7 +18,7 @@ import {IDPS} from './IDPs';
|
|
|
17
18
|
|
|
18
19
|
export const _package = new DG.Package();
|
|
19
20
|
|
|
20
|
-
const defaultInput = '
|
|
21
|
+
const defaultInput = 'fAmCmGmAmCpsmU';
|
|
21
22
|
const sequenceWasCopied = 'Copied';
|
|
22
23
|
const tooltipSequence = 'Copy sequence';
|
|
23
24
|
|
|
@@ -29,35 +30,40 @@ export function sequenceTranslator(): void {
|
|
|
29
30
|
windows.showToolbox = false;
|
|
30
31
|
windows.showHelp = false;
|
|
31
32
|
|
|
32
|
-
function updateTableAndMolecule(sequence: string): void {
|
|
33
|
+
function updateTableAndMolecule(sequence: string, inputFormat: string, isSet: boolean): void {
|
|
33
34
|
moleculeSvgDiv.innerHTML = '';
|
|
34
35
|
outputTableDiv.innerHTML = '';
|
|
35
36
|
const pi = DG.TaskBarProgressIndicator.create('Rendering table and molecule...');
|
|
36
37
|
let errorsExist = false;
|
|
37
38
|
try {
|
|
38
|
-
|
|
39
|
+
sequence = sequence.replace(/\s/g, '');
|
|
40
|
+
const output = isValidSequence(sequence, null);
|
|
41
|
+
if (isSet)
|
|
42
|
+
output.synthesizer = [inputFormat];
|
|
43
|
+
inputFormatChoiceInput.value = output.synthesizer![0];
|
|
44
|
+
const outputSequenceObj = convertSequence(sequence, output);
|
|
39
45
|
const tableRows = [];
|
|
40
46
|
|
|
41
47
|
for (const key of Object.keys(outputSequenceObj).slice(1)) {
|
|
42
|
-
const
|
|
43
|
-
JSON.parse(outputSequenceObj.
|
|
48
|
+
const indexOfFirstNotValidChar = ('indexOfFirstNotValidChar' in outputSequenceObj) ?
|
|
49
|
+
JSON.parse(outputSequenceObj.indexOfFirstNotValidChar!).indexOfFirstNotValidChar :
|
|
44
50
|
-1;
|
|
45
|
-
if ('
|
|
46
|
-
const
|
|
47
|
-
JSON.parse(outputSequenceObj.
|
|
51
|
+
if ('indexOfFirstNotValidChar' in outputSequenceObj) {
|
|
52
|
+
const indexOfFirstNotValidChar = ('indexOfFirstNotValidChar' in outputSequenceObj) ?
|
|
53
|
+
JSON.parse(outputSequenceObj.indexOfFirstNotValidChar!).indexOfFirstNotValidChar :
|
|
48
54
|
-1;
|
|
49
|
-
if (
|
|
55
|
+
if (indexOfFirstNotValidChar != -1)
|
|
50
56
|
errorsExist = true;
|
|
51
57
|
}
|
|
52
58
|
|
|
53
59
|
tableRows.push({
|
|
54
60
|
'key': key,
|
|
55
|
-
'value': ('
|
|
61
|
+
'value': ('indexOfFirstNotValidChar' in outputSequenceObj) ?
|
|
56
62
|
ui.divH([
|
|
57
|
-
ui.divText(sequence.slice(0,
|
|
63
|
+
ui.divText(sequence.slice(0, indexOfFirstNotValidChar), {style: {color: 'grey'}}),
|
|
58
64
|
ui.tooltip.bind(
|
|
59
|
-
ui.divText(sequence.slice(
|
|
60
|
-
'Expected format: ' + JSON.parse(outputSequenceObj.
|
|
65
|
+
ui.divText(sequence.slice(indexOfFirstNotValidChar), {style: {color: 'red'}}),
|
|
66
|
+
'Expected format: ' + JSON.parse(outputSequenceObj.indexOfFirstNotValidChar!).synthesizer +
|
|
61
67
|
'. See tables with valid codes on the right',
|
|
62
68
|
),
|
|
63
69
|
]) : //@ts-ignore
|
|
@@ -67,13 +73,12 @@ export function sequenceTranslator(): void {
|
|
|
67
73
|
}
|
|
68
74
|
|
|
69
75
|
if (errorsExist) {
|
|
70
|
-
const
|
|
71
|
-
.expectedSynthesizer.slice(0, -6);
|
|
76
|
+
const synthesizer = JSON.parse(outputSequenceObj.indexOfFirstNotValidChar!).synthesizer.slice(0, -6);
|
|
72
77
|
asoGapmersGrid.onCellPrepare(function(gc) {
|
|
73
|
-
gc.style.backColor = (gc.gridColumn.name ==
|
|
78
|
+
gc.style.backColor = (gc.gridColumn.name == synthesizer) ? 0xFFF00000 : 0xFFFFFFFF;
|
|
74
79
|
});
|
|
75
80
|
omeAndFluoroGrid.onCellPrepare(function(gc) {
|
|
76
|
-
gc.style.backColor = (gc.gridColumn.name ==
|
|
81
|
+
gc.style.backColor = (gc.gridColumn.name == synthesizer) ? 0xFFF00000 : 0xFFFFFFFF;
|
|
77
82
|
});
|
|
78
83
|
switchInput.enabled = true;
|
|
79
84
|
} else {
|
|
@@ -85,15 +90,15 @@ export function sequenceTranslator(): void {
|
|
|
85
90
|
ui.div([
|
|
86
91
|
DG.HtmlTable.create(tableRows, (item: { key: string; value: string; }) =>
|
|
87
92
|
[item.key, item.value], ['Code', 'Sequence']).root,
|
|
88
|
-
]
|
|
93
|
+
]),
|
|
89
94
|
);
|
|
90
|
-
semTypeOfInputSequence.textContent = 'Detected input type: ' + outputSequenceObj.type;
|
|
91
95
|
|
|
92
96
|
if (outputSequenceObj.type != undefinedInputSequence && outputSequenceObj.Error != undefinedInputSequence) {
|
|
93
97
|
const canvas = ui.canvas(300, 170);
|
|
94
98
|
canvas.addEventListener('click', () => {
|
|
95
99
|
const canv = ui.canvas($(window).width(), $(window).height());
|
|
96
|
-
const mol = sequenceToMolV3000(inputSequenceField.value.replace(/\s/g, ''), false, true
|
|
100
|
+
const mol = sequenceToMolV3000(inputSequenceField.value.replace(/\s/g, ''), false, true,
|
|
101
|
+
output.synthesizer![0]);
|
|
97
102
|
// @ts-ignore
|
|
98
103
|
OCL.StructureView.drawMolecule(canv, OCL.Molecule.fromMolfile(mol), {suppressChiralText: true});
|
|
99
104
|
ui.dialog('Molecule: ' + inputSequenceField.value)
|
|
@@ -102,7 +107,8 @@ export function sequenceTranslator(): void {
|
|
|
102
107
|
});
|
|
103
108
|
$(canvas).on('mouseover', () => $(canvas).css('cursor', 'zoom-in'));
|
|
104
109
|
$(canvas).on('mouseout', () => $(canvas).css('cursor', 'default'));
|
|
105
|
-
const mol = sequenceToMolV3000(inputSequenceField.value.replace(/\s/g, ''), false, true
|
|
110
|
+
const mol = sequenceToMolV3000(inputSequenceField.value.replace(/\s/g, ''), false, true,
|
|
111
|
+
output.synthesizer![0]);
|
|
106
112
|
// @ts-ignore
|
|
107
113
|
OCL.StructureView.drawMolecule(canvas, OCL.Molecule.fromMolfile(mol), {suppressChiralText: true});
|
|
108
114
|
moleculeSvgDiv.append(canvas);
|
|
@@ -113,10 +119,14 @@ export function sequenceTranslator(): void {
|
|
|
113
119
|
}
|
|
114
120
|
}
|
|
115
121
|
|
|
116
|
-
const
|
|
122
|
+
const inputFormatChoiceInput = ui.choiceInput(
|
|
123
|
+
'Input format: ', 'Janssen GCRS Codes', Object.keys(map), (format: string) => {
|
|
124
|
+
updateTableAndMolecule(inputSequenceField.value.replace(/\s/g, ''), format, true);
|
|
125
|
+
});
|
|
117
126
|
const moleculeSvgDiv = ui.block([]);
|
|
118
|
-
const outputTableDiv = ui.div([]
|
|
119
|
-
const inputSequenceField = ui.textInput('', defaultInput, (sequence: string) => updateTableAndMolecule(sequence
|
|
127
|
+
const outputTableDiv = ui.div([]);
|
|
128
|
+
const inputSequenceField = ui.textInput('', defaultInput, (sequence: string) => updateTableAndMolecule(sequence,
|
|
129
|
+
inputFormatChoiceInput.value!, false));
|
|
120
130
|
|
|
121
131
|
const asoDf = DG.DataFrame.fromObjects([
|
|
122
132
|
{'Name': '2\'MOE-5Me-rU', 'BioSpring': '5', 'Janssen GCRS': 'moeT'},
|
|
@@ -155,12 +165,11 @@ export function sequenceTranslator(): void {
|
|
|
155
165
|
);
|
|
156
166
|
|
|
157
167
|
const overhangModificationsGrid = DG.Viewer.grid(
|
|
158
|
-
DG.DataFrame.
|
|
159
|
-
|
|
160
|
-
{'Name': '(GalNAc-2-JNJ)'},
|
|
168
|
+
DG.DataFrame.fromColumns([
|
|
169
|
+
DG.Column.fromStrings('Name', Object.keys(MODIFICATIONS)),
|
|
161
170
|
])!, {showRowHeader: false, showCellTooltip: false},
|
|
162
171
|
);
|
|
163
|
-
updateTableAndMolecule(defaultInput);
|
|
172
|
+
updateTableAndMolecule(defaultInput, inputFormatChoiceInput.value!, true);
|
|
164
173
|
|
|
165
174
|
const appMainDescription = ui.info([
|
|
166
175
|
ui.divText('How to convert one sequence:', {style: {'font-weight': 'bolder'}}),
|
|
@@ -191,8 +200,8 @@ export function sequenceTranslator(): void {
|
|
|
191
200
|
ui.div([
|
|
192
201
|
inputSequenceField.root,
|
|
193
202
|
], 'input-base'),
|
|
194
|
-
], '
|
|
195
|
-
|
|
203
|
+
], 'inputSequence'),
|
|
204
|
+
ui.div([inputFormatChoiceInput], {style: {padding: '5px 0'}}),
|
|
196
205
|
ui.block([
|
|
197
206
|
ui.h1('Output'),
|
|
198
207
|
outputTableDiv,
|
|
@@ -217,14 +226,16 @@ export function sequenceTranslator(): void {
|
|
|
217
226
|
|
|
218
227
|
const topPanel = [
|
|
219
228
|
ui.iconFA('download', () => {
|
|
220
|
-
const result = sequenceToMolV3000(inputSequenceField.value.replace(/\s/g, '')
|
|
229
|
+
const result = sequenceToMolV3000(inputSequenceField.value.replace(/\s/g, ''), false, false,
|
|
230
|
+
inputFormatChoiceInput.value!);
|
|
221
231
|
const element = document.createElement('a');
|
|
222
232
|
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(result));
|
|
223
233
|
element.setAttribute('download', inputSequenceField.value.replace(/\s/g, '') + '.mol');
|
|
224
234
|
element.click();
|
|
225
235
|
}, 'Save .mol file'),
|
|
226
236
|
ui.iconFA('copy', () => {
|
|
227
|
-
navigator.clipboard.writeText(
|
|
237
|
+
navigator.clipboard.writeText(
|
|
238
|
+
sequenceToSmiles(inputSequenceField.value.replace(/\s/g, ''), false, inputFormatChoiceInput.value!))
|
|
228
239
|
.then(() => grok.shell.info(sequenceWasCopied));
|
|
229
240
|
}, 'Copy SMILES'),
|
|
230
241
|
switchInput.root,
|
|
@@ -233,18 +244,6 @@ export function sequenceTranslator(): void {
|
|
|
233
244
|
tabControl.onTabChanged.subscribe((_) =>
|
|
234
245
|
v.setRibbonPanels([(tabControl.currentPane.name == 'MAIN') ? topPanel : []]));
|
|
235
246
|
v.setRibbonPanels([topPanel]);
|
|
236
|
-
|
|
237
|
-
$('.sequence')
|
|
238
|
-
.children().css('padding', '5px 0');
|
|
239
|
-
$('.sequenceInput .input-base')
|
|
240
|
-
.css('margin', '0');
|
|
241
|
-
$('.sequenceInput textarea')
|
|
242
|
-
.css('resize', 'none')
|
|
243
|
-
.css('min-height', '50px')
|
|
244
|
-
.css('width', '100%')
|
|
245
|
-
.attr('spellcheck', 'false');
|
|
246
|
-
$('.sequenceInput select')
|
|
247
|
-
.css('width', '100%');
|
|
248
247
|
}
|
|
249
248
|
|
|
250
249
|
async function saveTableAsSdFile(table: DG.DataFrame) {
|
|
@@ -259,9 +258,10 @@ async function saveTableAsSdFile(table: DG.DataFrame) {
|
|
|
259
258
|
const typeColumn = table.col(COL_NAMES.TYPE)!;
|
|
260
259
|
let result = '';
|
|
261
260
|
for (let i = 0; i < table.rowCount; i++) {
|
|
261
|
+
const format = getFormat(structureColumn.get(i));
|
|
262
262
|
result += (typeColumn.get(i) == 'SS') ?
|
|
263
|
-
sequenceToMolV3000(structureColumn.get(i), false, true) + '\n' + `> <Sequence>\nSense Strand\n\n` :
|
|
264
|
-
sequenceToMolV3000(structureColumn.get(i), true, true) + '\n' + `> <Sequence>\nAnti Sense\n\n`;
|
|
263
|
+
sequenceToMolV3000(structureColumn.get(i), false, true, format!) + '\n' + `> <Sequence>\nSense Strand\n\n` :
|
|
264
|
+
sequenceToMolV3000(structureColumn.get(i), true, true, format!) + '\n' + `> <Sequence>\nAnti Sense\n\n`;
|
|
265
265
|
for (const col of table.columns) {
|
|
266
266
|
if (col.name != COL_NAMES.SEQUENCE)
|
|
267
267
|
result += `> <${col.name}>\n${col.get(i)}\n\n`;
|
|
@@ -324,6 +324,7 @@ export function oligoSdFile(table: DG.DataFrame) {
|
|
|
324
324
|
return grok.shell.error('Columns already exist!');
|
|
325
325
|
|
|
326
326
|
const sequence = t.col(COL_NAMES.SEQUENCE)!;
|
|
327
|
+
const salt = t.col(COL_NAMES.SALT)!;
|
|
327
328
|
const equivalents = t.col(COL_NAMES.EQUIVALENTS)!;
|
|
328
329
|
|
|
329
330
|
t.columns.addNewString(COL_NAMES.COMPOUND_NAME).init((i: number) => sequence.get(i));
|
|
@@ -331,11 +332,13 @@ export function oligoSdFile(table: DG.DataFrame) {
|
|
|
331
332
|
sequence.getString(i) + '; duplex of SS: ' + sequence.getString(i - 2) + ' and AS: ' + sequence.getString(i - 1) :
|
|
332
333
|
sequence.getString(i),
|
|
333
334
|
);
|
|
335
|
+
const molWeightCol = saltsDf.col('MOLWEIGHT')!;
|
|
336
|
+
const saltNamesList = saltsDf.col('DISPLAY')!.toList();
|
|
334
337
|
t.columns.addNewFloat(COL_NAMES.CPD_MW)
|
|
335
338
|
.init((i: number) => molecularWeight(sequence.get(i), weightsObj));
|
|
336
|
-
const mwCol = t.col(COL_NAMES.CPD_MW)!;
|
|
337
339
|
t.columns.addNewFloat(COL_NAMES.SALT_MASS).init((i: number) => {
|
|
338
|
-
const
|
|
340
|
+
const saltRowIndex = saltNamesList.indexOf(salt.get(i));
|
|
341
|
+
const mw = molWeightCol.get(saltRowIndex);
|
|
339
342
|
return mw * equivalents.get(i);
|
|
340
343
|
});
|
|
341
344
|
t.columns.addNewCalculated(COL_NAMES.BATCH_MW,
|
|
@@ -367,7 +370,7 @@ export function oligoSdFile(table: DG.DataFrame) {
|
|
|
367
370
|
|
|
368
371
|
view.table!.col(COL_NAMES.TYPE)!.setTag(DG.TAGS.CHOICES, '["AS", "SS", "Duplex"]');
|
|
369
372
|
view.table!.col(COL_NAMES.OWNER)!.setTag(DG.TAGS.CHOICES, stringifyItems(usersDf.columns.byIndex(0).toList()));
|
|
370
|
-
view.table!.col(COL_NAMES.SALT)!.setTag(DG.TAGS.CHOICES, stringifyItems(saltsDf.columns.byIndex(
|
|
373
|
+
view.table!.col(COL_NAMES.SALT)!.setTag(DG.TAGS.CHOICES, stringifyItems(saltsDf.columns.byIndex(0).toList()));
|
|
371
374
|
view.table!.col(COL_NAMES.SOURCE)!.setTag(DG.TAGS.CHOICES, stringifyItems(sourcesDf.columns.byIndex(0).toList()));
|
|
372
375
|
view.table!.col(COL_NAMES.ICD)!.setTag(DG.TAGS.CHOICES, stringifyItems(icdsDf.columns.byIndex(0).toList()));
|
|
373
376
|
view.table!.col(COL_NAMES.IDP)!.setTag(DG.TAGS.CHOICES, stringifyItems(idpsDf.columns.byIndex(0).toList()));
|
package/src/salts.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const SALTS_CSV = `
|
|
2
|
-
|
|
1
|
+
export const SALTS_CSV = `DISPLAY,MOLWEIGHT
|
|
2
|
+
no Data Added,100`;
|
|
@@ -2,8 +2,9 @@ import {map, stadardPhosphateLinkSmiles, SYNTHESIZERS, TECHNOLOGIES, MODIFICATIO
|
|
|
2
2
|
import {isValidSequence} from './sequence-codes-tools';
|
|
3
3
|
import {getNucleotidesMol} from './mol-transformations';
|
|
4
4
|
|
|
5
|
-
export function sequenceToMolV3000(sequence: string, inverted: boolean = false, oclRender: boolean = false
|
|
6
|
-
|
|
5
|
+
export function sequenceToMolV3000(sequence: string, inverted: boolean = false, oclRender: boolean = false,
|
|
6
|
+
format: string): string {
|
|
7
|
+
const obj = getObjectWithCodesAndSmiles(sequence, format);
|
|
7
8
|
let codes = sortByStringLengthInDescendingOrder(Object.keys(obj));
|
|
8
9
|
let i = 0;
|
|
9
10
|
const smilesCodes:string[] = [];
|
|
@@ -38,8 +39,8 @@ export function sequenceToMolV3000(sequence: string, inverted: boolean = false,
|
|
|
38
39
|
return getNucleotidesMol(smilesCodes, oclRender);
|
|
39
40
|
}
|
|
40
41
|
|
|
41
|
-
export function sequenceToSmiles(sequence: string, inverted: boolean = false): string {
|
|
42
|
-
const obj = getObjectWithCodesAndSmiles(sequence);
|
|
42
|
+
export function sequenceToSmiles(sequence: string, inverted: boolean = false, format: string): string {
|
|
43
|
+
const obj = getObjectWithCodesAndSmiles(sequence, format);
|
|
43
44
|
let codes = sortByStringLengthInDescendingOrder(Object.keys(obj));
|
|
44
45
|
let i = 0;
|
|
45
46
|
let smiles = '';
|
|
@@ -82,19 +83,26 @@ export function sequenceToSmiles(sequence: string, inverted: boolean = false): s
|
|
|
82
83
|
smiles.slice(0, smiles.length - stadardPhosphateLinkSmiles.length + 1);
|
|
83
84
|
}
|
|
84
85
|
|
|
85
|
-
function getObjectWithCodesAndSmiles(sequence: string) {
|
|
86
|
+
function getObjectWithCodesAndSmiles(sequence: string, format: string) {
|
|
86
87
|
const obj: { [code: string]: string } = {};
|
|
87
|
-
|
|
88
|
-
for (const
|
|
89
|
-
for (const
|
|
90
|
-
|
|
88
|
+
if (format == null) {
|
|
89
|
+
for (const synthesizer of Object.keys(map)) {
|
|
90
|
+
for (const technology of Object.keys(map[synthesizer])) {
|
|
91
|
+
for (const code of Object.keys(map[synthesizer][technology]))
|
|
92
|
+
obj[code] = map[synthesizer][technology][code].SMILES;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
} else {
|
|
96
|
+
for (const technology of Object.keys(map[format])) {
|
|
97
|
+
for (const code of Object.keys(map[format][technology]))
|
|
98
|
+
obj[code] = map[format][technology][code].SMILES;
|
|
91
99
|
}
|
|
92
100
|
}
|
|
93
101
|
// TODO: create object based from synthesizer type to avoid key(codes) duplicates
|
|
94
|
-
const output = isValidSequence(sequence);
|
|
95
|
-
if (output.
|
|
102
|
+
const output = isValidSequence(sequence, format);
|
|
103
|
+
if (output.synthesizer!.includes(SYNTHESIZERS.MERMADE_12))
|
|
96
104
|
obj['g'] = map[SYNTHESIZERS.MERMADE_12][TECHNOLOGIES.SI_RNA]['g'].SMILES;
|
|
97
|
-
else if (output.
|
|
105
|
+
else if (output.synthesizer!.includes(SYNTHESIZERS.AXOLABS))
|
|
98
106
|
obj['g'] = map[SYNTHESIZERS.AXOLABS][TECHNOLOGIES.SI_RNA]['g'].SMILES;
|
|
99
107
|
return obj;
|
|
100
108
|
}
|