@datagrok/sequence-translator 0.0.5 → 0.0.9
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/jest.config.js +33 -0
- package/package.json +12 -4
- 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 +175 -684
- 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 +428 -0
- package/src/structures-works/save-sense-antisense.ts +51 -0
- package/src/structures-works/sequence-codes-tools.ts +236 -0
- package/src/tests/smiles-tests.ts +1 -1
- package/src/users.ts +3 -0
- package/test-SequenceTranslator-2e08c8e54bde-1367d435.html +245 -0
- package/tsconfig.json +2 -1
- package/src/save-sense-antisense.ts +0 -36
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} 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
20
|
const defaultInput = 'AGGTCCTCTTGACTTAGGCC';
|
|
14
|
-
const undefinedInputSequence = 'Type of input sequence is undefined';
|
|
15
|
-
const noTranslationTableAvailable = 'No translation table available';
|
|
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 {
|
|
@@ -233,11 +39,11 @@ export function sequenceTranslator(): void {
|
|
|
233
39
|
const tableRows = [];
|
|
234
40
|
|
|
235
41
|
for (const key of Object.keys(outputSequenceObj).slice(1)) {
|
|
236
|
-
|
|
42
|
+
const indexOfFirstNotValidCharacter = ('indexOfFirstNotValidCharacter' in outputSequenceObj) ?
|
|
237
43
|
JSON.parse(outputSequenceObj.indexOfFirstNotValidCharacter!).indexOfFirstNotValidCharacter :
|
|
238
44
|
-1;
|
|
239
45
|
if ('indexOfFirstNotValidCharacter' in outputSequenceObj) {
|
|
240
|
-
|
|
46
|
+
const indexOfFirstNotValidCharacter = ('indexOfFirstNotValidCharacter' in outputSequenceObj) ?
|
|
241
47
|
JSON.parse(outputSequenceObj.indexOfFirstNotValidCharacter!).indexOfFirstNotValidCharacter :
|
|
242
48
|
-1;
|
|
243
49
|
if (indexOfFirstNotValidCharacter != -1)
|
|
@@ -251,54 +57,54 @@ export function sequenceTranslator(): void {
|
|
|
251
57
|
ui.divText(sequence.slice(0, indexOfFirstNotValidCharacter), {style: {color: 'grey'}}),
|
|
252
58
|
ui.tooltip.bind(
|
|
253
59
|
ui.divText(sequence.slice(indexOfFirstNotValidCharacter), {style: {color: 'red'}}),
|
|
254
|
-
'Expected format: ' + JSON.parse(outputSequenceObj.indexOfFirstNotValidCharacter!).expectedSynthesizer +
|
|
60
|
+
'Expected format: ' + JSON.parse(outputSequenceObj.indexOfFirstNotValidCharacter!).expectedSynthesizer +
|
|
61
|
+
'. See tables with valid codes on the right',
|
|
255
62
|
),
|
|
256
63
|
]) : //@ts-ignore
|
|
257
|
-
ui.link(outputSequenceObj[key], () => navigator.clipboard.writeText(outputSequenceObj[key])
|
|
64
|
+
ui.link(outputSequenceObj[key], () => navigator.clipboard.writeText(outputSequenceObj[key])
|
|
65
|
+
.then(() => grok.shell.info(sequenceWasCopied)), tooltipSequence, ''),
|
|
258
66
|
});
|
|
259
67
|
}
|
|
260
68
|
|
|
261
69
|
if (errorsExist) {
|
|
262
|
-
const expectedSynthesizer = JSON.parse(outputSequenceObj.indexOfFirstNotValidCharacter!)
|
|
263
|
-
|
|
70
|
+
const expectedSynthesizer = JSON.parse(outputSequenceObj.indexOfFirstNotValidCharacter!)
|
|
71
|
+
.expectedSynthesizer.slice(0, -6);
|
|
72
|
+
asoGapmersGrid.onCellPrepare(function(gc) {
|
|
264
73
|
gc.style.backColor = (gc.gridColumn.name == expectedSynthesizer) ? 0xFFF00000 : 0xFFFFFFFF;
|
|
265
74
|
});
|
|
266
|
-
omeAndFluoroGrid.onCellPrepare(function
|
|
75
|
+
omeAndFluoroGrid.onCellPrepare(function(gc) {
|
|
267
76
|
gc.style.backColor = (gc.gridColumn.name == expectedSynthesizer) ? 0xFFF00000 : 0xFFFFFFFF;
|
|
268
77
|
});
|
|
269
78
|
switchInput.enabled = true;
|
|
270
79
|
} else {
|
|
271
|
-
asoGapmersGrid.onCellPrepare(function
|
|
272
|
-
|
|
273
|
-
});
|
|
274
|
-
omeAndFluoroGrid.onCellPrepare(function (gc) {
|
|
275
|
-
gc.style.backColor = 0xFFFFFFFF;
|
|
276
|
-
});
|
|
80
|
+
asoGapmersGrid.onCellPrepare(function(gc) {gc.style.backColor = 0xFFFFFFFF;});
|
|
81
|
+
omeAndFluoroGrid.onCellPrepare(function(gc) {gc.style.backColor = 0xFFFFFFFF;});
|
|
277
82
|
}
|
|
278
83
|
|
|
279
84
|
outputTableDiv.append(
|
|
280
85
|
ui.div([
|
|
281
|
-
DG.HtmlTable.create(tableRows, (item: { key: string; value: string; }) =>
|
|
282
|
-
|
|
86
|
+
DG.HtmlTable.create(tableRows, (item: { key: string; value: string; }) =>
|
|
87
|
+
[item.key, item.value], ['Code', 'Sequence']).root,
|
|
88
|
+
], 'table'),
|
|
283
89
|
);
|
|
284
90
|
semTypeOfInputSequence.textContent = 'Detected input type: ' + outputSequenceObj.type;
|
|
285
91
|
|
|
286
92
|
if (outputSequenceObj.type != undefinedInputSequence && outputSequenceObj.Error != undefinedInputSequence) {
|
|
287
|
-
|
|
288
|
-
canvas.addEventListener(
|
|
289
|
-
|
|
290
|
-
const
|
|
93
|
+
const canvas = ui.canvas(300, 170);
|
|
94
|
+
canvas.addEventListener('click', () => {
|
|
95
|
+
const canv = ui.canvas($(window).width(), $(window).height());
|
|
96
|
+
const mol = sequenceToMolV3000(inputSequenceField.value.replace(/\s/g, ''), false, true);
|
|
291
97
|
// @ts-ignore
|
|
292
|
-
OCL.StructureView.drawMolecule(canv, OCL.Molecule.
|
|
293
|
-
ui.dialog('Molecule')
|
|
98
|
+
OCL.StructureView.drawMolecule(canv, OCL.Molecule.fromMolfile(mol), {suppressChiralText: true});
|
|
99
|
+
ui.dialog('Molecule: ' + inputSequenceField.value)
|
|
294
100
|
.add(canv)
|
|
295
101
|
.showModal(true);
|
|
296
102
|
});
|
|
297
103
|
$(canvas).on('mouseover', () => $(canvas).css('cursor', 'zoom-in'));
|
|
298
104
|
$(canvas).on('mouseout', () => $(canvas).css('cursor', 'default'));
|
|
299
|
-
const
|
|
105
|
+
const mol = sequenceToMolV3000(inputSequenceField.value.replace(/\s/g, ''), false, true);
|
|
300
106
|
// @ts-ignore
|
|
301
|
-
OCL.StructureView.drawMolecule(canvas, OCL.Molecule.
|
|
107
|
+
OCL.StructureView.drawMolecule(canvas, OCL.Molecule.fromMolfile(mol), {suppressChiralText: true});
|
|
302
108
|
moleculeSvgDiv.append(canvas);
|
|
303
109
|
} else
|
|
304
110
|
moleculeSvgDiv.innerHTML = '';
|
|
@@ -313,69 +119,66 @@ export function sequenceTranslator(): void {
|
|
|
313
119
|
const inputSequenceField = ui.textInput('', defaultInput, (sequence: string) => updateTableAndMolecule(sequence));
|
|
314
120
|
|
|
315
121
|
const asoDf = DG.DataFrame.fromObjects([
|
|
316
|
-
{
|
|
317
|
-
{
|
|
318
|
-
{
|
|
319
|
-
{
|
|
320
|
-
{
|
|
321
|
-
{
|
|
322
|
-
{
|
|
323
|
-
{
|
|
324
|
-
{
|
|
325
|
-
{
|
|
326
|
-
{
|
|
327
|
-
{
|
|
328
|
-
{
|
|
329
|
-
{
|
|
122
|
+
{'Name': '2\'MOE-5Me-rU', 'BioSpring': '5', 'Janssen GCRS': 'moeT'},
|
|
123
|
+
{'Name': '2\'MOE-rA', 'BioSpring': '6', 'Janssen GCRS': 'moeA'},
|
|
124
|
+
{'Name': '2\'MOE-5Me-rC', 'BioSpring': '7', 'Janssen GCRS': 'moe5mC'},
|
|
125
|
+
{'Name': '2\'MOE-rG', 'BioSpring': '8', 'Janssen GCRS': 'moeG'},
|
|
126
|
+
{'Name': '5-Methyl-dC', 'BioSpring': '9', 'Janssen GCRS': '5mC'},
|
|
127
|
+
{'Name': 'ps linkage', 'BioSpring': '*', 'Janssen GCRS': 'ps'},
|
|
128
|
+
{'Name': 'dA', 'BioSpring': 'A', 'Janssen GCRS': 'A, dA'},
|
|
129
|
+
{'Name': 'dC', 'BioSpring': 'C', 'Janssen GCRS': 'C, dC'},
|
|
130
|
+
{'Name': 'dG', 'BioSpring': 'G', 'Janssen GCRS': 'G, dG'},
|
|
131
|
+
{'Name': 'dT', 'BioSpring': 'T', 'Janssen GCRS': 'T, dT'},
|
|
132
|
+
{'Name': 'rA', 'BioSpring': '', 'Janssen GCRS': 'rA'},
|
|
133
|
+
{'Name': 'rC', 'BioSpring': '', 'Janssen GCRS': 'rC'},
|
|
134
|
+
{'Name': 'rG', 'BioSpring': '', 'Janssen GCRS': 'rG'},
|
|
135
|
+
{'Name': 'rU', 'BioSpring': '', 'Janssen GCRS': 'rU'},
|
|
330
136
|
])!;
|
|
331
|
-
const asoGapmersGrid = DG.Viewer.grid(
|
|
332
|
-
asoDf, { showRowHeader: false, showCellTooltip: false }
|
|
333
|
-
);
|
|
137
|
+
const asoGapmersGrid = DG.Viewer.grid(asoDf, {showRowHeader: false, showCellTooltip: false});
|
|
334
138
|
|
|
335
139
|
asoDf.onCurrentCellChanged.subscribe((_) => {
|
|
336
|
-
navigator.clipboard.writeText(asoDf.currentCell.value).then(() => grok.shell.info('Copied'))
|
|
140
|
+
navigator.clipboard.writeText(asoDf.currentCell.value).then(() => grok.shell.info('Copied'));
|
|
337
141
|
});
|
|
338
142
|
|
|
339
|
-
|
|
143
|
+
const omeAndFluoroGrid = DG.Viewer.grid(
|
|
340
144
|
DG.DataFrame.fromObjects([
|
|
341
|
-
{
|
|
342
|
-
{
|
|
343
|
-
{
|
|
344
|
-
{
|
|
345
|
-
{
|
|
346
|
-
{
|
|
347
|
-
{
|
|
348
|
-
{
|
|
349
|
-
{
|
|
350
|
-
])!, {
|
|
145
|
+
{'Name': '2\'-fluoro-U', 'BioSpring': '1', 'Axolabs': 'Uf', 'Janssen GCRS': 'fU'},
|
|
146
|
+
{'Name': '2\'-fluoro-A', 'BioSpring': '2', 'Axolabs': 'Af', 'Janssen GCRS': 'fA'},
|
|
147
|
+
{'Name': '2\'-fluoro-C', 'BioSpring': '3', 'Axolabs': 'Cf', 'Janssen GCRS': 'fC'},
|
|
148
|
+
{'Name': '2\'-fluoro-G', 'BioSpring': '4', 'Axolabs': 'Gf', 'Janssen GCRS': 'fG'},
|
|
149
|
+
{'Name': '2\'OMe-rU', 'BioSpring': '5', 'Axolabs': 'u', 'Janssen GCRS': 'mU'},
|
|
150
|
+
{'Name': '2\'OMe-rA', 'BioSpring': '6', 'Axolabs': 'a', 'Janssen GCRS': 'mA'},
|
|
151
|
+
{'Name': '2\'OMe-rC', 'BioSpring': '7', 'Axolabs': 'c', 'Janssen GCRS': 'mC'},
|
|
152
|
+
{'Name': '2\'OMe-rG', 'BioSpring': '8', 'Axolabs': 'g', 'Janssen GCRS': 'mG'},
|
|
153
|
+
{'Name': 'ps linkage', 'BioSpring': '*', 'Axolabs': 's', 'Janssen GCRS': 'ps'},
|
|
154
|
+
])!, {showRowHeader: false, showCellTooltip: false},
|
|
351
155
|
);
|
|
352
156
|
|
|
353
157
|
const overhangModificationsGrid = DG.Viewer.grid(
|
|
354
158
|
DG.DataFrame.fromObjects([
|
|
355
|
-
{
|
|
356
|
-
{
|
|
357
|
-
])!, {
|
|
159
|
+
{'Name': '(invabasic)'},
|
|
160
|
+
{'Name': '(GalNAc-2-JNJ)'},
|
|
161
|
+
])!, {showRowHeader: false, showCellTooltip: false},
|
|
358
162
|
);
|
|
359
163
|
updateTableAndMolecule(defaultInput);
|
|
360
164
|
|
|
361
165
|
const appMainDescription = ui.info([
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
);
|
|
166
|
+
ui.divText('How to convert one sequence:', {style: {'font-weight': 'bolder'}}),
|
|
167
|
+
ui.divText('Paste sequence into the text field below'),
|
|
168
|
+
ui.divText('\n How to convert many sequences:', {style: {'font-weight': 'bolder'}}),
|
|
169
|
+
ui.divText('1. Drag & drop an Excel or CSV file with sequences into Datagrok'),
|
|
170
|
+
ui.divText('2. Right-click on the column header, then see the \'Convert\' menu'),
|
|
171
|
+
ui.divText('This will add the result column to the right of the table'),
|
|
172
|
+
], 'Convert oligonucleotide sequences between Nucleotides, BioSpring, Axolabs, Mermade 12 and GCRS representations.');
|
|
370
173
|
|
|
371
174
|
const codesTablesDiv = ui.splitV([
|
|
372
|
-
ui.box(ui.h2('ASO Gapmers'), {
|
|
175
|
+
ui.box(ui.h2('ASO Gapmers'), {style: {maxHeight: '40px'}}),
|
|
373
176
|
asoGapmersGrid.root,
|
|
374
|
-
ui.box(ui.h2(
|
|
177
|
+
ui.box(ui.h2('2\'-OMe and 2\'-F siRNA'), {style: {maxHeight: '40px'}}),
|
|
375
178
|
omeAndFluoroGrid.root,
|
|
376
|
-
ui.box(ui.h2('Overhang modifications'), {
|
|
377
|
-
overhangModificationsGrid.root
|
|
378
|
-
], {
|
|
179
|
+
ui.box(ui.h2('Overhang modifications'), {style: {maxHeight: '40px'}}),
|
|
180
|
+
overhangModificationsGrid.root,
|
|
181
|
+
], {style: {maxWidth: '350px'}});
|
|
379
182
|
|
|
380
183
|
const tabControl = ui.tabControl({
|
|
381
184
|
'MAIN': ui.box(
|
|
@@ -404,18 +207,17 @@ export function sequenceTranslator(): void {
|
|
|
404
207
|
'SDF': saveSenseAntiSense(),
|
|
405
208
|
});
|
|
406
209
|
|
|
407
|
-
|
|
210
|
+
const v = grok.shell.newView('Sequence Translator', [tabControl]);
|
|
408
211
|
v.box = true;
|
|
409
212
|
|
|
410
213
|
const switchInput = ui.switchInput('Codes', true, (v: boolean) => (v) ?
|
|
411
214
|
$(codesTablesDiv).show() :
|
|
412
|
-
$(codesTablesDiv).hide()
|
|
215
|
+
$(codesTablesDiv).hide(),
|
|
413
216
|
);
|
|
414
217
|
|
|
415
218
|
const topPanel = [
|
|
416
219
|
ui.iconFA('download', () => {
|
|
417
|
-
const
|
|
418
|
-
const result = `${OCL.Molecule.fromSmiles(smiles).toMolfile()}\n`;
|
|
220
|
+
const result = sequenceToMolV3000(inputSequenceField.value.replace(/\s/g, ''));
|
|
419
221
|
const element = document.createElement('a');
|
|
420
222
|
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(result));
|
|
421
223
|
element.setAttribute('download', inputSequenceField.value.replace(/\s/g, '') + '.mol');
|
|
@@ -433,464 +235,153 @@ export function sequenceTranslator(): void {
|
|
|
433
235
|
v.setRibbonPanels([topPanel]);
|
|
434
236
|
|
|
435
237
|
$('.sequence')
|
|
436
|
-
.children().css('padding','5px 0');
|
|
238
|
+
.children().css('padding', '5px 0');
|
|
437
239
|
$('.sequenceInput .input-base')
|
|
438
|
-
.css('margin','0');
|
|
240
|
+
.css('margin', '0');
|
|
439
241
|
$('.sequenceInput textarea')
|
|
440
|
-
.css('resize','none')
|
|
441
|
-
.css('min-height','50px')
|
|
442
|
-
.css('width','100%')
|
|
242
|
+
.css('resize', 'none')
|
|
243
|
+
.css('min-height', '50px')
|
|
244
|
+
.css('width', '100%')
|
|
443
245
|
.attr('spellcheck', 'false');
|
|
444
246
|
$('.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]});
|
|
247
|
+
.css('width', '100%');
|
|
775
248
|
}
|
|
776
249
|
|
|
777
250
|
async function saveTableAsSdFile(table: DG.DataFrame) {
|
|
778
|
-
if (!table.columns.contains('Compound Name'))
|
|
779
|
-
grok.shell.warning(
|
|
780
|
-
|
|
251
|
+
if (!table.columns.contains('Compound Name')) {
|
|
252
|
+
grok.shell.warning(
|
|
253
|
+
'File saved without columns \'' +
|
|
254
|
+
[COL_NAMES.COMPOUND_NAME, COL_NAMES.COMPOUND_COMMENTS, COL_NAMES.CPD_MW,
|
|
255
|
+
COL_NAMES.SALT_MASS, COL_NAMES.BATCH_MW].join('\', \''),
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
const structureColumn = table.col(COL_NAMES.SEQUENCE)!;
|
|
259
|
+
const typeColumn = table.col(COL_NAMES.TYPE)!;
|
|
781
260
|
let result = '';
|
|
782
261
|
for (let i = 0; i < table.rowCount; i++) {
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
for (let col of table.columns)
|
|
262
|
+
result += (typeColumn.get(i) == 'SS') ?
|
|
263
|
+
sequenceToMolV3000(structureColumn.get(i), false, true) + '\n' + `> <Sequence>\nSense Strand\n\n` :
|
|
264
|
+
sequenceToMolV3000(structureColumn.get(i), true, true) + '\n' + `> <Sequence>\nAnti Sense\n\n`;
|
|
265
|
+
for (const col of table.columns) {
|
|
266
|
+
if (col.name != COL_NAMES.SEQUENCE)
|
|
789
267
|
result += `> <${col.name}>\n${col.get(i)}\n\n`;
|
|
790
|
-
result += '$$$$';
|
|
791
|
-
}
|
|
792
|
-
catch (error) {
|
|
793
|
-
console.error(error);
|
|
794
268
|
}
|
|
269
|
+
result += '$$$$\n\n';
|
|
795
270
|
}
|
|
796
|
-
|
|
271
|
+
const element = document.createElement('a');
|
|
797
272
|
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(result));
|
|
798
273
|
element.setAttribute('download', table.name + '.sdf');
|
|
799
274
|
element.click();
|
|
800
275
|
}
|
|
801
276
|
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
277
|
+
const weightsObj: {[code: string]: number} = {};
|
|
278
|
+
for (const synthesizer of Object.keys(map)) {
|
|
279
|
+
for (const technology of Object.keys(map[synthesizer])) {
|
|
280
|
+
for (const code of Object.keys(map[synthesizer][technology]))
|
|
281
|
+
weightsObj[code] = map[synthesizer][technology][code].weight;
|
|
282
|
+
}
|
|
807
283
|
}
|
|
284
|
+
for (const [key, value] of Object.entries(MODIFICATIONS))
|
|
285
|
+
weightsObj[key] = value.molecularWeight;
|
|
808
286
|
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
grok.events.onViewAdded.subscribe((v: any) => {
|
|
812
|
-
if (v.type == 'TableView' && v.dataFrame.columns.contains('Type'))
|
|
813
|
-
oligoSdFile(v.dataFrame);
|
|
814
|
-
});
|
|
287
|
+
function sortByStringLengthInDescendingOrder(array: string[]): string[] {
|
|
288
|
+
return array.sort(function(a, b) {return b.length - a.length;});
|
|
815
289
|
}
|
|
816
290
|
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
for (let code of Object.keys(map[synthesizer][technology]))
|
|
821
|
-
weightsObj[code] = map[synthesizer][technology][code].weight;
|
|
291
|
+
function stringifyItems(items: string[]): string {
|
|
292
|
+
return '["' + items.join('", "') + '"]';
|
|
293
|
+
}
|
|
822
294
|
|
|
823
|
-
function molecularWeight(sequence: string): number {
|
|
824
|
-
const codes = sortByStringLengthInDescendingOrder(Object.keys(weightsObj));
|
|
825
|
-
let weight = 0
|
|
295
|
+
function molecularWeight(sequence: string, weightsObj: {[index: string]: number}): number {
|
|
296
|
+
const codes = sortByStringLengthInDescendingOrder(Object.keys(weightsObj)).concat(Object.keys(MODIFICATIONS));
|
|
297
|
+
let weight = 0;
|
|
298
|
+
let i = 0;
|
|
826
299
|
while (i < sequence.length) {
|
|
827
|
-
|
|
300
|
+
const matchedCode = codes.find((s) => s == sequence.slice(i, i + s.length))!;
|
|
828
301
|
weight += weightsObj[sequence.slice(i, i + matchedCode.length)];
|
|
829
302
|
i += matchedCode!.length;
|
|
830
303
|
}
|
|
831
304
|
return weight - 61.97;
|
|
832
305
|
}
|
|
833
306
|
|
|
834
|
-
|
|
307
|
+
//tags: autostart
|
|
308
|
+
export function autostartOligoSdFileSubscription() {
|
|
309
|
+
grok.events.onViewAdded.subscribe((v: any) => {
|
|
310
|
+
if (v.type == 'TableView' && v.dataFrame.columns.contains(COL_NAMES.TYPE))
|
|
311
|
+
oligoSdFile(v.dataFrame);
|
|
312
|
+
});
|
|
313
|
+
}
|
|
835
314
|
|
|
836
|
-
|
|
837
|
-
|
|
315
|
+
export function oligoSdFile(table: DG.DataFrame) {
|
|
316
|
+
const saltsDf = DG.DataFrame.fromCsv(SALTS_CSV);
|
|
317
|
+
const usersDf = DG.DataFrame.fromCsv(USERS_CSV);
|
|
318
|
+
const sourcesDf = DG.DataFrame.fromCsv(SOURCES);
|
|
319
|
+
const icdsDf = DG.DataFrame.fromCsv(ICDS);
|
|
320
|
+
const idpsDf = DG.DataFrame.fromCsv(IDPS);
|
|
321
|
+
|
|
322
|
+
function addColumns(t: DG.DataFrame, saltsDf: DG.DataFrame) {
|
|
323
|
+
if (t.columns.contains(COL_NAMES.COMPOUND_NAME))
|
|
838
324
|
return grok.shell.error('Columns already exist!');
|
|
839
325
|
|
|
840
|
-
|
|
841
|
-
|
|
326
|
+
const sequence = t.col(COL_NAMES.SEQUENCE)!;
|
|
327
|
+
const equivalents = t.col(COL_NAMES.EQUIVALENTS)!;
|
|
842
328
|
|
|
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) ?
|
|
329
|
+
t.columns.addNewString(COL_NAMES.COMPOUND_NAME).init((i: number) => sequence.get(i));
|
|
330
|
+
t.columns.addNewString(COL_NAMES.COMPOUND_COMMENTS).init((i: number) => (i > 0 && i % 2 == 0) ?
|
|
849
331
|
sequence.getString(i) + '; duplex of SS: ' + sequence.getString(i - 2) + ' and AS: ' + sequence.getString(i - 1) :
|
|
850
|
-
sequence.getString(i)
|
|
332
|
+
sequence.getString(i),
|
|
333
|
+
);
|
|
334
|
+
t.columns.addNewFloat(COL_NAMES.CPD_MW)
|
|
335
|
+
.init((i: number) => molecularWeight(sequence.get(i), weightsObj));
|
|
336
|
+
const mwCol = t.col(COL_NAMES.CPD_MW)!;
|
|
337
|
+
t.columns.addNewFloat(COL_NAMES.SALT_MASS).init((i: number) => {
|
|
338
|
+
const mw = mwCol.get(i);
|
|
339
|
+
return mw * equivalents.get(i);
|
|
340
|
+
});
|
|
341
|
+
t.columns.addNewCalculated(COL_NAMES.BATCH_MW,
|
|
342
|
+
'${' + COL_NAMES.CPD_MW + '} + ${' + COL_NAMES.SALT_MASS + '}', DG.COLUMN_TYPE.FLOAT, false,
|
|
851
343
|
);
|
|
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
344
|
|
|
856
345
|
addColumnsPressed = true;
|
|
857
346
|
return newDf = t;
|
|
858
347
|
}
|
|
859
348
|
|
|
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
349
|
let newDf: DG.DataFrame;
|
|
863
350
|
let addColumnsPressed = false;
|
|
864
351
|
|
|
865
|
-
|
|
352
|
+
const d = ui.div([
|
|
866
353
|
ui.icons.edit(() => {
|
|
867
354
|
d.innerHTML = '';
|
|
355
|
+
if (table.col(COL_NAMES.IDP)!.type != DG.COLUMN_TYPE.STRING)
|
|
356
|
+
table.changeColumnType(COL_NAMES.IDP, DG.COLUMN_TYPE.STRING);
|
|
868
357
|
d.append(
|
|
869
|
-
ui.link('Add Columns',
|
|
870
|
-
|
|
871
|
-
grok.shell.tableView(table.name).grid.columns.setOrder(
|
|
872
|
-
}, 'Add columns:
|
|
873
|
-
|
|
358
|
+
ui.link('Add Columns', () => {
|
|
359
|
+
addColumns(table, saltsDf);
|
|
360
|
+
grok.shell.tableView(table.name).grid.columns.setOrder(Object.values(COL_NAMES));
|
|
361
|
+
}, 'Add columns: \'' + [COL_NAMES.COMPOUND_NAME, COL_NAMES.COMPOUND_COMMENTS, COL_NAMES.CPD_MW,
|
|
362
|
+
COL_NAMES.SALT_MASS, COL_NAMES.BATCH_MW].join('\', \''), ''),
|
|
363
|
+
ui.button('Save SD file', () => saveTableAsSdFile(addColumnsPressed ? newDf : table)),
|
|
874
364
|
);
|
|
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
365
|
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
366
|
+
const view = grok.shell.getTableView(table.name)!;
|
|
367
|
+
|
|
368
|
+
view.table!.col(COL_NAMES.TYPE)!.setTag(DG.TAGS.CHOICES, '["AS", "SS", "Duplex"]');
|
|
369
|
+
view.table!.col(COL_NAMES.OWNER)!.setTag(DG.TAGS.CHOICES, stringifyItems(usersDf.columns.byIndex(0).toList()));
|
|
370
|
+
view.table!.col(COL_NAMES.SALT)!.setTag(DG.TAGS.CHOICES, stringifyItems(saltsDf.columns.byIndex(1).toList()));
|
|
371
|
+
view.table!.col(COL_NAMES.SOURCE)!.setTag(DG.TAGS.CHOICES, stringifyItems(sourcesDf.columns.byIndex(0).toList()));
|
|
372
|
+
view.table!.col(COL_NAMES.ICD)!.setTag(DG.TAGS.CHOICES, stringifyItems(icdsDf.columns.byIndex(0).toList()));
|
|
373
|
+
view.table!.col(COL_NAMES.IDP)!.setTag(DG.TAGS.CHOICES, stringifyItems(idpsDf.columns.byIndex(0).toList()));
|
|
374
|
+
|
|
375
|
+
grok.events.onContextMenu.subscribe((args) => {
|
|
376
|
+
if ([COL_NAMES.TYPE, COL_NAMES.OWNER, COL_NAMES.SALT, COL_NAMES.SOURCE, COL_NAMES.ICD, COL_NAMES.IDP]
|
|
377
|
+
.includes(args.args.context.table.currentCol.name)) {
|
|
378
|
+
args.args.menu.item('Fill Column With Value', () => {
|
|
379
|
+
const v = args.args.context.table.currentCell.value;
|
|
380
|
+
args.args.context.table.currentCell.column.init(v);
|
|
381
|
+
});
|
|
382
|
+
}
|
|
892
383
|
});
|
|
893
|
-
})
|
|
384
|
+
}),
|
|
894
385
|
]);
|
|
895
386
|
grok.shell.v.setRibbonPanels([[d]]);
|
|
896
387
|
}
|