@datagrok/sequence-translator 0.0.4 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +39 -0
- package/detectors.js +2 -12
- package/package.json +7 -3
- package/src/axolabsMap.ts +101 -99
- package/src/defineAxolabsPattern.ts +240 -211
- package/src/drawAxolabsPattern.ts +127 -92
- package/src/package-test.ts +6 -7
- package/src/package.ts +301 -604
- package/src/salts.ts +2 -0
- package/src/structures-works/converters.ts +288 -0
- package/src/structures-works/from-monomers.ts +73 -0
- package/src/structures-works/map.ts +540 -0
- package/src/structures-works/save-sense-antisense.ts +44 -0
- package/src/structures-works/sequence-codes-tools.ts +236 -0
- package/src/tests/smiles-tests.ts +448 -7
- package/src/map.ts +0 -534
package/src/package.ts
CHANGED
|
@@ -3,657 +3,354 @@ import * as grok from 'datagrok-api/grok';
|
|
|
3
3
|
import * as ui from 'datagrok-api/ui';
|
|
4
4
|
import * as DG from 'datagrok-api/dg';
|
|
5
5
|
import * as OCL from 'openchemlib/full.js';
|
|
6
|
-
import $ from
|
|
7
|
-
import {defineAxolabsPattern} from
|
|
8
|
-
import {
|
|
6
|
+
import $ from 'cash-dom';
|
|
7
|
+
import {defineAxolabsPattern} from './defineAxolabsPattern';
|
|
8
|
+
import {saveSenseAntiSense} from './structures-works/save-sense-antisense';
|
|
9
|
+
import {sequenceToSmiles} from './structures-works/from-monomers';
|
|
10
|
+
import {convertSequence, undefinedInputSequence} from './structures-works/sequence-codes-tools';
|
|
11
|
+
import {SALTS_CSV} from './salts';
|
|
9
12
|
|
|
10
|
-
export
|
|
13
|
+
export const _package = new DG.Package();
|
|
11
14
|
|
|
12
|
-
const defaultInput =
|
|
13
|
-
const undefinedInputSequence = "Type of input sequence is undefined";
|
|
14
|
-
const noTranslationTableAvailable = "No translation table available";
|
|
15
|
+
const defaultInput = 'AGGTCCTCTTGACTTAGGCC';
|
|
15
16
|
const sequenceWasCopied = 'Copied';
|
|
16
17
|
const tooltipSequence = 'Copy sequence';
|
|
17
18
|
|
|
18
|
-
function getAllCodesOfSynthesizer(synthesizer: string) {
|
|
19
|
-
let codes: string[] = [];
|
|
20
|
-
for (let technology of Object.keys(map[synthesizer]))
|
|
21
|
-
codes = codes.concat(Object.keys(map[synthesizer][technology]));
|
|
22
|
-
return codes.concat(Object.keys(MODIFICATIONS));
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function getListOfPossibleSynthesizersByFirstMatchedCode(sequence: string): string[] {
|
|
26
|
-
let synthesizers: string[] = [];
|
|
27
|
-
Object.keys(map).forEach((synthesizer: string) => {
|
|
28
|
-
const codes = getAllCodesOfSynthesizer(synthesizer);
|
|
29
|
-
//TODO: get first non-dropdown code when there are two modifications
|
|
30
|
-
let start = 0;
|
|
31
|
-
for (let i = 0; i < sequence.length; i++)
|
|
32
|
-
if (sequence[i] == ')') {
|
|
33
|
-
start = i + 1;
|
|
34
|
-
break;
|
|
35
|
-
}
|
|
36
|
-
if (codes.some((s: string) => s == sequence.slice(start, start + s.length)))
|
|
37
|
-
synthesizers.push(synthesizer);
|
|
38
|
-
});
|
|
39
|
-
return synthesizers;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function getListOfPossibleTechnologiesByFirstMatchedCode(sequence: string, synthesizer: string): string[] {
|
|
43
|
-
let technologies: string[] = [];
|
|
44
|
-
Object.keys(map[synthesizer]).forEach((technology: string) => {
|
|
45
|
-
const codes = Object.keys(map[synthesizer][technology]).concat(Object.keys(MODIFICATIONS));
|
|
46
|
-
if (codes.some((s) => s == sequence.slice(0, s.length)))
|
|
47
|
-
technologies.push(technology);
|
|
48
|
-
});
|
|
49
|
-
return technologies;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function isValidSequence(sequence: string) {
|
|
53
|
-
let possibleSynthesizers = getListOfPossibleSynthesizersByFirstMatchedCode(sequence);
|
|
54
|
-
if (possibleSynthesizers.length == 0)
|
|
55
|
-
return { indexOfFirstNotValidCharacter: 0, expectedType: null };
|
|
56
|
-
|
|
57
|
-
let outputIndices = Array(possibleSynthesizers.length).fill(0);
|
|
58
|
-
|
|
59
|
-
const firstUniqueCharacters = ['r', 'd'], nucleotides = ["A", "U", "T", "C", "G"];
|
|
60
|
-
|
|
61
|
-
possibleSynthesizers.forEach((synthesizer, synthesizerIndex) => {
|
|
62
|
-
let codes = getAllCodesOfSynthesizer(synthesizer);
|
|
63
|
-
while (outputIndices[synthesizerIndex] < sequence.length) {
|
|
64
|
-
|
|
65
|
-
let matchedCode = codes
|
|
66
|
-
.find((c) => c == sequence.slice(outputIndices[synthesizerIndex], outputIndices[synthesizerIndex] + c.length));
|
|
67
|
-
|
|
68
|
-
if (matchedCode == null)
|
|
69
|
-
break;
|
|
70
|
-
|
|
71
|
-
if ( // for mistake pattern 'rAA'
|
|
72
|
-
outputIndices[synthesizerIndex] > 1 &&
|
|
73
|
-
nucleotides.includes(sequence[outputIndices[synthesizerIndex]]) &&
|
|
74
|
-
firstUniqueCharacters.includes(sequence[outputIndices[synthesizerIndex] - 2])
|
|
75
|
-
) break;
|
|
76
|
-
|
|
77
|
-
if ( // for mistake pattern 'ArA'
|
|
78
|
-
firstUniqueCharacters.includes(sequence[outputIndices[synthesizerIndex] + 1]) &&
|
|
79
|
-
nucleotides.includes(sequence[outputIndices[synthesizerIndex]])
|
|
80
|
-
) {
|
|
81
|
-
outputIndices[synthesizerIndex]++;
|
|
82
|
-
break;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
outputIndices[synthesizerIndex] += matchedCode.length;
|
|
86
|
-
}
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
const indexOfExpectedSythesizer = Math.max.apply(Math, outputIndices);
|
|
90
|
-
const indexOfFirstNotValidCharacter = (indexOfExpectedSythesizer == sequence.length) ? -1 : indexOfExpectedSythesizer;
|
|
91
|
-
const expectedSynthesizer = possibleSynthesizers[outputIndices.indexOf(indexOfExpectedSythesizer)];
|
|
92
|
-
if (indexOfFirstNotValidCharacter != -1)
|
|
93
|
-
return {
|
|
94
|
-
indexOfFirstNotValidCharacter: indexOfFirstNotValidCharacter,
|
|
95
|
-
expectedType: expectedSynthesizer
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
let possibleTechnologies = getListOfPossibleTechnologiesByFirstMatchedCode(sequence, expectedSynthesizer);
|
|
99
|
-
if (possibleTechnologies.length == 0)
|
|
100
|
-
return { indexOfFirstNotValidCharacter: 0, expectedRepresentation: null };
|
|
101
|
-
|
|
102
|
-
outputIndices = Array(possibleTechnologies.length).fill(0);
|
|
103
|
-
|
|
104
|
-
possibleTechnologies.forEach((technology, technologyIndex) => {
|
|
105
|
-
let codes = Object.keys(map[expectedSynthesizer][technology]);
|
|
106
|
-
while (outputIndices[technologyIndex] < sequence.length) {
|
|
107
|
-
|
|
108
|
-
let matchedCode = codes
|
|
109
|
-
.find((c) => c == sequence.slice(outputIndices[technologyIndex], outputIndices[technologyIndex] + c.length));
|
|
110
|
-
|
|
111
|
-
if (matchedCode == null)
|
|
112
|
-
break;
|
|
113
|
-
|
|
114
|
-
if ( // for mistake pattern 'rAA'
|
|
115
|
-
outputIndices[technologyIndex] > 1 &&
|
|
116
|
-
nucleotides.includes(sequence[outputIndices[technologyIndex]]) &&
|
|
117
|
-
firstUniqueCharacters.includes(sequence[outputIndices[technologyIndex] - 2])
|
|
118
|
-
) break;
|
|
119
|
-
|
|
120
|
-
if ( // for mistake pattern 'ArA'
|
|
121
|
-
firstUniqueCharacters.includes(sequence[outputIndices[technologyIndex] + 1]) &&
|
|
122
|
-
nucleotides.includes(sequence[outputIndices[technologyIndex]])
|
|
123
|
-
) {
|
|
124
|
-
outputIndices[technologyIndex]++;
|
|
125
|
-
break;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
outputIndices[technologyIndex] += matchedCode.length;
|
|
129
|
-
}
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
const indexOfExpectedTechnology = Math.max.apply(Math, outputIndices);
|
|
133
|
-
const expectedTechnology = possibleTechnologies[outputIndices.indexOf(indexOfExpectedTechnology)];
|
|
134
|
-
|
|
135
|
-
return {
|
|
136
|
-
indexOfFirstNotValidCharacter: indexOfFirstNotValidCharacter,
|
|
137
|
-
expectedType: expectedSynthesizer + ' ' + expectedTechnology
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
function sortByStringLengthInDescendingOrder(array: string[]): string[] {
|
|
142
|
-
return array.sort(function(a: string, b: string) { return b.length - a.length; });
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
function getObjectWithCodesAndSmiles() {
|
|
146
|
-
let obj: {[code: string]: string} = {};
|
|
147
|
-
for (let synthesizer of Object.keys(map))
|
|
148
|
-
for (let technology of Object.keys(map[synthesizer]))
|
|
149
|
-
for (let code of Object.keys(map[synthesizer][technology]))
|
|
150
|
-
obj[code] = map[synthesizer][technology][code].SMILES;
|
|
151
|
-
return obj;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
export function sequenceToSmiles(sequence: string) {
|
|
155
|
-
const obj = getObjectWithCodesAndSmiles();
|
|
156
|
-
let codes = sortByStringLengthInDescendingOrder(Object.keys(obj));
|
|
157
|
-
let i = 0, smiles = '', codesList = [];
|
|
158
|
-
const links = ['s', 'ps', '*'];
|
|
159
|
-
const includesStandardLinkAlready = ["e", "h", "g", "f", "i", "l", "k", "j"];
|
|
160
|
-
const dropdowns = Object.keys(MODIFICATIONS);
|
|
161
|
-
codes = codes.concat(dropdowns);
|
|
162
|
-
while (i < sequence.length) {
|
|
163
|
-
let code = codes.find((s: string) => s == sequence.slice(i, i + s.length))!;
|
|
164
|
-
i += code.length;
|
|
165
|
-
codesList.push(code);
|
|
166
|
-
}
|
|
167
|
-
for (let i = 0; i < codesList.length; i++) {
|
|
168
|
-
if (dropdowns.includes(codesList[i])) {
|
|
169
|
-
smiles += (i >= codesList.length / 2) ?
|
|
170
|
-
MODIFICATIONS[codesList[i]].right :
|
|
171
|
-
MODIFICATIONS[codesList[i]].left;
|
|
172
|
-
} else {
|
|
173
|
-
if (links.includes(codesList[i]) && i > 1 && !includesStandardLinkAlready.includes(codesList[i - 1]))
|
|
174
|
-
smiles = smiles.slice(0, smiles.length - stadardPhosphateLinkSmiles.length + 1);
|
|
175
|
-
else if (links.includes(codesList[i]) ||
|
|
176
|
-
includesStandardLinkAlready.includes(codesList[i]) ||
|
|
177
|
-
(i < codesList.length - 1 && (links.includes(codesList[i + 1]) || dropdowns.includes(codesList[i + 1])))
|
|
178
|
-
)
|
|
179
|
-
smiles += obj[codesList[i]];
|
|
180
|
-
else
|
|
181
|
-
smiles += obj[codesList[i]] + stadardPhosphateLinkSmiles;
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
smiles = smiles.replace(/OO/g, 'O');
|
|
185
|
-
return (
|
|
186
|
-
(
|
|
187
|
-
links.includes(codesList[codesList.length - 1]) &&
|
|
188
|
-
codesList.length > 1 &&
|
|
189
|
-
!includesStandardLinkAlready.includes(codesList[codesList.length - 2])
|
|
190
|
-
) ||
|
|
191
|
-
dropdowns.includes(codesList[codesList.length - 1]) ||
|
|
192
|
-
includesStandardLinkAlready.includes(codesList[codesList.length - 1])
|
|
193
|
-
) ?
|
|
194
|
-
smiles :
|
|
195
|
-
smiles.slice(0, smiles.length - stadardPhosphateLinkSmiles.length + 1);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
19
|
//name: Sequence Translator
|
|
199
20
|
//tags: app
|
|
200
|
-
export function sequenceTranslator() {
|
|
201
|
-
|
|
202
|
-
let windows = grok.shell.windows;
|
|
21
|
+
export function sequenceTranslator(): void {
|
|
22
|
+
const windows = grok.shell.windows;
|
|
203
23
|
windows.showProperties = false;
|
|
204
24
|
windows.showToolbox = false;
|
|
205
25
|
windows.showHelp = false;
|
|
206
26
|
|
|
207
|
-
function updateTableAndMolecule(sequence: string) {
|
|
208
|
-
moleculeSvgDiv.innerHTML =
|
|
209
|
-
outputTableDiv.innerHTML =
|
|
210
|
-
|
|
27
|
+
function updateTableAndMolecule(sequence: string): void {
|
|
28
|
+
moleculeSvgDiv.innerHTML = '';
|
|
29
|
+
outputTableDiv.innerHTML = '';
|
|
30
|
+
const pi = DG.TaskBarProgressIndicator.create('Rendering table and molecule...');
|
|
31
|
+
let errorsExist = false;
|
|
211
32
|
try {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
33
|
+
const outputSequenceObj = convertSequence(sequence);
|
|
34
|
+
const tableRows = [];
|
|
35
|
+
|
|
36
|
+
for (const key of Object.keys(outputSequenceObj).slice(1)) {
|
|
37
|
+
const indexOfFirstNotValidCharacter = ('indexOfFirstNotValidCharacter' in outputSequenceObj) ?
|
|
38
|
+
JSON.parse(outputSequenceObj.indexOfFirstNotValidCharacter!).indexOfFirstNotValidCharacter :
|
|
39
|
+
-1;
|
|
40
|
+
if ('indexOfFirstNotValidCharacter' in outputSequenceObj) {
|
|
41
|
+
const indexOfFirstNotValidCharacter = ('indexOfFirstNotValidCharacter' in outputSequenceObj) ?
|
|
42
|
+
JSON.parse(outputSequenceObj.indexOfFirstNotValidCharacter!).indexOfFirstNotValidCharacter :
|
|
43
|
+
-1;
|
|
44
|
+
if (indexOfFirstNotValidCharacter != -1)
|
|
45
|
+
errorsExist = true;
|
|
46
|
+
}
|
|
47
|
+
|
|
215
48
|
tableRows.push({
|
|
216
49
|
'key': key,
|
|
217
|
-
'value': (
|
|
50
|
+
'value': ('indexOfFirstNotValidCharacter' in outputSequenceObj) ?
|
|
218
51
|
ui.divH([
|
|
219
|
-
ui.divText(sequence.slice(0,
|
|
52
|
+
ui.divText(sequence.slice(0, indexOfFirstNotValidCharacter), {style: {color: 'grey'}}),
|
|
220
53
|
ui.tooltip.bind(
|
|
221
|
-
ui.divText(sequence.slice(
|
|
222
|
-
|
|
223
|
-
|
|
54
|
+
ui.divText(sequence.slice(indexOfFirstNotValidCharacter), {style: {color: 'red'}}),
|
|
55
|
+
'Expected format: ' + JSON.parse(outputSequenceObj.indexOfFirstNotValidCharacter!).expectedSynthesizer +
|
|
56
|
+
'. See tables with valid codes on the right',
|
|
57
|
+
),
|
|
224
58
|
]) : //@ts-ignore
|
|
225
|
-
ui.link(outputSequenceObj[key], () => navigator.clipboard.writeText(outputSequenceObj[key])
|
|
226
|
-
|
|
59
|
+
ui.link(outputSequenceObj[key], () => navigator.clipboard.writeText(outputSequenceObj[key])
|
|
60
|
+
.then(() => grok.shell.info(sequenceWasCopied)), tooltipSequence, ''),
|
|
61
|
+
});
|
|
227
62
|
}
|
|
63
|
+
|
|
64
|
+
if (errorsExist) {
|
|
65
|
+
const expectedSynthesizer = JSON.parse(outputSequenceObj.indexOfFirstNotValidCharacter!)
|
|
66
|
+
.expectedSynthesizer.slice(0, -6);
|
|
67
|
+
asoGapmersGrid.onCellPrepare(function(gc) {
|
|
68
|
+
gc.style.backColor = (gc.gridColumn.name == expectedSynthesizer) ? 0xFFF00000 : 0xFFFFFFFF;
|
|
69
|
+
});
|
|
70
|
+
omeAndFluoroGrid.onCellPrepare(function(gc) {
|
|
71
|
+
gc.style.backColor = (gc.gridColumn.name == expectedSynthesizer) ? 0xFFF00000 : 0xFFFFFFFF;
|
|
72
|
+
});
|
|
73
|
+
switchInput.enabled = true;
|
|
74
|
+
} else {
|
|
75
|
+
asoGapmersGrid.onCellPrepare(function(gc) {
|
|
76
|
+
gc.style.backColor = 0xFFFFFFFF;
|
|
77
|
+
});
|
|
78
|
+
omeAndFluoroGrid.onCellPrepare(function(gc) {
|
|
79
|
+
gc.style.backColor = 0xFFFFFFFF;
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
228
83
|
outputTableDiv.append(
|
|
229
|
-
ui.div([
|
|
84
|
+
ui.div([
|
|
85
|
+
DG.HtmlTable.create(tableRows, (item: { key: string; value: string; }) =>
|
|
86
|
+
[item.key, item.value], ['Code', 'Sequence']).root,
|
|
87
|
+
], 'table'),
|
|
230
88
|
);
|
|
231
89
|
semTypeOfInputSequence.textContent = 'Detected input type: ' + outputSequenceObj.type;
|
|
232
90
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
91
|
+
if (outputSequenceObj.type != undefinedInputSequence && outputSequenceObj.Error != undefinedInputSequence) {
|
|
92
|
+
const canvas = ui.canvas(300, 170);
|
|
93
|
+
canvas.addEventListener('click', () => {
|
|
94
|
+
const canv = ui.canvas($(window).width(), $(window).height());
|
|
95
|
+
const smiles = sequenceToSmiles(inputSequenceField.value.replace(/\s/g, ''));
|
|
96
|
+
// @ts-ignore
|
|
97
|
+
OCL.StructureView.drawMolecule(canv, OCL.Molecule.fromSmiles(smiles), {suppressChiralText: true});
|
|
98
|
+
ui.dialog('Molecule: ' + inputSequenceField.value)
|
|
99
|
+
.add(canv)
|
|
100
|
+
.showModal(true);
|
|
101
|
+
});
|
|
102
|
+
$(canvas).on('mouseover', () => $(canvas).css('cursor', 'zoom-in'));
|
|
103
|
+
$(canvas).on('mouseout', () => $(canvas).css('cursor', 'default'));
|
|
104
|
+
const smiles = sequenceToSmiles(inputSequenceField.value.replace(/\s/g, ''));
|
|
105
|
+
// @ts-ignore
|
|
106
|
+
OCL.StructureView.drawMolecule(canvas, OCL.Molecule.fromSmiles(smiles), {suppressChiralText: true});
|
|
239
107
|
moleculeSvgDiv.append(canvas);
|
|
108
|
+
} else
|
|
109
|
+
moleculeSvgDiv.innerHTML = '';
|
|
240
110
|
} finally {
|
|
241
111
|
pi.close();
|
|
242
112
|
}
|
|
243
113
|
}
|
|
244
114
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
115
|
+
const semTypeOfInputSequence = ui.divText('');
|
|
116
|
+
const moleculeSvgDiv = ui.block([]);
|
|
117
|
+
const outputTableDiv = ui.div([], 'table');
|
|
118
|
+
const inputSequenceField = ui.textInput('', defaultInput, (sequence: string) => updateTableAndMolecule(sequence));
|
|
119
|
+
|
|
120
|
+
const asoDf = DG.DataFrame.fromObjects([
|
|
121
|
+
{'Name': '2\'MOE-5Me-rU', 'BioSpring': '5', 'Janssen GCRS': 'moeT'},
|
|
122
|
+
{'Name': '2\'MOE-rA', 'BioSpring': '6', 'Janssen GCRS': 'moeA'},
|
|
123
|
+
{'Name': '2\'MOE-5Me-rC', 'BioSpring': '7', 'Janssen GCRS': 'moe5mC'},
|
|
124
|
+
{'Name': '2\'MOE-rG', 'BioSpring': '8', 'Janssen GCRS': 'moeG'},
|
|
125
|
+
{'Name': '5-Methyl-dC', 'BioSpring': '9', 'Janssen GCRS': '5mC'},
|
|
126
|
+
{'Name': 'ps linkage', 'BioSpring': '*', 'Janssen GCRS': 'ps'},
|
|
127
|
+
{'Name': 'dA', 'BioSpring': 'A', 'Janssen GCRS': 'A, dA'},
|
|
128
|
+
{'Name': 'dC', 'BioSpring': 'C', 'Janssen GCRS': 'C, dC'},
|
|
129
|
+
{'Name': 'dG', 'BioSpring': 'G', 'Janssen GCRS': 'G, dG'},
|
|
130
|
+
{'Name': 'dT', 'BioSpring': 'T', 'Janssen GCRS': 'T, dT'},
|
|
131
|
+
{'Name': 'rA', 'BioSpring': '', 'Janssen GCRS': 'rA'},
|
|
132
|
+
{'Name': 'rC', 'BioSpring': '', 'Janssen GCRS': 'rC'},
|
|
133
|
+
{'Name': 'rG', 'BioSpring': '', 'Janssen GCRS': 'rG'},
|
|
134
|
+
{'Name': 'rU', 'BioSpring': '', 'Janssen GCRS': 'rU'},
|
|
135
|
+
])!;
|
|
136
|
+
const asoGapmersGrid = DG.Viewer.grid(asoDf, {showRowHeader: false, showCellTooltip: false});
|
|
137
|
+
|
|
138
|
+
asoDf.onCurrentCellChanged.subscribe((_) => {
|
|
139
|
+
navigator.clipboard.writeText(asoDf.currentCell.value).then(() => grok.shell.info('Copied'));
|
|
140
|
+
});
|
|
250
141
|
|
|
251
|
-
|
|
252
|
-
DG.
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
(item: {name: string; code: string;}) => [item['name'], item['code']],
|
|
264
|
-
[synthesizer + ' ' + technology, 'Code']
|
|
265
|
-
).root,
|
|
266
|
-
ui.div([], {style: {height: '30px'}})
|
|
267
|
-
);
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
let showCodesButton = ui.button('SHOW CODES', () => ui.dialog('Codes').add(tablesWithCodes).show());
|
|
271
|
-
let copySmiles = ui.button(
|
|
272
|
-
'COPY SMILES',
|
|
273
|
-
() => navigator.clipboard.writeText(sequenceToSmiles(inputSequenceField.value.replace(/\s/g, '')))
|
|
274
|
-
.then(() => grok.shell.info(sequenceWasCopied))
|
|
142
|
+
const omeAndFluoroGrid = DG.Viewer.grid(
|
|
143
|
+
DG.DataFrame.fromObjects([
|
|
144
|
+
{'Name': '2\'-fluoro-U', 'BioSpring': '1', 'Axolabs': 'Uf', 'Janssen GCRS': 'fU'},
|
|
145
|
+
{'Name': '2\'-fluoro-A', 'BioSpring': '2', 'Axolabs': 'Af', 'Janssen GCRS': 'fA'},
|
|
146
|
+
{'Name': '2\'-fluoro-C', 'BioSpring': '3', 'Axolabs': 'Cf', 'Janssen GCRS': 'fC'},
|
|
147
|
+
{'Name': '2\'-fluoro-G', 'BioSpring': '4', 'Axolabs': 'Gf', 'Janssen GCRS': 'fG'},
|
|
148
|
+
{'Name': '2\'OMe-rU', 'BioSpring': '5', 'Axolabs': 'u', 'Janssen GCRS': 'mU'},
|
|
149
|
+
{'Name': '2\'OMe-rA', 'BioSpring': '6', 'Axolabs': 'a', 'Janssen GCRS': 'mA'},
|
|
150
|
+
{'Name': '2\'OMe-rC', 'BioSpring': '7', 'Axolabs': 'c', 'Janssen GCRS': 'mC'},
|
|
151
|
+
{'Name': '2\'OMe-rG', 'BioSpring': '8', 'Axolabs': 'g', 'Janssen GCRS': 'mG'},
|
|
152
|
+
{'Name': 'ps linkage', 'BioSpring': '*', 'Axolabs': 's', 'Janssen GCRS': 'ps'},
|
|
153
|
+
])!, {showRowHeader: false, showCellTooltip: false},
|
|
275
154
|
);
|
|
276
|
-
let saveMolFileButton = ui.bigButton('SAVE MOL FILE', () => {
|
|
277
|
-
let smiles = sequenceToSmiles(inputSequenceField.value.replace(/\s/g, ''));
|
|
278
|
-
let result = `${OCL.Molecule.fromSmiles(smiles).toMolfile()}\n`;
|
|
279
|
-
let element = document.createElement('a');
|
|
280
|
-
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(result));
|
|
281
|
-
element.setAttribute('download', inputSequenceField.value.replace(/\s/g, '') + '.mol');
|
|
282
|
-
element.click();
|
|
283
|
-
});
|
|
284
155
|
|
|
285
|
-
const
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
ui.divText('2. Right-click on the column header, then see the \'Convert\' menu'),
|
|
291
|
-
ui.divText("This will add the result column to the right of the table"),
|
|
292
|
-
], 'Convert oligonucleotide sequences between Nucleotides, BioSpring, Axolabs, Mermade 12 and GCRS representations.'
|
|
156
|
+
const overhangModificationsGrid = DG.Viewer.grid(
|
|
157
|
+
DG.DataFrame.fromObjects([
|
|
158
|
+
{'Name': '(invabasic)'},
|
|
159
|
+
{'Name': '(GalNAc-2-JNJ)'},
|
|
160
|
+
])!, {showRowHeader: false, showCellTooltip: false},
|
|
293
161
|
);
|
|
162
|
+
updateTableAndMolecule(defaultInput);
|
|
294
163
|
|
|
295
|
-
|
|
296
|
-
ui.
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
164
|
+
const appMainDescription = ui.info([
|
|
165
|
+
ui.divText('How to convert one sequence:', {style: {'font-weight': 'bolder'}}),
|
|
166
|
+
ui.divText('Paste sequence into the text field below'),
|
|
167
|
+
ui.divText('\n How to convert many sequences:', {style: {'font-weight': 'bolder'}}),
|
|
168
|
+
ui.divText('1. Drag & drop an Excel or CSV file with sequences into Datagrok'),
|
|
169
|
+
ui.divText('2. Right-click on the column header, then see the \'Convert\' menu'),
|
|
170
|
+
ui.divText('This will add the result column to the right of the table'),
|
|
171
|
+
], 'Convert oligonucleotide sequences between Nucleotides, BioSpring, Axolabs, Mermade 12 and GCRS representations.');
|
|
172
|
+
|
|
173
|
+
const codesTablesDiv = ui.splitV([
|
|
174
|
+
ui.box(ui.h2('ASO Gapmers'), {style: {maxHeight: '40px'}}),
|
|
175
|
+
asoGapmersGrid.root,
|
|
176
|
+
ui.box(ui.h2('2\'-OMe and 2\'-F siRNA'), {style: {maxHeight: '40px'}}),
|
|
177
|
+
omeAndFluoroGrid.root,
|
|
178
|
+
ui.box(ui.h2('Overhang modifications'), {style: {maxHeight: '40px'}}),
|
|
179
|
+
overhangModificationsGrid.root,
|
|
180
|
+
], {style: {maxWidth: '350px'}});
|
|
181
|
+
|
|
182
|
+
const tabControl = ui.tabControl({
|
|
183
|
+
'MAIN': ui.box(
|
|
184
|
+
ui.splitH([
|
|
185
|
+
ui.splitV([
|
|
186
|
+
ui.panel([
|
|
187
|
+
appMainDescription,
|
|
302
188
|
ui.div([
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
189
|
+
ui.h1('Input sequence'),
|
|
190
|
+
ui.div([
|
|
191
|
+
inputSequenceField.root,
|
|
192
|
+
], 'input-base'),
|
|
193
|
+
], 'sequenceInput'),
|
|
194
|
+
semTypeOfInputSequence,
|
|
195
|
+
ui.block([
|
|
196
|
+
ui.h1('Output'),
|
|
197
|
+
outputTableDiv,
|
|
198
|
+
]),
|
|
199
|
+
moleculeSvgDiv,
|
|
200
|
+
], 'sequence'),
|
|
201
|
+
]),
|
|
202
|
+
codesTablesDiv,
|
|
203
|
+
], {style: {height: '100%', width: '100%'}}),
|
|
204
|
+
),
|
|
205
|
+
'AXOLABS': defineAxolabsPattern(),
|
|
206
|
+
'SDF': saveSenseAntiSense(),
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
const v = grok.shell.newView('Sequence Translator', [tabControl]);
|
|
318
210
|
v.box = true;
|
|
319
211
|
|
|
212
|
+
const switchInput = ui.switchInput('Codes', true, (v: boolean) => (v) ?
|
|
213
|
+
$(codesTablesDiv).show() :
|
|
214
|
+
$(codesTablesDiv).hide(),
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
const topPanel = [
|
|
218
|
+
ui.iconFA('download', () => {
|
|
219
|
+
const smiles = sequenceToSmiles(inputSequenceField.value.replace(/\s/g, ''));
|
|
220
|
+
const result = `${OCL.Molecule.fromSmiles(smiles).toMolfile()}\n`;
|
|
221
|
+
const element = document.createElement('a');
|
|
222
|
+
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(result));
|
|
223
|
+
element.setAttribute('download', inputSequenceField.value.replace(/\s/g, '') + '.mol');
|
|
224
|
+
element.click();
|
|
225
|
+
}, 'Save .mol file'),
|
|
226
|
+
ui.iconFA('copy', () => {
|
|
227
|
+
navigator.clipboard.writeText(sequenceToSmiles(inputSequenceField.value.replace(/\s/g, '')))
|
|
228
|
+
.then(() => grok.shell.info(sequenceWasCopied));
|
|
229
|
+
}, 'Copy SMILES'),
|
|
230
|
+
switchInput.root,
|
|
231
|
+
];
|
|
232
|
+
|
|
233
|
+
tabControl.onTabChanged.subscribe((_) =>
|
|
234
|
+
v.setRibbonPanels([(tabControl.currentPane.name == 'MAIN') ? topPanel : []]));
|
|
235
|
+
v.setRibbonPanels([topPanel]);
|
|
236
|
+
|
|
320
237
|
$('.sequence')
|
|
321
|
-
.children().css('padding','5px 0');
|
|
238
|
+
.children().css('padding', '5px 0');
|
|
322
239
|
$('.sequenceInput .input-base')
|
|
323
|
-
.css('margin','0');
|
|
240
|
+
.css('margin', '0');
|
|
324
241
|
$('.sequenceInput textarea')
|
|
325
|
-
.css('resize','none')
|
|
326
|
-
.css('min-height','50px')
|
|
327
|
-
.css('width','100%')
|
|
328
|
-
.attr(
|
|
242
|
+
.css('resize', 'none')
|
|
243
|
+
.css('min-height', '50px')
|
|
244
|
+
.css('width', '100%')
|
|
245
|
+
.attr('spellcheck', 'false');
|
|
329
246
|
$('.sequenceInput select')
|
|
330
|
-
.css('width','100%');
|
|
247
|
+
.css('width', '100%');
|
|
331
248
|
}
|
|
332
249
|
|
|
333
|
-
function
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
return {
|
|
351
|
-
type: SYNTHESIZERS.BIOSPRING + ' ' + TECHNOLOGIES.ASO_GAPMERS,
|
|
352
|
-
Nucleotides: asoGapmersBioSpringToNucleotides(seq),
|
|
353
|
-
BioSpring: seq,
|
|
354
|
-
GCRS: asoGapmersBioSpringToGcrs(seq)
|
|
355
|
-
};
|
|
356
|
-
if (output.expectedType == SYNTHESIZERS.GCRS + ' ' + TECHNOLOGIES.ASO_GAPMERS)
|
|
357
|
-
return {
|
|
358
|
-
type: SYNTHESIZERS.GCRS + ' ' + TECHNOLOGIES.ASO_GAPMERS,
|
|
359
|
-
Nucleotides: asoGapmersGcrsToNucleotides(seq),
|
|
360
|
-
BioSpring: asoGapmersGcrsToBioSpring(seq),
|
|
361
|
-
Mermade12: gcrsToMermade12(seq),
|
|
362
|
-
GCRS: seq
|
|
363
|
-
};
|
|
364
|
-
if (output.expectedType == SYNTHESIZERS.RAW_NUCLEOTIDES + ' ' + TECHNOLOGIES.RNA)
|
|
365
|
-
return {
|
|
366
|
-
type: SYNTHESIZERS.RAW_NUCLEOTIDES + ' ' + TECHNOLOGIES.RNA,
|
|
367
|
-
Nucleotides: seq,
|
|
368
|
-
BioSpring: siRnaNucleotideToBioSpringSenseStrand(seq),
|
|
369
|
-
Axolabs: siRnaNucleotideToAxolabsSenseStrand(seq),
|
|
370
|
-
GCRS: siRnaNucleotidesToGcrs(seq)
|
|
371
|
-
};
|
|
372
|
-
if (output.expectedType == SYNTHESIZERS.BIOSPRING + ' ' + TECHNOLOGIES.SI_RNA)
|
|
373
|
-
return {
|
|
374
|
-
type: SYNTHESIZERS.BIOSPRING + ' ' + TECHNOLOGIES.SI_RNA,
|
|
375
|
-
Nucleotides: siRnaBioSpringToNucleotides(seq),
|
|
376
|
-
BioSpring: seq,
|
|
377
|
-
Axolabs: siRnaBioSpringToAxolabs(seq),
|
|
378
|
-
GCRS: siRnaBioSpringToGcrs(seq)
|
|
379
|
-
};
|
|
380
|
-
if (output.expectedType == SYNTHESIZERS.AXOLABS + ' ' + TECHNOLOGIES.SI_RNA)
|
|
381
|
-
return {
|
|
382
|
-
type: SYNTHESIZERS.AXOLABS + ' ' + TECHNOLOGIES.SI_RNA,
|
|
383
|
-
Nucleotides: siRnaAxolabsToNucleotides(seq),
|
|
384
|
-
BioSpring: siRnaAxolabsToBioSpring(seq),
|
|
385
|
-
Axolabs: seq,
|
|
386
|
-
GCRS: siRnaAxolabsToGcrs(seq)
|
|
387
|
-
};
|
|
388
|
-
if (output.expectedType == SYNTHESIZERS.GCRS + ' ' + TECHNOLOGIES.SI_RNA)
|
|
389
|
-
return {
|
|
390
|
-
type: SYNTHESIZERS.GCRS + ' ' + TECHNOLOGIES.SI_RNA,
|
|
391
|
-
Nucleotides: siRnaGcrsToNucleotides(seq),
|
|
392
|
-
BioSpring: siRnaGcrsToBioSpring(seq),
|
|
393
|
-
Axolabs: siRnaGcrsToAxolabs(seq),
|
|
394
|
-
MM12: gcrsToMermade12(seq),
|
|
395
|
-
GCRS: seq
|
|
396
|
-
};
|
|
397
|
-
if (output.expectedType == SYNTHESIZERS.GCRS)
|
|
398
|
-
return {
|
|
399
|
-
type: SYNTHESIZERS.GCRS,
|
|
400
|
-
Nucleotides: gcrsToNucleotides(seq),
|
|
401
|
-
GCRS: seq,
|
|
402
|
-
Mermade12: gcrsToMermade12(seq)
|
|
250
|
+
async function saveTableAsSdFile(table: DG.DataFrame) {
|
|
251
|
+
if (!table.columns.contains('Compound Name')) {
|
|
252
|
+
grok.shell.warning(
|
|
253
|
+
'File saved without columns \'Compound Name\', \'Compound Components\', \'Cpd MW\', \'Salt mass\', \'Batch MW\'');
|
|
254
|
+
}
|
|
255
|
+
const structureColumn = table.columns.byName('Sequence');
|
|
256
|
+
let result = '';
|
|
257
|
+
for (let i = 0; i < table.rowCount; i++) {
|
|
258
|
+
try {
|
|
259
|
+
const smiles = sequenceToSmiles(structureColumn.get(i));
|
|
260
|
+
const mol = OCL.Molecule.fromSmiles(smiles);
|
|
261
|
+
result += `\n${mol.toMolfile()}\n`;
|
|
262
|
+
for (const col of table.columns)
|
|
263
|
+
result += `> <${col.name}>\n${col.get(i)}\n\n`;
|
|
264
|
+
result += '$$$$';
|
|
265
|
+
} catch (error) {
|
|
266
|
+
console.error(error);
|
|
403
267
|
}
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
Mermade12: seq
|
|
410
|
-
};
|
|
411
|
-
return {
|
|
412
|
-
type: undefinedInputSequence,
|
|
413
|
-
Nucleotides: undefinedInputSequence
|
|
414
|
-
};
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
//name: asoGapmersNucleotidesToBioSpring
|
|
418
|
-
//input: string nucleotides {semType: DNA nucleotides}
|
|
419
|
-
//output: string result {semType: BioSpring / Gapmers}
|
|
420
|
-
export function asoGapmersNucleotidesToBioSpring(nucleotides: string) {
|
|
421
|
-
let count: number = -1;
|
|
422
|
-
const objForEdges: {[index: string]: string} = {"(invabasic)": "(invabasic)", "(GalNAc-2-JNJ)": "(GalNAc-2-JNJ)", "T": "5*", "A": "6*", "C": "7*", "G": "8*"};
|
|
423
|
-
const objForCenter: {[index: string]: string} = {"(invabasic)": "(invabasic)", "(GalNAc-2-JNJ)": "(GalNAc-2-JNJ)", "T": "T*", "A": "A*", "C": "9*", "G": "G*"};
|
|
424
|
-
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|A|T|C|G)/g, function (x: string) {
|
|
425
|
-
count++;
|
|
426
|
-
return (count > 4 && count < 15) ? objForCenter[x] : objForEdges[x];
|
|
427
|
-
}).slice(0, (nucleotides.endsWith("(invabasic)") || nucleotides.endsWith("(GalNAc-2-JNJ)")) ? nucleotides.length : 2 * count + 1);
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
//name: asoGapmersNucleotidesToGcrs
|
|
431
|
-
//input: string nucleotides {semType: DNA nucleotides}
|
|
432
|
-
//output: string result {semType: GCRS / Gapmers}
|
|
433
|
-
export function asoGapmersNucleotidesToGcrs(nucleotides: string) {
|
|
434
|
-
let count: number = -1;
|
|
435
|
-
const objForEdges: {[index: string]: string} = {"(invabasic)": "(invabasic)", "(GalNAc-2-JNJ)": "(GalNAc-2-JNJ)", "T": "moeUnps", "A": "moeAnps", "C": "moe5mCnps", "G": "moeGnps"};
|
|
436
|
-
const objForCenter: {[index: string]: string} = {"(invabasic)": "(invabasic)", "(GalNAc-2-JNJ)": "(GalNAc-2-JNJ)", "C": "5mCps", "A": "Aps", "T": "Tps", "G": "Gps"};
|
|
437
|
-
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|A|T|C|G)/g, function (x: string) {
|
|
438
|
-
count++;
|
|
439
|
-
if (count < 5) return (count == 4) ? objForEdges[x].slice(0, -3) + 'ps' : objForEdges[x];
|
|
440
|
-
if (count < 15) return (count == 14) ? objForCenter[x].slice(0, -2) + 'nps' : objForCenter[x];
|
|
441
|
-
return objForEdges[x];
|
|
442
|
-
}).slice(0, (nucleotides.endsWith("(invabasic)") || nucleotides.endsWith("(GalNAc-2-JNJ)")) ? nucleotides.length : -3);
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
//name: asoGapmersBioSpringToNucleotides
|
|
446
|
-
//input: string nucleotides {semType: BioSpring / Gapmers}
|
|
447
|
-
//output: string result {semType: DNA nucleotides}
|
|
448
|
-
export function asoGapmersBioSpringToNucleotides(nucleotides: string) {
|
|
449
|
-
const obj: {[index: string]: string} = {"(invabasic)": "(invabasic)", "(GalNAc-2-JNJ)": "(GalNAc-2-JNJ)", "*": "", "5": "T", "6": "A", "7": "C", "8": "G", "9": "C"};
|
|
450
|
-
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|\*|5|6|7|8|9)/g, function (x: string) {return obj[x];});
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
//name: asoGapmersBioSpringToGcrs
|
|
454
|
-
//input: string nucleotides {semType: BioSpring / Gapmers}
|
|
455
|
-
//output: string result {semType: GCRS / Gapmers}
|
|
456
|
-
export function asoGapmersBioSpringToGcrs(nucleotides: string) {
|
|
457
|
-
let count: number = -1;
|
|
458
|
-
const obj: {[index: string]: string} = {"(invabasic)": "(invabasic)", "(GalNAc-2-JNJ)": "(GalNAc-2-JNJ)",
|
|
459
|
-
"5*": "moeUnps", "6*": "moeAnps", "7*": "moe5mCnps", "8*": "moeGnps", "9*": "5mCps", "A*": "Aps", "T*": "Tps",
|
|
460
|
-
"G*": "Gps", "C*": "Cps", "5": "moeU", "6": "moeA", "7": "moe5mC", "8": "moeG"
|
|
461
|
-
};
|
|
462
|
-
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|5\*|6\*|7\*|8\*|9\*|A\*|T\*|G\*|C\*|5|6|7|8)/g, function (x: string) {
|
|
463
|
-
count++;
|
|
464
|
-
return (count == 4) ? obj[x].slice(0, -3) + 'ps' : (count == 14) ? obj[x].slice(0, -2) + 'nps' : obj[x];
|
|
465
|
-
});
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
//name: asoGapmersGcrsToBioSpring
|
|
469
|
-
//input: string nucleotides {semType: GCRS / Gapmers}
|
|
470
|
-
//output: string result {semType: BioSpring / Gapmers}
|
|
471
|
-
export function asoGapmersGcrsToBioSpring(nucleotides: string) {
|
|
472
|
-
const obj: {[index: string]: string} = {"(invabasic)": "(invabasic)", "(GalNAc-2-JNJ)": "(GalNAc-2-JNJ)",
|
|
473
|
-
"moeT": "5", "moeA": "6", "moe5mC": "7", "moeG": "8", "moeU": "5", "5mC": "9", "nps": "*", "ps": "*", "U": "T"
|
|
474
|
-
};
|
|
475
|
-
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|moeT|moeA|moe5mC|moeG|moeU|5mC|nps|ps|U)/g, function (x: string) {return obj[x];});
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
//name: asoGapmersGcrsToNucleotides
|
|
479
|
-
//input: string nucleotides {semType: GCRS / Gapmers}
|
|
480
|
-
//output: string result {semType: DNA nucleotides}
|
|
481
|
-
export function asoGapmersGcrsToNucleotides(nucleotides: string) {
|
|
482
|
-
const obj: {[index: string]: string} = {"(invabasic)": "(invabasic)", "(GalNAc-2-JNJ)": "(GalNAc-2-JNJ)", "moe": "", "5m": "", "n": "", "ps": "", "U": "T"};
|
|
483
|
-
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|moe|5m|n|ps|U)/g, function (x: string) {return obj[x];});
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
//name: siRnaBioSpringToNucleotides
|
|
487
|
-
//input: string nucleotides {semType: BioSpring / siRNA}
|
|
488
|
-
//output: string result {semType: RNA nucleotides}
|
|
489
|
-
export function siRnaBioSpringToNucleotides(nucleotides: string) {
|
|
490
|
-
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", "*": ""};
|
|
491
|
-
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|1|2|3|4|5|6|7|8|\*)/g, function (x: string) {return obj[x];});
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
//name: siRnaBioSpringToAxolabs
|
|
495
|
-
//input: string nucleotides {semType: BioSpring / siRNA}
|
|
496
|
-
//output: string result {semType: Axolabs / siRNA}
|
|
497
|
-
export function siRnaBioSpringToAxolabs(nucleotides: string) {
|
|
498
|
-
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"};
|
|
499
|
-
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|1|2|3|4|5|6|7|8|\*)/g, function (x: string) {return obj[x];});
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
//name: siRnaBioSpringToGcrs
|
|
503
|
-
//input: string nucleotides {semType: BioSpring / siRNA}
|
|
504
|
-
//output: string result {semType: GCRS}
|
|
505
|
-
export function siRnaBioSpringToGcrs(nucleotides: string) {
|
|
506
|
-
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"};
|
|
507
|
-
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|1|2|3|4|5|6|7|8|\*)/g, function (x: string) {return obj[x];});
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
//name: siRnaAxolabsToGcrs
|
|
511
|
-
//input: string nucleotides {semType: Axolabs / siRNA}
|
|
512
|
-
//output: string result {semType: GCRS}
|
|
513
|
-
export function siRnaAxolabsToGcrs(nucleotides: string) {
|
|
514
|
-
const obj: {[index: string]: string} = {"(invabasic)": "(invabasic)", "(GalNAc-2-JNJ)": "(GalNAc-2-JNJ)",
|
|
515
|
-
"Uf": "fU", "Af": "fA", "Cf": "fC", "Gf": "fG", "u": "mU", "a": "mA", "c": "mC", "g": "mG", "s": "ps"
|
|
516
|
-
};
|
|
517
|
-
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|Uf|Af|Cf|Gf|u|a|c|g|s)/g, function (x: string) {return obj[x];});
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
//name: siRnaAxolabsToBioSpring
|
|
521
|
-
//input: string nucleotides {semType: Axolabs / siRNA}
|
|
522
|
-
//output: string result {semType: BioSpring / siRNA}
|
|
523
|
-
export function siRnaAxolabsToBioSpring(nucleotides: string) {
|
|
524
|
-
const obj: {[index: string]: string} = {"(invabasic)": "(invabasic)", "(GalNAc-2-JNJ)": "(GalNAc-2-JNJ)",
|
|
525
|
-
"Uf": "1", "Af": "2", "Cf": "3", "Gf": "4", "u": "5", "a": "6", "c": "7", "g": "8", "s": "*"
|
|
526
|
-
};
|
|
527
|
-
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|Uf|Af|Cf|Gf|u|a|c|g|s)/g, function (x: string) {return obj[x];});
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
//name: siRnaAxolabsToNucleotides
|
|
531
|
-
//input: string nucleotides {semType: Axolabs / siRNA}
|
|
532
|
-
//output: string result {semType: RNA nucleotides}
|
|
533
|
-
export function siRnaAxolabsToNucleotides(nucleotides: string) {
|
|
534
|
-
const obj: {[index: string]: string} = {"(invabasic)": "(invabasic)", "(GalNAc-2-JNJ)": "(GalNAc-2-JNJ)",
|
|
535
|
-
"Uf": "U", "Af": "A", "Cf": "C", "Gf": "G", "u": "U", "a": "A", "c": "C", "g": "G", "s": ""
|
|
536
|
-
};
|
|
537
|
-
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|Uf|Af|Cf|Gf|u|a|c|g|s)/g, function (x: string) {return obj[x];});
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
//name: siRnaGcrsToNucleotides
|
|
541
|
-
//input: string nucleotides {semType: GCRS}
|
|
542
|
-
//output: string result {semType: RNA nucleotides}
|
|
543
|
-
export function siRnaGcrsToNucleotides(nucleotides: string) {
|
|
544
|
-
const obj: {[index: string]: string} = {"(invabasic)": "(invabasic)", "(GalNAc-2-JNJ)": "(GalNAc-2-JNJ)",
|
|
545
|
-
"fU": "U", "fA": "A", "fC": "C", "fG": "G", "mU": "U", "mA": "A", "mC": "C", "mG": "G", "ps": ""
|
|
546
|
-
};
|
|
547
|
-
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|fU|fA|fC|fG|mU|mA|mC|mG|ps)/g, function (x: string) {return obj[x];});
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
//name: siRnaGcrsToBioSpring
|
|
551
|
-
//input: string nucleotides {semType: GCRS}
|
|
552
|
-
//output: string result {semType: BioSpring / siRNA}
|
|
553
|
-
export function siRnaGcrsToBioSpring(nucleotides: string) {
|
|
554
|
-
const obj: {[index: string]: string} = {"(invabasic)": "(invabasic)", "(GalNAc-2-JNJ)": "(GalNAc-2-JNJ)",
|
|
555
|
-
"fU": "1", "fA": "2", "fC": "3", "fG": "4", "mU": "5", "mA": "6", "mC": "7", "mG": "8", "ps": "*"
|
|
556
|
-
};
|
|
557
|
-
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|fU|fA|fC|fG|mU|mA|mC|mG|ps)/g, function (x: string) {return obj[x];});
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
//name: siRnaGcrsToAxolabs
|
|
561
|
-
//input: string nucleotides {semType: GCRS}
|
|
562
|
-
//output: string result {semType: Axolabs / siRNA}
|
|
563
|
-
export function siRnaGcrsToAxolabs(nucleotides: string) {
|
|
564
|
-
const obj: {[index: string]: string} = {"(invabasic)": "(invabasic)", "(GalNAc-2-JNJ)": "(GalNAc-2-JNJ)",
|
|
565
|
-
"fU": "Uf", "fA": "Af", "fC": "Cf", "fG": "Gf", "mU": "u", "mA": "a", "mC": "c", "mG": "g", "ps": "s"
|
|
566
|
-
};
|
|
567
|
-
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|fU|fA|fC|fG|mU|mA|mC|mG|ps)/g, function (x: string) {return obj[x];});
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
//name: siRnaNucleotideToBioSpringSenseStrand
|
|
571
|
-
//input: string nucleotides {semType: RNA nucleotides}
|
|
572
|
-
//output: string result {semType: BioSpring / siRNA}
|
|
573
|
-
export function siRnaNucleotideToBioSpringSenseStrand(nucleotides: string) {
|
|
574
|
-
let count: number = -1;
|
|
575
|
-
const objForLeftEdge: {[index: string]: string} = {"(invabasic)": "(invabasic)", "(GalNAc-2-JNJ)": "(GalNAc-2-JNJ)", "A": "6*", "U": "5*", "G": "8*", "C": "7*"};
|
|
576
|
-
const objForRightEdge: {[index: string]: string} = {"(invabasic)": "(invabasic)", "(GalNAc-2-JNJ)": "(GalNAc-2-JNJ)", "A": "*6", "U": "*5", "G": "*8", "C": "*7"};
|
|
577
|
-
const objForOddIndices: {[index: string]: string} = {"(invabasic)": "(invabasic)", "(GalNAc-2-JNJ)": "(GalNAc-2-JNJ)", "A": "6", "U": "5", "G": "8", "C": "7"};
|
|
578
|
-
const objForEvenIndices: {[index: string]: string} = {"(invabasic)": "(invabasic)", "(GalNAc-2-JNJ)": "(GalNAc-2-JNJ)", "A": "2", "U": "1", "G": "4", "C": "3"};
|
|
579
|
-
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|A|U|G|C)/g, function (x: string) {
|
|
580
|
-
count++;
|
|
581
|
-
if (count < 2) return objForLeftEdge[x];
|
|
582
|
-
if (count > nucleotides.length - 3) return objForRightEdge[x];
|
|
583
|
-
return (count % 2 == 0) ? objForEvenIndices[x] : objForOddIndices[x];
|
|
584
|
-
});
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
//name: siRnaNucleotidesToGcrs
|
|
588
|
-
//input: string nucleotides {semType: RNA nucleotides}
|
|
589
|
-
//output: string result {semType: GCRS}
|
|
590
|
-
export function siRnaNucleotidesToGcrs(nucleotides: string) {
|
|
591
|
-
let count: number = -1;
|
|
592
|
-
const objForLeftEdge: {[index: string]: string} = {"(invabasic)": "(invabasic)", "(GalNAc-2-JNJ)": "(GalNAc-2-JNJ)", "A": "mAps", "U": "mUps", "G": "mGps", "C": "mCps"};
|
|
593
|
-
const objForRightEdge: {[index: string]: string} = {"(invabasic)": "(invabasic)", "(GalNAc-2-JNJ)": "(GalNAc-2-JNJ)", "A": "psmA", "U": "psmU", "G": "psmG", "C": "psmC"};
|
|
594
|
-
const objForEvenIndices: {[index: string]: string} = {"(invabasic)": "(invabasic)", "(GalNAc-2-JNJ)": "(GalNAc-2-JNJ)", "A": "fA", "U": "fU", "G": "fG", "C": "fC"};
|
|
595
|
-
const objForOddIndices: {[index: string]: string} = {"(invabasic)": "(invabasic)", "(GalNAc-2-JNJ)": "(GalNAc-2-JNJ)", "A": "mA", "U": "mU", "G": "mG", "C": "mC"};
|
|
596
|
-
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|A|U|G|C)/g, function (x: string) {
|
|
597
|
-
count++;
|
|
598
|
-
if (count < 2) return objForLeftEdge[x];
|
|
599
|
-
if (count > nucleotides.length - 3) return objForRightEdge[x];
|
|
600
|
-
return (count % 2 == 0) ? objForEvenIndices[x] : objForOddIndices[x];
|
|
601
|
-
});
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
//name: siRnaNucleotideToAxolabsSenseStrand
|
|
605
|
-
//input: string nucleotides {semType: RNA nucleotides}
|
|
606
|
-
//output: string result {semType: Axolabs}
|
|
607
|
-
export function siRnaNucleotideToAxolabsSenseStrand(nucleotides: string) {
|
|
608
|
-
let count: number = -1;
|
|
609
|
-
const objForLeftEdge: {[index: string]: string} = {"(invabasic)": "(invabasic)", "(GalNAc-2-JNJ)": "(GalNAc-2-JNJ)", "A": "as", "U": "us", "G": "gs", "C": "cs"};
|
|
610
|
-
const objForSomeIndices: {[index: string]: string} = {"(invabasic)": "(invabasic)", "(GalNAc-2-JNJ)": "(GalNAc-2-JNJ)", "A": "Af", "U": "Uf", "G": "Gf", "C": "Cf"};
|
|
611
|
-
const obj: {[index: string]: string} = {"(invabasic)": "(invabasic)", "(GalNAc-2-JNJ)": "(GalNAc-2-JNJ)", "A": "a", "U": "u", "G": "g", "C": "c"};
|
|
612
|
-
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|A|U|G|C)/g, function (x: string) {
|
|
613
|
-
count++;
|
|
614
|
-
if (count < 2) return objForLeftEdge[x];
|
|
615
|
-
if (count == 6 || (count > 7 && count < 11)) return objForSomeIndices[x]
|
|
616
|
-
if (count == nucleotides.length - 1) return 'a';
|
|
617
|
-
return obj[x];
|
|
618
|
-
});
|
|
268
|
+
}
|
|
269
|
+
const element = document.createElement('a');
|
|
270
|
+
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(result));
|
|
271
|
+
element.setAttribute('download', table.name + '.sdf');
|
|
272
|
+
element.click();
|
|
619
273
|
}
|
|
620
274
|
|
|
621
|
-
//
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
const objForSmallLinkages: {[index: string]: string} = {"(invabasic)": "(invabasic)", "(GalNAc-2-JNJ)": "(GalNAc-2-JNJ)", "A": "as", "U": "us", "G": "gs", "C": "cs"};
|
|
627
|
-
const objForBigLinkages: {[index: string]: string} = {"(invabasic)": "(invabasic)", "(GalNAc-2-JNJ)": "(GalNAc-2-JNJ)", "A": "Afs", "U": "Ufs", "G": "Gfs", "C": "Cfs"};
|
|
628
|
-
const objForSomeIndices: {[index: string]: string} = {"(invabasic)": "(invabasic)", "(GalNAc-2-JNJ)": "(GalNAc-2-JNJ)", "A": "Af", "U": "Uf", "G": "Gf", "C": "Cf"};
|
|
629
|
-
const obj: {[index: string]: string} = {"(invabasic)": "(invabasic)", "(GalNAc-2-JNJ)": "(GalNAc-2-JNJ)", "A": "a", "U": "u", "G": "g", "C": "c"};
|
|
630
|
-
return nucleotides.replace(/(\(invabasic\)|\(GalNAc-2-JNJ\)|A|U|G|C)/g, function (x: string) {
|
|
631
|
-
count++;
|
|
632
|
-
if (count > 19 && count < 22) return objForSmallLinkages[x];
|
|
633
|
-
if (count == 0) return 'us';
|
|
634
|
-
if (count == 1) return objForBigLinkages[x];
|
|
635
|
-
return (count == 5 || count == 7 || count == 8 || count == 13 || count == 15) ? objForSomeIndices[x] : obj[x];
|
|
275
|
+
//tags: autostart
|
|
276
|
+
export function autostartOligoSdFileSubscription() {
|
|
277
|
+
grok.events.onViewAdded.subscribe((v: any) => {
|
|
278
|
+
if (v.type == 'TableView' && v.dataFrame.columns.contains('Type'))
|
|
279
|
+
oligoSdFile(v.dataFrame);
|
|
636
280
|
});
|
|
637
281
|
}
|
|
638
282
|
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
283
|
+
export function oligoSdFile(table: DG.DataFrame) {
|
|
284
|
+
const saltsDf = DG.DataFrame.fromCsv(SALTS_CSV);
|
|
285
|
+
function addColumns(t: DG.DataFrame, saltsDf: DG.DataFrame) {
|
|
286
|
+
if (t.columns.contains('Compound Name'))
|
|
287
|
+
return grok.shell.error('Columns already exist!');
|
|
288
|
+
|
|
289
|
+
table.col('Source')?.init('Johnson and Johnson Pharma');
|
|
290
|
+
table.col('ICD')?.init('No Contract');
|
|
291
|
+
|
|
292
|
+
const sequence = t.col('Sequence')!;
|
|
293
|
+
const salt = t.col('Salt')!;
|
|
294
|
+
const equivalents = t.col('Equivalents')!;
|
|
295
|
+
|
|
296
|
+
t.columns.addNewString('Compound Name').init((i: number) => sequence.get(i));
|
|
297
|
+
t.columns.addNewString('Compound Comments').init((i: number) => (i > 0 && i % 2 == 0) ?
|
|
298
|
+
sequence.getString(i) + '; duplex of SS: ' + sequence.getString(i - 2) + ' and AS: ' + sequence.getString(i - 1) :
|
|
299
|
+
sequence.getString(i),
|
|
300
|
+
);
|
|
301
|
+
const chargeCol = saltsDf.col('CHARGE')!.toList();
|
|
302
|
+
const saltNames = saltsDf.col('DISPLAY')!.toList();
|
|
303
|
+
const molWeight = saltsDf.col('MOLWEIGHT')!.toList();
|
|
304
|
+
t.columns.addNewFloat('Cpd MW').init((i: number) => ((i + 1) % 3 == 0) ? DG.FLOAT_NULL : molWeight[i]);
|
|
305
|
+
t.columns.addNewFloat('Salt mass').init((i: number) => {
|
|
306
|
+
const v = chargeCol[saltNames.indexOf(salt.get(i))];
|
|
307
|
+
const n = (v == null) ? 0 : chargeCol[saltNames.indexOf(salt.get(i))];
|
|
308
|
+
return n * equivalents.get(i);
|
|
309
|
+
});
|
|
310
|
+
t.columns.addNewCalculated('Batch MW', '${Cpd MW} + ${Salt mass}', DG.COLUMN_TYPE.FLOAT, false);
|
|
311
|
+
|
|
312
|
+
addColumnsPressed = true;
|
|
313
|
+
return newDf = t;
|
|
314
|
+
}
|
|
649
315
|
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
316
|
+
const columnsOrder = ['Chemistry', 'Number', 'Type', 'Chemistry Name', 'Internal compound ID',
|
|
317
|
+
'IDP', 'Sequence', 'Compound Name', 'Compound Comments', 'Salt', 'Equivalents', 'Purity', 'Cpd MW', 'Salt mass',
|
|
318
|
+
'Batch MW', 'Source', 'ICD', 'Owner'];
|
|
319
|
+
let newDf: DG.DataFrame;
|
|
320
|
+
let addColumnsPressed = false;
|
|
321
|
+
|
|
322
|
+
const d = ui.div([
|
|
323
|
+
ui.icons.edit(() => {
|
|
324
|
+
d.innerHTML = '';
|
|
325
|
+
d.append(
|
|
326
|
+
ui.link('Add Columns', async () => {
|
|
327
|
+
await addColumns(table, saltsDf);
|
|
328
|
+
grok.shell.tableView(table.name).grid.columns.setOrder(columnsOrder);
|
|
329
|
+
}, 'Add columns: Compound Name, Compound Components, Cpd MW, Salt mass, Batch MW', ''),
|
|
330
|
+
ui.button('Save SD file', () => saveTableAsSdFile(addColumnsPressed ? newDf : table)),
|
|
331
|
+
);
|
|
332
|
+
const view = grok.shell.getTableView(table.name);
|
|
333
|
+
const typeCol = view.grid.col('Type')!;
|
|
334
|
+
const saltCol = view.grid.col('Salt')!;
|
|
335
|
+
saltCol.cellType = 'html';
|
|
336
|
+
typeCol.cellType = 'html';
|
|
337
|
+
view.grid.onCellPrepare(function(gc: DG.GridCell) {
|
|
338
|
+
if (gc.isTableCell) {
|
|
339
|
+
if (gc.gridColumn.name == 'Type')
|
|
340
|
+
gc.style.element = ui.choiceInput('', gc.cell.value, ['AS', 'SS', 'Duplex']).root;
|
|
341
|
+
else if (gc.gridColumn.name == 'Salt') {
|
|
342
|
+
gc.style.element = ui.choiceInput('', gc.cell.value, saltsDf.columns.byIndex(1).toList(), () => {
|
|
343
|
+
view.dataFrame.col('Salt')!.set(gc.gridRow, '');
|
|
344
|
+
}).root;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
table.onDataChanged.subscribe((_) => {
|
|
350
|
+
if (table.currentCol.name == 'IDP' && typeof table.currentCell.value != 'number')
|
|
351
|
+
grok.shell.error('Value should be numeric');
|
|
352
|
+
});
|
|
353
|
+
}),
|
|
354
|
+
]);
|
|
355
|
+
grok.shell.v.setRibbonPanels([[d]]);
|
|
659
356
|
}
|