@datagrok/sequence-translator 1.0.5 → 1.0.7
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/detectors.js +10 -8
- package/dist/package-test.js +346 -310
- package/dist/package.js +169 -108
- package/package.json +8 -4
- package/src/__jest__/remote.test.ts +9 -8
- package/src/__jest__/test-node.ts +3 -2
- package/src/autostart/registration.ts +61 -41
- package/src/axolabs/define-pattern.ts +10 -0
- package/src/main/main-view.ts +11 -12
- package/src/structures-works/converters.ts +18 -9
- package/src/structures-works/from-monomers.ts +3 -2
- package/src/structures-works/map.ts +7 -0
- package/src/structures-works/mol-transformations.ts +18 -16
- package/src/structures-works/save-sense-antisense.ts +26 -13
- package/src/structures-works/sequence-codes-tools.ts +14 -6
- package/src/tests/smiles-tests.ts +279 -279
- package/test-SequenceTranslator-4ba776b36f56-5798c6fc.html +246 -0
- package/test-SequenceTranslator-4f0c8bae6479-6545fe31.html +0 -276
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datagrok/sequence-translator",
|
|
3
3
|
"friendlyName": "Sequence Translator",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.7",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Vadym Kovadlo",
|
|
7
7
|
"email": "vkovadlo@datagrok.ai"
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"@datagrok-libraries/utils": "^0.1.0",
|
|
17
17
|
"@types/react": "^18.0.15",
|
|
18
|
-
"datagrok-api": "^1.
|
|
18
|
+
"datagrok-api": "^1.6.0",
|
|
19
19
|
"datagrok-tools": "^4.1.2",
|
|
20
20
|
"npm": "^8.11.0",
|
|
21
21
|
"openchemlib": "6.0.1",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"release-sequencetranslator-public": "grok publish public --release",
|
|
34
34
|
"debug-sequencetranslator-local": "grok publish local",
|
|
35
35
|
"release-sequencetranslator-local": "grok publish local --release",
|
|
36
|
-
"test": "
|
|
36
|
+
"test": "jest",
|
|
37
37
|
"test-dev": "set HOST=dev && jest",
|
|
38
38
|
"test-local": "set HOST=localhost && jest"
|
|
39
39
|
},
|
|
@@ -54,7 +54,11 @@
|
|
|
54
54
|
"puppeteer": "^13.7.0",
|
|
55
55
|
"ts-jest": "^27.0.0",
|
|
56
56
|
"webpack": "^5.31.0",
|
|
57
|
-
"webpack-cli": "^4.6.0"
|
|
57
|
+
"webpack-cli": "^4.6.0",
|
|
58
|
+
"@types/js-yaml": "^4.0.5",
|
|
59
|
+
"js-yaml": "^4.1.0",
|
|
60
|
+
"@types/node-fetch": "^2.6.2",
|
|
61
|
+
"node-fetch": "^2.6.7"
|
|
58
62
|
},
|
|
59
63
|
"category": "Bioinformatics"
|
|
60
64
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import * as utils from './test-node';
|
|
6
6
|
import puppeteer from 'puppeteer';
|
|
7
7
|
|
|
8
|
-
const P_START_TIMEOUT: number =
|
|
8
|
+
const P_START_TIMEOUT: number = 3600000;
|
|
9
9
|
let browser: puppeteer.Browser;
|
|
10
10
|
let page: puppeteer.Page;
|
|
11
11
|
|
|
@@ -42,19 +42,20 @@ it('TEST', async () => {
|
|
|
42
42
|
let r = await page.evaluate((targetPackage):Promise<object> => {
|
|
43
43
|
return new Promise<object>((resolve, reject) => {
|
|
44
44
|
(<any>window).grok.functions.eval(targetPackage + ':test()').then((df: any) => {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
const cStatus = df.columns.byName('success');
|
|
46
|
+
const cMessage = df.columns.byName('result');
|
|
47
|
+
const cCat = df.columns.byName('category');
|
|
48
|
+
const cName = df.columns.byName('name');
|
|
49
|
+
const cTime = df.columns.byName('ms');
|
|
49
50
|
let failed = false;
|
|
50
51
|
let passReport = '';
|
|
51
52
|
let failReport = '';
|
|
52
53
|
for (let i = 0; i < df.rowCount; i++) {
|
|
53
54
|
if (cStatus.get(i)) {
|
|
54
|
-
passReport += `Test result : ${targetPackage}.${cCat.get(i)}.${cName.get(i)} : ${cMessage.get(i)}\n`;
|
|
55
|
+
passReport += `Test result : Success : ${cTime.get(i)} : ${targetPackage}.${cCat.get(i)}.${cName.get(i)} : ${cMessage.get(i)}\n`;
|
|
55
56
|
} else {
|
|
56
57
|
failed = true;
|
|
57
|
-
failReport += `Test result : ${targetPackage}.${cCat.get(i)}.${cName.get(i)} : ${cMessage.get(i)}\n`;
|
|
58
|
+
failReport += `Test result : Failed : ${cTime.get(i)} : ${targetPackage}.${cCat.get(i)}.${cName.get(i)} : ${cMessage.get(i)}\n`;
|
|
58
59
|
}
|
|
59
60
|
}
|
|
60
61
|
resolve({failReport, passReport, failed});
|
|
@@ -65,4 +66,4 @@ it('TEST', async () => {
|
|
|
65
66
|
console.log(r.passReport);
|
|
66
67
|
// @ts-ignore
|
|
67
68
|
expect(r.failed).checkOutput(false, r.failReport);
|
|
68
|
-
},
|
|
69
|
+
}, 3600000);
|
|
@@ -67,6 +67,7 @@ export async function getBrowserPage(puppeteer: any): Promise<{browser: any, pag
|
|
|
67
67
|
});
|
|
68
68
|
|
|
69
69
|
let page = await browser.newPage();
|
|
70
|
+
await page.setDefaultNavigationTimeout(0);
|
|
70
71
|
await page.goto(`${url}/oauth/`);
|
|
71
72
|
await page.setCookie({name: 'auth', value: token});
|
|
72
73
|
await page.evaluate((token: any) => {
|
|
@@ -74,8 +75,8 @@ export async function getBrowserPage(puppeteer: any): Promise<{browser: any, pag
|
|
|
74
75
|
}, token);
|
|
75
76
|
await page.goto(url);
|
|
76
77
|
try {
|
|
77
|
-
await page.waitForSelector('.grok-preloader');
|
|
78
|
-
await page.waitForFunction(() => document.querySelector('.grok-preloader') == null, {timeout:
|
|
78
|
+
// await page.waitForSelector('.grok-preloader', { timeout: 1800000 });
|
|
79
|
+
await page.waitForFunction(() => document.querySelector('.grok-preloader') == null, {timeout: 3600000});
|
|
79
80
|
} catch (error) {
|
|
80
81
|
throw error;
|
|
81
82
|
}
|
|
@@ -4,7 +4,7 @@ import * as DG from 'datagrok-api/dg';
|
|
|
4
4
|
import {siRnaAxolabsToGcrs, gcrsToNucleotides, asoGapmersBioSpringToGcrs, gcrsToMermade12,
|
|
5
5
|
} from '../structures-works/converters';
|
|
6
6
|
import {map, COL_NAMES, MODIFICATIONS} from '../structures-works/map';
|
|
7
|
-
import {
|
|
7
|
+
import {isValidSequence} from '../structures-works/sequence-codes-tools';
|
|
8
8
|
import {sequenceToMolV3000} from '../structures-works/from-monomers';
|
|
9
9
|
|
|
10
10
|
import {SALTS_CSV} from '../salts';
|
|
@@ -13,16 +13,6 @@ import {ICDS} from '../ICDs';
|
|
|
13
13
|
import {SOURCES} from '../sources';
|
|
14
14
|
import {IDPS} from '../IDPs';
|
|
15
15
|
|
|
16
|
-
const weightsObj: {[code: string]: number} = {};
|
|
17
|
-
for (const synthesizer of Object.keys(map)) {
|
|
18
|
-
for (const technology of Object.keys(map[synthesizer])) {
|
|
19
|
-
for (const code of Object.keys(map[synthesizer][technology]))
|
|
20
|
-
weightsObj[code] ?? map[synthesizer][technology][code].weight;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
for (const [key, value] of Object.entries(MODIFICATIONS))
|
|
24
|
-
weightsObj[key] = value.molecularWeight;
|
|
25
|
-
|
|
26
16
|
|
|
27
17
|
function sortByStringLengthInDescendingOrder(array: string[]): string[] {
|
|
28
18
|
return array.sort(function(a, b) {return b.length - a.length;});
|
|
@@ -56,15 +46,15 @@ async function saveTableAsSdFile(table: DG.DataFrame) {
|
|
|
56
46
|
const typeColumn = table.getCol(COL_NAMES.TYPE);
|
|
57
47
|
let result = '';
|
|
58
48
|
for (let i = 0; i < table.rowCount; i++) {
|
|
59
|
-
const format = getFormat(structureColumn.get(i))!;
|
|
49
|
+
const format = 'Janssen GCRS Codes'; //getFormat(structureColumn.get(i))!;
|
|
60
50
|
result += (typeColumn.get(i) == 'SS') ?
|
|
61
|
-
sequenceToMolV3000(structureColumn.get(i), false, true, format) + '\n' + `>
|
|
62
|
-
sequenceToMolV3000(structureColumn.get(i), true, true, format) + '\n' + `>
|
|
51
|
+
sequenceToMolV3000(structureColumn.get(i), false, true, format) + '\n' + `> <Sequence>\nSense Strand\n\n` :
|
|
52
|
+
sequenceToMolV3000(structureColumn.get(i), true, true, format) + '\n' + `> <Sequence>\nAnti Sense\n\n`;
|
|
63
53
|
for (const col of table.columns) {
|
|
64
54
|
if (col.name != COL_NAMES.SEQUENCE)
|
|
65
|
-
result += `>
|
|
55
|
+
result += `> <${col.name}>\n${col.get(i)}\n\n`;
|
|
66
56
|
}
|
|
67
|
-
result += '$$$$\n
|
|
57
|
+
result += '$$$$\n';
|
|
68
58
|
}
|
|
69
59
|
const element = document.createElement('a');
|
|
70
60
|
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(result));
|
|
@@ -78,14 +68,16 @@ export function autostartOligoSdFileSubscription() {
|
|
|
78
68
|
if (v.dataFrame.columns.contains(COL_NAMES.TYPE))
|
|
79
69
|
oligoSdFile(v.dataFrame);
|
|
80
70
|
grok.events.onContextMenu.subscribe((args) => {
|
|
81
|
-
const seqCol = args.args.context.table.currentCol;
|
|
82
|
-
if (DG.Detector.sampleCategories(seqCol,
|
|
71
|
+
const seqCol = args.args.context.table.currentCol; // /^[fsACGUacgu]{6,}$/
|
|
72
|
+
if (DG.Detector.sampleCategories(seqCol,
|
|
73
|
+
(s) => /(\(invabasic\)|\(GalNAc-2-JNJ\)|f|s|A|C|G|U|a|c|g|u){6,}$/.test(s))) {
|
|
83
74
|
args.args.menu.item('Convert Axolabs to GCRS', () => {
|
|
84
75
|
args.args.context.table.columns.addNewString(seqCol.name + ' to GCRS').init((i: number) => {
|
|
85
76
|
return siRnaAxolabsToGcrs(seqCol.get(i));
|
|
86
77
|
});
|
|
87
|
-
});
|
|
88
|
-
} else if (DG.Detector.sampleCategories(seqCol,
|
|
78
|
+
}); // /^[fmpsACGU]{6,}$/
|
|
79
|
+
} else if (DG.Detector.sampleCategories(seqCol,
|
|
80
|
+
(s) => /(\(invabasic\)|\(GalNAc-2-JNJ\)|f|m|ps|A|C|G|U){6,}$/.test(s)) ||
|
|
89
81
|
DG.Detector.sampleCategories(seqCol, (s) => /^(?=.*moe)(?=.*5mC)(?=.*ps){6,}/.test(s))) {
|
|
90
82
|
args.args.menu.item('Convert GCRS to raw', () => {
|
|
91
83
|
args.args.context.table.columns.addNewString(seqCol.name + ' to raw').init((i: number) => {
|
|
@@ -96,15 +88,17 @@ export function autostartOligoSdFileSubscription() {
|
|
|
96
88
|
args.args.context.table.columns.addNewString(seqCol.name + ' to MM12').init((i: number) => {
|
|
97
89
|
return gcrsToMermade12(seqCol.get(i));
|
|
98
90
|
});
|
|
99
|
-
});
|
|
100
|
-
} else if (DG.Detector.sampleCategories(seqCol,
|
|
91
|
+
}); // /^[*56789ATGC]{6,}$/
|
|
92
|
+
} else if (DG.Detector.sampleCategories(seqCol,
|
|
93
|
+
(s) => /(\(invabasic\)|\(GalNAc-2-JNJ\)|\*|5|6|7|8|9|A|T|G|C){6,}$/.test(s))) {
|
|
101
94
|
args.args.menu.item('Convert Biospring to GCRS', () => {
|
|
102
95
|
const seqCol = args.args.context.table.currentCol;
|
|
103
96
|
args.args.context.table.columns.addNewString(seqCol.name + ' to GCRS').init((i: number) => {
|
|
104
97
|
return asoGapmersBioSpringToGcrs(seqCol.get(i));
|
|
105
98
|
});
|
|
106
|
-
});
|
|
107
|
-
} else if (DG.Detector.sampleCategories(seqCol,
|
|
99
|
+
}); // /^[*1-8]{6,}$/
|
|
100
|
+
} else if (DG.Detector.sampleCategories(seqCol,
|
|
101
|
+
(s) => /(\(invabasic\)|\(GalNAc-2-JNJ\)|\*|1|2|3|4|5|6|7|8){6,}$/.test(s))) {
|
|
108
102
|
args.args.menu.item('Convert Biospring to GCRS', () => {
|
|
109
103
|
args.args.context.table.columns.addNewString(seqCol.name + ' to GCRS').init((i: number) => {
|
|
110
104
|
return siRnaAxolabsToGcrs(seqCol.get(i));
|
|
@@ -123,29 +117,54 @@ export function oligoSdFile(table: DG.DataFrame) {
|
|
|
123
117
|
const icdsDf = DG.DataFrame.fromCsv(ICDS);
|
|
124
118
|
const idpsDf = DG.DataFrame.fromCsv(IDPS);
|
|
125
119
|
|
|
126
|
-
function addColumns(t: DG.DataFrame, saltsDf: DG.DataFrame) {
|
|
120
|
+
async function addColumns(t: DG.DataFrame, saltsDf: DG.DataFrame) {
|
|
127
121
|
if (t.columns.contains(COL_NAMES.COMPOUND_NAME))
|
|
128
122
|
return grok.shell.error('Columns already exist');
|
|
129
123
|
|
|
130
|
-
const
|
|
131
|
-
const
|
|
132
|
-
const
|
|
124
|
+
const sequenceCol = t.getCol(COL_NAMES.SEQUENCE);
|
|
125
|
+
const saltCol = t.getCol(COL_NAMES.SALT);
|
|
126
|
+
const equivalentsCol = t.getCol(COL_NAMES.EQUIVALENTS);
|
|
127
|
+
|
|
128
|
+
for (let i = t.rowCount - 1; i > -1; i--) {
|
|
129
|
+
if (sequenceCol.get(i) == '')
|
|
130
|
+
t.rows.removeAt(i, 1, false);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
t.columns.addNewString(COL_NAMES.COMPOUND_NAME).init((i: number) => sequenceCol.get(i));
|
|
133
134
|
|
|
134
|
-
t.columns.addNewString(COL_NAMES.COMPOUND_NAME).init((i: number) => sequence.get(i));
|
|
135
135
|
t.columns.addNewString(COL_NAMES.COMPOUND_COMMENTS).init((i: number) => (i > 0 && i % 2 == 0) ?
|
|
136
|
-
|
|
137
|
-
|
|
136
|
+
sequenceCol.get(i) + '; duplex of SS: ' + sequenceCol.get(i - 2) + ' and AS: ' + sequenceCol.get(i - 1) :
|
|
137
|
+
sequenceCol.get(i),
|
|
138
138
|
);
|
|
139
139
|
const molWeightCol = saltsDf.getCol('MOLWEIGHT');
|
|
140
140
|
const saltNamesList = saltsDf.getCol('DISPLAY').toList();
|
|
141
|
-
|
|
142
|
-
|
|
141
|
+
const weightsObj: {[code: string]: number} = {};
|
|
142
|
+
for (const synthesizer of Object.keys(map)) {
|
|
143
|
+
for (const technology of Object.keys(map[synthesizer])) {
|
|
144
|
+
for (const code of Object.keys(map[synthesizer][technology]))
|
|
145
|
+
weightsObj[code] = map[synthesizer][technology][code].weight!;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
for (const [key, value] of Object.entries(MODIFICATIONS))
|
|
149
|
+
weightsObj[key] = value.molecularWeight;
|
|
150
|
+
|
|
151
|
+
t.columns.addNewFloat(COL_NAMES.CPD_MW).init((i: number) => {
|
|
152
|
+
return (isValidSequence(sequenceCol.get(i), null).indexOfFirstNotValidChar == -1) ?
|
|
153
|
+
molecularWeight(sequenceCol.get(i), weightsObj) :
|
|
154
|
+
DG.FLOAT_NULL;
|
|
155
|
+
});
|
|
156
|
+
|
|
143
157
|
t.columns.addNewFloat(COL_NAMES.SALT_MASS).init((i: number) => {
|
|
144
|
-
const saltRowIndex = saltNamesList.indexOf(
|
|
145
|
-
|
|
146
|
-
|
|
158
|
+
const saltRowIndex = saltNamesList.indexOf(saltCol.get(i));
|
|
159
|
+
return (saltRowIndex == -1) ? DG.FLOAT_NULL : molWeightCol.get(saltRowIndex) * equivalentsCol.get(i);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
t.columns.addNewFloat(COL_NAMES.SALT_MOL_WEIGHT).init((i: number) => {
|
|
163
|
+
const saltRowIndex = saltNamesList.indexOf(saltCol.get(i));
|
|
164
|
+
return (saltRowIndex == -1) ? DG.FLOAT_NULL : molWeightCol.get(saltRowIndex);
|
|
147
165
|
});
|
|
148
|
-
|
|
166
|
+
|
|
167
|
+
await t.columns.addNewCalculated(COL_NAMES.BATCH_MW,
|
|
149
168
|
'${' + COL_NAMES.CPD_MW + '} + ${' + COL_NAMES.SALT_MASS + '}', DG.COLUMN_TYPE.FLOAT, false,
|
|
150
169
|
);
|
|
151
170
|
|
|
@@ -162,11 +181,12 @@ export function oligoSdFile(table: DG.DataFrame) {
|
|
|
162
181
|
if (table.getCol(COL_NAMES.IDP).type != DG.COLUMN_TYPE.STRING)
|
|
163
182
|
table.changeColumnType(COL_NAMES.IDP, DG.COLUMN_TYPE.STRING);
|
|
164
183
|
d.append(
|
|
165
|
-
ui.link('Add Columns', () => {
|
|
166
|
-
addColumns(table, saltsDf);
|
|
167
|
-
|
|
184
|
+
ui.link('Add Columns', async () => {
|
|
185
|
+
await addColumns(table, saltsDf);
|
|
186
|
+
view.grid.columns.setOrder(Object.values(COL_NAMES));
|
|
168
187
|
}, 'Add columns: \'' + [COL_NAMES.COMPOUND_NAME, COL_NAMES.COMPOUND_COMMENTS, COL_NAMES.CPD_MW,
|
|
169
|
-
COL_NAMES.SALT_MASS, COL_NAMES.BATCH_MW].join('\', \''), ''
|
|
188
|
+
COL_NAMES.SALT_MASS, COL_NAMES.BATCH_MW].join('\', \''), '',
|
|
189
|
+
),
|
|
170
190
|
ui.button('Save SD file', () => saveTableAsSdFile(addColumnsPressed ? newDf : table)),
|
|
171
191
|
);
|
|
172
192
|
|
|
@@ -361,6 +361,11 @@ export function defineAxolabsPattern() {
|
|
|
361
361
|
})
|
|
362
362
|
.show();
|
|
363
363
|
}
|
|
364
|
+
if (col.get(0) != ssLength.value) {
|
|
365
|
+
const d = ui.dialog('Length was updated by value to from imported file');
|
|
366
|
+
d.add(ui.divText('Latest modifications may not take effect during translation'))
|
|
367
|
+
.onOK(() => grok.shell.info('Lengths changed')).show();
|
|
368
|
+
}
|
|
364
369
|
return allLengthsAreTheSame;
|
|
365
370
|
}
|
|
366
371
|
|
|
@@ -513,7 +518,9 @@ export function defineAxolabsPattern() {
|
|
|
513
518
|
let asPtoLinkages = Array(defaultSequenceLength).fill(ui.boolInput('', defaultPto));
|
|
514
519
|
|
|
515
520
|
const ssLength = ui.intInput('SS Length', defaultSequenceLength, () => updateUiForNewSequenceLength());
|
|
521
|
+
ssLength.setTooltip('Length of sense strand, including overhangs');
|
|
516
522
|
const asLength = ui.intInput('AS Length', defaultSequenceLength, () => updateUiForNewSequenceLength());
|
|
523
|
+
asLength.setTooltip('Length of sense strand, including overhangs');
|
|
517
524
|
const asLengthDiv = ui.div([asLength.root]);
|
|
518
525
|
|
|
519
526
|
function validateSsColumn(colName: string): void {
|
|
@@ -605,7 +612,9 @@ export function defineAxolabsPattern() {
|
|
|
605
612
|
});
|
|
606
613
|
|
|
607
614
|
const firstSsPto = ui.boolInput('First SS PTO', fullyPto.value!, () => updateSvgScheme());
|
|
615
|
+
firstSsPto.setTooltip('ps linkage before first nucleotide of sense strand');
|
|
608
616
|
const firstAsPto = ui.boolInput('First AS PTO', fullyPto.value!, () => updateSvgScheme());
|
|
617
|
+
firstAsPto.setTooltip('ps linkage before first nucleotide of antisense strand');
|
|
609
618
|
firstAsPtoDiv.append(firstAsPto.root);
|
|
610
619
|
|
|
611
620
|
const createAsStrand = ui.boolInput('Create AS Strand', true, (v: boolean) => {
|
|
@@ -617,6 +626,7 @@ export function defineAxolabsPattern() {
|
|
|
617
626
|
firstAsPtoDiv.hidden = (!v);
|
|
618
627
|
updateSvgScheme();
|
|
619
628
|
});
|
|
629
|
+
createAsStrand.setTooltip('Create antisense strand sections on SVG and table to the right');
|
|
620
630
|
|
|
621
631
|
const saveAs = ui.textInput('Save As', 'Pattern Name', () => updateSvgScheme());
|
|
622
632
|
saveAs.setTooltip('Name Of New Pattern');
|
package/src/main/main-view.ts
CHANGED
|
@@ -4,7 +4,6 @@ import * as DG from 'datagrok-api/dg';
|
|
|
4
4
|
import {convertSequence, undefinedInputSequence, isValidSequence} from '../structures-works/sequence-codes-tools';
|
|
5
5
|
import {map, MODIFICATIONS} from '../structures-works/map';
|
|
6
6
|
import {sequenceToSmiles, sequenceToMolV3000} from '../structures-works/from-monomers';
|
|
7
|
-
|
|
8
7
|
import $ from 'cash-dom';
|
|
9
8
|
|
|
10
9
|
const defaultInput = 'fAmCmGmAmCpsmU';
|
|
@@ -12,7 +11,7 @@ const sequenceWasCopied = 'Copied';
|
|
|
12
11
|
const tooltipSequence = 'Copy sequence';
|
|
13
12
|
|
|
14
13
|
export function mainView() {
|
|
15
|
-
function updateTableAndMolecule(sequence: string, inputFormat: string
|
|
14
|
+
function updateTableAndMolecule(sequence: string, inputFormat: string): void {
|
|
16
15
|
moleculeSvgDiv.innerHTML = '';
|
|
17
16
|
outputTableDiv.innerHTML = '';
|
|
18
17
|
const pi = DG.TaskBarProgressIndicator.create('Rendering table and molecule...');
|
|
@@ -20,9 +19,8 @@ export function mainView() {
|
|
|
20
19
|
try {
|
|
21
20
|
sequence = sequence.replace(/\s/g, '');
|
|
22
21
|
const output = isValidSequence(sequence, null);
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
inputFormatChoiceInput.value = output.synthesizer![0];
|
|
22
|
+
output.synthesizer = [inputFormat];
|
|
23
|
+
// inputFormatChoiceInput.value = output.synthesizer![0];
|
|
26
24
|
const outputSequenceObj = convertSequence(sequence, output);
|
|
27
25
|
const tableRows = [];
|
|
28
26
|
|
|
@@ -101,14 +99,15 @@ export function mainView() {
|
|
|
101
99
|
}
|
|
102
100
|
}
|
|
103
101
|
|
|
104
|
-
const inputFormatChoiceInput = ui.choiceInput(
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
102
|
+
const inputFormatChoiceInput = ui.choiceInput('Input format: ', 'Janssen GCRS Codes', Object.keys(map));
|
|
103
|
+
inputFormatChoiceInput.onInput((format: string) => {
|
|
104
|
+
updateTableAndMolecule(inputSequenceField.value.replace(/\s/g, ''), format);
|
|
105
|
+
});
|
|
108
106
|
const moleculeSvgDiv = ui.block([]);
|
|
109
107
|
const outputTableDiv = ui.div([]);
|
|
110
|
-
const inputSequenceField = ui.textInput('', defaultInput, (sequence: string) =>
|
|
111
|
-
|
|
108
|
+
const inputSequenceField = ui.textInput('', defaultInput, (sequence: string) => {
|
|
109
|
+
updateTableAndMolecule(sequence, inputFormatChoiceInput.value!);
|
|
110
|
+
});
|
|
112
111
|
|
|
113
112
|
const asoDf = DG.DataFrame.fromObjects([
|
|
114
113
|
{'Name': '2\'MOE-5Me-rU', 'BioSpring': '5', 'Janssen GCRS': 'moeT'},
|
|
@@ -151,7 +150,7 @@ export function mainView() {
|
|
|
151
150
|
DG.Column.fromStrings('Name', Object.keys(MODIFICATIONS)),
|
|
152
151
|
])!, {showRowHeader: false, showCellTooltip: false},
|
|
153
152
|
);
|
|
154
|
-
updateTableAndMolecule(defaultInput, inputFormatChoiceInput.value
|
|
153
|
+
updateTableAndMolecule(defaultInput, inputFormatChoiceInput.value!);
|
|
155
154
|
|
|
156
155
|
const codesTablesDiv = ui.splitV([
|
|
157
156
|
ui.box(ui.h2('ASO Gapmers'), {style: {maxHeight: '40px'}}),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {lcmsToGcrs} from './map';
|
|
2
2
|
import * as DG from 'datagrok-api/dg';
|
|
3
|
-
|
|
3
|
+
import {delimiter} from './map';
|
|
4
4
|
//name: gcrsToLcms
|
|
5
5
|
//input: string nucleotides {semType: GCRS}
|
|
6
6
|
//output: string result {semType: LCMS}
|
|
@@ -10,15 +10,24 @@ export function gcrsToLcms(sequence: string): string {
|
|
|
10
10
|
const arr2 = df.getCol('LCMS').toList();
|
|
11
11
|
const obj: {[i: string]: string} = {};
|
|
12
12
|
arr1.forEach((element, index) => obj[element] = arr2[index]);
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
obj[delimiter] = delimiter;
|
|
14
|
+
// for (let i = 0; i < arr1.length; i++) {
|
|
15
|
+
// arr1[i] = arr1[i].replace('(', '\\(');
|
|
16
|
+
// arr1[i] = arr1[i].replace(')', '\\)');
|
|
17
|
+
// }
|
|
18
|
+
// const regExp = new RegExp('(' + arr1.join('|') + ')', 'g');
|
|
19
|
+
// let r1 = sequence.replace(regExp, function(code) {return obj[code];});
|
|
20
|
+
const codes = arr1.concat(delimiter).sort(function(a, b) {return b.length - a.length;});
|
|
21
|
+
let i = 0;
|
|
22
|
+
let r1 = '';
|
|
23
|
+
while (i < sequence.length) {
|
|
24
|
+
const matchedCode = codes.find((c) => c == sequence.slice(i, i + c.length));
|
|
25
|
+
r1 += obj[sequence.slice(i, i + matchedCode.length)];
|
|
26
|
+
i += matchedCode.length;
|
|
16
27
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
r1 = r1.replace('//', '/');
|
|
21
|
-
return r1.replace('//', '/');
|
|
28
|
+
while (r1.indexOf('//') != -1)
|
|
29
|
+
r1 = r1.replace('//', '/');
|
|
30
|
+
return r1;
|
|
22
31
|
}
|
|
23
32
|
|
|
24
33
|
//name: asoGapmersNucleotidesToBioSpring
|
|
@@ -22,7 +22,8 @@ export function sequenceToMolV3000(sequence: string, inverted: boolean = false,
|
|
|
22
22
|
if (dropdowns.includes(codesList[i])) {
|
|
23
23
|
smilesCodes.push((i >= codesList.length / 2) ?
|
|
24
24
|
MODIFICATIONS[codesList[i]].right : MODIFICATIONS[codesList[i]].left);
|
|
25
|
-
|
|
25
|
+
if (!(i < codesList.length - 1 && links.includes(codesList[i + 1])))
|
|
26
|
+
smilesCodes.push(stadardPhosphateLinkSmiles);
|
|
26
27
|
} else {
|
|
27
28
|
if (links.includes(codesList[i]) ||
|
|
28
29
|
includesStandardLinkAlready.includes(codesList[i]) ||
|
|
@@ -36,7 +37,7 @@ export function sequenceToMolV3000(sequence: string, inverted: boolean = false,
|
|
|
36
37
|
}
|
|
37
38
|
}
|
|
38
39
|
|
|
39
|
-
return getNucleotidesMol(smilesCodes
|
|
40
|
+
return getNucleotidesMol(smilesCodes);
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
export function sequenceToSmiles(sequence: string, inverted: boolean = false, format: string): string {
|
|
@@ -30,6 +30,7 @@ export const COL_NAMES = {
|
|
|
30
30
|
EQUIVALENTS: 'Equivalents',
|
|
31
31
|
PURITY: 'Purity',
|
|
32
32
|
CPD_MW: 'Cpd MW',
|
|
33
|
+
SALT_MOL_WEIGHT: 'Salt MW',
|
|
33
34
|
SALT_MASS: 'Salt mass',
|
|
34
35
|
BATCH_MW: 'Batch MW',
|
|
35
36
|
SOURCE: 'Source',
|
|
@@ -340,6 +341,12 @@ export const map: {[synthesizer: string]:
|
|
|
340
341
|
'normalized': '',
|
|
341
342
|
'SMILES': 'OP(=O)(S)O',
|
|
342
343
|
},
|
|
344
|
+
's': {
|
|
345
|
+
'name': 'ps linkage',
|
|
346
|
+
'weight': 16.07,
|
|
347
|
+
'normalized': '',
|
|
348
|
+
'SMILES': 'OP(=O)(S)O',
|
|
349
|
+
},
|
|
343
350
|
'A': {
|
|
344
351
|
'name': 'Adenine',
|
|
345
352
|
'weight': 313.21,
|
|
@@ -78,7 +78,7 @@ M V30 END COLLECTION
|
|
|
78
78
|
M V30 END CTAB
|
|
79
79
|
M END`;
|
|
80
80
|
|
|
81
|
-
export function getNucleotidesMol(smilesCodes: string[]
|
|
81
|
+
export function getNucleotidesMol(smilesCodes: string[]) {
|
|
82
82
|
const molBlocks: string[] = [];
|
|
83
83
|
|
|
84
84
|
for (let i = 0; i < smilesCodes.length - 1; i++) {
|
|
@@ -88,10 +88,10 @@ export function getNucleotidesMol(smilesCodes: string[], oclRender: boolean = fa
|
|
|
88
88
|
molBlocks.push(rotateNucleotidesV3000(smilesCodes[i]));
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
return linkV3000(molBlocks, false
|
|
91
|
+
return linkV3000(molBlocks, false);
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
export function linkV3000(molBlocks: string[], twoChains: boolean = false,
|
|
94
|
+
export function linkV3000(molBlocks: string[], twoChains: boolean = false, useChirality: boolean = true) {
|
|
95
95
|
let macroMolBlock = '\nDatagrok macromolecule handler\n\n';
|
|
96
96
|
macroMolBlock += ' 0 0 0 0 0 0 999 V3000\n';
|
|
97
97
|
macroMolBlock += 'M V30 BEGIN CTAB\n';
|
|
@@ -213,14 +213,14 @@ export function linkV3000(molBlocks: string[], twoChains: boolean = false, oclRe
|
|
|
213
213
|
const entries = 4;
|
|
214
214
|
const collNumber = Math.ceil(collection.length / entries);
|
|
215
215
|
|
|
216
|
-
if (oclRender) {
|
|
217
|
-
collectionBlock += 'M V30 MDLV30/STEABS ATOMS=(' + collection.length;
|
|
216
|
+
//if (oclRender) {
|
|
217
|
+
// collectionBlock += 'M V30 MDLV30/STEABS ATOMS=(' + collection.length;
|
|
218
218
|
|
|
219
|
-
for (let j = 0; j < collection.length; j++)
|
|
220
|
-
|
|
219
|
+
// for (let j = 0; j < collection.length; j++)
|
|
220
|
+
// collectionBlock += ' ' + collection[j];
|
|
221
221
|
|
|
222
|
-
collectionBlock += ')\n';
|
|
223
|
-
} else {
|
|
222
|
+
// collectionBlock += ')\n';
|
|
223
|
+
//} else {
|
|
224
224
|
collectionBlock += 'M V30 MDLV30/STEABS ATOMS=(' + collection.length + ' -\n';
|
|
225
225
|
for (let i = 0; i < collNumber; i++) {
|
|
226
226
|
collectionBlock += 'M V30 ';
|
|
@@ -231,7 +231,7 @@ export function linkV3000(molBlocks: string[], twoChains: boolean = false, oclRe
|
|
|
231
231
|
collection[entries*i + j] + ' ';
|
|
232
232
|
}
|
|
233
233
|
}
|
|
234
|
-
}
|
|
234
|
+
//}
|
|
235
235
|
|
|
236
236
|
//generate file
|
|
237
237
|
twoChains? natom : natom++;
|
|
@@ -242,13 +242,15 @@ export function linkV3000(molBlocks: string[], twoChains: boolean = false, oclRe
|
|
|
242
242
|
macroMolBlock += 'M V30 BEGIN BOND\n';
|
|
243
243
|
macroMolBlock += bondBlock;
|
|
244
244
|
macroMolBlock += 'M V30 END BOND\n';
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
245
|
+
if(useChirality){
|
|
246
|
+
macroMolBlock += 'M V30 BEGIN COLLECTION\n';
|
|
247
|
+
macroMolBlock += collectionBlock;
|
|
248
|
+
macroMolBlock += 'M V30 END COLLECTION\n';
|
|
249
|
+
} else
|
|
250
|
+
macroMolBlock = macroMolBlock.replace(/ CFG=\d/g, ' ');
|
|
250
251
|
|
|
251
|
-
macroMolBlock
|
|
252
|
+
macroMolBlock += 'M V30 END CTAB\n';
|
|
253
|
+
macroMolBlock += 'M END';
|
|
252
254
|
|
|
253
255
|
return macroMolBlock;
|
|
254
256
|
}
|
|
@@ -3,20 +3,20 @@ import {sequenceToMolV3000} from '../structures-works/from-monomers';
|
|
|
3
3
|
import {linkV3000} from '../structures-works/mol-transformations';
|
|
4
4
|
import {getFormat} from '../structures-works/sequence-codes-tools';
|
|
5
5
|
|
|
6
|
-
export function saveSdf(as: string, ss: string, oneEntity: boolean,
|
|
6
|
+
export function saveSdf(as: string, ss: string, oneEntity: boolean, useChirality: boolean, invertSS: boolean, invertAS: boolean) {
|
|
7
7
|
const formatAs = getFormat(as);
|
|
8
8
|
const formatSs = getFormat(ss);
|
|
9
|
-
const molSS = sequenceToMolV3000(ss,
|
|
10
|
-
const molAS = sequenceToMolV3000(as,
|
|
9
|
+
const molSS = sequenceToMolV3000(ss, invertSS, false, formatSs!);
|
|
10
|
+
const molAS = sequenceToMolV3000(as, invertAS, false, formatAs!);
|
|
11
11
|
let result: string;
|
|
12
12
|
if (oneEntity)
|
|
13
|
-
result = linkV3000([molSS, molAS], true,
|
|
13
|
+
result = linkV3000([molSS, molAS], true, useChirality) + '\n$$$$\n';
|
|
14
14
|
else {
|
|
15
15
|
result =
|
|
16
16
|
molSS + '\n' +
|
|
17
|
-
`>
|
|
17
|
+
`> <Sequence>\nSense Strand\n$$$$\n` +
|
|
18
18
|
molAS + '\n' +
|
|
19
|
-
`>
|
|
19
|
+
`> <Sequence>\nAnti Sense\n$$$$\n`;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
const element = document.createElement('a');
|
|
@@ -27,22 +27,35 @@ export function saveSdf(as: string, ss: string, oneEntity: boolean, fit3dx: bool
|
|
|
27
27
|
|
|
28
28
|
export function saveSenseAntiSense() {
|
|
29
29
|
const moleculeSvgDiv = ui.block([]);
|
|
30
|
-
const ssInput = ui.textInput('Sense Strand
|
|
31
|
-
const asInput = ui.textInput('Anti Sense
|
|
30
|
+
const ssInput = ui.textInput('Sense Strand', '');
|
|
31
|
+
const asInput = ui.textInput('Anti Sense', '');
|
|
32
|
+
const straight = '5\' ->3\'';
|
|
33
|
+
const inverse = '3\' ->5\'';
|
|
34
|
+
let ssInverse = false;
|
|
35
|
+
let asInverse = false;
|
|
36
|
+
|
|
37
|
+
const changeSense = ui.choiceInput('SS direction', straight, [straight, inverse]);
|
|
38
|
+
changeSense.onChanged(() => {ssInverse = changeSense.value == inverse;});
|
|
39
|
+
const changeAntiSense = ui.choiceInput('AS direction', straight, [straight, inverse]);
|
|
40
|
+
changeAntiSense.onChanged(() => {asInverse = changeAntiSense.value == inverse;});
|
|
41
|
+
|
|
32
42
|
const saveOption = ui.switchInput('Save as one entity', true);
|
|
33
|
-
const
|
|
43
|
+
const chirality = ui.switchInput('Use chiral', true);
|
|
34
44
|
const saveBtn = ui.button('Save SDF', () =>
|
|
35
|
-
saveSdf(asInput.value, ssInput.value, saveOption.value,
|
|
45
|
+
saveSdf(asInput.value, ssInput.value, saveOption.value, chirality.value, ssInverse, asInverse));
|
|
36
46
|
|
|
37
47
|
const saveSection = ui.panel([
|
|
38
48
|
ui.div([
|
|
39
49
|
ui.div([
|
|
40
50
|
ui.divH([ui.h1('Inputs')]),
|
|
41
51
|
ui.divV([
|
|
42
|
-
|
|
43
|
-
|
|
52
|
+
ssInput,
|
|
53
|
+
asInput,
|
|
54
|
+
ui.div([changeSense], {style: {width: '40'}}),
|
|
55
|
+
changeSense,
|
|
56
|
+
changeAntiSense,
|
|
44
57
|
saveOption,
|
|
45
|
-
|
|
58
|
+
chirality,
|
|
46
59
|
ui.buttonsInput([saveBtn]),
|
|
47
60
|
], 'ui-form'),
|
|
48
61
|
], 'ui-form'),
|