@datagrok/sequence-translator 1.0.11 → 1.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/package-test.js +254 -94
- package/dist/package.js +602 -364
- package/package.json +2 -2
- package/src/__jest__/remote.test.ts +11 -3
- package/src/{ICDs.ts → autostart/ICDs.ts} +0 -0
- package/src/{IDPs.ts → autostart/IDPs.ts} +0 -0
- package/src/autostart/calculations.ts +37 -0
- package/src/autostart/constants.ts +37 -0
- package/src/autostart/registration.ts +94 -129
- package/src/{salts.ts → autostart/salts.ts} +0 -0
- package/src/{sources.ts → autostart/sources.ts} +0 -0
- package/src/{users.ts → autostart/users.ts} +0 -0
- package/src/axolabs/define-pattern.ts +42 -34
- package/src/axolabs/draw-svg.ts +19 -19
- package/src/helpers.ts +28 -0
- package/src/main/main-view.ts +48 -70
- package/src/package.ts +6 -7
- package/src/structures-works/from-monomers.ts +1 -4
- package/src/structures-works/map.ts +14 -28
- package/src/structures-works/mol-transformations.ts +177 -16
- package/src/structures-works/save-sense-antisense.ts +32 -11
- package/src/structures-works/sequence-codes-tools.ts +1 -3
- package/{test-SequenceTranslator-916a90d7d48b-7afd2a61.html → test-SequenceTranslator-62cc009524f3-4a9916b0.html} +11 -8
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.13",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Vadym Kovadlo",
|
|
7
7
|
"email": "vkovadlo@datagrok.ai"
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"directory": "packages/SequenceTranslator"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@datagrok-libraries/utils": "^1.
|
|
16
|
+
"@datagrok-libraries/utils": "^1.15.5",
|
|
17
17
|
"@types/react": "^18.0.15",
|
|
18
18
|
"datagrok-api": "^1.7.2",
|
|
19
19
|
"datagrok-tools": "^4.1.2",
|
|
@@ -43,27 +43,35 @@ it('TEST', async () => {
|
|
|
43
43
|
return new Promise<object>((resolve, reject) => {
|
|
44
44
|
(<any>window).grok.functions.eval(targetPackage + ':test()').then((df: any) => {
|
|
45
45
|
const cStatus = df.columns.byName('success');
|
|
46
|
+
const cSkipped = df.columns.byName('skipped');
|
|
46
47
|
const cMessage = df.columns.byName('result');
|
|
47
48
|
const cCat = df.columns.byName('category');
|
|
48
49
|
const cName = df.columns.byName('name');
|
|
49
50
|
const cTime = df.columns.byName('ms');
|
|
50
51
|
let failed = false;
|
|
52
|
+
let skipReport = '';
|
|
51
53
|
let passReport = '';
|
|
52
54
|
let failReport = '';
|
|
53
55
|
for (let i = 0; i < df.rowCount; i++) {
|
|
54
56
|
if (cStatus.get(i)) {
|
|
55
|
-
|
|
57
|
+
if (cSkipped.get(i)) {
|
|
58
|
+
skipReport += `Test result : Skipped : ${cTime.get(i)} : ${targetPackage}.${cCat.get(i)}.${cName.get(i)} : ${cMessage.get(i)}\n`;
|
|
59
|
+
} else {
|
|
60
|
+
passReport += `Test result : Success : ${cTime.get(i)} : ${targetPackage}.${cCat.get(i)}.${cName.get(i)} : ${cMessage.get(i)}\n`;
|
|
61
|
+
}
|
|
56
62
|
} else {
|
|
57
63
|
failed = true;
|
|
58
64
|
failReport += `Test result : Failed : ${cTime.get(i)} : ${targetPackage}.${cCat.get(i)}.${cName.get(i)} : ${cMessage.get(i)}\n`;
|
|
59
65
|
}
|
|
60
66
|
}
|
|
61
|
-
resolve({failReport, passReport, failed});
|
|
67
|
+
resolve({failReport, skipReport, passReport, failed});
|
|
62
68
|
}).catch((e: any) => reject(e));
|
|
63
69
|
});
|
|
64
70
|
}, targetPackage);
|
|
65
71
|
// @ts-ignore
|
|
66
72
|
console.log(r.passReport);
|
|
67
73
|
// @ts-ignore
|
|
74
|
+
console.log(r.skipReport);
|
|
75
|
+
// @ts-ignore
|
|
68
76
|
expect(r.failed).checkOutput(false, r.failReport);
|
|
69
|
-
},
|
|
77
|
+
}, 7200000);
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import * as DG from 'datagrok-api/dg';
|
|
2
|
+
import {sortByStringLengthInDescendingOrder} from '../helpers';
|
|
3
|
+
import {MODIFICATIONS} from '../structures-works/map';
|
|
4
|
+
|
|
5
|
+
export function saltMass(
|
|
6
|
+
saltNames: string[], molWeightCol: DG.Column, equivalentsCol: DG.Column, i: number, saltCol: DG.Column,
|
|
7
|
+
): number {
|
|
8
|
+
const saltRowIndex = saltNames.indexOf(saltCol.get(i));
|
|
9
|
+
return (
|
|
10
|
+
saltRowIndex == -1 || molWeightCol.get(saltRowIndex) == DG.FLOAT_NULL || equivalentsCol.get(i) == DG.INT_NULL
|
|
11
|
+
) ?
|
|
12
|
+
DG.FLOAT_NULL :
|
|
13
|
+
molWeightCol.get(saltRowIndex) * equivalentsCol.get(i);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function saltMolWeigth(saltNamesList: string[], saltCol: DG.Column, molWeightCol: DG.Column, i: number): number {
|
|
17
|
+
const saltRowIndex = saltNamesList.indexOf(saltCol.get(i));
|
|
18
|
+
return (saltRowIndex == -1) ? DG.FLOAT_NULL : molWeightCol.get(saltRowIndex);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function batchMolWeight(compoundMolWeightCol: DG.Column, saltMassCol: DG.Column, i: number): number {
|
|
22
|
+
return (compoundMolWeightCol.getString(i) == '' || saltMassCol.getString(i) == '') ?
|
|
23
|
+
DG.FLOAT_NULL :
|
|
24
|
+
compoundMolWeightCol.get(i) + saltMassCol.get(i);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function molecularWeight(sequence: string, weightsObj: {[index: string]: number}): number {
|
|
28
|
+
const codes = sortByStringLengthInDescendingOrder(Object.keys(weightsObj)).concat(Object.keys(MODIFICATIONS));
|
|
29
|
+
let weight = 0;
|
|
30
|
+
let i = 0;
|
|
31
|
+
while (i < sequence.length) {
|
|
32
|
+
const matchedCode = codes.find((s) => s == sequence.slice(i, i + s.length))!;
|
|
33
|
+
weight += weightsObj[sequence.slice(i, i + matchedCode.length)];
|
|
34
|
+
i += matchedCode.length;
|
|
35
|
+
}
|
|
36
|
+
return weight - 61.97;
|
|
37
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export const SEQUENCE_TYPES = {
|
|
2
|
+
SENSE_STRAND: 'SS',
|
|
3
|
+
ANTISENSE_STRAND: 'AS',
|
|
4
|
+
DUPLEX: 'Duplex',
|
|
5
|
+
TRIPLEX: 'Triplex',
|
|
6
|
+
DIMER: 'Dimer',
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export const COL_NAMES = {
|
|
10
|
+
CHEMISTRY: 'Chemistry',
|
|
11
|
+
NUMBER: 'Number',
|
|
12
|
+
TYPE: 'Type',
|
|
13
|
+
CHEMISTRY_NAME: 'Chemistry Name',
|
|
14
|
+
INTERNAL_COMPOUND_ID: 'Internal compound ID',
|
|
15
|
+
IDP: 'IDP',
|
|
16
|
+
SEQUENCE: 'Sequence',
|
|
17
|
+
COMPOUND_NAME: 'Compound Name',
|
|
18
|
+
COMPOUND_COMMENTS: 'Compound Comments',
|
|
19
|
+
SALT: 'Salt',
|
|
20
|
+
EQUIVALENTS: 'Equivalents',
|
|
21
|
+
PURITY: 'Purity',
|
|
22
|
+
COMPOUND_MOL_WEIGHT: 'Cpd MW',
|
|
23
|
+
SALT_MOL_WEIGHT: 'Salt MW',
|
|
24
|
+
SALT_MASS: 'Salt mass',
|
|
25
|
+
BATCH_MOL_WEIGHT: 'Batch MW',
|
|
26
|
+
SOURCE: 'Source',
|
|
27
|
+
ICD: 'ICD',
|
|
28
|
+
OWNER: 'Owner',
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const GENERATED_COL_NAMES = [
|
|
32
|
+
COL_NAMES.COMPOUND_NAME,
|
|
33
|
+
COL_NAMES.COMPOUND_COMMENTS,
|
|
34
|
+
COL_NAMES.COMPOUND_MOL_WEIGHT,
|
|
35
|
+
COL_NAMES.SALT_MASS,
|
|
36
|
+
COL_NAMES.BATCH_MOL_WEIGHT,
|
|
37
|
+
];
|
|
@@ -3,90 +3,59 @@ import * as ui from 'datagrok-api/ui';
|
|
|
3
3
|
import * as DG from 'datagrok-api/dg';
|
|
4
4
|
import {siRnaBioSpringToGcrs, siRnaAxolabsToGcrs, gcrsToNucleotides, asoGapmersBioSpringToGcrs, gcrsToMermade12,
|
|
5
5
|
siRnaNucleotidesToGcrs} from '../structures-works/converters';
|
|
6
|
-
import {
|
|
6
|
+
import {weightsObj, SYNTHESIZERS} from '../structures-works/map';
|
|
7
|
+
import {SEQUENCE_TYPES, COL_NAMES, GENERATED_COL_NAMES} from './constants';
|
|
8
|
+
import {saltMass, saltMolWeigth, molecularWeight, batchMolWeight} from './calculations';
|
|
7
9
|
import {isValidSequence} from '../structures-works/sequence-codes-tools';
|
|
8
10
|
import {sequenceToMolV3000} from '../structures-works/from-monomers';
|
|
9
|
-
import {
|
|
11
|
+
import {linkStrandsV3000} from '../structures-works/mol-transformations';
|
|
12
|
+
import {stringify, download, removeEmptyRows, differenceOfTwoArrays} from '../helpers';
|
|
10
13
|
|
|
11
|
-
import {SALTS_CSV} from '
|
|
12
|
-
import {USERS_CSV} from '
|
|
13
|
-
import {ICDS} from '
|
|
14
|
-
import {SOURCES} from '
|
|
15
|
-
import {IDPS} from '
|
|
14
|
+
import {SALTS_CSV} from './salts';
|
|
15
|
+
import {USERS_CSV} from './users';
|
|
16
|
+
import {ICDS} from './ICDs';
|
|
17
|
+
import {SOURCES} from './sources';
|
|
18
|
+
import {IDPS} from './IDPs';
|
|
16
19
|
|
|
17
20
|
|
|
18
|
-
function
|
|
19
|
-
|
|
21
|
+
function parseStrandsFromDuplexCell(s: string): {SS: string, AS: string} {
|
|
22
|
+
const arr = s.slice(3).split('\r\nAS ');
|
|
23
|
+
return {SS: arr[0], AS: arr[1]};
|
|
20
24
|
}
|
|
21
25
|
|
|
22
|
-
function
|
|
23
|
-
|
|
26
|
+
function parseStrandsFromTriplexOrDimerCell(s: string): {SS: string, AS1: string, AS2: string} {
|
|
27
|
+
const arr1 = s.slice(3).split('\r\nAS1 ');
|
|
28
|
+
const arr2 = arr1[1].split('\r\nAS2 ');
|
|
29
|
+
return {SS: arr1[0], AS1: arr2[0], AS2: arr2[1]};
|
|
24
30
|
}
|
|
25
31
|
|
|
26
|
-
function
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
saltRowIndex == -1 || molWeightCol.get(saltRowIndex) == DG.FLOAT_NULL || equivalentsCol.get(i) == DG.INT_NULL) ?
|
|
31
|
-
DG.FLOAT_NULL :
|
|
32
|
-
molWeightCol.get(saltRowIndex) * equivalentsCol.get(i);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function saltMolWeigth(saltNamesList: string[], saltCol: DG.Column, molWeightCol: DG.Column, i: number) {
|
|
36
|
-
const saltRowIndex = saltNamesList.indexOf(saltCol.get(i));
|
|
37
|
-
return (saltRowIndex == -1) ? DG.FLOAT_NULL : molWeightCol.get(saltRowIndex);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function batchMolWeight(compoundMolWeightCol: DG.Column, saltMassCol: DG.Column, i: number) {
|
|
41
|
-
return (compoundMolWeightCol.getString(i) == '' || saltMassCol.getString(i) == '') ?
|
|
42
|
-
DG.FLOAT_NULL :
|
|
43
|
-
compoundMolWeightCol.get(i) + saltMassCol.get(i);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function molecularWeight(sequence: string, weightsObj: {[index: string]: number}): number {
|
|
47
|
-
const codes = sortByStringLengthInDescendingOrder(Object.keys(weightsObj)).concat(Object.keys(MODIFICATIONS));
|
|
48
|
-
let weight = 0;
|
|
49
|
-
let i = 0;
|
|
50
|
-
while (i < sequence.length) {
|
|
51
|
-
const matchedCode = codes.find((s) => s == sequence.slice(i, i + s.length))!;
|
|
52
|
-
weight += weightsObj[sequence.slice(i, i + matchedCode.length)];
|
|
53
|
-
i += matchedCode.length;
|
|
32
|
+
async function saveTableAsSdFile(table: DG.DataFrame) {
|
|
33
|
+
if (GENERATED_COL_NAMES.some((colName) => !table.columns.contains(colName))) {
|
|
34
|
+
const absentColNames = differenceOfTwoArrays(GENERATED_COL_NAMES, table.columns.names()).join(`', '`);
|
|
35
|
+
grok.shell.warning(`File saved without columns '${absentColNames}'`);
|
|
54
36
|
}
|
|
55
|
-
return weight - 61.97;
|
|
56
|
-
}
|
|
57
37
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
38
|
+
const sequenceCol = table.getCol(COL_NAMES.SEQUENCE);
|
|
39
|
+
const typeCol = table.getCol(COL_NAMES.TYPE);
|
|
61
40
|
|
|
62
|
-
async function saveTableAsSdFile(table: DG.DataFrame) {
|
|
63
|
-
if (!table.columns.contains('Compound Name')) {
|
|
64
|
-
grok.shell.warning(
|
|
65
|
-
'File saved without columns \'' +
|
|
66
|
-
[COL_NAMES.COMPOUND_NAME, COL_NAMES.COMPOUND_COMMENTS, COL_NAMES.CPD_MW,
|
|
67
|
-
COL_NAMES.SALT_MASS, COL_NAMES.BATCH_MW].join('\', \''),
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
|
-
const structureColumn = table.getCol(COL_NAMES.SEQUENCE);
|
|
71
|
-
const typeColumn = table.getCol(COL_NAMES.TYPE);
|
|
72
41
|
let result = '';
|
|
73
42
|
for (let i = 0; i < table.rowCount; i++) {
|
|
74
|
-
const format =
|
|
75
|
-
if (
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
result +=
|
|
43
|
+
const format = SYNTHESIZERS.GCRS; //getFormat(sequenceCol.get(i))!;
|
|
44
|
+
if (typeCol.get(i) == SEQUENCE_TYPES.SENSE_STRAND)
|
|
45
|
+
result += `${sequenceToMolV3000(sequenceCol.get(i), false, true, format)}\n> <Sequence>\nSense Strand\n\n`;
|
|
46
|
+
else if (typeCol.get(i) == SEQUENCE_TYPES.ANTISENSE_STRAND)
|
|
47
|
+
result += `${sequenceToMolV3000(sequenceCol.get(i), true, true, format)}\n> <Sequence>\nAnti Sense\n\n`;
|
|
48
|
+
else if (typeCol.get(i) == SEQUENCE_TYPES.DUPLEX) {
|
|
49
|
+
const obj = parseStrandsFromDuplexCell(sequenceCol.get(i));
|
|
50
|
+
const as = `${sequenceToMolV3000(obj.AS, true, true, format)}\n> <Sequence>\nAnti Sense\n\n`;
|
|
51
|
+
const ss = `${sequenceToMolV3000(obj.SS, false, true, format)}\n> <Sequence>\nSense Strand\n\n`;
|
|
52
|
+
result += `${linkStrandsV3000({senseStrands: [ss], antiStrands: [as]}, true)}\n\n`;
|
|
53
|
+
} else if ([SEQUENCE_TYPES.TRIPLEX, SEQUENCE_TYPES.DIMER].includes(typeCol.get(i))) {
|
|
54
|
+
const obj = parseStrandsFromTriplexOrDimerCell(sequenceCol.get(i));
|
|
55
|
+
const as1 = `${sequenceToMolV3000(obj.AS1, true, true, format)}\n> <Sequence>\nAnti Sense\n\n`;
|
|
56
|
+
const as2 = `${sequenceToMolV3000(obj.AS2, true, true, format)}\n> <Sequence>\nAnti Sense\n\n`;
|
|
57
|
+
const ss = `${sequenceToMolV3000(obj.SS, false, true, format)}\n> <Sequence>\nSense Strand\n\n`;
|
|
58
|
+
result += `${linkStrandsV3000({senseStrands: [ss], antiStrands: [as1, as2]}, true)}\n\n`;
|
|
90
59
|
}
|
|
91
60
|
|
|
92
61
|
for (const col of table.columns) {
|
|
@@ -95,17 +64,16 @@ async function saveTableAsSdFile(table: DG.DataFrame) {
|
|
|
95
64
|
}
|
|
96
65
|
result += '$$$$\n';
|
|
97
66
|
}
|
|
98
|
-
|
|
99
|
-
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(result));
|
|
100
|
-
element.setAttribute('download', table.name + '.sdf');
|
|
101
|
-
element.click();
|
|
67
|
+
download(`${table.name}.sdf`, encodeURIComponent(result));
|
|
102
68
|
}
|
|
103
69
|
|
|
104
70
|
export function autostartOligoSdFileSubscription() {
|
|
105
71
|
grok.events.onViewAdded.subscribe((v: any) => {
|
|
106
|
-
if (v.type ==
|
|
72
|
+
if (v.type == DG.VIEW_TYPE.TABLE_VIEW) {
|
|
107
73
|
if (v.dataFrame.columns.contains(COL_NAMES.TYPE))
|
|
108
74
|
oligoSdFile(v.dataFrame);
|
|
75
|
+
|
|
76
|
+
// Should be removed after fixing bug https://github.com/datagrok-ai/public/issues/808
|
|
109
77
|
grok.events.onContextMenu.subscribe((args) => {
|
|
110
78
|
const seqCol = args.args.context.table.currentCol; // /^[fsACGUacgu]{6,}$/
|
|
111
79
|
if (DG.Detector.sampleCategories(seqCol,
|
|
@@ -166,56 +134,56 @@ export function oligoSdFile(table: DG.DataFrame) {
|
|
|
166
134
|
const sequenceCol = table.getCol(COL_NAMES.SEQUENCE);
|
|
167
135
|
const saltCol = table.getCol(COL_NAMES.SALT);
|
|
168
136
|
const equivalentsCol = table.getCol(COL_NAMES.EQUIVALENTS);
|
|
169
|
-
const
|
|
137
|
+
const typeCol = table.getCol(COL_NAMES.TYPE);
|
|
170
138
|
const chemistryNameCol = table.getCol(COL_NAMES.CHEMISTRY_NAME);
|
|
171
139
|
|
|
172
140
|
const molWeightCol = saltsDf.getCol('MOLWEIGHT');
|
|
173
141
|
const saltNamesList = saltsDf.getCol('DISPLAY').toList();
|
|
174
142
|
|
|
143
|
+
let newDf: DG.DataFrame;
|
|
144
|
+
let addColumnsPressed = false;
|
|
145
|
+
|
|
175
146
|
function addColumns(t: DG.DataFrame) {
|
|
176
|
-
if (t.columns.contains(
|
|
147
|
+
if (GENERATED_COL_NAMES.some((colName) => t.columns.contains(colName)))
|
|
177
148
|
return grok.shell.error('Columns already exist');
|
|
178
149
|
|
|
179
|
-
|
|
180
|
-
if (sequenceCol.get(i) == '')
|
|
181
|
-
t.rows.removeAt(i, 1, false);
|
|
182
|
-
}
|
|
150
|
+
t = removeEmptyRows(t, sequenceCol);
|
|
183
151
|
|
|
184
152
|
t.columns.addNewString(COL_NAMES.COMPOUND_NAME).init((i: number) => {
|
|
185
|
-
return (
|
|
153
|
+
return ([SEQUENCE_TYPES.DUPLEX, SEQUENCE_TYPES.DIMER, SEQUENCE_TYPES.TRIPLEX].includes(typeCol.get(i))) ?
|
|
154
|
+
chemistryNameCol.get(i) :
|
|
155
|
+
sequenceCol.get(i);
|
|
186
156
|
});
|
|
187
157
|
|
|
188
158
|
t.columns.addNewString(COL_NAMES.COMPOUND_COMMENTS).init((i: number) => {
|
|
189
|
-
if (
|
|
190
|
-
|
|
191
|
-
|
|
159
|
+
if ([SEQUENCE_TYPES.SENSE_STRAND, SEQUENCE_TYPES.ANTISENSE_STRAND].includes(typeCol.get(i)))
|
|
160
|
+
return sequenceCol.get(i);
|
|
161
|
+
else if (typeCol.get(i) == SEQUENCE_TYPES.DUPLEX) {
|
|
162
|
+
const obj = parseStrandsFromDuplexCell(sequenceCol.get(i));
|
|
163
|
+
return `${chemistryNameCol.get(i)}; duplex of SS: ${obj.SS} and AS: ${obj.AS}`;
|
|
164
|
+
} else if ([SEQUENCE_TYPES.DIMER, SEQUENCE_TYPES.TRIPLEX].includes(typeCol.get(i))) {
|
|
165
|
+
const obj = parseStrandsFromTriplexOrDimerCell(sequenceCol.get(i));
|
|
166
|
+
return `${chemistryNameCol.get(i)}; duplex of SS: ${obj.SS} and AS1: ${obj.AS1} and AS2: ${obj.AS2}`;
|
|
192
167
|
}
|
|
193
|
-
return sequenceCol.get(i);
|
|
194
168
|
});
|
|
195
169
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
isValidSequence(arr[1], null).indexOfFirstNotValidChar == -1
|
|
212
|
-
) ?
|
|
213
|
-
molecularWeight(arr[0], weightsObj) + molecularWeight(arr[1], weightsObj) :
|
|
170
|
+
t.columns.addNewFloat(COL_NAMES.COMPOUND_MOL_WEIGHT).init((i: number) => {
|
|
171
|
+
if ([SEQUENCE_TYPES.SENSE_STRAND, SEQUENCE_TYPES.ANTISENSE_STRAND].includes(typeCol.get(i))) {
|
|
172
|
+
return (isValidSequence(sequenceCol.get(i), null).indexOfFirstNotValidChar == -1) ?
|
|
173
|
+
molecularWeight(sequenceCol.get(i), weightsObj) :
|
|
174
|
+
DG.FLOAT_NULL;
|
|
175
|
+
} else if (typeCol.get(i) == SEQUENCE_TYPES.DUPLEX) {
|
|
176
|
+
const obj = parseStrandsFromDuplexCell(sequenceCol.get(i));
|
|
177
|
+
return (Object.values(obj).every((seq) => isValidSequence(seq, null).indexOfFirstNotValidChar == -1)) ?
|
|
178
|
+
molecularWeight(obj.SS, weightsObj) + molecularWeight(obj.AS, weightsObj) :
|
|
179
|
+
DG.FLOAT_NULL;
|
|
180
|
+
} else if ([SEQUENCE_TYPES.DIMER, SEQUENCE_TYPES.TRIPLEX].includes(typeCol.get(i))) {
|
|
181
|
+
const obj = parseStrandsFromTriplexOrDimerCell(sequenceCol.get(i));
|
|
182
|
+
return (Object.values(obj).every((seq) => isValidSequence(seq, null).indexOfFirstNotValidChar == -1)) ?
|
|
183
|
+
molecularWeight(obj.SS, weightsObj) + molecularWeight(obj.AS1, weightsObj) +
|
|
184
|
+
molecularWeight(obj.AS2, weightsObj) :
|
|
214
185
|
DG.FLOAT_NULL;
|
|
215
186
|
}
|
|
216
|
-
return (isValidSequence(sequenceCol.get(i), null).indexOfFirstNotValidChar == -1) ?
|
|
217
|
-
molecularWeight(sequenceCol.get(i), weightsObj) :
|
|
218
|
-
DG.FLOAT_NULL;
|
|
219
187
|
});
|
|
220
188
|
|
|
221
189
|
t.columns.addNewFloat(COL_NAMES.SALT_MASS).init((i: number) =>
|
|
@@ -224,15 +192,24 @@ export function oligoSdFile(table: DG.DataFrame) {
|
|
|
224
192
|
t.columns.addNewFloat(COL_NAMES.SALT_MOL_WEIGHT).init((i: number) =>
|
|
225
193
|
saltMolWeigth(saltNamesList, saltCol, molWeightCol, i));
|
|
226
194
|
|
|
227
|
-
t.
|
|
228
|
-
|
|
195
|
+
const compoundMolWeightCol = t.getCol(COL_NAMES.COMPOUND_MOL_WEIGHT);
|
|
196
|
+
const saltMassCol = t.getCol(COL_NAMES.SALT_MASS);
|
|
197
|
+
t.columns.addNewFloat(COL_NAMES.BATCH_MOL_WEIGHT).init((i: number) =>
|
|
198
|
+
batchMolWeight(compoundMolWeightCol, saltMassCol, i));
|
|
229
199
|
|
|
200
|
+
grok.shell.getTableView(table.name).grid.columns.setOrder(Object.values(COL_NAMES));
|
|
230
201
|
addColumnsPressed = true;
|
|
231
202
|
return newDf = t;
|
|
232
203
|
}
|
|
233
204
|
|
|
234
|
-
|
|
235
|
-
|
|
205
|
+
function updateCalculatedColumns(t: DG.DataFrame, i: number): void {
|
|
206
|
+
const smValue = saltMass(saltNamesList, molWeightCol, equivalentsCol, i, saltCol);
|
|
207
|
+
t.getCol(COL_NAMES.SALT_MASS).set(i, smValue, false);
|
|
208
|
+
const smwValue = saltMolWeigth(saltNamesList, saltCol, molWeightCol, i);
|
|
209
|
+
t.getCol(COL_NAMES.SALT_MOL_WEIGHT).set(i, smwValue, false);
|
|
210
|
+
const bmw = batchMolWeight(t.getCol(COL_NAMES.COMPOUND_MOL_WEIGHT), t.getCol(COL_NAMES.SALT_MASS), i);
|
|
211
|
+
t.getCol(COL_NAMES.BATCH_MOL_WEIGHT).set(i, bmw, false);
|
|
212
|
+
}
|
|
236
213
|
|
|
237
214
|
const d = ui.div([
|
|
238
215
|
ui.icons.edit(() => {
|
|
@@ -240,18 +217,15 @@ export function oligoSdFile(table: DG.DataFrame) {
|
|
|
240
217
|
if (table.getCol(COL_NAMES.IDP).type != DG.COLUMN_TYPE.STRING)
|
|
241
218
|
table.changeColumnType(COL_NAMES.IDP, DG.COLUMN_TYPE.STRING);
|
|
242
219
|
d.append(
|
|
243
|
-
ui.
|
|
244
|
-
addColumns(table)
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
COL_NAMES.SALT_MASS, COL_NAMES.BATCH_MW].join('\', \''), '',
|
|
248
|
-
),
|
|
249
|
-
ui.button('Save SD file', () => saveTableAsSdFile(addColumnsPressed ? newDf : table)),
|
|
220
|
+
ui.divH([
|
|
221
|
+
ui.icons.add(() => addColumns(table), `Add columns: '${GENERATED_COL_NAMES.join(`', '`)}'`),
|
|
222
|
+
ui.icons.save(() => saveTableAsSdFile(addColumnsPressed ? newDf : table), 'Save SD file'),
|
|
223
|
+
]),
|
|
250
224
|
);
|
|
251
225
|
|
|
252
226
|
const view = grok.shell.getTableView(table.name);
|
|
253
|
-
|
|
254
|
-
view.dataFrame.getCol(COL_NAMES.TYPE).setTag(DG.TAGS.CHOICES,
|
|
227
|
+
view.grid.setOptions({rowHeight: 45});
|
|
228
|
+
view.dataFrame.getCol(COL_NAMES.TYPE).setTag(DG.TAGS.CHOICES, stringify(Object.values(SEQUENCE_TYPES)));
|
|
255
229
|
view.dataFrame.getCol(COL_NAMES.OWNER).setTag(DG.TAGS.CHOICES, stringify(usersDf.columns.byIndex(0).toList()));
|
|
256
230
|
view.dataFrame.getCol(COL_NAMES.SALT).setTag(DG.TAGS.CHOICES, stringify(saltsDf.columns.byIndex(0).toList()));
|
|
257
231
|
view.dataFrame.getCol(COL_NAMES.SOURCE).setTag(DG.TAGS.CHOICES, stringify(sourcesDf.columns.byIndex(0).toList()));
|
|
@@ -275,15 +249,6 @@ export function oligoSdFile(table: DG.DataFrame) {
|
|
|
275
249
|
if ([COL_NAMES.SALT, COL_NAMES.EQUIVALENTS, COL_NAMES.SALT_MOL_WEIGHT].includes(colName))
|
|
276
250
|
updateCalculatedColumns(view.dataFrame, view.dataFrame.currentRowIdx);
|
|
277
251
|
});
|
|
278
|
-
|
|
279
|
-
function updateCalculatedColumns(t: DG.DataFrame, i: number): void {
|
|
280
|
-
const smValue = saltMass(saltNamesList, molWeightCol, equivalentsCol, i, saltCol);
|
|
281
|
-
t.getCol(COL_NAMES.SALT_MASS).set(i, smValue, false);
|
|
282
|
-
const smwValue = saltMolWeigth(saltNamesList, saltCol, molWeightCol, i);
|
|
283
|
-
t.getCol(COL_NAMES.SALT_MOL_WEIGHT).set(i, smwValue, false);
|
|
284
|
-
const bmw = batchMolWeight(t.getCol(COL_NAMES.CPD_MW), t.getCol(COL_NAMES.SALT_MASS), i);
|
|
285
|
-
t.getCol(COL_NAMES.BATCH_MW).set(i, bmw, false);
|
|
286
|
-
}
|
|
287
252
|
}),
|
|
288
253
|
]);
|
|
289
254
|
grok.shell.v.setRibbonPanels([[d]]);
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -131,17 +131,20 @@ export function defineAxolabsPattern() {
|
|
|
131
131
|
asBases[i] = ui.choiceInput('', asBases[i].value, baseChoices, (v: string) => {
|
|
132
132
|
if (!enumerateModifications.includes(v)) {
|
|
133
133
|
enumerateModifications.push(v);
|
|
134
|
-
isEnumerateModificationsDiv.append(
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
enumerateModifications.
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
134
|
+
isEnumerateModificationsDiv.append(
|
|
135
|
+
ui.divText('', {style: {width: '25px'}}),
|
|
136
|
+
ui.boolInput(v, true, (boolV: boolean) => {
|
|
137
|
+
if (boolV) {
|
|
138
|
+
if (!enumerateModifications.includes(v))
|
|
139
|
+
enumerateModifications.push(v);
|
|
140
|
+
} else {
|
|
141
|
+
const index = enumerateModifications.indexOf(v, 0);
|
|
142
|
+
if (index > -1)
|
|
143
|
+
enumerateModifications.splice(index, 1);
|
|
144
|
+
}
|
|
145
|
+
updateSvgScheme();
|
|
146
|
+
}).root,
|
|
147
|
+
);
|
|
145
148
|
}
|
|
146
149
|
updateAsModification();
|
|
147
150
|
updateSvgScheme();
|
|
@@ -174,17 +177,20 @@ export function defineAxolabsPattern() {
|
|
|
174
177
|
ssBases[i] = ui.choiceInput('', ssBases[i].value, baseChoices, (v: string) => {
|
|
175
178
|
if (!enumerateModifications.includes(v)) {
|
|
176
179
|
enumerateModifications.push(v);
|
|
177
|
-
isEnumerateModificationsDiv.append(
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
enumerateModifications.
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
180
|
+
isEnumerateModificationsDiv.append(
|
|
181
|
+
ui.divText('', {style: {width: '25px'}}),
|
|
182
|
+
ui.boolInput(v, true, (boolV: boolean) => {
|
|
183
|
+
if (boolV) {
|
|
184
|
+
if (!enumerateModifications.includes(v))
|
|
185
|
+
enumerateModifications.push(v);
|
|
186
|
+
} else {
|
|
187
|
+
const index = enumerateModifications.indexOf(v, 0);
|
|
188
|
+
if (index > -1)
|
|
189
|
+
enumerateModifications.splice(index, 1);
|
|
190
|
+
}
|
|
191
|
+
updateSvgScheme();
|
|
192
|
+
}).root,
|
|
193
|
+
);
|
|
188
194
|
}
|
|
189
195
|
updateSsModification();
|
|
190
196
|
updateSvgScheme();
|
|
@@ -499,18 +505,20 @@ export function defineAxolabsPattern() {
|
|
|
499
505
|
const loadPatternDiv = ui.div([]);
|
|
500
506
|
const asModificationDiv = ui.div([]);
|
|
501
507
|
const firstAsPtoDiv = ui.div([]);
|
|
502
|
-
const isEnumerateModificationsDiv = ui.divH([
|
|
503
|
-
|
|
504
|
-
if (
|
|
505
|
-
enumerateModifications.
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
508
|
+
const isEnumerateModificationsDiv = ui.divH([
|
|
509
|
+
ui.boolInput(defaultBase, true, (v: boolean) => {
|
|
510
|
+
if (v) {
|
|
511
|
+
if (!enumerateModifications.includes(defaultBase))
|
|
512
|
+
enumerateModifications.push(defaultBase);
|
|
513
|
+
} else {
|
|
514
|
+
const index = enumerateModifications.indexOf(defaultBase, 0);
|
|
515
|
+
if (index > -1)
|
|
516
|
+
enumerateModifications.splice(index, 1);
|
|
517
|
+
}
|
|
518
|
+
updateSvgScheme();
|
|
519
|
+
updateOutputExamples();
|
|
520
|
+
}).root,
|
|
521
|
+
]);
|
|
514
522
|
|
|
515
523
|
let ssBases = Array(defaultSequenceLength).fill(ui.choiceInput('', defaultBase, baseChoices));
|
|
516
524
|
let asBases = Array(defaultSequenceLength).fill(ui.choiceInput('', defaultBase, baseChoices));
|
package/src/axolabs/draw-svg.ts
CHANGED
|
@@ -35,14 +35,8 @@ function getTextWidth(text: string, font: number): number {
|
|
|
35
35
|
return 2 * context.measureText(text).width;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
function getTextInsideCircle(
|
|
39
|
-
bases
|
|
40
|
-
numberOfNucleotides: number, enumerateModifications: string[]): string {
|
|
41
|
-
return ((bases[index].slice(-3) == '(o)') || !enumerateModifications.includes(bases[index])) ?
|
|
42
|
-
'' :
|
|
43
|
-
(['A', 'G', 'C', 'U', 'T'].includes(bases[index])) ?
|
|
44
|
-
bases[index] :
|
|
45
|
-
'';//String(numberOfNucleotides - nucleotideCounter);
|
|
38
|
+
function getTextInsideCircle(bases: string[], index: number): string {
|
|
39
|
+
return (bases[index].slice(-3) == '(o)' || !['A', 'G', 'C', 'U', 'T'].includes(bases[index])) ? '' : bases[index];
|
|
46
40
|
}
|
|
47
41
|
|
|
48
42
|
function getFontColorVisibleOnBackground(rgbString: string): string {
|
|
@@ -160,14 +154,15 @@ export function drawAxolabsPattern(
|
|
|
160
154
|
Math.max(xOfSsRightModifications, xOfAsRightModifications) +
|
|
161
155
|
widthOfLeftModification + baseDiameter * (Math.max(ssRightOverhangs, asRightOverhangs));
|
|
162
156
|
const yOfTitle = baseRadius;
|
|
163
|
-
const
|
|
157
|
+
const yOfSsNumbers = 2 * baseRadius;
|
|
158
|
+
const yOfAsNumbers = 8.5 * baseRadius;
|
|
164
159
|
const yOfSsTexts = 4 * baseRadius;
|
|
165
160
|
const yOfAsTexts = 7 * baseRadius;
|
|
166
161
|
const yOfComment = asExists ? 11 * baseRadius : 8.5 * baseRadius;
|
|
167
162
|
const yOfSsCircles = 3.5 * baseRadius;
|
|
168
163
|
const yOfAsCircles = 6.5 * baseRadius;
|
|
169
|
-
const yOfCirclesInLegends = asExists ? 9 * baseRadius : 6 * baseRadius;
|
|
170
|
-
const yOfTextLegend = asExists ?
|
|
164
|
+
const yOfCirclesInLegends = asExists ? 9.5 * baseRadius : 6 * baseRadius;
|
|
165
|
+
const yOfTextLegend = asExists ? 10 * baseRadius - 3 : yOfAsCircles - 3;
|
|
171
166
|
|
|
172
167
|
const image = svg.render(width, height);
|
|
173
168
|
|
|
@@ -196,11 +191,13 @@ export function drawAxolabsPattern(
|
|
|
196
191
|
getShiftToAlignNumberInsideCircle(ssBases, ssBases.length - i, numberOfSsNucleotides - nucleotideCounter);
|
|
197
192
|
if (ssBases[i].slice(-3) != '(o)')
|
|
198
193
|
nucleotideCounter--;
|
|
194
|
+
const n = (ssBases[i].slice(-3) != '(o)' && enumerateModifications.includes(ssBases[i])) ?
|
|
195
|
+
String(numberOfSsNucleotides - nucleotideCounter) : '';
|
|
199
196
|
image.append(
|
|
200
|
-
svg.text(
|
|
197
|
+
svg.text(n, xOfNumbers, yOfSsNumbers, legendFontSize, fontColor),
|
|
201
198
|
svg.circle(getXOfBaseCircles(i, ssRightOverhangs), yOfSsCircles, baseRadius, getBaseColor(ssBases[i])),
|
|
202
|
-
svg.text(getTextInsideCircle(ssBases, i,
|
|
203
|
-
|
|
199
|
+
svg.text(getTextInsideCircle(ssBases, i), xOfNumbers, yOfSsTexts, baseFontSize,
|
|
200
|
+
getFontColorVisibleOnBackground(getBaseColor(ssBases[i]))),
|
|
204
201
|
ssPtoStatuses[i] ?
|
|
205
202
|
svg.star(getXOfBaseCircles(i, ssRightOverhangs) + baseRadius, yOfSsTexts + psLinkageRadius, psLinkageColor) :
|
|
206
203
|
'',
|
|
@@ -222,13 +219,16 @@ export function drawAxolabsPattern(
|
|
|
222
219
|
for (let i = asBases.length - 1; i > -1; i--) {
|
|
223
220
|
if (asBases[i].slice(-3) != '(o)')
|
|
224
221
|
nucleotideCounter--;
|
|
222
|
+
const xOfNumbers = getXOfBaseCircles(i, asRightOverhangs) +
|
|
223
|
+
getShiftToAlignNumberInsideCircle(asBases, i, nucleotideCounter + 1);
|
|
224
|
+
const n = (asBases[i].slice(-3) != '(o)' && enumerateModifications.includes(asBases[i])) ?
|
|
225
|
+
String(nucleotideCounter + 1) : '';
|
|
225
226
|
image.append(
|
|
227
|
+
svg.text(n, xOfNumbers, yOfAsNumbers, legendFontSize, fontColor),
|
|
226
228
|
svg.circle(getXOfBaseCircles(i, asRightOverhangs), yOfAsCircles, baseRadius, getBaseColor(asBases[i])),
|
|
227
|
-
svg.text(getTextInsideCircle(
|
|
228
|
-
asBases, i,
|
|
229
|
-
|
|
230
|
-
getShiftToAlignNumberInsideCircle(asBases, i, nucleotideCounter + 1),
|
|
231
|
-
yOfAsTexts, baseFontSize, getFontColorVisibleOnBackground(axolabsMap[asBases[i]]['color'])),
|
|
229
|
+
svg.text(getTextInsideCircle(asBases, i),
|
|
230
|
+
getXOfBaseCircles(i, asRightOverhangs) + getShiftToAlignNumberInsideCircle(asBases, i, nucleotideCounter + 1),
|
|
231
|
+
yOfAsTexts, baseFontSize, getFontColorVisibleOnBackground(getBaseColor(asBases[i]))),
|
|
232
232
|
asPtoStatuses[i] ? svg.star(getXOfBaseCircles(i, asRightOverhangs) +
|
|
233
233
|
baseRadius, yOfAsTexts + psLinkageRadius, psLinkageColor) : '',
|
|
234
234
|
);
|