@datagrok/sequence-translator 0.0.6 → 0.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/css/style.css +18 -0
- package/dist/package-test.js +2387 -0
- package/dist/package.js +5151 -0
- package/jest.config.js +33 -0
- package/package.json +21 -5
- package/setup.cmd +1 -1
- package/src/ICDs.ts +3 -0
- package/src/IDPs.ts +3 -0
- package/src/__jest__/remote.test.ts +49 -0
- package/src/__jest__/test-node.ts +96 -0
- package/src/defineAxolabsPattern.ts +2 -8
- package/src/package-test.ts +2 -1
- package/src/package.ts +186 -703
- package/src/salts.ts +2 -0
- package/src/sources.ts +3 -0
- package/src/structures-works/converters.ts +288 -0
- package/src/structures-works/from-monomers.ts +104 -0
- package/src/{map.ts → structures-works/map.ts} +28 -6
- package/src/structures-works/mol-transformations.ts +432 -0
- package/src/structures-works/save-sense-antisense.ts +51 -0
- package/src/structures-works/sequence-codes-tools.ts +252 -0
- package/src/tests/smiles-tests.ts +1 -1
- package/src/users.ts +3 -0
- package/test-SequenceTranslator-c2bbc2b235db-afc0e1c5.html +245 -0
- package/tsconfig.json +2 -1
- package/src/save-sense-antisense.ts +0 -44
package/src/package.ts
CHANGED
|
@@ -5,216 +5,22 @@ import * as DG from 'datagrok-api/dg';
|
|
|
5
5
|
import * as OCL from 'openchemlib/full.js';
|
|
6
6
|
import $ from 'cash-dom';
|
|
7
7
|
import {defineAxolabsPattern} from './defineAxolabsPattern';
|
|
8
|
-
import {saveSenseAntiSense} from './save-sense-antisense';
|
|
9
|
-
import {
|
|
8
|
+
import {saveSenseAntiSense} from './structures-works/save-sense-antisense';
|
|
9
|
+
import {sequenceToSmiles, sequenceToMolV3000} from './structures-works/from-monomers';
|
|
10
|
+
import {convertSequence, undefinedInputSequence, isValidSequence} from './structures-works/sequence-codes-tools';
|
|
11
|
+
import {map, COL_NAMES, MODIFICATIONS} from './structures-works/map';
|
|
12
|
+
import {SALTS_CSV} from './salts';
|
|
13
|
+
import {USERS_CSV} from './users';
|
|
14
|
+
import {ICDS} from './ICDs';
|
|
15
|
+
import {SOURCES} from './sources';
|
|
16
|
+
import {IDPS} from './IDPs';
|
|
10
17
|
|
|
11
18
|
export const _package = new DG.Package();
|
|
12
19
|
|
|
13
|
-
const defaultInput = '
|
|
14
|
-
const undefinedInputSequence = 'Type of input sequence is undefined';
|
|
15
|
-
const noTranslationTableAvailable = 'No translation table available';
|
|
20
|
+
const defaultInput = 'fAmCmGmAmCpsmU';
|
|
16
21
|
const sequenceWasCopied = 'Copied';
|
|
17
22
|
const tooltipSequence = 'Copy sequence';
|
|
18
23
|
|
|
19
|
-
function getAllCodesOfSynthesizer(synthesizer: string): string[] {
|
|
20
|
-
let codes: string[] = [];
|
|
21
|
-
for (const technology of Object.keys(map[synthesizer]))
|
|
22
|
-
codes = codes.concat(Object.keys(map[synthesizer][technology]));
|
|
23
|
-
return codes.concat(Object.keys(MODIFICATIONS));
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function getListOfPossibleSynthesizersByFirstMatchedCode(sequence: string): string[] {
|
|
27
|
-
const synthesizers: string[] = [];
|
|
28
|
-
Object.keys(map).forEach((synthesizer: string) => {
|
|
29
|
-
const codes = getAllCodesOfSynthesizer(synthesizer);
|
|
30
|
-
//TODO: get first non-dropdown code when there are two modifications
|
|
31
|
-
let start = 0;
|
|
32
|
-
for (let i = 0; i < sequence.length; i++) {
|
|
33
|
-
if (sequence[i] == ')') {
|
|
34
|
-
start = i + 1;
|
|
35
|
-
break;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
if (codes.some((s: string) => s == sequence.slice(start, start + s.length)))
|
|
39
|
-
synthesizers.push(synthesizer);
|
|
40
|
-
});
|
|
41
|
-
return synthesizers;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function getListOfPossibleTechnologiesByFirstMatchedCode(sequence: string, synthesizer: string): string[] {
|
|
45
|
-
const technologies: string[] = [];
|
|
46
|
-
Object.keys(map[synthesizer]).forEach((technology: string) => {
|
|
47
|
-
const codes = Object.keys(map[synthesizer][technology]).concat(Object.keys(MODIFICATIONS));
|
|
48
|
-
if (codes.some((s) => s == sequence.slice(0, s.length)))
|
|
49
|
-
technologies.push(technology);
|
|
50
|
-
});
|
|
51
|
-
return technologies;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export function isValidSequence(sequence: string): {
|
|
55
|
-
indexOfFirstNotValidCharacter: number,
|
|
56
|
-
expectedSynthesizer: string | null,
|
|
57
|
-
expectedTechnology: string | null
|
|
58
|
-
} {
|
|
59
|
-
const possibleSynthesizers = getListOfPossibleSynthesizersByFirstMatchedCode(sequence);
|
|
60
|
-
if (possibleSynthesizers.length == 0)
|
|
61
|
-
return {indexOfFirstNotValidCharacter: 0, expectedSynthesizer: null, expectedTechnology: null};
|
|
62
|
-
|
|
63
|
-
let outputIndices = Array(possibleSynthesizers.length).fill(0);
|
|
64
|
-
|
|
65
|
-
const firstUniqueCharacters = ['r', 'd'];
|
|
66
|
-
const nucleotides = ['A', 'U', 'T', 'C', 'G'];
|
|
67
|
-
|
|
68
|
-
possibleSynthesizers.forEach((synthesizer, synthesizerIndex) => {
|
|
69
|
-
const codes = getAllCodesOfSynthesizer(synthesizer);
|
|
70
|
-
while (outputIndices[synthesizerIndex] < sequence.length) {
|
|
71
|
-
const matchedCode = codes
|
|
72
|
-
.find((c) => c == sequence.slice(outputIndices[synthesizerIndex], outputIndices[synthesizerIndex] + c.length));
|
|
73
|
-
|
|
74
|
-
if (matchedCode == null)
|
|
75
|
-
break;
|
|
76
|
-
|
|
77
|
-
if ( // for mistake pattern 'rAA'
|
|
78
|
-
outputIndices[synthesizerIndex] > 1 &&
|
|
79
|
-
nucleotides.includes(sequence[outputIndices[synthesizerIndex]]) &&
|
|
80
|
-
firstUniqueCharacters.includes(sequence[outputIndices[synthesizerIndex] - 2])
|
|
81
|
-
) break;
|
|
82
|
-
|
|
83
|
-
if ( // for mistake pattern 'ArA'
|
|
84
|
-
firstUniqueCharacters.includes(sequence[outputIndices[synthesizerIndex] + 1]) &&
|
|
85
|
-
nucleotides.includes(sequence[outputIndices[synthesizerIndex]])
|
|
86
|
-
) {
|
|
87
|
-
outputIndices[synthesizerIndex]++;
|
|
88
|
-
break;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
outputIndices[synthesizerIndex] += matchedCode.length;
|
|
92
|
-
}
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
const indexOfExpectedSythesizer = Math.max.apply(Math, outputIndices);
|
|
96
|
-
const indexOfFirstNotValidCharacter = (indexOfExpectedSythesizer == sequence.length) ? -1 : indexOfExpectedSythesizer;
|
|
97
|
-
const expectedSynthesizer = possibleSynthesizers[outputIndices.indexOf(indexOfExpectedSythesizer)];
|
|
98
|
-
if (indexOfFirstNotValidCharacter != -1)
|
|
99
|
-
return {
|
|
100
|
-
indexOfFirstNotValidCharacter: indexOfFirstNotValidCharacter,
|
|
101
|
-
expectedSynthesizer: expectedSynthesizer,
|
|
102
|
-
expectedTechnology: null
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
let possibleTechnologies = getListOfPossibleTechnologiesByFirstMatchedCode(sequence, expectedSynthesizer);
|
|
106
|
-
if (possibleTechnologies.length == 0)
|
|
107
|
-
return { indexOfFirstNotValidCharacter: 0, expectedSynthesizer: null, expectedTechnology: null };
|
|
108
|
-
|
|
109
|
-
outputIndices = Array(possibleTechnologies.length).fill(0);
|
|
110
|
-
|
|
111
|
-
possibleTechnologies.forEach((technology: string, technologyIndex: number) => {
|
|
112
|
-
let codes = Object.keys(map[expectedSynthesizer][technology]);
|
|
113
|
-
while (outputIndices[technologyIndex] < sequence.length) {
|
|
114
|
-
|
|
115
|
-
let matchedCode = codes
|
|
116
|
-
.find((c) => c == sequence.slice(outputIndices[technologyIndex], outputIndices[technologyIndex] + c.length));
|
|
117
|
-
|
|
118
|
-
if (matchedCode == null)
|
|
119
|
-
break;
|
|
120
|
-
|
|
121
|
-
if ( // for mistake pattern 'rAA'
|
|
122
|
-
outputIndices[technologyIndex] > 1 &&
|
|
123
|
-
nucleotides.includes(sequence[outputIndices[technologyIndex]]) &&
|
|
124
|
-
firstUniqueCharacters.includes(sequence[outputIndices[technologyIndex] - 2])
|
|
125
|
-
) break;
|
|
126
|
-
|
|
127
|
-
if ( // for mistake pattern 'ArA'
|
|
128
|
-
firstUniqueCharacters.includes(sequence[outputIndices[technologyIndex] + 1]) &&
|
|
129
|
-
nucleotides.includes(sequence[outputIndices[technologyIndex]])
|
|
130
|
-
) {
|
|
131
|
-
outputIndices[technologyIndex]++;
|
|
132
|
-
break;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
outputIndices[technologyIndex] += matchedCode.length;
|
|
136
|
-
}
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
const indexOfExpectedTechnology = Math.max.apply(Math, outputIndices);
|
|
140
|
-
const expectedTechnology = possibleTechnologies[outputIndices.indexOf(indexOfExpectedTechnology)];
|
|
141
|
-
|
|
142
|
-
return {
|
|
143
|
-
indexOfFirstNotValidCharacter: indexOfFirstNotValidCharacter,
|
|
144
|
-
expectedSynthesizer: expectedSynthesizer,
|
|
145
|
-
expectedTechnology: expectedTechnology
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
function sortByStringLengthInDescendingOrder(array: string[]): string[] {
|
|
150
|
-
return array.sort(function(a: string, b: string) { return b.length - a.length; });
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
function getObjectWithCodesAndSmiles(sequence: string) {
|
|
154
|
-
const obj: { [code: string]: string } = {};
|
|
155
|
-
for (const synthesizer of Object.keys(map))
|
|
156
|
-
for (const technology of Object.keys(map[synthesizer]))
|
|
157
|
-
for (let code of Object.keys(map[synthesizer][technology]))
|
|
158
|
-
obj[code] = map[synthesizer][technology][code].SMILES;
|
|
159
|
-
// TODO: create object based from synthesizer type to avoid key(codes) duplicates
|
|
160
|
-
const output = isValidSequence(sequence);
|
|
161
|
-
if (output.expectedSynthesizer == SYNTHESIZERS.MERMADE_12)
|
|
162
|
-
obj['g'] = map[SYNTHESIZERS.MERMADE_12][TECHNOLOGIES.SI_RNA]['g'].SMILES;
|
|
163
|
-
else if (output.expectedSynthesizer == SYNTHESIZERS.AXOLABS)
|
|
164
|
-
obj['g'] = map[SYNTHESIZERS.AXOLABS][TECHNOLOGIES.SI_RNA]['g'].SMILES;
|
|
165
|
-
return obj;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
export function sequenceToSmiles(sequence: string, inverted: boolean = false): string {
|
|
169
|
-
const obj = getObjectWithCodesAndSmiles(sequence);
|
|
170
|
-
let codes = sortByStringLengthInDescendingOrder(Object.keys(obj));
|
|
171
|
-
let i = 0;
|
|
172
|
-
let smiles = '';
|
|
173
|
-
const codesList = [];
|
|
174
|
-
const links = ['s', 'ps', '*'];
|
|
175
|
-
const includesStandardLinkAlready = ['e', 'h', /*'g',*/ 'f', 'i', 'l', 'k', 'j'];
|
|
176
|
-
const dropdowns = Object.keys(MODIFICATIONS);
|
|
177
|
-
codes = codes.concat(dropdowns);
|
|
178
|
-
while (i < sequence.length) {
|
|
179
|
-
const code = codes.find((s: string) => s == sequence.slice(i, i + s.length))!;
|
|
180
|
-
i += code.length;
|
|
181
|
-
inverted ? codesList.unshift(code) : codesList.push(code);
|
|
182
|
-
}
|
|
183
|
-
for (let i = 0; i < codesList.length; i++) {
|
|
184
|
-
if (dropdowns.includes(codesList[i])) {
|
|
185
|
-
if (i == codesList.length -1 || (i < codesList.length - 1 && links.includes(codesList[i + 1]))) {
|
|
186
|
-
smiles += (i >= codesList.length / 2) ?
|
|
187
|
-
MODIFICATIONS[codesList[i]].right:
|
|
188
|
-
MODIFICATIONS[codesList[i]].left;
|
|
189
|
-
} else if (i < codesList.length - 1) {
|
|
190
|
-
smiles += (i >= codesList.length / 2) ?
|
|
191
|
-
MODIFICATIONS[codesList[i]].right + stadardPhosphateLinkSmiles:
|
|
192
|
-
MODIFICATIONS[codesList[i]].left + stadardPhosphateLinkSmiles;
|
|
193
|
-
}
|
|
194
|
-
} else {
|
|
195
|
-
if (links.includes(codesList[i]) ||
|
|
196
|
-
includesStandardLinkAlready.includes(codesList[i]) ||
|
|
197
|
-
(i < codesList.length - 1 && links.includes(codesList[i + 1]))
|
|
198
|
-
)
|
|
199
|
-
smiles += obj[codesList[i]];
|
|
200
|
-
else
|
|
201
|
-
smiles += obj[codesList[i]] + stadardPhosphateLinkSmiles;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
smiles = smiles.replace(/OO/g, 'O');
|
|
205
|
-
return (
|
|
206
|
-
(
|
|
207
|
-
links.includes(codesList[codesList.length - 1]) &&
|
|
208
|
-
codesList.length > 1 &&
|
|
209
|
-
!includesStandardLinkAlready.includes(codesList[codesList.length - 2])
|
|
210
|
-
) ||
|
|
211
|
-
dropdowns.includes(codesList[codesList.length - 1]) ||
|
|
212
|
-
includesStandardLinkAlready.includes(codesList[codesList.length - 1])
|
|
213
|
-
) ?
|
|
214
|
-
smiles :
|
|
215
|
-
smiles.slice(0, smiles.length - stadardPhosphateLinkSmiles.length + 1);
|
|
216
|
-
}
|
|
217
|
-
|
|
218
24
|
//name: Sequence Translator
|
|
219
25
|
//tags: app
|
|
220
26
|
export function sequenceTranslator(): void {
|
|
@@ -229,76 +35,77 @@ export function sequenceTranslator(): void {
|
|
|
229
35
|
const pi = DG.TaskBarProgressIndicator.create('Rendering table and molecule...');
|
|
230
36
|
let errorsExist = false;
|
|
231
37
|
try {
|
|
232
|
-
|
|
38
|
+
sequence = sequence.replace(/\s/g, '');
|
|
39
|
+
const output = isValidSequence(sequence);
|
|
40
|
+
const outputSequenceObj = convertSequence(sequence, output);
|
|
233
41
|
const tableRows = [];
|
|
234
42
|
|
|
235
43
|
for (const key of Object.keys(outputSequenceObj).slice(1)) {
|
|
236
|
-
|
|
237
|
-
JSON.parse(outputSequenceObj.
|
|
44
|
+
const indexOfFirstNotValidChar = ('indexOfFirstNotValidChar' in outputSequenceObj) ?
|
|
45
|
+
JSON.parse(outputSequenceObj.indexOfFirstNotValidChar!).indexOfFirstNotValidChar :
|
|
238
46
|
-1;
|
|
239
|
-
if ('
|
|
240
|
-
|
|
241
|
-
JSON.parse(outputSequenceObj.
|
|
47
|
+
if ('indexOfFirstNotValidChar' in outputSequenceObj) {
|
|
48
|
+
const indexOfFirstNotValidChar = ('indexOfFirstNotValidChar' in outputSequenceObj) ?
|
|
49
|
+
JSON.parse(outputSequenceObj.indexOfFirstNotValidChar!).indexOfFirstNotValidChar :
|
|
242
50
|
-1;
|
|
243
|
-
if (
|
|
51
|
+
if (indexOfFirstNotValidChar != -1)
|
|
244
52
|
errorsExist = true;
|
|
245
53
|
}
|
|
246
54
|
|
|
247
55
|
tableRows.push({
|
|
248
56
|
'key': key,
|
|
249
|
-
'value': ('
|
|
57
|
+
'value': ('indexOfFirstNotValidChar' in outputSequenceObj) ?
|
|
250
58
|
ui.divH([
|
|
251
|
-
ui.divText(sequence.slice(0,
|
|
59
|
+
ui.divText(sequence.slice(0, indexOfFirstNotValidChar), {style: {color: 'grey'}}),
|
|
252
60
|
ui.tooltip.bind(
|
|
253
|
-
ui.divText(sequence.slice(
|
|
254
|
-
'Expected format: ' + JSON.parse(outputSequenceObj.
|
|
61
|
+
ui.divText(sequence.slice(indexOfFirstNotValidChar), {style: {color: 'red'}}),
|
|
62
|
+
'Expected format: ' + JSON.parse(outputSequenceObj.indexOfFirstNotValidChar!).synthesizer +
|
|
63
|
+
'. See tables with valid codes on the right',
|
|
255
64
|
),
|
|
256
65
|
]) : //@ts-ignore
|
|
257
|
-
ui.link(outputSequenceObj[key], () => navigator.clipboard.writeText(outputSequenceObj[key])
|
|
66
|
+
ui.link(outputSequenceObj[key], () => navigator.clipboard.writeText(outputSequenceObj[key])
|
|
67
|
+
.then(() => grok.shell.info(sequenceWasCopied)), tooltipSequence, ''),
|
|
258
68
|
});
|
|
259
69
|
}
|
|
260
70
|
|
|
261
71
|
if (errorsExist) {
|
|
262
|
-
const
|
|
263
|
-
asoGapmersGrid.onCellPrepare(function
|
|
264
|
-
gc.style.backColor = (gc.gridColumn.name ==
|
|
72
|
+
const synthesizer = JSON.parse(outputSequenceObj.indexOfFirstNotValidChar!).synthesizer.slice(0, -6);
|
|
73
|
+
asoGapmersGrid.onCellPrepare(function(gc) {
|
|
74
|
+
gc.style.backColor = (gc.gridColumn.name == synthesizer) ? 0xFFF00000 : 0xFFFFFFFF;
|
|
265
75
|
});
|
|
266
|
-
omeAndFluoroGrid.onCellPrepare(function
|
|
267
|
-
gc.style.backColor = (gc.gridColumn.name ==
|
|
76
|
+
omeAndFluoroGrid.onCellPrepare(function(gc) {
|
|
77
|
+
gc.style.backColor = (gc.gridColumn.name == synthesizer) ? 0xFFF00000 : 0xFFFFFFFF;
|
|
268
78
|
});
|
|
269
79
|
switchInput.enabled = true;
|
|
270
80
|
} else {
|
|
271
|
-
asoGapmersGrid.onCellPrepare(function
|
|
272
|
-
|
|
273
|
-
});
|
|
274
|
-
omeAndFluoroGrid.onCellPrepare(function (gc) {
|
|
275
|
-
gc.style.backColor = 0xFFFFFFFF;
|
|
276
|
-
});
|
|
81
|
+
asoGapmersGrid.onCellPrepare(function(gc) {gc.style.backColor = 0xFFFFFFFF;});
|
|
82
|
+
omeAndFluoroGrid.onCellPrepare(function(gc) {gc.style.backColor = 0xFFFFFFFF;});
|
|
277
83
|
}
|
|
278
84
|
|
|
279
85
|
outputTableDiv.append(
|
|
280
86
|
ui.div([
|
|
281
|
-
DG.HtmlTable.create(tableRows, (item: { key: string; value: string; }) =>
|
|
282
|
-
|
|
87
|
+
DG.HtmlTable.create(tableRows, (item: { key: string; value: string; }) =>
|
|
88
|
+
[item.key, item.value], ['Code', 'Sequence']).root,
|
|
89
|
+
]),
|
|
283
90
|
);
|
|
284
91
|
semTypeOfInputSequence.textContent = 'Detected input type: ' + outputSequenceObj.type;
|
|
285
92
|
|
|
286
93
|
if (outputSequenceObj.type != undefinedInputSequence && outputSequenceObj.Error != undefinedInputSequence) {
|
|
287
|
-
|
|
288
|
-
canvas.addEventListener(
|
|
289
|
-
|
|
290
|
-
const
|
|
94
|
+
const canvas = ui.canvas(300, 170);
|
|
95
|
+
canvas.addEventListener('click', () => {
|
|
96
|
+
const canv = ui.canvas($(window).width(), $(window).height());
|
|
97
|
+
const mol = sequenceToMolV3000(inputSequenceField.value.replace(/\s/g, ''), false, true);
|
|
291
98
|
// @ts-ignore
|
|
292
|
-
OCL.StructureView.drawMolecule(canv, OCL.Molecule.
|
|
293
|
-
ui.dialog('Molecule')
|
|
99
|
+
OCL.StructureView.drawMolecule(canv, OCL.Molecule.fromMolfile(mol), {suppressChiralText: true});
|
|
100
|
+
ui.dialog('Molecule: ' + inputSequenceField.value)
|
|
294
101
|
.add(canv)
|
|
295
102
|
.showModal(true);
|
|
296
103
|
});
|
|
297
104
|
$(canvas).on('mouseover', () => $(canvas).css('cursor', 'zoom-in'));
|
|
298
105
|
$(canvas).on('mouseout', () => $(canvas).css('cursor', 'default'));
|
|
299
|
-
const
|
|
106
|
+
const mol = sequenceToMolV3000(inputSequenceField.value.replace(/\s/g, ''), false, true);
|
|
300
107
|
// @ts-ignore
|
|
301
|
-
OCL.StructureView.drawMolecule(canvas, OCL.Molecule.
|
|
108
|
+
OCL.StructureView.drawMolecule(canvas, OCL.Molecule.fromMolfile(mol), {suppressChiralText: true});
|
|
302
109
|
moleculeSvgDiv.append(canvas);
|
|
303
110
|
} else
|
|
304
111
|
moleculeSvgDiv.innerHTML = '';
|
|
@@ -309,73 +116,70 @@ export function sequenceTranslator(): void {
|
|
|
309
116
|
|
|
310
117
|
const semTypeOfInputSequence = ui.divText('');
|
|
311
118
|
const moleculeSvgDiv = ui.block([]);
|
|
312
|
-
const outputTableDiv = ui.div([]
|
|
119
|
+
const outputTableDiv = ui.div([]);
|
|
313
120
|
const inputSequenceField = ui.textInput('', defaultInput, (sequence: string) => updateTableAndMolecule(sequence));
|
|
314
121
|
|
|
315
122
|
const asoDf = DG.DataFrame.fromObjects([
|
|
316
|
-
{
|
|
317
|
-
{
|
|
318
|
-
{
|
|
319
|
-
{
|
|
320
|
-
{
|
|
321
|
-
{
|
|
322
|
-
{
|
|
323
|
-
{
|
|
324
|
-
{
|
|
325
|
-
{
|
|
326
|
-
{
|
|
327
|
-
{
|
|
328
|
-
{
|
|
329
|
-
{
|
|
123
|
+
{'Name': '2\'MOE-5Me-rU', 'BioSpring': '5', 'Janssen GCRS': 'moeT'},
|
|
124
|
+
{'Name': '2\'MOE-rA', 'BioSpring': '6', 'Janssen GCRS': 'moeA'},
|
|
125
|
+
{'Name': '2\'MOE-5Me-rC', 'BioSpring': '7', 'Janssen GCRS': 'moe5mC'},
|
|
126
|
+
{'Name': '2\'MOE-rG', 'BioSpring': '8', 'Janssen GCRS': 'moeG'},
|
|
127
|
+
{'Name': '5-Methyl-dC', 'BioSpring': '9', 'Janssen GCRS': '5mC'},
|
|
128
|
+
{'Name': 'ps linkage', 'BioSpring': '*', 'Janssen GCRS': 'ps'},
|
|
129
|
+
{'Name': 'dA', 'BioSpring': 'A', 'Janssen GCRS': 'A, dA'},
|
|
130
|
+
{'Name': 'dC', 'BioSpring': 'C', 'Janssen GCRS': 'C, dC'},
|
|
131
|
+
{'Name': 'dG', 'BioSpring': 'G', 'Janssen GCRS': 'G, dG'},
|
|
132
|
+
{'Name': 'dT', 'BioSpring': 'T', 'Janssen GCRS': 'T, dT'},
|
|
133
|
+
{'Name': 'rA', 'BioSpring': '', 'Janssen GCRS': 'rA'},
|
|
134
|
+
{'Name': 'rC', 'BioSpring': '', 'Janssen GCRS': 'rC'},
|
|
135
|
+
{'Name': 'rG', 'BioSpring': '', 'Janssen GCRS': 'rG'},
|
|
136
|
+
{'Name': 'rU', 'BioSpring': '', 'Janssen GCRS': 'rU'},
|
|
330
137
|
])!;
|
|
331
|
-
const asoGapmersGrid = DG.Viewer.grid(
|
|
332
|
-
asoDf, { showRowHeader: false, showCellTooltip: false }
|
|
333
|
-
);
|
|
138
|
+
const asoGapmersGrid = DG.Viewer.grid(asoDf, {showRowHeader: false, showCellTooltip: false});
|
|
334
139
|
|
|
335
140
|
asoDf.onCurrentCellChanged.subscribe((_) => {
|
|
336
|
-
navigator.clipboard.writeText(asoDf.currentCell.value).then(() => grok.shell.info('Copied'))
|
|
141
|
+
navigator.clipboard.writeText(asoDf.currentCell.value).then(() => grok.shell.info('Copied'));
|
|
337
142
|
});
|
|
338
143
|
|
|
339
|
-
|
|
144
|
+
const omeAndFluoroGrid = DG.Viewer.grid(
|
|
340
145
|
DG.DataFrame.fromObjects([
|
|
341
|
-
{
|
|
342
|
-
{
|
|
343
|
-
{
|
|
344
|
-
{
|
|
345
|
-
{
|
|
346
|
-
{
|
|
347
|
-
{
|
|
348
|
-
{
|
|
349
|
-
{
|
|
350
|
-
])!, {
|
|
146
|
+
{'Name': '2\'-fluoro-U', 'BioSpring': '1', 'Axolabs': 'Uf', 'Janssen GCRS': 'fU'},
|
|
147
|
+
{'Name': '2\'-fluoro-A', 'BioSpring': '2', 'Axolabs': 'Af', 'Janssen GCRS': 'fA'},
|
|
148
|
+
{'Name': '2\'-fluoro-C', 'BioSpring': '3', 'Axolabs': 'Cf', 'Janssen GCRS': 'fC'},
|
|
149
|
+
{'Name': '2\'-fluoro-G', 'BioSpring': '4', 'Axolabs': 'Gf', 'Janssen GCRS': 'fG'},
|
|
150
|
+
{'Name': '2\'OMe-rU', 'BioSpring': '5', 'Axolabs': 'u', 'Janssen GCRS': 'mU'},
|
|
151
|
+
{'Name': '2\'OMe-rA', 'BioSpring': '6', 'Axolabs': 'a', 'Janssen GCRS': 'mA'},
|
|
152
|
+
{'Name': '2\'OMe-rC', 'BioSpring': '7', 'Axolabs': 'c', 'Janssen GCRS': 'mC'},
|
|
153
|
+
{'Name': '2\'OMe-rG', 'BioSpring': '8', 'Axolabs': 'g', 'Janssen GCRS': 'mG'},
|
|
154
|
+
{'Name': 'ps linkage', 'BioSpring': '*', 'Axolabs': 's', 'Janssen GCRS': 'ps'},
|
|
155
|
+
])!, {showRowHeader: false, showCellTooltip: false},
|
|
351
156
|
);
|
|
352
157
|
|
|
353
158
|
const overhangModificationsGrid = DG.Viewer.grid(
|
|
354
159
|
DG.DataFrame.fromObjects([
|
|
355
|
-
{
|
|
356
|
-
{
|
|
357
|
-
])!, {
|
|
160
|
+
{'Name': '(invabasic)'},
|
|
161
|
+
{'Name': '(GalNAc-2-JNJ)'},
|
|
162
|
+
])!, {showRowHeader: false, showCellTooltip: false},
|
|
358
163
|
);
|
|
359
164
|
updateTableAndMolecule(defaultInput);
|
|
360
165
|
|
|
361
166
|
const appMainDescription = ui.info([
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
);
|
|
167
|
+
ui.divText('How to convert one sequence:', {style: {'font-weight': 'bolder'}}),
|
|
168
|
+
ui.divText('Paste sequence into the text field below'),
|
|
169
|
+
ui.divText('\n How to convert many sequences:', {style: {'font-weight': 'bolder'}}),
|
|
170
|
+
ui.divText('1. Drag & drop an Excel or CSV file with sequences into Datagrok'),
|
|
171
|
+
ui.divText('2. Right-click on the column header, then see the \'Convert\' menu'),
|
|
172
|
+
ui.divText('This will add the result column to the right of the table'),
|
|
173
|
+
], 'Convert oligonucleotide sequences between Nucleotides, BioSpring, Axolabs, Mermade 12 and GCRS representations.');
|
|
370
174
|
|
|
371
175
|
const codesTablesDiv = ui.splitV([
|
|
372
|
-
ui.box(ui.h2('ASO Gapmers'), {
|
|
176
|
+
ui.box(ui.h2('ASO Gapmers'), {style: {maxHeight: '40px'}}),
|
|
373
177
|
asoGapmersGrid.root,
|
|
374
|
-
ui.box(ui.h2(
|
|
178
|
+
ui.box(ui.h2('2\'-OMe and 2\'-F siRNA'), {style: {maxHeight: '40px'}}),
|
|
375
179
|
omeAndFluoroGrid.root,
|
|
376
|
-
ui.box(ui.h2('Overhang modifications'), {
|
|
377
|
-
overhangModificationsGrid.root
|
|
378
|
-
], {
|
|
180
|
+
ui.box(ui.h2('Overhang modifications'), {style: {maxHeight: '40px'}}),
|
|
181
|
+
overhangModificationsGrid.root,
|
|
182
|
+
], {style: {maxWidth: '350px'}});
|
|
379
183
|
|
|
380
184
|
const tabControl = ui.tabControl({
|
|
381
185
|
'MAIN': ui.box(
|
|
@@ -388,7 +192,7 @@ export function sequenceTranslator(): void {
|
|
|
388
192
|
ui.div([
|
|
389
193
|
inputSequenceField.root,
|
|
390
194
|
], 'input-base'),
|
|
391
|
-
], '
|
|
195
|
+
], 'inputSequence'),
|
|
392
196
|
semTypeOfInputSequence,
|
|
393
197
|
ui.block([
|
|
394
198
|
ui.h1('Output'),
|
|
@@ -404,18 +208,17 @@ export function sequenceTranslator(): void {
|
|
|
404
208
|
'SDF': saveSenseAntiSense(),
|
|
405
209
|
});
|
|
406
210
|
|
|
407
|
-
|
|
211
|
+
const v = grok.shell.newView('Sequence Translator', [tabControl]);
|
|
408
212
|
v.box = true;
|
|
409
213
|
|
|
410
214
|
const switchInput = ui.switchInput('Codes', true, (v: boolean) => (v) ?
|
|
411
215
|
$(codesTablesDiv).show() :
|
|
412
|
-
$(codesTablesDiv).hide()
|
|
216
|
+
$(codesTablesDiv).hide(),
|
|
413
217
|
);
|
|
414
218
|
|
|
415
219
|
const topPanel = [
|
|
416
220
|
ui.iconFA('download', () => {
|
|
417
|
-
const
|
|
418
|
-
const result = `${OCL.Molecule.fromSmiles(smiles).toMolfile()}\n`;
|
|
221
|
+
const result = sequenceToMolV3000(inputSequenceField.value.replace(/\s/g, ''));
|
|
419
222
|
const element = document.createElement('a');
|
|
420
223
|
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(result));
|
|
421
224
|
element.setAttribute('download', inputSequenceField.value.replace(/\s/g, '') + '.mol');
|
|
@@ -431,466 +234,146 @@ export function sequenceTranslator(): void {
|
|
|
431
234
|
tabControl.onTabChanged.subscribe((_) =>
|
|
432
235
|
v.setRibbonPanels([(tabControl.currentPane.name == 'MAIN') ? topPanel : []]));
|
|
433
236
|
v.setRibbonPanels([topPanel]);
|
|
434
|
-
|
|
435
|
-
$('.sequence')
|
|
436
|
-
.children().css('padding','5px 0');
|
|
437
|
-
$('.sequenceInput .input-base')
|
|
438
|
-
.css('margin','0');
|
|
439
|
-
$('.sequenceInput textarea')
|
|
440
|
-
.css('resize','none')
|
|
441
|
-
.css('min-height','50px')
|
|
442
|
-
.css('width','100%')
|
|
443
|
-
.attr('spellcheck', 'false');
|
|
444
|
-
$('.sequenceInput select')
|
|
445
|
-
.css('width','100%');
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
function convertSequence(text: string) {
|
|
449
|
-
text = text.replace(/\s/g, '');
|
|
450
|
-
let seq = text;
|
|
451
|
-
let output = isValidSequence(seq);
|
|
452
|
-
if (output.indexOfFirstNotValidCharacter != -1)
|
|
453
|
-
return {
|
|
454
|
-
// type: '',
|
|
455
|
-
indexOfFirstNotValidCharacter: JSON.stringify(output),
|
|
456
|
-
Error: undefinedInputSequence
|
|
457
|
-
};
|
|
458
|
-
if (output.expectedSynthesizer == SYNTHESIZERS.RAW_NUCLEOTIDES && output.expectedTechnology == TECHNOLOGIES.DNA)
|
|
459
|
-
return {
|
|
460
|
-
type: SYNTHESIZERS.RAW_NUCLEOTIDES + ' ' + TECHNOLOGIES.DNA,
|
|
461
|
-
Nucleotides: seq,
|
|
462
|
-
BioSpring: asoGapmersNucleotidesToBioSpring(seq),
|
|
463
|
-
GCRS: asoGapmersNucleotidesToGcrs(seq)
|
|
464
|
-
};
|
|
465
|
-
if (output.expectedSynthesizer == SYNTHESIZERS.BIOSPRING && output.expectedTechnology == TECHNOLOGIES.ASO_GAPMERS)
|
|
466
|
-
return {
|
|
467
|
-
type: SYNTHESIZERS.BIOSPRING + ' ' + TECHNOLOGIES.ASO_GAPMERS,
|
|
468
|
-
Nucleotides: asoGapmersBioSpringToNucleotides(seq),
|
|
469
|
-
BioSpring: seq,
|
|
470
|
-
GCRS: asoGapmersBioSpringToGcrs(seq)
|
|
471
|
-
};
|
|
472
|
-
if (output.expectedSynthesizer == SYNTHESIZERS.GCRS && output.expectedTechnology == TECHNOLOGIES.ASO_GAPMERS)
|
|
473
|
-
return {
|
|
474
|
-
type: SYNTHESIZERS.GCRS + ' ' + TECHNOLOGIES.ASO_GAPMERS,
|
|
475
|
-
Nucleotides: asoGapmersGcrsToNucleotides(seq),
|
|
476
|
-
BioSpring: asoGapmersGcrsToBioSpring(seq),
|
|
477
|
-
Mermade12: gcrsToMermade12(seq),
|
|
478
|
-
GCRS: seq
|
|
479
|
-
};
|
|
480
|
-
if (output.expectedSynthesizer == SYNTHESIZERS.RAW_NUCLEOTIDES && output.expectedTechnology == TECHNOLOGIES.RNA)
|
|
481
|
-
return {
|
|
482
|
-
type: SYNTHESIZERS.RAW_NUCLEOTIDES + ' ' + TECHNOLOGIES.RNA,
|
|
483
|
-
Nucleotides: seq,
|
|
484
|
-
BioSpring: siRnaNucleotideToBioSpringSenseStrand(seq),
|
|
485
|
-
Axolabs: siRnaNucleotideToAxolabsSenseStrand(seq),
|
|
486
|
-
GCRS: siRnaNucleotidesToGcrs(seq)
|
|
487
|
-
};
|
|
488
|
-
if (output.expectedSynthesizer == SYNTHESIZERS.BIOSPRING && output.expectedTechnology == TECHNOLOGIES.SI_RNA)
|
|
489
|
-
return {
|
|
490
|
-
type: SYNTHESIZERS.BIOSPRING + ' ' + TECHNOLOGIES.SI_RNA,
|
|
491
|
-
Nucleotides: siRnaBioSpringToNucleotides(seq),
|
|
492
|
-
BioSpring: seq,
|
|
493
|
-
Axolabs: siRnaBioSpringToAxolabs(seq),
|
|
494
|
-
GCRS: siRnaBioSpringToGcrs(seq)
|
|
495
|
-
};
|
|
496
|
-
if (output.expectedSynthesizer == SYNTHESIZERS.AXOLABS && output.expectedTechnology == TECHNOLOGIES.SI_RNA)
|
|
497
|
-
return {
|
|
498
|
-
type: SYNTHESIZERS.AXOLABS + ' ' + TECHNOLOGIES.SI_RNA,
|
|
499
|
-
Nucleotides: siRnaAxolabsToNucleotides(seq),
|
|
500
|
-
BioSpring: siRnaAxolabsToBioSpring(seq),
|
|
501
|
-
Axolabs: seq,
|
|
502
|
-
GCRS: siRnaAxolabsToGcrs(seq)
|
|
503
|
-
};
|
|
504
|
-
if (output.expectedSynthesizer == SYNTHESIZERS.GCRS && output.expectedTechnology == TECHNOLOGIES.SI_RNA)
|
|
505
|
-
return {
|
|
506
|
-
type: SYNTHESIZERS.GCRS + ' ' + TECHNOLOGIES.SI_RNA,
|
|
507
|
-
Nucleotides: siRnaGcrsToNucleotides(seq),
|
|
508
|
-
BioSpring: siRnaGcrsToBioSpring(seq),
|
|
509
|
-
Axolabs: siRnaGcrsToAxolabs(seq),
|
|
510
|
-
MM12: gcrsToMermade12(seq),
|
|
511
|
-
GCRS: seq
|
|
512
|
-
};
|
|
513
|
-
if (output.expectedSynthesizer == SYNTHESIZERS.GCRS)
|
|
514
|
-
return {
|
|
515
|
-
type: SYNTHESIZERS.GCRS,
|
|
516
|
-
Nucleotides: gcrsToNucleotides(seq),
|
|
517
|
-
GCRS: seq,
|
|
518
|
-
Mermade12: gcrsToMermade12(seq)
|
|
519
|
-
}
|
|
520
|
-
if (output.expectedSynthesizer == SYNTHESIZERS.MERMADE_12)
|
|
521
|
-
return {
|
|
522
|
-
type: SYNTHESIZERS.MERMADE_12,
|
|
523
|
-
Nucleotides: noTranslationTableAvailable,
|
|
524
|
-
GCRS: noTranslationTableAvailable,
|
|
525
|
-
Mermade12: seq
|
|
526
|
-
};
|
|
527
|
-
return {
|
|
528
|
-
type: undefinedInputSequence,
|
|
529
|
-
Nucleotides: undefinedInputSequence
|
|
530
|
-
};
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
//name: asoGapmersNucleotidesToBioSpring
|
|
534
|
-
//input: string nucleotides {semType: DNA nucleotides}
|
|
535
|
-
//output: string result {semType: BioSpring / Gapmers}
|
|
536
|
-
export function asoGapmersNucleotidesToBioSpring(nucleotides: string): string {
|
|
537
|
-
let count: number = -1;
|
|
538
|
-
const objForEdges: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', 'T': '5*', 'A': '6*', 'C': '7*', 'G': '8*'};
|
|
539
|
-
const objForCenter: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', 'T': 'T*', 'A': 'A*', 'C': '9*', 'G': 'G*'};
|
|
540
|
-
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|A|T|C|G)/g, function (x: string) {
|
|
541
|
-
count++;
|
|
542
|
-
return (count > 4 && count < 15) ? objForCenter[x] : objForEdges[x];
|
|
543
|
-
}).slice(0, (nucleotides.endsWith('(invabasic)') || nucleotides.endsWith('(GalNAc-2-JNJ)')) ? nucleotides.length : 2 * count + 1);
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
//name: asoGapmersNucleotidesToGcrs
|
|
547
|
-
//input: string nucleotides {semType: DNA nucleotides}
|
|
548
|
-
//output: string result {semType: GCRS / Gapmers}
|
|
549
|
-
export function asoGapmersNucleotidesToGcrs(nucleotides: string): string {
|
|
550
|
-
let count: number = -1;
|
|
551
|
-
const objForEdges: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', 'T': 'moeUnps', 'A': 'moeAnps', 'C': 'moe5mCnps', 'G': 'moeGnps'};
|
|
552
|
-
const objForCenter: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', 'C': '5mCps', 'A': 'Aps', 'T': 'Tps', 'G': 'Gps'};
|
|
553
|
-
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|A|T|C|G)/g, function (x: string) {
|
|
554
|
-
count++;
|
|
555
|
-
if (count < 5) return (count == 4) ? objForEdges[x].slice(0, -3) + 'ps' : objForEdges[x];
|
|
556
|
-
if (count < 15) return (count == 14) ? objForCenter[x].slice(0, -2) + 'nps' : objForCenter[x];
|
|
557
|
-
return objForEdges[x];
|
|
558
|
-
}).slice(0, (nucleotides.endsWith('(invabasic)') || nucleotides.endsWith('(GalNAc-2-JNJ)')) ? nucleotides.length : -3);
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
//name: asoGapmersBioSpringToNucleotides
|
|
562
|
-
//input: string nucleotides {semType: BioSpring / Gapmers}
|
|
563
|
-
//output: string result {semType: DNA nucleotides}
|
|
564
|
-
export function asoGapmersBioSpringToNucleotides(nucleotides: string): string {
|
|
565
|
-
const obj: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', '*': '', '5': 'T', '6': 'A', '7': 'C', '8': 'G', '9': 'C'};
|
|
566
|
-
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|\*|5|6|7|8|9)/g, function (x: string) {return obj[x];});
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
//name: asoGapmersBioSpringToGcrs
|
|
570
|
-
//input: string nucleotides {semType: BioSpring / Gapmers}
|
|
571
|
-
//output: string result {semType: GCRS / Gapmers}
|
|
572
|
-
export function asoGapmersBioSpringToGcrs(nucleotides: string): string {
|
|
573
|
-
let count: number = -1;
|
|
574
|
-
const obj: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)',
|
|
575
|
-
'5*': 'moeUnps', '6*': 'moeAnps', '7*': 'moe5mCnps', '8*': 'moeGnps', '9*': '5mCps', 'A*': 'Aps', 'T*': 'Tps',
|
|
576
|
-
'G*': 'Gps', 'C*': 'Cps', '5': 'moeU', '6': 'moeA', '7': 'moe5mC', '8': 'moeG'
|
|
577
|
-
};
|
|
578
|
-
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|5\*|6\*|7\*|8\*|9\*|A\*|T\*|G\*|C\*|5|6|7|8)/g, function (x: string) {
|
|
579
|
-
count++;
|
|
580
|
-
return (count == 4) ? obj[x].slice(0, -3) + 'ps' : (count == 14) ? obj[x].slice(0, -2) + 'nps' : obj[x];
|
|
581
|
-
});
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
//name: asoGapmersGcrsToBioSpring
|
|
585
|
-
//input: string nucleotides {semType: GCRS / Gapmers}
|
|
586
|
-
//output: string result {semType: BioSpring / Gapmers}
|
|
587
|
-
export function asoGapmersGcrsToBioSpring(nucleotides: string): string {
|
|
588
|
-
const obj: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)',
|
|
589
|
-
'moeT': '5', 'moeA': '6', 'moe5mC': '7', 'moeG': '8', 'moeU': '5', '5mC': '9', 'nps': '*', 'ps': '*', 'U': 'T'
|
|
590
|
-
};
|
|
591
|
-
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|moeT|moeA|moe5mC|moeG|moeU|5mC|nps|ps|U)/g, function (x: string) {return obj[x];});
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
//name: asoGapmersGcrsToNucleotides
|
|
595
|
-
//input: string nucleotides {semType: GCRS / Gapmers}
|
|
596
|
-
//output: string result {semType: DNA nucleotides}
|
|
597
|
-
export function asoGapmersGcrsToNucleotides(nucleotides: string) {
|
|
598
|
-
const obj: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', 'moe': '', '5m': '', 'n': '', 'ps': '', 'U': 'T'};
|
|
599
|
-
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|moe|5m|n|ps|U)/g, function (x: string) {return obj[x];});
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
//name: siRnaBioSpringToNucleotides
|
|
603
|
-
//input: string nucleotides {semType: BioSpring / siRNA}
|
|
604
|
-
//output: string result {semType: RNA nucleotides}
|
|
605
|
-
export function siRnaBioSpringToNucleotides(nucleotides: string) {
|
|
606
|
-
const obj: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', '1': 'U', '2': 'A', '3': 'C', '4': 'G', '5': 'U', '6': 'A', '7': 'C', '8': 'G', '*': ''};
|
|
607
|
-
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|1|2|3|4|5|6|7|8|\*)/g, function (x: string) {return obj[x];});
|
|
608
|
-
}
|
|
609
|
-
|
|
610
|
-
//name: siRnaBioSpringToAxolabs
|
|
611
|
-
//input: string nucleotides {semType: BioSpring / siRNA}
|
|
612
|
-
//output: string result {semType: Axolabs / siRNA}
|
|
613
|
-
export function siRnaBioSpringToAxolabs(nucleotides: string) {
|
|
614
|
-
const obj: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', '1': 'Uf', '2': 'Af', '3': 'Cf', '4': 'Gf', '5': 'u', '6': 'a', '7': 'c', '8': 'g', '*': 's'};
|
|
615
|
-
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|1|2|3|4|5|6|7|8|\*)/g, function (x: string) {return obj[x];});
|
|
616
|
-
}
|
|
617
|
-
|
|
618
|
-
//name: siRnaBioSpringToGcrs
|
|
619
|
-
//input: string nucleotides {semType: BioSpring / siRNA}
|
|
620
|
-
//output: string result {semType: GCRS}
|
|
621
|
-
export function siRnaBioSpringToGcrs(nucleotides: string) {
|
|
622
|
-
const obj: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', '1': 'fU', '2': 'fA', '3': 'fC', '4': 'fG', '5': 'mU', '6': 'mA', '7': 'mC', '8': 'mG', '*': 'ps'};
|
|
623
|
-
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|1|2|3|4|5|6|7|8|\*)/g, function (x: string) {return obj[x];});
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
//name: siRnaAxolabsToGcrs
|
|
627
|
-
//input: string nucleotides {semType: Axolabs / siRNA}
|
|
628
|
-
//output: string result {semType: GCRS}
|
|
629
|
-
export function siRnaAxolabsToGcrs(nucleotides: string) {
|
|
630
|
-
const obj: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)',
|
|
631
|
-
'Uf': 'fU', 'Af': 'fA', 'Cf': 'fC', 'Gf': 'fG', 'u': 'mU', 'a': 'mA', 'c': 'mC', 'g': 'mG', 's': 'ps'
|
|
632
|
-
};
|
|
633
|
-
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|Uf|Af|Cf|Gf|u|a|c|g|s)/g, function (x: string) {return obj[x];});
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
//name: siRnaAxolabsToBioSpring
|
|
637
|
-
//input: string nucleotides {semType: Axolabs / siRNA}
|
|
638
|
-
//output: string result {semType: BioSpring / siRNA}
|
|
639
|
-
export function siRnaAxolabsToBioSpring(nucleotides: string) {
|
|
640
|
-
const obj: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)',
|
|
641
|
-
'Uf': '1', 'Af': '2', 'Cf': '3', 'Gf': '4', 'u': '5', 'a': '6', 'c': '7', 'g': '8', 's': '*'
|
|
642
|
-
};
|
|
643
|
-
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|Uf|Af|Cf|Gf|u|a|c|g|s)/g, function (x: string) {return obj[x];});
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
//name: siRnaAxolabsToNucleotides
|
|
647
|
-
//input: string nucleotides {semType: Axolabs / siRNA}
|
|
648
|
-
//output: string result {semType: RNA nucleotides}
|
|
649
|
-
export function siRnaAxolabsToNucleotides(nucleotides: string) {
|
|
650
|
-
const obj: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)',
|
|
651
|
-
'Uf': 'U', 'Af': 'A', 'Cf': 'C', 'Gf': 'G', 'u': 'U', 'a': 'A', 'c': 'C', 'g': 'G', 's': ''
|
|
652
|
-
};
|
|
653
|
-
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|Uf|Af|Cf|Gf|u|a|c|g|s)/g, function (x: string) {return obj[x];});
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
//name: siRnaGcrsToNucleotides
|
|
657
|
-
//input: string nucleotides {semType: GCRS}
|
|
658
|
-
//output: string result {semType: RNA nucleotides}
|
|
659
|
-
export function siRnaGcrsToNucleotides(nucleotides: string) {
|
|
660
|
-
const obj: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)',
|
|
661
|
-
'fU': 'U', 'fA': 'A', 'fC': 'C', 'fG': 'G', 'mU': 'U', 'mA': 'A', 'mC': 'C', 'mG': 'G', 'ps': ''
|
|
662
|
-
};
|
|
663
|
-
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|fU|fA|fC|fG|mU|mA|mC|mG|ps)/g, function (x: string) {return obj[x];});
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
//name: siRnaGcrsToBioSpring
|
|
667
|
-
//input: string nucleotides {semType: GCRS}
|
|
668
|
-
//output: string result {semType: BioSpring / siRNA}
|
|
669
|
-
export function siRnaGcrsToBioSpring(nucleotides: string) {
|
|
670
|
-
const obj: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)',
|
|
671
|
-
'fU': '1', 'fA': '2', 'fC': '3', 'fG': '4', 'mU': '5', 'mA': '6', 'mC': '7', 'mG': '8', 'ps': '*'
|
|
672
|
-
};
|
|
673
|
-
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|fU|fA|fC|fG|mU|mA|mC|mG|ps)/g, function (x: string) {return obj[x];});
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
//name: siRnaGcrsToAxolabs
|
|
677
|
-
//input: string nucleotides {semType: GCRS}
|
|
678
|
-
//output: string result {semType: Axolabs / siRNA}
|
|
679
|
-
export function siRnaGcrsToAxolabs(nucleotides: string) {
|
|
680
|
-
const obj: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)',
|
|
681
|
-
'fU': 'Uf', 'fA': 'Af', 'fC': 'Cf', 'fG': 'Gf', 'mU': 'u', 'mA': 'a', 'mC': 'c', 'mG': 'g', 'ps': 's'
|
|
682
|
-
};
|
|
683
|
-
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|fU|fA|fC|fG|mU|mA|mC|mG|ps)/g, function (x: string) {return obj[x];});
|
|
684
|
-
}
|
|
685
|
-
|
|
686
|
-
//name: siRnaNucleotideToBioSpringSenseStrand
|
|
687
|
-
//input: string nucleotides {semType: RNA nucleotides}
|
|
688
|
-
//output: string result {semType: BioSpring / siRNA}
|
|
689
|
-
export function siRnaNucleotideToBioSpringSenseStrand(nucleotides: string) {
|
|
690
|
-
let count: number = -1;
|
|
691
|
-
const objForLeftEdge: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', 'A': '6*', 'U': '5*', 'G': '8*', 'C': '7*'};
|
|
692
|
-
const objForRightEdge: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', 'A': '*6', 'U': '*5', 'G': '*8', 'C': '*7'};
|
|
693
|
-
const objForOddIndices: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', 'A': '6', 'U': '5', 'G': '8', 'C': '7'};
|
|
694
|
-
const objForEvenIndices: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', 'A': '2', 'U': '1', 'G': '4', 'C': '3'};
|
|
695
|
-
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|A|U|G|C)/g, function (x: string) {
|
|
696
|
-
count++;
|
|
697
|
-
if (count < 2) return objForLeftEdge[x];
|
|
698
|
-
if (count > nucleotides.length - 3) return objForRightEdge[x];
|
|
699
|
-
return (count % 2 == 0) ? objForEvenIndices[x] : objForOddIndices[x];
|
|
700
|
-
});
|
|
701
|
-
}
|
|
702
|
-
|
|
703
|
-
//name: siRnaNucleotidesToGcrs
|
|
704
|
-
//input: string nucleotides {semType: RNA nucleotides}
|
|
705
|
-
//output: string result {semType: GCRS}
|
|
706
|
-
export function siRnaNucleotidesToGcrs(nucleotides: string) {
|
|
707
|
-
let count: number = -1;
|
|
708
|
-
const objForLeftEdge: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', 'A': 'mAps', 'U': 'mUps', 'G': 'mGps', 'C': 'mCps'};
|
|
709
|
-
const objForRightEdge: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', 'A': 'psmA', 'U': 'psmU', 'G': 'psmG', 'C': 'psmC'};
|
|
710
|
-
const objForEvenIndices: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', 'A': 'fA', 'U': 'fU', 'G': 'fG', 'C': 'fC'};
|
|
711
|
-
const objForOddIndices: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', 'A': 'mA', 'U': 'mU', 'G': 'mG', 'C': 'mC'};
|
|
712
|
-
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|A|U|G|C)/g, function (x: string) {
|
|
713
|
-
count++;
|
|
714
|
-
if (count < 2) return objForLeftEdge[x];
|
|
715
|
-
if (count > nucleotides.length - 3) return objForRightEdge[x];
|
|
716
|
-
return (count % 2 == 0) ? objForEvenIndices[x] : objForOddIndices[x];
|
|
717
|
-
});
|
|
718
|
-
}
|
|
719
|
-
|
|
720
|
-
//name: siRnaNucleotideToAxolabsSenseStrand
|
|
721
|
-
//input: string nucleotides {semType: RNA nucleotides}
|
|
722
|
-
//output: string result {semType: Axolabs}
|
|
723
|
-
export function siRnaNucleotideToAxolabsSenseStrand(nucleotides: string) {
|
|
724
|
-
let count: number = -1;
|
|
725
|
-
const objForLeftEdge: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', 'A': 'as', 'U': 'us', 'G': 'gs', 'C': 'cs'};
|
|
726
|
-
const objForSomeIndices: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', 'A': 'Af', 'U': 'Uf', 'G': 'Gf', 'C': 'Cf'};
|
|
727
|
-
const obj: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', 'A': 'a', 'U': 'u', 'G': 'g', 'C': 'c'};
|
|
728
|
-
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|A|U|G|C)/g, function (x: string) {
|
|
729
|
-
count++;
|
|
730
|
-
if (count < 2) return objForLeftEdge[x];
|
|
731
|
-
if (count == 6 || (count > 7 && count < 11)) return objForSomeIndices[x]
|
|
732
|
-
if (count == nucleotides.length - 1) return 'a';
|
|
733
|
-
return obj[x];
|
|
734
|
-
});
|
|
735
|
-
}
|
|
736
|
-
|
|
737
|
-
//name: siRnaNucleotideToAxolabsAntisenseStrand
|
|
738
|
-
//input: string nucleotides {semType: RNA nucleotides}
|
|
739
|
-
//output: string result {semType: Axolabs}
|
|
740
|
-
export function siRnaNucleotideToAxolabsAntisenseStrand(nucleotides: string) {
|
|
741
|
-
let count: number = -1;
|
|
742
|
-
const objForSmallLinkages: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', 'A': 'as', 'U': 'us', 'G': 'gs', 'C': 'cs'};
|
|
743
|
-
const objForBigLinkages: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', 'A': 'Afs', 'U': 'Ufs', 'G': 'Gfs', 'C': 'Cfs'};
|
|
744
|
-
const objForSomeIndices: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', 'A': 'Af', 'U': 'Uf', 'G': 'Gf', 'C': 'Cf'};
|
|
745
|
-
const obj: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)', 'A': 'a', 'U': 'u', 'G': 'g', 'C': 'c'};
|
|
746
|
-
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|A|U|G|C)/g, function (x: string) {
|
|
747
|
-
count++;
|
|
748
|
-
if (count > 19 && count < 22) return objForSmallLinkages[x];
|
|
749
|
-
if (count == 0) return 'us';
|
|
750
|
-
if (count == 1) return objForBigLinkages[x];
|
|
751
|
-
return (count == 5 || count == 7 || count == 8 || count == 13 || count == 15) ? objForSomeIndices[x] : obj[x];
|
|
752
|
-
});
|
|
753
|
-
}
|
|
754
|
-
|
|
755
|
-
//name: gcrsToNucleotides
|
|
756
|
-
//input: string nucleotides {semType: GCRS}
|
|
757
|
-
//output: string result {semType: RNA nucleotides}
|
|
758
|
-
export function gcrsToNucleotides(nucleotides: string) {
|
|
759
|
-
const obj: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)',
|
|
760
|
-
'mAps': 'A', 'mUps': 'U', 'mGps': 'G', 'mCps': 'C', 'fAps': 'A', 'fUps': 'U', 'fGps': 'G', 'fCps': 'C',
|
|
761
|
-
'fU': 'U', 'fA': 'A', 'fC': 'C', 'fG': 'G', 'mU': 'U', 'mA': 'A', 'mC': 'C', 'mG': 'G'
|
|
762
|
-
};
|
|
763
|
-
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|mAps|mUps|mGps|mCps|fAps|fUps|fGps|fCps|fU|fA|fC|fG|mU|mA|mC|mG)/g, function (x: string) {return obj[x];});
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
//name: gcrsToMermade12
|
|
767
|
-
//input: string nucleotides {semType: GCRS}
|
|
768
|
-
//output: string result {semType: Mermade 12 / siRNA}
|
|
769
|
-
export function gcrsToMermade12(nucleotides: string) {
|
|
770
|
-
const obj: {[index: string]: string} = {'(invabasic)': '(invabasic)', '(GalNAc-2-JNJ)': '(GalNAc-2-JNJ)',
|
|
771
|
-
'mAps': 'e', 'mUps': 'h', 'mGps': 'g', 'mCps': 'f', 'fAps': 'i', 'fUps': 'l', 'fGps': 'k', 'fCps': 'j', 'fU': 'L',
|
|
772
|
-
'fA': 'I', 'fC': 'J', 'fG': 'K', 'mU': 'H', 'mA': 'E', 'mC': 'F', 'mG': 'G'
|
|
773
|
-
};
|
|
774
|
-
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|mAps|mUps|mGps|mCps|fAps|fUps|fGps|fCps|fU|fA|fC|fG|mU|mA|mC|mG)/g, function (x: string) {return obj[x]});
|
|
775
237
|
}
|
|
776
238
|
|
|
777
239
|
async function saveTableAsSdFile(table: DG.DataFrame) {
|
|
778
|
-
if (!table.columns.contains('Compound Name'))
|
|
779
|
-
grok.shell.warning(
|
|
780
|
-
|
|
240
|
+
if (!table.columns.contains('Compound Name')) {
|
|
241
|
+
grok.shell.warning(
|
|
242
|
+
'File saved without columns \'' +
|
|
243
|
+
[COL_NAMES.COMPOUND_NAME, COL_NAMES.COMPOUND_COMMENTS, COL_NAMES.CPD_MW,
|
|
244
|
+
COL_NAMES.SALT_MASS, COL_NAMES.BATCH_MW].join('\', \''),
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
const structureColumn = table.col(COL_NAMES.SEQUENCE)!;
|
|
248
|
+
const typeColumn = table.col(COL_NAMES.TYPE)!;
|
|
781
249
|
let result = '';
|
|
782
250
|
for (let i = 0; i < table.rowCount; i++) {
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
for (let col of table.columns)
|
|
251
|
+
result += (typeColumn.get(i) == 'SS') ?
|
|
252
|
+
sequenceToMolV3000(structureColumn.get(i), false, true) + '\n' + `> <Sequence>\nSense Strand\n\n` :
|
|
253
|
+
sequenceToMolV3000(structureColumn.get(i), true, true) + '\n' + `> <Sequence>\nAnti Sense\n\n`;
|
|
254
|
+
for (const col of table.columns) {
|
|
255
|
+
if (col.name != COL_NAMES.SEQUENCE)
|
|
789
256
|
result += `> <${col.name}>\n${col.get(i)}\n\n`;
|
|
790
|
-
result += '$$$$';
|
|
791
|
-
}
|
|
792
|
-
catch (error) {
|
|
793
|
-
console.error(error);
|
|
794
257
|
}
|
|
258
|
+
result += '$$$$\n\n';
|
|
795
259
|
}
|
|
796
|
-
|
|
260
|
+
const element = document.createElement('a');
|
|
797
261
|
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(result));
|
|
798
262
|
element.setAttribute('download', table.name + '.sdf');
|
|
799
263
|
element.click();
|
|
800
264
|
}
|
|
801
265
|
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
266
|
+
const weightsObj: {[code: string]: number} = {};
|
|
267
|
+
for (const synthesizer of Object.keys(map)) {
|
|
268
|
+
for (const technology of Object.keys(map[synthesizer])) {
|
|
269
|
+
for (const code of Object.keys(map[synthesizer][technology]))
|
|
270
|
+
weightsObj[code] = map[synthesizer][technology][code].weight;
|
|
271
|
+
}
|
|
807
272
|
}
|
|
273
|
+
for (const [key, value] of Object.entries(MODIFICATIONS))
|
|
274
|
+
weightsObj[key] = value.molecularWeight;
|
|
808
275
|
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
grok.events.onViewAdded.subscribe((v: any) => {
|
|
812
|
-
if (v.type == 'TableView' && v.dataFrame.columns.contains('Type'))
|
|
813
|
-
oligoSdFile(v.dataFrame);
|
|
814
|
-
});
|
|
276
|
+
function sortByStringLengthInDescendingOrder(array: string[]): string[] {
|
|
277
|
+
return array.sort(function(a, b) {return b.length - a.length;});
|
|
815
278
|
}
|
|
816
279
|
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
for (let code of Object.keys(map[synthesizer][technology]))
|
|
821
|
-
weightsObj[code] = map[synthesizer][technology][code].weight;
|
|
280
|
+
function stringifyItems(items: string[]): string {
|
|
281
|
+
return '["' + items.join('", "') + '"]';
|
|
282
|
+
}
|
|
822
283
|
|
|
823
|
-
function molecularWeight(sequence: string): number {
|
|
824
|
-
const codes = sortByStringLengthInDescendingOrder(Object.keys(weightsObj));
|
|
825
|
-
let weight = 0
|
|
284
|
+
function molecularWeight(sequence: string, weightsObj: {[index: string]: number}): number {
|
|
285
|
+
const codes = sortByStringLengthInDescendingOrder(Object.keys(weightsObj)).concat(Object.keys(MODIFICATIONS));
|
|
286
|
+
let weight = 0;
|
|
287
|
+
let i = 0;
|
|
826
288
|
while (i < sequence.length) {
|
|
827
|
-
|
|
289
|
+
const matchedCode = codes.find((s) => s == sequence.slice(i, i + s.length))!;
|
|
828
290
|
weight += weightsObj[sequence.slice(i, i + matchedCode.length)];
|
|
829
291
|
i += matchedCode!.length;
|
|
830
292
|
}
|
|
831
293
|
return weight - 61.97;
|
|
832
294
|
}
|
|
833
295
|
|
|
834
|
-
|
|
296
|
+
//tags: autostart
|
|
297
|
+
export function autostartOligoSdFileSubscription() {
|
|
298
|
+
grok.events.onViewAdded.subscribe((v: any) => {
|
|
299
|
+
if (v.type == 'TableView' && v.dataFrame.columns.contains(COL_NAMES.TYPE))
|
|
300
|
+
oligoSdFile(v.dataFrame);
|
|
301
|
+
});
|
|
302
|
+
}
|
|
835
303
|
|
|
836
|
-
|
|
837
|
-
|
|
304
|
+
export function oligoSdFile(table: DG.DataFrame) {
|
|
305
|
+
const saltsDf = DG.DataFrame.fromCsv(SALTS_CSV);
|
|
306
|
+
const usersDf = DG.DataFrame.fromCsv(USERS_CSV);
|
|
307
|
+
const sourcesDf = DG.DataFrame.fromCsv(SOURCES);
|
|
308
|
+
const icdsDf = DG.DataFrame.fromCsv(ICDS);
|
|
309
|
+
const idpsDf = DG.DataFrame.fromCsv(IDPS);
|
|
310
|
+
|
|
311
|
+
function addColumns(t: DG.DataFrame, saltsDf: DG.DataFrame) {
|
|
312
|
+
if (t.columns.contains(COL_NAMES.COMPOUND_NAME))
|
|
838
313
|
return grok.shell.error('Columns already exist!');
|
|
839
314
|
|
|
840
|
-
|
|
841
|
-
|
|
315
|
+
const sequence = t.col(COL_NAMES.SEQUENCE)!;
|
|
316
|
+
const salt = t.col(COL_NAMES.SALT)!;
|
|
317
|
+
const equivalents = t.col(COL_NAMES.EQUIVALENTS)!;
|
|
842
318
|
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
let equivalents = t.col('Equivalents')!;
|
|
846
|
-
|
|
847
|
-
t.columns.addNewString('Compound Name').init((i: number) => sequence.get(i));
|
|
848
|
-
t.columns.addNewString('Compound Comments').init((i: number) => (i > 0 && i % 2 == 0) ?
|
|
319
|
+
t.columns.addNewString(COL_NAMES.COMPOUND_NAME).init((i: number) => sequence.get(i));
|
|
320
|
+
t.columns.addNewString(COL_NAMES.COMPOUND_COMMENTS).init((i: number) => (i > 0 && i % 2 == 0) ?
|
|
849
321
|
sequence.getString(i) + '; duplex of SS: ' + sequence.getString(i - 2) + ' and AS: ' + sequence.getString(i - 1) :
|
|
850
|
-
sequence.getString(i)
|
|
322
|
+
sequence.getString(i),
|
|
323
|
+
);
|
|
324
|
+
const molWeightCol = saltsDf.col('MOLWEIGHT')!;
|
|
325
|
+
const saltNamesList = saltsDf.col('DISPLAY')!.toList();
|
|
326
|
+
t.columns.addNewFloat(COL_NAMES.CPD_MW)
|
|
327
|
+
.init((i: number) => molecularWeight(sequence.get(i), weightsObj));
|
|
328
|
+
t.columns.addNewFloat(COL_NAMES.SALT_MASS).init((i: number) => {
|
|
329
|
+
const saltRowIndex = saltNamesList.indexOf(salt.get(i));
|
|
330
|
+
const mw = molWeightCol.get(saltRowIndex);
|
|
331
|
+
return mw * equivalents.get(i);
|
|
332
|
+
});
|
|
333
|
+
t.columns.addNewCalculated(COL_NAMES.BATCH_MW,
|
|
334
|
+
'${' + COL_NAMES.CPD_MW + '} + ${' + COL_NAMES.SALT_MASS + '}', DG.COLUMN_TYPE.FLOAT, false,
|
|
851
335
|
);
|
|
852
|
-
t.columns.addNewFloat('Cpd MW').init((i: number) => ((i + 1) % 3 == 0) ? DG.FLOAT_NULL : molecularWeight(sequence.get(i)));
|
|
853
|
-
t.columns.addNewFloat('Salt mass').init((i: number) => parseNumber(salt.get(i)) * equivalents.get(i));
|
|
854
|
-
t.columns.addNewCalculated('Batch MW', '${Cpd MW} + ${Salt mass}', DG.COLUMN_TYPE.FLOAT, false);
|
|
855
336
|
|
|
856
337
|
addColumnsPressed = true;
|
|
857
338
|
return newDf = t;
|
|
858
339
|
}
|
|
859
340
|
|
|
860
|
-
const columnsOrder = ["Chemistry", "Number", "Type", "Chemistry Name", "Internal compound ID", "IDP", "Sequence", "Compound Name",
|
|
861
|
-
"Compound Comments", "Salt", "Equivalents", "Purity", "Cpd MW", "Salt mass", "Batch MW", "Source", "ICD", "Owner"];
|
|
862
341
|
let newDf: DG.DataFrame;
|
|
863
342
|
let addColumnsPressed = false;
|
|
864
343
|
|
|
865
|
-
|
|
344
|
+
const d = ui.div([
|
|
866
345
|
ui.icons.edit(() => {
|
|
867
346
|
d.innerHTML = '';
|
|
347
|
+
if (table.col(COL_NAMES.IDP)!.type != DG.COLUMN_TYPE.STRING)
|
|
348
|
+
table.changeColumnType(COL_NAMES.IDP, DG.COLUMN_TYPE.STRING);
|
|
868
349
|
d.append(
|
|
869
|
-
ui.link('Add Columns',
|
|
870
|
-
|
|
871
|
-
grok.shell.tableView(table.name).grid.columns.setOrder(
|
|
872
|
-
}, 'Add columns:
|
|
873
|
-
|
|
350
|
+
ui.link('Add Columns', () => {
|
|
351
|
+
addColumns(table, saltsDf);
|
|
352
|
+
grok.shell.tableView(table.name).grid.columns.setOrder(Object.values(COL_NAMES));
|
|
353
|
+
}, 'Add columns: \'' + [COL_NAMES.COMPOUND_NAME, COL_NAMES.COMPOUND_COMMENTS, COL_NAMES.CPD_MW,
|
|
354
|
+
COL_NAMES.SALT_MASS, COL_NAMES.BATCH_MW].join('\', \''), ''),
|
|
355
|
+
ui.button('Save SD file', () => saveTableAsSdFile(addColumnsPressed ? newDf : table)),
|
|
874
356
|
);
|
|
875
|
-
let view = grok.shell.getTableView(table.name);
|
|
876
|
-
let typeCol = view.grid.col('Type')!;
|
|
877
|
-
let saltCol = view.grid.col('Salt')!;
|
|
878
|
-
saltCol.cellType = 'html';
|
|
879
|
-
typeCol.cellType = 'html';
|
|
880
|
-
view.grid.onCellPrepare(function (gc: DG.GridCell) {
|
|
881
|
-
if (gc.isTableCell) {
|
|
882
|
-
if (gc.gridColumn.name == 'Type')
|
|
883
|
-
gc.style.element = ui.choiceInput('', gc.cell.value, ['AS', 'SS', 'Duplex']).root;
|
|
884
|
-
else if (gc.gridColumn.name == 'Salt')
|
|
885
|
-
gc.style.element = ui.choiceInput('', gc.cell.value, ['Sodium (+1)', 'Sodium (+2)']).root;
|
|
886
|
-
}
|
|
887
|
-
});
|
|
888
357
|
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
358
|
+
const view = grok.shell.getTableView(table.name)!;
|
|
359
|
+
|
|
360
|
+
view.table!.col(COL_NAMES.TYPE)!.setTag(DG.TAGS.CHOICES, '["AS", "SS", "Duplex"]');
|
|
361
|
+
view.table!.col(COL_NAMES.OWNER)!.setTag(DG.TAGS.CHOICES, stringifyItems(usersDf.columns.byIndex(0).toList()));
|
|
362
|
+
view.table!.col(COL_NAMES.SALT)!.setTag(DG.TAGS.CHOICES, stringifyItems(saltsDf.columns.byIndex(0).toList()));
|
|
363
|
+
view.table!.col(COL_NAMES.SOURCE)!.setTag(DG.TAGS.CHOICES, stringifyItems(sourcesDf.columns.byIndex(0).toList()));
|
|
364
|
+
view.table!.col(COL_NAMES.ICD)!.setTag(DG.TAGS.CHOICES, stringifyItems(icdsDf.columns.byIndex(0).toList()));
|
|
365
|
+
view.table!.col(COL_NAMES.IDP)!.setTag(DG.TAGS.CHOICES, stringifyItems(idpsDf.columns.byIndex(0).toList()));
|
|
366
|
+
|
|
367
|
+
grok.events.onContextMenu.subscribe((args) => {
|
|
368
|
+
if ([COL_NAMES.TYPE, COL_NAMES.OWNER, COL_NAMES.SALT, COL_NAMES.SOURCE, COL_NAMES.ICD, COL_NAMES.IDP]
|
|
369
|
+
.includes(args.args.context.table.currentCol.name)) {
|
|
370
|
+
args.args.menu.item('Fill Column With Value', () => {
|
|
371
|
+
const v = args.args.context.table.currentCell.value;
|
|
372
|
+
args.args.context.table.currentCell.column.init(v);
|
|
373
|
+
});
|
|
374
|
+
}
|
|
892
375
|
});
|
|
893
|
-
})
|
|
376
|
+
}),
|
|
894
377
|
]);
|
|
895
378
|
grok.shell.v.setRibbonPanels([[d]]);
|
|
896
379
|
}
|