@datagrok/sequence-translator 1.0.14 → 1.0.16
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/.eslintrc.json +16 -3
- package/dist/package-test.js +715 -316
- package/dist/package.js +684 -301
- package/package.json +25 -22
- package/scripts/build-monomer-lib.py +52 -14
- package/src/apps/oligo-sd-file-app.ts +58 -0
- package/src/autostart/calculations.ts +9 -6
- package/src/autostart/constants.ts +0 -12
- package/src/autostart/registration.ts +121 -149
- package/src/axolabs/constants.ts +4 -4
- package/src/main/main-view.ts +90 -49
- package/src/package.ts +52 -5
- package/src/structures-works/const.ts +3 -16
- package/src/structures-works/converters.ts +28 -26
- package/src/structures-works/mol-transformations.ts +73 -75
- package/src/utils/parse.ts +27 -0
- package/src/utils/sdf-add-columns.ts +118 -0
- package/src/utils/sdf-save-table.ts +56 -0
- package/{test-SequenceTranslator-e8c06047b7e7-eb4db608.html → test-SequenceTranslator-6288c2fbe346-cce4ac1d.html} +6 -6
|
@@ -11,8 +11,8 @@ export function getNucleotidesMol(codes: string[]) {
|
|
|
11
11
|
// }
|
|
12
12
|
|
|
13
13
|
for (let i = 0; i < codes.length - 1; i++) {
|
|
14
|
-
if(codes[i].includes('MODIFICATION')) {
|
|
15
|
-
if(i == 0)
|
|
14
|
+
if (codes[i].includes('MODIFICATION')) {
|
|
15
|
+
if (i == 0)
|
|
16
16
|
molBlocks.push(reflect(codes[i]));
|
|
17
17
|
else
|
|
18
18
|
molBlocks.push(codes[i]);
|
|
@@ -24,7 +24,7 @@ export function getNucleotidesMol(codes: string[]) {
|
|
|
24
24
|
return linkV3000(molBlocks);
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
export function linkStrandsV3000(strands:{senseStrands: string[], antiStrands: string[]}, useChirality: boolean = true) {
|
|
27
|
+
export function linkStrandsV3000(strands: { senseStrands: string[], antiStrands: string[] }, useChirality: boolean = true) {
|
|
28
28
|
let macroMolBlock = '\nDatagrok macromolecule handler\n\n';
|
|
29
29
|
macroMolBlock += ' 0 0 0 0 0 0 999 V3000\n';
|
|
30
30
|
macroMolBlock += 'M V30 BEGIN CTAB\n';
|
|
@@ -40,7 +40,7 @@ export function linkStrandsV3000(strands:{senseStrands: string[], antiStrands: s
|
|
|
40
40
|
// molBlocks[1] = invertNucleotidesV3000(molBlocks[1]);
|
|
41
41
|
|
|
42
42
|
if (strands.antiStrands.length > 0) {
|
|
43
|
-
for(let i = 0; i < strands.antiStrands.length; i++) {
|
|
43
|
+
for (let i = 0; i < strands.antiStrands.length; i++) {
|
|
44
44
|
strands.antiStrands[i] = invertNucleotidesV3000(strands.antiStrands[i]);
|
|
45
45
|
}
|
|
46
46
|
}
|
|
@@ -90,15 +90,15 @@ export function linkStrandsV3000(strands:{senseStrands: string[], antiStrands: s
|
|
|
90
90
|
|
|
91
91
|
const totalShift = true ? 0 : xShift - coordinates.x[0];
|
|
92
92
|
let coordinate = true ?
|
|
93
|
-
Math.round(10000*coordinates.x[j])/10000 :
|
|
94
|
-
Math.round(10000*(parseFloat(molBlocks[i].substring(index, indexEnd)) + totalShift))/10000;
|
|
93
|
+
Math.round(10000 * coordinates.x[j]) / 10000 :
|
|
94
|
+
Math.round(10000 * (parseFloat(molBlocks[i].substring(index, indexEnd)) + totalShift)) / 10000;
|
|
95
95
|
molBlocks[i] = molBlocks[i].slice(0, index) + coordinate + molBlocks[i].slice(indexEnd);
|
|
96
96
|
|
|
97
97
|
index = molBlocks[i].indexOf(' ', index) + 1;
|
|
98
98
|
indexEnd = molBlocks[i].indexOf(' ', index);
|
|
99
99
|
coordinate = true ?
|
|
100
|
-
Math.round(10000*coordinates.y[j])/10000 :
|
|
101
|
-
Math.round(10000*(parseFloat(molBlocks[i].substring(index, indexEnd))))/10000;
|
|
100
|
+
Math.round(10000 * coordinates.y[j]) / 10000 :
|
|
101
|
+
Math.round(10000 * (parseFloat(molBlocks[i].substring(index, indexEnd)))) / 10000;
|
|
102
102
|
molBlocks[i] = molBlocks[i].slice(0, index) + coordinate + molBlocks[i].slice(indexEnd);
|
|
103
103
|
|
|
104
104
|
index = molBlocks[i].indexOf('\n', index) + 1;
|
|
@@ -158,27 +158,27 @@ export function linkStrandsV3000(strands:{senseStrands: string[], antiStrands: s
|
|
|
158
158
|
const collNumber = Math.ceil(collection.length / entries);
|
|
159
159
|
|
|
160
160
|
//if (oclRender) {
|
|
161
|
-
|
|
161
|
+
// collectionBlock += 'M V30 MDLV30/STEABS ATOMS=(' + collection.length;
|
|
162
162
|
|
|
163
|
-
|
|
164
|
-
|
|
163
|
+
// for (let j = 0; j < collection.length; j++)
|
|
164
|
+
// collectionBlock += ' ' + collection[j];
|
|
165
165
|
|
|
166
|
-
|
|
166
|
+
// collectionBlock += ')\n';
|
|
167
167
|
//} else {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
168
|
+
collectionBlock += 'M V30 MDLV30/STEABS ATOMS=(' + collection.length + ' -\n';
|
|
169
|
+
for (let i = 0; i < collNumber; i++) {
|
|
170
|
+
collectionBlock += 'M V30 ';
|
|
171
|
+
const entriesCurrent = i + 1 == collNumber ? collection.length - (collNumber - 1) * entries : entries;
|
|
172
|
+
for (let j = 0; j < entriesCurrent; j++) {
|
|
173
|
+
collectionBlock += (j + 1 == entriesCurrent) ?
|
|
174
|
+
(i == collNumber - 1 ? collection[entries * i + j] + ')\n' : collection[entries * i + j] + ' -\n') :
|
|
175
|
+
collection[entries * i + j] + ' ';
|
|
177
176
|
}
|
|
177
|
+
}
|
|
178
178
|
//}
|
|
179
179
|
|
|
180
180
|
//generate file
|
|
181
|
-
true? natom : natom++;
|
|
181
|
+
true ? natom : natom++;
|
|
182
182
|
macroMolBlock += 'M V30 COUNTS ' + natom + ' ' + nbond + ' 0 0 0\n';
|
|
183
183
|
macroMolBlock += 'M V30 BEGIN ATOM\n';
|
|
184
184
|
macroMolBlock += atomBlock;
|
|
@@ -186,7 +186,7 @@ export function linkStrandsV3000(strands:{senseStrands: string[], antiStrands: s
|
|
|
186
186
|
macroMolBlock += 'M V30 BEGIN BOND\n';
|
|
187
187
|
macroMolBlock += bondBlock;
|
|
188
188
|
macroMolBlock += 'M V30 END BOND\n';
|
|
189
|
-
if(useChirality){
|
|
189
|
+
if (useChirality) {
|
|
190
190
|
macroMolBlock += 'M V30 BEGIN COLLECTION\n';
|
|
191
191
|
macroMolBlock += collectionBlock;
|
|
192
192
|
macroMolBlock += 'M V30 END COLLECTION\n';
|
|
@@ -218,7 +218,7 @@ export function linkV3000(molBlocks: string[], useChirality: boolean = true) {
|
|
|
218
218
|
const coordinates = extractAtomDataV3000(molBlocks[i]);
|
|
219
219
|
specLength = coordinates.atomIndex.length;
|
|
220
220
|
}
|
|
221
|
-
|
|
221
|
+
|
|
222
222
|
|
|
223
223
|
molBlocks[i] = molBlocks[i].replaceAll('(-\nM V30 ', '(')
|
|
224
224
|
.replaceAll('-\nM V30 ', '').replaceAll(' )', ')');
|
|
@@ -236,11 +236,11 @@ export function linkV3000(molBlocks: string[], useChirality: boolean = true) {
|
|
|
236
236
|
index = molBlocks[i].indexOf('V30', index) + 4;
|
|
237
237
|
indexEnd = molBlocks[i].indexOf(' ', index);
|
|
238
238
|
let atomNumber = 0;
|
|
239
|
-
if(isBoundary) {
|
|
239
|
+
if (isBoundary) {
|
|
240
240
|
atomNumber = parseInt(molBlocks[i].substring(index, indexEnd))
|
|
241
|
-
if(atomNumber == 1)
|
|
241
|
+
if (atomNumber == 1)
|
|
242
242
|
atomNumber = specLength;
|
|
243
|
-
else if(atomNumber == specLength)
|
|
243
|
+
else if (atomNumber == specLength)
|
|
244
244
|
atomNumber = 1;
|
|
245
245
|
atomNumber += natom;
|
|
246
246
|
} else {
|
|
@@ -254,14 +254,14 @@ export function linkV3000(molBlocks: string[], useChirality: boolean = true) {
|
|
|
254
254
|
indexEnd = molBlocks[i].indexOf(' ', index);
|
|
255
255
|
|
|
256
256
|
const totalShift = xShift - coordinates.x[0];
|
|
257
|
-
let coordinate =
|
|
258
|
-
Math.round(10000*(parseFloat(molBlocks[i].substring(index, indexEnd)) + totalShift))/10000;
|
|
257
|
+
let coordinate =
|
|
258
|
+
Math.round(10000 * (parseFloat(molBlocks[i].substring(index, indexEnd)) + totalShift)) / 10000;
|
|
259
259
|
molBlocks[i] = molBlocks[i].slice(0, index) + coordinate + molBlocks[i].slice(indexEnd);
|
|
260
260
|
|
|
261
261
|
index = molBlocks[i].indexOf(' ', index) + 1;
|
|
262
262
|
indexEnd = molBlocks[i].indexOf(' ', index);
|
|
263
|
-
coordinate =
|
|
264
|
-
Math.round(10000*(parseFloat(molBlocks[i].substring(index, indexEnd))))/10000;
|
|
263
|
+
coordinate =
|
|
264
|
+
Math.round(10000 * (parseFloat(molBlocks[i].substring(index, indexEnd)))) / 10000;
|
|
265
265
|
molBlocks[i] = molBlocks[i].slice(0, index) + coordinate + molBlocks[i].slice(indexEnd);
|
|
266
266
|
|
|
267
267
|
index = molBlocks[i].indexOf('\n', index) + 1;
|
|
@@ -292,11 +292,11 @@ export function linkV3000(molBlocks: string[], useChirality: boolean = true) {
|
|
|
292
292
|
index = molBlocks[i].indexOf(' ', index) + 1;
|
|
293
293
|
indexEnd = molBlocks[i].indexOf(' ', index);
|
|
294
294
|
let atomNumber = 0;
|
|
295
|
-
if(isBoundary) {
|
|
295
|
+
if (isBoundary) {
|
|
296
296
|
atomNumber = parseInt(molBlocks[i].substring(index, indexEnd))
|
|
297
|
-
if(atomNumber == 1)
|
|
297
|
+
if (atomNumber == 1)
|
|
298
298
|
atomNumber = specLength;
|
|
299
|
-
else if(atomNumber == specLength)
|
|
299
|
+
else if (atomNumber == specLength)
|
|
300
300
|
atomNumber = 1;
|
|
301
301
|
atomNumber += natom;
|
|
302
302
|
} else {
|
|
@@ -307,11 +307,11 @@ export function linkV3000(molBlocks: string[], useChirality: boolean = true) {
|
|
|
307
307
|
index = molBlocks[i].indexOf(' ', index) + 1;
|
|
308
308
|
indexEnd = Math.min(molBlocks[i].indexOf('\n', index), molBlocks[i].indexOf(' ', index));
|
|
309
309
|
atomNumber = 0;
|
|
310
|
-
if(isBoundary) {
|
|
310
|
+
if (isBoundary) {
|
|
311
311
|
atomNumber = parseInt(molBlocks[i].substring(index, indexEnd))
|
|
312
|
-
if(atomNumber == 1)
|
|
312
|
+
if (atomNumber == 1)
|
|
313
313
|
atomNumber = specLength;
|
|
314
|
-
else if(atomNumber == specLength)
|
|
314
|
+
else if (atomNumber == specLength)
|
|
315
315
|
atomNumber = 1;
|
|
316
316
|
atomNumber += natom;
|
|
317
317
|
} else {
|
|
@@ -340,7 +340,7 @@ export function linkV3000(molBlocks: string[], useChirality: boolean = true) {
|
|
|
340
340
|
|
|
341
341
|
natom += numbers.natom - 1;
|
|
342
342
|
nbond += numbers.nbond;
|
|
343
|
-
if(isBoundary)
|
|
343
|
+
if (isBoundary)
|
|
344
344
|
xShift += Math.max(...coordinates.x);
|
|
345
345
|
else
|
|
346
346
|
xShift += coordinates.x[numbers.natom - 1] - coordinates.x[0];
|
|
@@ -350,23 +350,23 @@ export function linkV3000(molBlocks: string[], useChirality: boolean = true) {
|
|
|
350
350
|
const collNumber = Math.ceil(collection.length / entries);
|
|
351
351
|
|
|
352
352
|
//if (oclRender) {
|
|
353
|
-
|
|
353
|
+
// collectionBlock += 'M V30 MDLV30/STEABS ATOMS=(' + collection.length;
|
|
354
354
|
|
|
355
|
-
|
|
356
|
-
|
|
355
|
+
// for (let j = 0; j < collection.length; j++)
|
|
356
|
+
// collectionBlock += ' ' + collection[j];
|
|
357
357
|
|
|
358
|
-
|
|
358
|
+
// collectionBlock += ')\n';
|
|
359
359
|
//} else {
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
}
|
|
360
|
+
collectionBlock += 'M V30 MDLV30/STEABS ATOMS=(' + collection.length + ' -\n';
|
|
361
|
+
for (let i = 0; i < collNumber; i++) {
|
|
362
|
+
collectionBlock += 'M V30 ';
|
|
363
|
+
const entriesCurrent = i + 1 == collNumber ? collection.length - (collNumber - 1) * entries : entries;
|
|
364
|
+
for (let j = 0; j < entriesCurrent; j++) {
|
|
365
|
+
collectionBlock += (j + 1 == entriesCurrent) ?
|
|
366
|
+
(i == collNumber - 1 ? collection[entries * i + j] + ')\n' : collection[entries * i + j] + ' -\n') :
|
|
367
|
+
collection[entries * i + j] + ' ';
|
|
369
368
|
}
|
|
369
|
+
}
|
|
370
370
|
//}
|
|
371
371
|
|
|
372
372
|
//generate file
|
|
@@ -378,7 +378,7 @@ export function linkV3000(molBlocks: string[], useChirality: boolean = true) {
|
|
|
378
378
|
macroMolBlock += 'M V30 BEGIN BOND\n';
|
|
379
379
|
macroMolBlock += bondBlock;
|
|
380
380
|
macroMolBlock += 'M V30 END BOND\n';
|
|
381
|
-
if(useChirality){
|
|
381
|
+
if (useChirality) {
|
|
382
382
|
macroMolBlock += 'M V30 BEGIN COLLECTION\n';
|
|
383
383
|
macroMolBlock += collectionBlock;
|
|
384
384
|
macroMolBlock += 'M V30 END COLLECTION\n';
|
|
@@ -404,8 +404,8 @@ function rotateNucleotidesV3000(molecule: string) {
|
|
|
404
404
|
if (natom > 8)
|
|
405
405
|
fix5Prime(coordinates, indexFivePrime, indexThreePrime);
|
|
406
406
|
|
|
407
|
-
const xCenter = (coordinates.x[indexThreePrime] + coordinates.x[indexFivePrime])/2;
|
|
408
|
-
const yCenter = (coordinates.y[indexThreePrime] + coordinates.y[indexFivePrime])/2;
|
|
407
|
+
const xCenter = (coordinates.x[indexThreePrime] + coordinates.x[indexFivePrime]) / 2;
|
|
408
|
+
const yCenter = (coordinates.y[indexThreePrime] + coordinates.y[indexFivePrime]) / 2;
|
|
409
409
|
|
|
410
410
|
//place to center
|
|
411
411
|
for (let i = 0; i < natom; i++) {
|
|
@@ -415,16 +415,14 @@ function rotateNucleotidesV3000(molecule: string) {
|
|
|
415
415
|
|
|
416
416
|
let angle = 0;
|
|
417
417
|
if (coordinates.x[indexFivePrime] == 0)
|
|
418
|
-
angle = coordinates.y[indexFivePrime] > coordinates.y[indexThreePrime] ? Math.PI/2 : 3*Math.PI/2;
|
|
418
|
+
angle = coordinates.y[indexFivePrime] > coordinates.y[indexThreePrime] ? Math.PI / 2 : 3 * Math.PI / 2;
|
|
419
419
|
else if (coordinates.y[indexFivePrime] == 0)
|
|
420
420
|
angle = coordinates.x[indexFivePrime] > coordinates.x[indexThreePrime] ? Math.PI : 0;
|
|
421
421
|
else {
|
|
422
|
-
const derivative = coordinates.y[indexFivePrime]/coordinates.x[indexFivePrime];
|
|
423
|
-
angle = derivative > 0
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
- Math.PI - Math.atan(derivative)
|
|
427
|
-
);
|
|
422
|
+
const derivative = coordinates.y[indexFivePrime] / coordinates.x[indexFivePrime];
|
|
423
|
+
angle = derivative > 0
|
|
424
|
+
? (coordinates.x[indexFivePrime] > 0 ? Math.PI - Math.atan(derivative) : Math.PI * 2 - Math.atan(derivative))
|
|
425
|
+
: (coordinates.x[indexFivePrime] > 0 ? -Math.PI - Math.atan(derivative) : Math.atan(derivative));
|
|
428
426
|
}
|
|
429
427
|
|
|
430
428
|
const cos = Math.cos(angle);
|
|
@@ -432,8 +430,8 @@ function rotateNucleotidesV3000(molecule: string) {
|
|
|
432
430
|
|
|
433
431
|
for (let i = 0; i < natom; i++) {
|
|
434
432
|
const xAdd = coordinates.x[i];
|
|
435
|
-
coordinates.x[i] = xAdd*cos - coordinates.y[i]*sin;
|
|
436
|
-
coordinates.y[i] = xAdd*sin + coordinates.y[i]*cos;
|
|
433
|
+
coordinates.x[i] = xAdd * cos - coordinates.y[i] * sin;
|
|
434
|
+
coordinates.y[i] = xAdd * sin + coordinates.y[i] * cos;
|
|
437
435
|
}
|
|
438
436
|
|
|
439
437
|
//place to right
|
|
@@ -471,8 +469,8 @@ function reflect(molecule: string) {
|
|
|
471
469
|
const indexFivePrime = coordinates.atomIndex.indexOf(1);
|
|
472
470
|
const indexThreePrime = coordinates.atomIndex.indexOf(natom);
|
|
473
471
|
|
|
474
|
-
const xCenter = (coordinates.x[indexThreePrime] + coordinates.x[indexFivePrime])/2;
|
|
475
|
-
const yCenter = (coordinates.y[indexThreePrime] + coordinates.y[indexFivePrime])/2;
|
|
472
|
+
const xCenter = (coordinates.x[indexThreePrime] + coordinates.x[indexFivePrime]) / 2;
|
|
473
|
+
const yCenter = (coordinates.y[indexThreePrime] + coordinates.y[indexFivePrime]) / 2;
|
|
476
474
|
|
|
477
475
|
//place to center
|
|
478
476
|
for (let i = 0; i < natom; i++) {
|
|
@@ -517,8 +515,8 @@ function invertNucleotidesV3000(molecule: string) {
|
|
|
517
515
|
const coordinates = extractAtomDataV3000(molBlock);
|
|
518
516
|
const natom = coordinates.atomIndex.length;
|
|
519
517
|
|
|
520
|
-
const xCenter = (Math.max(...coordinates.x) + Math.min(...coordinates.x))/2;
|
|
521
|
-
const yCenter = (Math.max(...coordinates.y) + Math.min(...coordinates.y))/2;
|
|
518
|
+
const xCenter = (Math.max(...coordinates.x) + Math.min(...coordinates.x)) / 2;
|
|
519
|
+
const yCenter = (Math.max(...coordinates.y) + Math.min(...coordinates.y)) / 2;
|
|
522
520
|
|
|
523
521
|
//place to center
|
|
524
522
|
for (let i = 0; i < natom; i++) {
|
|
@@ -533,8 +531,8 @@ function invertNucleotidesV3000(molecule: string) {
|
|
|
533
531
|
|
|
534
532
|
for (let i = 0; i < natom; i++) {
|
|
535
533
|
const xAdd = coordinates.x[i];
|
|
536
|
-
coordinates.x[i] = xAdd*cos - coordinates.y[i]*sin;
|
|
537
|
-
coordinates.y[i] = xAdd*sin + coordinates.y[i]*cos;
|
|
534
|
+
coordinates.x[i] = xAdd * cos - coordinates.y[i] * sin;
|
|
535
|
+
coordinates.y[i] = xAdd * sin + coordinates.y[i] * cos;
|
|
538
536
|
}
|
|
539
537
|
|
|
540
538
|
//place back
|
|
@@ -565,7 +563,7 @@ function invertNucleotidesV3000(molecule: string) {
|
|
|
565
563
|
return molBlock;
|
|
566
564
|
}
|
|
567
565
|
|
|
568
|
-
function fix5Prime(coordinates: {atomIndex: number[], atomType: string[], x: number[], y: number[]},
|
|
566
|
+
function fix5Prime(coordinates: { atomIndex: number[], atomType: string[], x: number[], y: number[] },
|
|
569
567
|
indexFivePrime: number, indexThreePrime: number) {
|
|
570
568
|
const indexFivePrimeNeighbour = indexFivePrime + 1;
|
|
571
569
|
const xShift = coordinates.x[indexFivePrimeNeighbour];
|
|
@@ -575,21 +573,21 @@ function fix5Prime(coordinates: {atomIndex: number[], atomType: string[], x: num
|
|
|
575
573
|
const base5PrimeX = coordinates.x[indexFivePrime] - xShift;
|
|
576
574
|
const base5PrimeY = coordinates.y[indexFivePrime] - yShift;
|
|
577
575
|
|
|
578
|
-
const rotated5PrimeX = base5PrimeX*Math.cos(Math.PI*2/3) - base5PrimeY*Math.sin(Math.PI*2/3);
|
|
579
|
-
const rotated5PrimeY = base5PrimeX*Math.sin(Math.PI*2/3) + base5PrimeY*Math.cos(Math.PI*2/3);
|
|
576
|
+
const rotated5PrimeX = base5PrimeX * Math.cos(Math.PI * 2 / 3) - base5PrimeY * Math.sin(Math.PI * 2 / 3);
|
|
577
|
+
const rotated5PrimeY = base5PrimeX * Math.sin(Math.PI * 2 / 3) + base5PrimeY * Math.cos(Math.PI * 2 / 3);
|
|
580
578
|
|
|
581
579
|
const dx = base5PrimeX - base3PrimeX;
|
|
582
580
|
const dy = base5PrimeY - base3PrimeY;
|
|
583
581
|
const dxRotated = rotated5PrimeX - base3PrimeX;
|
|
584
582
|
const dyRotated = rotated5PrimeY - base3PrimeY;
|
|
585
583
|
|
|
586
|
-
if (Math.sqrt(dyRotated*dyRotated + dxRotated*dxRotated) >= Math.sqrt(dy*dy + dx*dx)) {
|
|
584
|
+
if (Math.sqrt(dyRotated * dyRotated + dxRotated * dxRotated) >= Math.sqrt(dy * dy + dx * dx)) {
|
|
587
585
|
coordinates.x[indexFivePrime] = rotated5PrimeX + xShift;
|
|
588
586
|
coordinates.y[indexFivePrime] = rotated5PrimeY + yShift;
|
|
589
587
|
}
|
|
590
588
|
}
|
|
591
589
|
|
|
592
|
-
function extractAtomsBondsNumbersV3000(molBlock: string): {natom: number, nbond: number} {
|
|
590
|
+
function extractAtomsBondsNumbersV3000(molBlock: string): { natom: number, nbond: number } {
|
|
593
591
|
molBlock = molBlock.replaceAll('\r', ''); //equalize old and new sdf standards
|
|
594
592
|
let index = molBlock.indexOf('COUNTS') + 7; // V3000 index for atoms and bonds number
|
|
595
593
|
let indexEnd = molBlock.indexOf(' ', index);
|
|
@@ -602,7 +600,7 @@ function extractAtomsBondsNumbersV3000(molBlock: string): {natom: number, nbond:
|
|
|
602
600
|
return {natom: atomsNumber, nbond: bondsNumber};
|
|
603
601
|
}
|
|
604
602
|
|
|
605
|
-
function extractAtomDataV3000(molBlock: string) {
|
|
603
|
+
export function extractAtomDataV3000(molBlock: string) {
|
|
606
604
|
const numbers = extractAtomsBondsNumbersV3000(molBlock);
|
|
607
605
|
let index = molBlock.indexOf('M V30 BEGIN ATOM'); // V3000 index for atoms coordinates
|
|
608
606
|
index = molBlock.indexOf('\n', index);
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export const CELL_STRUCTURE = {
|
|
2
|
+
DUPLEX: {
|
|
3
|
+
BEFORE_SS: 'SS ',
|
|
4
|
+
BEFORE_AS: '\r\nAS ',
|
|
5
|
+
},
|
|
6
|
+
TRIPLEX_OR_DIMER: {
|
|
7
|
+
BEFORE_SS: 'SS ',
|
|
8
|
+
BEFORE_AS1: '\r\nAS1 ',
|
|
9
|
+
BEFORE_AS2: '\r\nAS2 ',
|
|
10
|
+
},
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export function parseStrandsFromDuplexCell(s: string): { SS: string, AS: string } {
|
|
14
|
+
const arr = s
|
|
15
|
+
.slice(CELL_STRUCTURE.DUPLEX.BEFORE_SS.length)
|
|
16
|
+
.split(CELL_STRUCTURE.DUPLEX.BEFORE_AS);
|
|
17
|
+
return {SS: arr[0], AS: arr[1]};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function parseStrandsFromTriplexOrDimerCell(s: string): { SS: string, AS1: string, AS2: string } {
|
|
21
|
+
const arr1 = s
|
|
22
|
+
.slice(CELL_STRUCTURE.TRIPLEX_OR_DIMER.BEFORE_SS.length)
|
|
23
|
+
.split(CELL_STRUCTURE.TRIPLEX_OR_DIMER.BEFORE_AS1);
|
|
24
|
+
const arr2 = arr1[1]
|
|
25
|
+
.split(CELL_STRUCTURE.TRIPLEX_OR_DIMER.BEFORE_AS2);
|
|
26
|
+
return {SS: arr1[0], AS1: arr2[0], AS2: arr2[1]};
|
|
27
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import * as DG from 'datagrok-api/dg';
|
|
2
|
+
import {COL_NAMES, GENERATED_COL_NAMES, SEQUENCE_TYPES} from '../autostart/constants';
|
|
3
|
+
import * as grok from 'datagrok-api/grok';
|
|
4
|
+
import {removeEmptyRows} from '../helpers';
|
|
5
|
+
import {parseStrandsFromDuplexCell, parseStrandsFromTriplexOrDimerCell} from './parse';
|
|
6
|
+
import {isValidSequence} from '../structures-works/sequence-codes-tools';
|
|
7
|
+
import {batchMolWeight, molecularWeight, saltMass, saltMolWeigth} from '../autostart/calculations';
|
|
8
|
+
import {weightsObj} from '../structures-works/map';
|
|
9
|
+
|
|
10
|
+
export class SdfColumnsExistsError extends Error {
|
|
11
|
+
constructor(message: string) {
|
|
12
|
+
super();
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function sdfAddColumns(
|
|
17
|
+
df: DG.DataFrame, saltNamesList: string[], saltsMolWeightList: number[], onError: (rowI: number, err: any) => void
|
|
18
|
+
): DG.DataFrame {
|
|
19
|
+
const sequenceCol = df.getCol(COL_NAMES.SEQUENCE);
|
|
20
|
+
const saltCol = df.getCol(COL_NAMES.SALT);
|
|
21
|
+
const equivalentsCol = df.getCol(COL_NAMES.EQUIVALENTS);
|
|
22
|
+
const typeCol = df.getCol(COL_NAMES.TYPE);
|
|
23
|
+
const chemistryNameCol = df.getCol(COL_NAMES.CHEMISTRY_NAME);
|
|
24
|
+
|
|
25
|
+
if (GENERATED_COL_NAMES.some((colName) => df.columns.contains(colName)))
|
|
26
|
+
throw new SdfColumnsExistsError('Columns already exist');
|
|
27
|
+
|
|
28
|
+
df = removeEmptyRows(df, sequenceCol);
|
|
29
|
+
|
|
30
|
+
df.columns.addNewString(COL_NAMES.COMPOUND_NAME).init((i: number) => {
|
|
31
|
+
let res: string = '';
|
|
32
|
+
try {
|
|
33
|
+
res = ([SEQUENCE_TYPES.DUPLEX, SEQUENCE_TYPES.DIMER, SEQUENCE_TYPES.TRIPLEX].includes(typeCol.get(i))) ?
|
|
34
|
+
chemistryNameCol.get(i) :
|
|
35
|
+
sequenceCol.get(i);
|
|
36
|
+
} catch (err) {
|
|
37
|
+
onError(i, err);
|
|
38
|
+
}
|
|
39
|
+
return res;
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
df.columns.addNewString(COL_NAMES.COMPOUND_COMMENTS).init((i: number) => {
|
|
43
|
+
let res: string = '';
|
|
44
|
+
try {
|
|
45
|
+
if ([SEQUENCE_TYPES.SENSE_STRAND, SEQUENCE_TYPES.ANTISENSE_STRAND].includes(typeCol.get(i))) {
|
|
46
|
+
res = sequenceCol.get(i);
|
|
47
|
+
} else if (typeCol.get(i) == SEQUENCE_TYPES.DUPLEX) {
|
|
48
|
+
const obj = parseStrandsFromDuplexCell(sequenceCol.get(i));
|
|
49
|
+
res = `${chemistryNameCol.get(i)}; duplex of SS: ${obj.SS} and AS: ${obj.AS}`;
|
|
50
|
+
} else if ([SEQUENCE_TYPES.DIMER, SEQUENCE_TYPES.TRIPLEX].includes(typeCol.get(i))) {
|
|
51
|
+
const obj = parseStrandsFromTriplexOrDimerCell(sequenceCol.get(i));
|
|
52
|
+
res = `${chemistryNameCol.get(i)}; duplex of SS: ${obj.SS} and AS1: ${obj.AS1} and AS2: ${obj.AS2}`;
|
|
53
|
+
}
|
|
54
|
+
} catch (err) {
|
|
55
|
+
onError(i, err);
|
|
56
|
+
}
|
|
57
|
+
return res;
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
df.columns.addNewFloat(COL_NAMES.COMPOUND_MOL_WEIGHT).init((i: number) => {
|
|
61
|
+
let res: number = Number.NaN;
|
|
62
|
+
try {
|
|
63
|
+
if ([SEQUENCE_TYPES.SENSE_STRAND, SEQUENCE_TYPES.ANTISENSE_STRAND].includes(typeCol.get(i))) {
|
|
64
|
+
res = (isValidSequence(sequenceCol.get(i), null).indexOfFirstNotValidChar == -1) ?
|
|
65
|
+
molecularWeight(sequenceCol.get(i), weightsObj) :
|
|
66
|
+
DG.FLOAT_NULL;
|
|
67
|
+
} else if (typeCol.get(i) == SEQUENCE_TYPES.DUPLEX) {
|
|
68
|
+
const obj = parseStrandsFromDuplexCell(sequenceCol.get(i));
|
|
69
|
+
res = (Object.values(obj).every((seq) => isValidSequence(seq, null).indexOfFirstNotValidChar == -1)) ?
|
|
70
|
+
molecularWeight(obj.SS, weightsObj) + molecularWeight(obj.AS, weightsObj) :
|
|
71
|
+
DG.FLOAT_NULL;
|
|
72
|
+
} else if ([SEQUENCE_TYPES.DIMER, SEQUENCE_TYPES.TRIPLEX].includes(typeCol.get(i))) {
|
|
73
|
+
const obj = parseStrandsFromTriplexOrDimerCell(sequenceCol.get(i));
|
|
74
|
+
res = (Object.values(obj).every((seq) => isValidSequence(seq, null).indexOfFirstNotValidChar == -1)) ?
|
|
75
|
+
molecularWeight(obj.SS, weightsObj) + molecularWeight(obj.AS1, weightsObj) +
|
|
76
|
+
molecularWeight(obj.AS2, weightsObj) :
|
|
77
|
+
DG.FLOAT_NULL;
|
|
78
|
+
}
|
|
79
|
+
} catch (err) {
|
|
80
|
+
onError(i, err);
|
|
81
|
+
}
|
|
82
|
+
return res;
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
df.columns.addNewFloat(COL_NAMES.SALT_MASS).init((i: number) => {
|
|
86
|
+
let res: number = Number.NaN;
|
|
87
|
+
try {
|
|
88
|
+
res = saltMass(saltNamesList, saltsMolWeightList, equivalentsCol, i, saltCol);
|
|
89
|
+
} catch (err) {
|
|
90
|
+
onError(i, err);
|
|
91
|
+
}
|
|
92
|
+
return res;
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
df.columns.addNewFloat(COL_NAMES.SALT_MOL_WEIGHT).init((i: number) => {
|
|
96
|
+
let res: number = Number.NaN;
|
|
97
|
+
try {
|
|
98
|
+
res = saltMolWeigth(saltNamesList, saltCol, saltsMolWeightList, i);
|
|
99
|
+
} catch (err) {
|
|
100
|
+
onError(i, err);
|
|
101
|
+
}
|
|
102
|
+
return res;
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
const compoundMolWeightCol = df.getCol(COL_NAMES.COMPOUND_MOL_WEIGHT);
|
|
106
|
+
const saltMassCol = df.getCol(COL_NAMES.SALT_MASS);
|
|
107
|
+
df.columns.addNewFloat(COL_NAMES.BATCH_MOL_WEIGHT).init((i: number) => {
|
|
108
|
+
let res: number = Number.NaN;
|
|
109
|
+
try {
|
|
110
|
+
res = batchMolWeight(compoundMolWeightCol, saltMassCol, i);
|
|
111
|
+
} catch (err) {
|
|
112
|
+
onError(i, err);
|
|
113
|
+
}
|
|
114
|
+
return res;
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
return df;
|
|
118
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import * as DG from 'datagrok-api/dg';
|
|
2
|
+
import {COL_NAMES, GENERATED_COL_NAMES, SEQUENCE_TYPES} from '../autostart/constants';
|
|
3
|
+
import {differenceOfTwoArrays, download} from '../helpers';
|
|
4
|
+
import * as grok from 'datagrok-api/grok';
|
|
5
|
+
import {SYNTHESIZERS} from '../structures-works/map';
|
|
6
|
+
import {sequenceToMolV3000} from '../structures-works/from-monomers';
|
|
7
|
+
import {parseStrandsFromDuplexCell, parseStrandsFromTriplexOrDimerCell} from './parse';
|
|
8
|
+
import {linkStrandsV3000} from '../structures-works/mol-transformations';
|
|
9
|
+
|
|
10
|
+
export async function sdfSaveTable(table: DG.DataFrame, onError: (rowI: number, err: any) => void) {
|
|
11
|
+
if (GENERATED_COL_NAMES.some((colName) => !table.columns.contains(colName))) {
|
|
12
|
+
const absentColNames = differenceOfTwoArrays(GENERATED_COL_NAMES, table.columns.names()).join(`', '`);
|
|
13
|
+
grok.shell.warning(`File saved without columns '${absentColNames}'`);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const sequenceCol = table.getCol(COL_NAMES.SEQUENCE);
|
|
17
|
+
const typeCol = table.getCol(COL_NAMES.TYPE);
|
|
18
|
+
|
|
19
|
+
let resultStr = '';
|
|
20
|
+
const rowCount = table.rowCount;
|
|
21
|
+
for (let i = 0; i < rowCount; i++) {
|
|
22
|
+
try {
|
|
23
|
+
let rowStr = '';
|
|
24
|
+
const format = SYNTHESIZERS.GCRS; //getFormat(sequenceCol.get(i))!;
|
|
25
|
+
if (typeCol.get(i) == SEQUENCE_TYPES.SENSE_STRAND) {
|
|
26
|
+
rowStr += `${sequenceToMolV3000(sequenceCol.get(i), false, true, format)}\n> <Sequence>\nSense Strand\n\n`;
|
|
27
|
+
} else if (typeCol.get(i) == SEQUENCE_TYPES.ANTISENSE_STRAND) {
|
|
28
|
+
rowStr += `${sequenceToMolV3000(sequenceCol.get(i), true, true, format)}\n> <Sequence>\nAnti Sense\n\n`;
|
|
29
|
+
} else if (typeCol.get(i) == SEQUENCE_TYPES.DUPLEX) {
|
|
30
|
+
const obj = parseStrandsFromDuplexCell(sequenceCol.get(i));
|
|
31
|
+
const as = `${sequenceToMolV3000(obj.AS, true, true, format)}\n> <Sequence>\nAnti Sense\n\n`;
|
|
32
|
+
const ss = `${sequenceToMolV3000(obj.SS, false, true, format)}\n> <Sequence>\nSense Strand\n\n`;
|
|
33
|
+
rowStr += `${linkStrandsV3000({senseStrands: [ss], antiStrands: [as]}, true)}\n\n`;
|
|
34
|
+
} else if ([SEQUENCE_TYPES.TRIPLEX, SEQUENCE_TYPES.DIMER].includes(typeCol.get(i))) {
|
|
35
|
+
const obj = parseStrandsFromTriplexOrDimerCell(sequenceCol.get(i));
|
|
36
|
+
const as1 = `${sequenceToMolV3000(obj.AS1, true, true, format)}\n> <Sequence>\nAnti Sense\n\n`;
|
|
37
|
+
const as2 = `${sequenceToMolV3000(obj.AS2, true, true, format)}\n> <Sequence>\nAnti Sense\n\n`;
|
|
38
|
+
const ss = `${sequenceToMolV3000(obj.SS, false, true, format)}\n> <Sequence>\nSense Strand\n\n`;
|
|
39
|
+
rowStr += `${linkStrandsV3000({senseStrands: [ss], antiStrands: [as1, as2]}, true)}\n\n`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
for (const col of table.columns) {
|
|
43
|
+
if (col.name != COL_NAMES.SEQUENCE)
|
|
44
|
+
rowStr += `> <${col.name}>\n${col.get(i)}\n\n`;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
rowStr += '$$$$\n';
|
|
48
|
+
|
|
49
|
+
resultStr += rowStr;
|
|
50
|
+
} catch (err: any) {
|
|
51
|
+
onError(i, err);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
download(`${table.name}.sdf`, encodeURIComponent(resultStr));
|
|
56
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<html><head><meta charset="utf-8"/><title>SequenceTranslator Test Report. Datagrok version datagrok/datagrok:latest SHA=
|
|
1
|
+
<html><head><meta charset="utf-8"/><title>SequenceTranslator Test Report. Datagrok version datagrok/datagrok:latest SHA=6288c2fbe346. Commit cce4ac1d.</title><style type="text/css">html,
|
|
2
2
|
body {
|
|
3
3
|
font-family: Arial, Helvetica, sans-serif;
|
|
4
4
|
font-size: 1rem;
|
|
@@ -229,7 +229,7 @@ header {
|
|
|
229
229
|
font-size: 1rem;
|
|
230
230
|
padding: 0 0.5rem;
|
|
231
231
|
}
|
|
232
|
-
</style></head><body><div id="jesthtml-content"><header><h1 id="title">SequenceTranslator Test Report. Datagrok version datagrok/datagrok:latest SHA=
|
|
232
|
+
</style></head><body><div id="jesthtml-content"><header><h1 id="title">SequenceTranslator Test Report. Datagrok version datagrok/datagrok:latest SHA=6288c2fbe346. Commit cce4ac1d.</h1></header><div id="metadata-container"><div id="timestamp">Started: 2022-12-12 14:55:37</div><div id="summary"><div id="suite-summary"><div class="summary-total">Suites (1)</div><div class="summary-passed">1 passed</div><div class="summary-failed summary-empty">0 failed</div><div class="summary-pending summary-empty">0 pending</div></div><div id="test-summary"><div class="summary-total">Tests (1)</div><div class="summary-passed">1 passed</div><div class="summary-failed summary-empty">0 failed</div><div class="summary-pending summary-empty">0 pending</div></div></div></div><div id="suite-1" class="suite-container"><div class="suite-info"><div class="suite-path">/home/runner/work/public/public/packages/SequenceTranslator/src/__jest__/remote.test.ts</div><div class="suite-time warn">21.067s</div></div><div class="suite-tests"><div class="test-result passed"><div class="test-info"><div class="test-suitename"> </div><div class="test-title">TEST</div><div class="test-status">passed</div><div class="test-duration">6.276s</div></div></div></div><div class="suite-consolelog"><div class="suite-consolelog-header">Console Log</div><div class="suite-consolelog-item"><pre class="suite-consolelog-item-origin"> at Object.<anonymous> (/home/runner/work/public/public/packages/SequenceTranslator/src/__jest__/test-node.ts:62:11)
|
|
233
233
|
at Generator.next (<anonymous>)
|
|
234
234
|
at fulfilled (/home/runner/work/public/public/packages/SequenceTranslator/src/__jest__/test-node.ts:28:58)
|
|
235
235
|
at processTicksAndRejections (internal/process/task_queues.js:97:5)</pre><pre class="suite-consolelog-item-message">Using web root: http://localhost:8080</pre></div><div class="suite-consolelog-item"><pre class="suite-consolelog-item-origin"> at /home/runner/work/public/public/packages/SequenceTranslator/src/__jest__/remote.test.ts:40:11
|
|
@@ -242,17 +242,17 @@ header {
|
|
|
242
242
|
at new Promise (<anonymous>)</pre><pre class="suite-consolelog-item-message">Testing SequenceTranslator package</pre></div><div class="suite-consolelog-item"><pre class="suite-consolelog-item-origin"> at /home/runner/work/public/public/packages/SequenceTranslator/src/__jest__/remote.test.ts:72:11
|
|
243
243
|
at Generator.next (<anonymous>)
|
|
244
244
|
at fulfilled (/home/runner/work/public/public/packages/SequenceTranslator/src/__jest__/remote.test.ts:28:58)
|
|
245
|
-
at processTicksAndRejections (internal/process/task_queues.js:97:5)</pre><pre class="suite-consolelog-item-message">Test result : Success :
|
|
245
|
+
at processTicksAndRejections (internal/process/task_queues.js:97:5)</pre><pre class="suite-consolelog-item-message">Test result : Success : 2 : SequenceTranslator.sequence-translator.usCfCfUfGfAf : OK
|
|
246
246
|
Test result : Success : 0 : SequenceTranslator.sequence-translator.usAfsusgsgsg : OK
|
|
247
|
-
Test result : Success :
|
|
247
|
+
Test result : Success : 0 : SequenceTranslator.sequence-translator.UfUfUfsCfsuacg : OK
|
|
248
248
|
Test result : Success : 0 : SequenceTranslator.sequence-translator.susususauasu : OK
|
|
249
249
|
Test result : Success : 0 : SequenceTranslator.sequence-translator.CfGfCfsGfsCf : OK
|
|
250
250
|
Test result : Success : 1 : SequenceTranslator.sequence-translator.acacacsacsac : OK
|
|
251
251
|
Test result : Success : 0 : SequenceTranslator.sequence-translator.cccgggusug : OK
|
|
252
252
|
Test result : Success : 0 : SequenceTranslator.sequence-translator.UfAfCfGfGfCfAfUf : OK
|
|
253
253
|
Test result : Success : 1 : SequenceTranslator.sequence-translator.(invabasic)cuCfuUfsc : OK
|
|
254
|
-
Test result : Success :
|
|
255
|
-
Test result : Success :
|
|
254
|
+
Test result : Success : 1 : SequenceTranslator.sequence-translator.(invabasic)usAfsucuCfuUfAfgcugUfgCfacususu : OK
|
|
255
|
+
Test result : Success : 1 : SequenceTranslator.sequence-translator.(invabasic)asacgGfuGfCfAfacucuauuca : OK
|
|
256
256
|
</pre></div><div class="suite-consolelog-item"><pre class="suite-consolelog-item-origin"> at /home/runner/work/public/public/packages/SequenceTranslator/src/__jest__/remote.test.ts:74:11
|
|
257
257
|
at Generator.next (<anonymous>)
|
|
258
258
|
at fulfilled (/home/runner/work/public/public/packages/SequenceTranslator/src/__jest__/remote.test.ts:28:58)
|