@datagrok/helm 2.0.7 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/package-test.js +432 -59644
- package/dist/package.js +912 -613
- package/package.json +2 -2
- package/src/cell-renderer.ts +110 -0
- package/src/constants.ts +10 -8
- package/src/package.ts +90 -481
- package/src/tests/helm-tests.ts +1 -27
- package/src/utils.ts +154 -29
- package/{test-Helm-5e15f45ca638-10548f95.html → test-Helm-3afbd4014fa1-27e36d83.html} +3 -6
- package/tsconfig.json +2 -2
- package/files/libraries/HELMCoreLibrary.json +0 -18218
package/src/package.ts
CHANGED
|
@@ -2,32 +2,68 @@
|
|
|
2
2
|
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
|
-
import * as bio from '@datagrok-libraries/bio';
|
|
6
5
|
|
|
7
|
-
import {
|
|
8
|
-
import {MONOMER_MANAGER_MAP, RGROUPS, RGROUP_CAP_GROUP_NAME, RGROUP_LABEL, SMILES} from './constants';
|
|
6
|
+
import {WebEditorMonomer, RGROUP_CAP_GROUP_NAME, RGROUP_LABEL, SMILES} from './constants';
|
|
9
7
|
import {HelmWebEditor} from './helm-web-editor';
|
|
10
|
-
import {
|
|
8
|
+
import {NotationConverter, IMonomerLib, Monomer} from '@datagrok-libraries/bio';
|
|
9
|
+
import {HelmCellRenderer} from './cell-renderer';
|
|
11
10
|
|
|
12
11
|
export const _package = new DG.Package();
|
|
13
|
-
|
|
14
|
-
const STORAGE_NAME = 'Libraries';
|
|
15
|
-
const LIB_PATH = 'libraries/';
|
|
12
|
+
let monomerLib: IMonomerLib | null = null;
|
|
16
13
|
|
|
17
14
|
//tags: init
|
|
18
15
|
export async function initHelm(): Promise<void> {
|
|
19
|
-
return new Promise(
|
|
16
|
+
return Promise.all([new Promise((resolve, reject) => {
|
|
20
17
|
// @ts-ignore
|
|
21
18
|
dojo.ready(function() { resolve(null); });
|
|
22
|
-
|
|
19
|
+
}), await grok.functions.call('Bio:getBioLib')]).then(([_, lib]: [void, IMonomerLib]) => {
|
|
20
|
+
monomerLib = lib;
|
|
21
|
+
rewriteLibraries();
|
|
22
|
+
monomerLib.onChanged.subscribe((_) => {
|
|
23
|
+
rewriteLibraries();
|
|
24
|
+
})
|
|
23
25
|
});
|
|
24
26
|
}
|
|
25
27
|
|
|
28
|
+
function rewriteLibraries() {
|
|
29
|
+
org.helm.webeditor.Monomers.clear();
|
|
30
|
+
monomerLib.getTypes().forEach(type => {
|
|
31
|
+
const mms = monomerLib.getMonomerNamesByType(type);
|
|
32
|
+
mms.forEach(symbol => {
|
|
33
|
+
let isBroken = false;
|
|
34
|
+
const monomer: Monomer = monomerLib.getMonomer(type, symbol);
|
|
35
|
+
const webEditorMonomer: WebEditorMonomer = {
|
|
36
|
+
id: symbol,
|
|
37
|
+
m: monomer.molfile,
|
|
38
|
+
n: monomer.name,
|
|
39
|
+
na: monomer.naturalAnalog,
|
|
40
|
+
rs: monomer.rgroups.length,
|
|
41
|
+
type: monomer.polymerType,
|
|
42
|
+
mt: monomer.monomerType,
|
|
43
|
+
at: {}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
if(monomer.rgroups.length > 0) {
|
|
47
|
+
webEditorMonomer.rs = monomer.rgroups.length;
|
|
48
|
+
const at = {};
|
|
49
|
+
monomer.rgroups.forEach(it => {
|
|
50
|
+
at[it[RGROUP_LABEL]] = it[RGROUP_CAP_GROUP_NAME];
|
|
51
|
+
});
|
|
52
|
+
webEditorMonomer.at = at;
|
|
53
|
+
} else if (monomer.data[SMILES] != null){
|
|
54
|
+
webEditorMonomer.rs = Object.keys(getRS(monomer.data[SMILES].toString())).length;
|
|
55
|
+
webEditorMonomer.at = getRS(monomer.data[SMILES].toString());
|
|
56
|
+
} else
|
|
57
|
+
isBroken = true;
|
|
58
|
+
|
|
59
|
+
if(!isBroken)
|
|
60
|
+
org.helm.webeditor.Monomers.addOneMonomer(webEditorMonomer);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
26
63
|
|
|
27
|
-
|
|
28
|
-
let
|
|
29
|
-
|
|
30
|
-
await monomerManager(uploadedLibraries[i]);
|
|
64
|
+
// Obsolete
|
|
65
|
+
let grid: DG.Grid = grok.shell.tv.grid;
|
|
66
|
+
grid.invalidate();
|
|
31
67
|
}
|
|
32
68
|
|
|
33
69
|
//name: helmCellRenderer
|
|
@@ -39,57 +75,12 @@ export function helmCellRenderer(): HelmCellRenderer {
|
|
|
39
75
|
return new HelmCellRenderer();
|
|
40
76
|
}
|
|
41
77
|
|
|
42
|
-
|
|
43
|
-
function webEditor(cell?: DG.GridCell, value?: string) {
|
|
44
|
-
let view = ui.div();
|
|
45
|
-
org.helm.webeditor.MolViewer.molscale = 0.8;
|
|
46
|
-
let app = new scil.helm.App(view, {
|
|
47
|
-
showabout: false,
|
|
48
|
-
mexfontsize: '90%',
|
|
49
|
-
mexrnapinontab: true,
|
|
50
|
-
topmargin: 20,
|
|
51
|
-
mexmonomerstab: true,
|
|
52
|
-
sequenceviewonly: false,
|
|
53
|
-
mexfavoritefirst: true,
|
|
54
|
-
mexfilter: true
|
|
55
|
-
});
|
|
56
|
-
var sizes = app.calculateSizes();
|
|
57
|
-
app.canvas.resize(sizes.rightwidth - 100, sizes.topheight - 210);
|
|
58
|
-
var s = {width: sizes.rightwidth - 100 + 'px', height: sizes.bottomheight + 'px'};
|
|
59
|
-
//@ts-ignore
|
|
60
|
-
scil.apply(app.sequence.style, s);
|
|
61
|
-
//@ts-ignore
|
|
62
|
-
scil.apply(app.notation.style, s);
|
|
63
|
-
s = {width: sizes.rightwidth + 'px', height: (sizes.bottomheight + app.toolbarheight) + 'px'};
|
|
64
|
-
//@ts-ignore
|
|
65
|
-
scil.apply(app.properties.parent.style, s);
|
|
66
|
-
app.structureview.resize(sizes.rightwidth, sizes.bottomheight + app.toolbarheight);
|
|
67
|
-
app.mex.resize(sizes.topheight - 80);
|
|
68
|
-
setTimeout(function() {
|
|
69
|
-
if (typeof cell !== 'undefined') {
|
|
70
|
-
app.canvas.helm.setSequence(cell.cell.value, 'HELM');
|
|
71
|
-
} else {
|
|
72
|
-
app.canvas.helm.setSequence(value, 'HELM');
|
|
73
|
-
}
|
|
74
|
-
}, 200);
|
|
75
|
-
//@ts-ignore
|
|
76
|
-
ui.dialog({showHeader: false, showFooter: true})
|
|
77
|
-
.add(view)
|
|
78
|
-
.onOK(() => {
|
|
79
|
-
if (typeof cell !== 'undefined') {
|
|
80
|
-
cell.cell.value = app.canvas.getHelm(true).replace(/<\/span>/g, '').replace(/<span style='background:#bbf;'>/g, '');
|
|
81
|
-
}
|
|
82
|
-
}).show({modal: true, fullScreen: true});
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
|
|
86
78
|
//tags: cellEditor
|
|
87
79
|
//description: Macromolecule
|
|
88
80
|
//input: grid_cell cell
|
|
89
81
|
export function editMoleculeCell(cell: DG.GridCell): void {
|
|
90
|
-
if (cell.gridColumn.column.tags[DG.TAGS.UNITS] === 'helm')
|
|
82
|
+
if (cell.gridColumn.column.tags[DG.TAGS.UNITS] === 'helm')
|
|
91
83
|
webEditor(cell);
|
|
92
|
-
}
|
|
93
84
|
}
|
|
94
85
|
|
|
95
86
|
//name: Open Helm Web Editor
|
|
@@ -98,7 +89,7 @@ export function editMoleculeCell(cell: DG.GridCell): void {
|
|
|
98
89
|
//input: string mol { semType: Macromolecule }
|
|
99
90
|
export function openEditor(mol: string): void {
|
|
100
91
|
let df = grok.shell.tv.grid.dataFrame;
|
|
101
|
-
let converter = new
|
|
92
|
+
let converter = new NotationConverter(df.columns.bySemType('Macromolecule'));
|
|
102
93
|
const resStr = converter.convertStringToHelm(mol, '/');
|
|
103
94
|
webEditor(undefined, resStr);
|
|
104
95
|
}
|
|
@@ -129,50 +120,48 @@ export async function propertiesPanel(helmString: string) {
|
|
|
129
120
|
);
|
|
130
121
|
}
|
|
131
122
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
123
|
+
function webEditor(cell?: DG.GridCell, value?: string) {
|
|
124
|
+
let view = ui.div();
|
|
125
|
+
org.helm.webeditor.MolViewer.molscale = 0.8;
|
|
126
|
+
let app = new scil.helm.App(view, {
|
|
127
|
+
showabout: false,
|
|
128
|
+
mexfontsize: '90%',
|
|
129
|
+
mexrnapinontab: true,
|
|
130
|
+
topmargin: 20,
|
|
131
|
+
mexmonomerstab: true,
|
|
132
|
+
sequenceviewonly: false,
|
|
133
|
+
mexfavoritefirst: true,
|
|
134
|
+
mexfilter: true
|
|
135
|
+
});
|
|
136
|
+
var sizes = app.calculateSizes();
|
|
137
|
+
app.canvas.resize(sizes.rightwidth - 100, sizes.topheight - 210);
|
|
138
|
+
var s = {width: sizes.rightwidth - 100 + 'px', height: sizes.bottomheight + 'px'};
|
|
138
139
|
//@ts-ignore
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
ui.divV([filesButton])
|
|
163
|
-
]));
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
//name: manageFiles
|
|
167
|
-
export async function manageFiles() {
|
|
168
|
-
const a = ui.dialog({title: 'Manage files'})
|
|
169
|
-
//@ts-ignore
|
|
170
|
-
.add(ui.fileBrowser({path: 'System:AppData/Helm/libraries'}).root)
|
|
171
|
-
.addButton('OK', () => a.close())
|
|
172
|
-
.show();
|
|
140
|
+
scil.apply(app.sequence.style, s);
|
|
141
|
+
//@ts-ignore
|
|
142
|
+
scil.apply(app.notation.style, s);
|
|
143
|
+
s = {width: sizes.rightwidth + 'px', height: (sizes.bottomheight + app.toolbarheight) + 'px'};
|
|
144
|
+
//@ts-ignore
|
|
145
|
+
scil.apply(app.properties.parent.style, s);
|
|
146
|
+
app.structureview.resize(sizes.rightwidth, sizes.bottomheight + app.toolbarheight);
|
|
147
|
+
app.mex.resize(sizes.topheight - 80);
|
|
148
|
+
setTimeout(function() {
|
|
149
|
+
if (typeof cell !== 'undefined') {
|
|
150
|
+
app.canvas.helm.setSequence(cell.cell.value, 'HELM');
|
|
151
|
+
} else {
|
|
152
|
+
app.canvas.helm.setSequence(value, 'HELM');
|
|
153
|
+
}
|
|
154
|
+
}, 200);
|
|
155
|
+
//@ts-ignore
|
|
156
|
+
ui.dialog({showHeader: false, showFooter: true})
|
|
157
|
+
.add(view)
|
|
158
|
+
.onOK(() => {
|
|
159
|
+
if (typeof cell !== 'undefined') {
|
|
160
|
+
cell.cell.value = app.canvas.getHelm(true).replace(/<\/span>/g, '').replace(/<span style='background:#bbf;'>/g, '');
|
|
161
|
+
}
|
|
162
|
+
}).show({modal: true, fullScreen: true});
|
|
173
163
|
}
|
|
174
164
|
|
|
175
|
-
|
|
176
165
|
async function accessServer(url: string, key: string) {
|
|
177
166
|
const params: RequestInit = {
|
|
178
167
|
method: 'GET',
|
|
@@ -185,7 +174,6 @@ async function accessServer(url: string, key: string) {
|
|
|
185
174
|
return json[key];
|
|
186
175
|
}
|
|
187
176
|
|
|
188
|
-
|
|
189
177
|
//name: helmToFasta
|
|
190
178
|
//input: string helmString {semType: Macromolecule}
|
|
191
179
|
//output: string res
|
|
@@ -203,7 +191,6 @@ export async function helmToRNA(helmString: string) {
|
|
|
203
191
|
return await accessServer(url, 'Sequence');
|
|
204
192
|
}
|
|
205
193
|
|
|
206
|
-
|
|
207
194
|
//name: helmToPeptide
|
|
208
195
|
//description: converts to peptide analogue sequence
|
|
209
196
|
//input: string helmString {semType: Macromolecule}
|
|
@@ -244,258 +231,6 @@ function getRS(smiles: string) {
|
|
|
244
231
|
return res;
|
|
245
232
|
}
|
|
246
233
|
|
|
247
|
-
//name: monomerManager
|
|
248
|
-
//input: string value
|
|
249
|
-
export async function monomerManager(value: string) {
|
|
250
|
-
let df: any[];
|
|
251
|
-
let file;
|
|
252
|
-
let dfSdf;
|
|
253
|
-
if (value.endsWith('.sdf')) {
|
|
254
|
-
const funcList: DG.Func[] = DG.Func.find({package: 'Chem', name: 'importSdf'});
|
|
255
|
-
console.debug(`Helm: initHelm() funcList.length = ${funcList.length}`);
|
|
256
|
-
if (funcList.length === 1) {
|
|
257
|
-
file = await _package.files.readAsBytes(`${LIB_PATH}${value}`);
|
|
258
|
-
dfSdf = await grok.functions.call('Chem:importSdf', {bytes: file});
|
|
259
|
-
df = createJsonMonomerLibFromSdf(dfSdf[0]);
|
|
260
|
-
} else {
|
|
261
|
-
grok.shell.warning('Chem package is not installed');
|
|
262
|
-
}
|
|
263
|
-
} else {
|
|
264
|
-
const file = await _package.files.readAsText(`${LIB_PATH}${value}`);
|
|
265
|
-
df = JSON.parse(file);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
df.forEach(monomer => {
|
|
269
|
-
const m = {};
|
|
270
|
-
Object.keys(MONOMER_MANAGER_MAP).forEach(field => {
|
|
271
|
-
m[field] = monomer[MONOMER_MANAGER_MAP[field]] ?? '';
|
|
272
|
-
});
|
|
273
|
-
if (monomer[RGROUPS]) {
|
|
274
|
-
m['rs'] = monomer[RGROUPS].length;
|
|
275
|
-
const at = {};
|
|
276
|
-
monomer[RGROUPS].forEach(it => {
|
|
277
|
-
at[it[RGROUP_LABEL]] = it[RGROUP_CAP_GROUP_NAME];
|
|
278
|
-
});
|
|
279
|
-
m['at'] = at;
|
|
280
|
-
} else {
|
|
281
|
-
m['rs'] = Object.keys(getRS(df[SMILES].toString())).length;
|
|
282
|
-
m['at'] = getRS(df[SMILES].toString());
|
|
283
|
-
}
|
|
284
|
-
org.helm.webeditor.Monomers.addOneMonomer(m);
|
|
285
|
-
});
|
|
286
|
-
|
|
287
|
-
// Now after updating org.helm.webeditor.Monomers we update MonomerLib window singleton (fires onChanged event)
|
|
288
|
-
(getMonomerLibObj() as MonomerLib).update(getAllLibsData());
|
|
289
|
-
//grok.events.fireCustomEvent('monomersLibChanged', null);
|
|
290
|
-
|
|
291
|
-
// Obsolete
|
|
292
|
-
let grid: DG.Grid = grok.shell.tv.grid;
|
|
293
|
-
grid.invalidate();
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
//name: helmColumnToSmiles
|
|
297
|
-
//input: column helmColumn {semType: Macromolecule}
|
|
298
|
-
export function helmColumnToSmiles(helmColumn: DG.Column) {
|
|
299
|
-
//todo: add column with smiles to col.dataFrame.
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
function split(s: string, sep: string) {
|
|
304
|
-
var ret = [];
|
|
305
|
-
var frag = '';
|
|
306
|
-
var parentheses = 0;
|
|
307
|
-
var bracket = 0;
|
|
308
|
-
var braces = 0;
|
|
309
|
-
var quote = 0;
|
|
310
|
-
for (var i = 0; i < s.length; ++i) {
|
|
311
|
-
var c = s.substring(i, i + 1);
|
|
312
|
-
if (c == sep && bracket == 0 && parentheses == 0 && braces == 0 && quote == 0) {
|
|
313
|
-
ret.push(frag);
|
|
314
|
-
frag = '';
|
|
315
|
-
} else {
|
|
316
|
-
frag += c;
|
|
317
|
-
if (quote > 0) {
|
|
318
|
-
if (c == '\\' && i + 1 < s.length) {
|
|
319
|
-
++i;
|
|
320
|
-
var c2 = s.substring(i, i + 1);
|
|
321
|
-
frag += c2;
|
|
322
|
-
c += c2;
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
if (c == '\"') {
|
|
326
|
-
if (!(i > 0 && s.substring(i - 1, i) == '\\'))
|
|
327
|
-
quote = quote == 0 ? 1 : 0;
|
|
328
|
-
} else if (c == '[')
|
|
329
|
-
++bracket;
|
|
330
|
-
else if (c == ']')
|
|
331
|
-
--bracket;
|
|
332
|
-
else if (c == '(')
|
|
333
|
-
++parentheses;
|
|
334
|
-
else if (c == ')')
|
|
335
|
-
--parentheses;
|
|
336
|
-
else if (c == '{')
|
|
337
|
-
++braces;
|
|
338
|
-
else if (c == '}')
|
|
339
|
-
--braces;
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
ret.push(frag);
|
|
343
|
-
return ret;
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
function detachAnnotation(s: string) {
|
|
347
|
-
var ret = _detachAppendix(s, '\"');
|
|
348
|
-
if (ret.tag != null)
|
|
349
|
-
return ret;
|
|
350
|
-
|
|
351
|
-
var r = _detachAppendix(s, '\'');
|
|
352
|
-
return {tag: ret.tag, repeat: r.tag, str: r.str};
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
function _detachAppendix(s: string, c: string) {
|
|
356
|
-
var tag = null;
|
|
357
|
-
//@ts-ignore
|
|
358
|
-
if (scil.Utils.endswith(s, c)) {
|
|
359
|
-
var p = s.length - 1;
|
|
360
|
-
while (p > 0) {
|
|
361
|
-
p = s.lastIndexOf(c, p - 1);
|
|
362
|
-
if (p <= 0 || s.substring(p - 1, p) != '\\')
|
|
363
|
-
break;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
if (p > 0 && p < s.length - 1) {
|
|
367
|
-
tag = s.substring(p + 1, s.length - 1);
|
|
368
|
-
s = s.substring(0, p);
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
if (tag != null)
|
|
372
|
-
tag = tag.replace(new RegExp('\\' + c, 'g'), c);
|
|
373
|
-
return {tag: unescape(tag), str: s};
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
function unescape(s: string) {
|
|
377
|
-
//@ts-ignore
|
|
378
|
-
if (scil.Utils.isNullOrEmpty(s))
|
|
379
|
-
return s;
|
|
380
|
-
|
|
381
|
-
return s.replace(/[\\]./g, function(m) {
|
|
382
|
-
switch (m) {
|
|
383
|
-
case '\\r':
|
|
384
|
-
return '\r';
|
|
385
|
-
case '\\n':
|
|
386
|
-
return '\n';
|
|
387
|
-
case '\\t':
|
|
388
|
-
return '\t';
|
|
389
|
-
default:
|
|
390
|
-
return m.substring(1);
|
|
391
|
-
}
|
|
392
|
-
});
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
//name: parseHelm
|
|
396
|
-
//input: string s
|
|
397
|
-
export function parseHelm(s: string) {
|
|
398
|
-
var sections = split(s, '$');
|
|
399
|
-
s = sections[0];
|
|
400
|
-
var monomers = [];
|
|
401
|
-
//@ts-ignore
|
|
402
|
-
if (!scil.Utils.isNullOrEmpty(s)) {
|
|
403
|
-
var seqs = split(s, '|');
|
|
404
|
-
for (var i = 0; i < seqs.length; ++i) {
|
|
405
|
-
var e = detachAnnotation(seqs[i]);
|
|
406
|
-
s = e.str;
|
|
407
|
-
|
|
408
|
-
var p = s.indexOf('{');
|
|
409
|
-
|
|
410
|
-
s = s.substring(p + 1);
|
|
411
|
-
p = s.indexOf('}');
|
|
412
|
-
s = s.substring(0, p);
|
|
413
|
-
|
|
414
|
-
var ss = split(s, '.');
|
|
415
|
-
for (var monomer of ss) {
|
|
416
|
-
if (monomer.includes('(') && monomer.includes(')')) {
|
|
417
|
-
var elements = monomer.replace(/[()]/g, '').split('');
|
|
418
|
-
for (var el of elements) {
|
|
419
|
-
monomers.push(el);
|
|
420
|
-
}
|
|
421
|
-
} else if (monomer.includes('[') && monomer.includes(']')) {
|
|
422
|
-
var element = monomer.match(/(?<=\[).*?(?=\])/g, '');
|
|
423
|
-
monomers.push(element[0]);
|
|
424
|
-
} else {
|
|
425
|
-
monomers.push(monomer);
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
return monomers;
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
//name: findMonomers
|
|
434
|
-
//input: string helmString
|
|
435
|
-
export function findMonomers(helmString: string) {
|
|
436
|
-
//@ts-ignore
|
|
437
|
-
const types = Object.keys(org.helm.webeditor.monomerTypeList());
|
|
438
|
-
const monomers: any = [];
|
|
439
|
-
const monomer_names: any = [];
|
|
440
|
-
for (var i = 0; i < types.length; i++) {
|
|
441
|
-
//@ts-ignore
|
|
442
|
-
monomers.push(new scil.helm.Monomers.getMonomerSet(types[i]));
|
|
443
|
-
Object.keys(monomers[i]).forEach(k => {
|
|
444
|
-
monomer_names.push(monomers[i][k].id);
|
|
445
|
-
});
|
|
446
|
-
}
|
|
447
|
-
const split_string = parseHelm(helmString);
|
|
448
|
-
return new Set(split_string.filter(val => !monomer_names.includes(val)));
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
class MonomerLib implements bio.IMonomerLib {
|
|
453
|
-
private _monomers: { [type: string]: { [name: string]: bio.Monomer } };
|
|
454
|
-
private _onChanged = new Subject<any>();
|
|
455
|
-
|
|
456
|
-
get(monomerType: string, monomerName: string): bio.Monomer | null {
|
|
457
|
-
if (monomerType in this._monomers && monomerName in this._monomers[monomerType])
|
|
458
|
-
return this._monomers[monomerType][monomerName];
|
|
459
|
-
else
|
|
460
|
-
return null;
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
get onChanged(): Observable<any> {
|
|
464
|
-
return this._onChanged;
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
public update(monomers: { [type: string]: { [name: string]: bio.Monomer } }): void {
|
|
468
|
-
this._monomers = monomers;
|
|
469
|
-
this._onChanged.next();
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
function getAllLibsData(): { [type: string]: { [name: string]: bio.Monomer } } {
|
|
474
|
-
//@ts-ignore
|
|
475
|
-
const types = Object.keys(org.helm.webeditor.monomerTypeList());
|
|
476
|
-
//const monomers: any = [];
|
|
477
|
-
const monomers: { [type: string]: { [name: string]: bio.Monomer } } = {};
|
|
478
|
-
for (let i = 0; i < types.length; i++) {
|
|
479
|
-
monomers[types[i]] = new scil.helm.Monomers.getMonomerSet(types[i]);
|
|
480
|
-
//@ts-ignore
|
|
481
|
-
//monomers.push(new scil.helm.Monomers.getMonomerSet(types[i]));
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
return monomers;
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
//name: getMonomerLibObj
|
|
488
|
-
//description: Get object of IMonomerLib interface (singleton)
|
|
489
|
-
//output: object result
|
|
490
|
-
export function getMonomerLibObj(): bio.IMonomerLib {
|
|
491
|
-
if (!('monomerLib' in window)) {
|
|
492
|
-
window['monomerLib'] = new MonomerLib();
|
|
493
|
-
window['monomerLib'].update(getAllLibsData()); // TODO: refactor
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
return window['monomerLib'];
|
|
497
|
-
}
|
|
498
|
-
|
|
499
234
|
//name: getMolfiles
|
|
500
235
|
//input: column col {semType: Macromolecule}
|
|
501
236
|
//output: column res
|
|
@@ -517,132 +252,6 @@ export function getMolfiles(col: DG.Column): DG.Column {
|
|
|
517
252
|
return res;
|
|
518
253
|
}
|
|
519
254
|
|
|
520
|
-
function getParts(subParts: string[], s: string): string[] {
|
|
521
|
-
let j = 0;
|
|
522
|
-
let allParts: string[] = [];
|
|
523
|
-
for (let k = 0; k < subParts.length; ++k) {
|
|
524
|
-
let indexOfMonomer = s.indexOf(subParts[k]);
|
|
525
|
-
let helmBeforeMonomer = s.slice(j, indexOfMonomer);
|
|
526
|
-
allParts.push(helmBeforeMonomer);
|
|
527
|
-
allParts.push(subParts[k]);
|
|
528
|
-
s = s.substring(indexOfMonomer + subParts[k].length);
|
|
529
|
-
}
|
|
530
|
-
allParts.push(s);
|
|
531
|
-
return allParts;
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
class HelmCellRenderer extends DG.GridCellRenderer {
|
|
535
|
-
get name() { return 'helm'; }
|
|
536
|
-
|
|
537
|
-
get cellType() { return 'helm'; }
|
|
538
|
-
|
|
539
|
-
get defaultWidth(): number | null { return 400; }
|
|
540
|
-
|
|
541
|
-
get defaultHeight(): number | null { return 100; }
|
|
542
|
-
|
|
543
|
-
onMouseMove(gridCell: DG.GridCell, e: MouseEvent): void {
|
|
544
|
-
const maxLengthWordsSum = gridCell.cell.column.temp['helm-sum-maxLengthWords'];
|
|
545
|
-
const maxIndex = Object.values(gridCell.cell.column.temp['helm-maxLengthWords']).length - 1;
|
|
546
|
-
const argsX = e.offsetX - gridCell.gridColumn.left + (gridCell.gridColumn.left - gridCell.bounds.x);
|
|
547
|
-
let left = 0;
|
|
548
|
-
let right = maxIndex;
|
|
549
|
-
let found = false;
|
|
550
|
-
maxLengthWordsSum[maxIndex + 1] = argsX + 1;
|
|
551
|
-
let mid = 0;
|
|
552
|
-
if (argsX > maxLengthWordsSum[0]) {
|
|
553
|
-
while (!found) {
|
|
554
|
-
mid = Math.floor((right + left) / 2);
|
|
555
|
-
if (argsX >= maxLengthWordsSum[mid] && argsX <= maxLengthWordsSum[mid + 1]) {
|
|
556
|
-
left = mid;
|
|
557
|
-
found = true;
|
|
558
|
-
} else if (argsX < maxLengthWordsSum[mid]) {
|
|
559
|
-
right = mid - 1;
|
|
560
|
-
} else if (argsX > maxLengthWordsSum[mid + 1]) {
|
|
561
|
-
left = mid + 1;
|
|
562
|
-
}
|
|
563
|
-
if (left == right) {
|
|
564
|
-
found = true;
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
}
|
|
568
|
-
left = (argsX >= maxLengthWordsSum[left]) ? left + 1 : left;
|
|
569
|
-
const monomers = findMonomers(gridCell.cell.value);
|
|
570
|
-
let s: string = gridCell.cell.value ?? '';
|
|
571
|
-
let subParts: string[] = parseHelm(s);
|
|
572
|
-
let allParts: string[] = getParts(subParts, s);
|
|
573
|
-
let tooltipMessage: HTMLElement[] = [];
|
|
574
|
-
for (let i = 0; i < allParts.length; ++i) {
|
|
575
|
-
if (monomers.has(allParts[i]))
|
|
576
|
-
tooltipMessage[i] = ui.divV([
|
|
577
|
-
ui.divText(`Monomer ${allParts[i]} not found.`),
|
|
578
|
-
ui.divText('Open the Property Panel, then expand Manage Libraries')
|
|
579
|
-
]);
|
|
580
|
-
}
|
|
581
|
-
(((tooltipMessage[left]?.childNodes.length ?? 0) > 0))
|
|
582
|
-
? ui.tooltip.show(ui.div(tooltipMessage[left]), e.x + 16, e.y + 16)
|
|
583
|
-
: ui.tooltip.hide();
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
render(g: CanvasRenderingContext2D, x: number, y: number, w: number, h: number,
|
|
587
|
-
gridCell: DG.GridCell, cellStyle: DG.GridCellStyle
|
|
588
|
-
) {
|
|
589
|
-
const grid = gridCell.gridRow !== -1 ? gridCell.grid : undefined;
|
|
590
|
-
const undefinedColor = 'rgb(100,100,100)';
|
|
591
|
-
const grayColor = '#808080';
|
|
592
|
-
const monomers = findMonomers(gridCell.cell.value);
|
|
593
|
-
let s: string = gridCell.cell.value ?? '';
|
|
594
|
-
let subParts: string[] = parseHelm(s);
|
|
595
|
-
if (monomers.size == 0) {
|
|
596
|
-
const host = ui.div([], {style: {width: `${w}px`, height: `${h}px`}});
|
|
597
|
-
host.setAttribute('dataformat', 'helm');
|
|
598
|
-
host.setAttribute('data', gridCell.cell.value);
|
|
599
|
-
gridCell.element = host;
|
|
600
|
-
//@ts-ignore
|
|
601
|
-
const canvas = new JSDraw2.Editor(host, {width: w, height: h, skin: 'w8', viewonly: true});
|
|
602
|
-
return;
|
|
603
|
-
}
|
|
604
|
-
if (monomers.size > 0) {
|
|
605
|
-
w = grid ? Math.min(grid.canvas.width - x, w) : g.canvas.width - x;
|
|
606
|
-
g.save();
|
|
607
|
-
g.beginPath();
|
|
608
|
-
g.rect(x, y, w, h);
|
|
609
|
-
g.clip();
|
|
610
|
-
g.font = '12px monospace';
|
|
611
|
-
g.textBaseline = 'top';
|
|
612
|
-
let x1 = x;
|
|
613
|
-
let maxLengthWords: any = {};
|
|
614
|
-
let maxLengthWordSum: any = {};
|
|
615
|
-
let allParts: string[] = getParts(subParts, s);
|
|
616
|
-
for (let i = 0; i < allParts.length; ++i) {
|
|
617
|
-
maxLengthWords[i] = allParts[i].length * 7;
|
|
618
|
-
let color = monomers.has(allParts[i]) ? 'red' : grayColor;
|
|
619
|
-
g.fillStyle = undefinedColor;
|
|
620
|
-
x1 = bio.printLeftOrCentered(x1, y, w, h, g, allParts[i], color, 0, true, 1.0);
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
maxLengthWordSum[0] = maxLengthWords[0];
|
|
624
|
-
for (let i = 1; i < allParts.length; i++) {
|
|
625
|
-
maxLengthWordSum[i] = maxLengthWordSum[i - 1] + maxLengthWords[i];
|
|
626
|
-
}
|
|
627
|
-
gridCell.cell.column.temp = {
|
|
628
|
-
'helm-sum-maxLengthWords': maxLengthWordSum,
|
|
629
|
-
'helm-maxLengthWords': maxLengthWords
|
|
630
|
-
};
|
|
631
|
-
g.restore();
|
|
632
|
-
return;
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
//name: getMonomerLib
|
|
638
|
-
//input: string type
|
|
639
|
-
//output: string monomerSetJSON
|
|
640
|
-
export function getMonomerLib(type: string): string {
|
|
641
|
-
// TODO: deprecate
|
|
642
|
-
return JSON.stringify(scil.helm.Monomers.getMonomerSet(type));
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
|
|
646
255
|
//name: helmWebEditor
|
|
647
256
|
//output: object
|
|
648
257
|
export function helmWebEditor(): HelmWebEditor {
|
package/src/tests/helm-tests.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {after, before, category, delay, expect, test} from '@datagrok-libraries/utils/src/test';
|
|
2
2
|
//import {findMonomers, helmToFasta, helmToPeptide, helmToRNA, initHelm} from '../package';
|
|
3
3
|
import {_package} from '../package-test';
|
|
4
|
-
import {
|
|
4
|
+
import {parseHelm} from '../utils';
|
|
5
5
|
import * as DG from 'datagrok-api/dg';
|
|
6
6
|
import * as grok from 'datagrok-api/grok';
|
|
7
7
|
|
|
@@ -46,31 +46,6 @@ category('Helm', () => {
|
|
|
46
46
|
// expect(col.tags[DG.TAGS.UNITS], 'HELM');
|
|
47
47
|
// });
|
|
48
48
|
|
|
49
|
-
test('manageFiles', async () => {
|
|
50
|
-
return await manageFiles();
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
test('monomerManager', async() => {
|
|
55
|
-
const df: DG.DataFrame = DG.DataFrame.fromCsv(await _package.files.readAsText('tests/test.csv'));
|
|
56
|
-
grok.shell.addTableView(df);
|
|
57
|
-
await grok.functions.call('Helm:monomerManager', {value: 'HELMCoreLibrary.json'});
|
|
58
|
-
const checkName = '2-Chloroadenine';
|
|
59
|
-
let flag = false;
|
|
60
|
-
const types = Object.keys(org.helm.webeditor.monomerTypeList());
|
|
61
|
-
const monomers: any = [];
|
|
62
|
-
for (var i = 0; i < types.length; i++) {
|
|
63
|
-
//@ts-ignore
|
|
64
|
-
monomers.push(new scil.helm.Monomers.getMonomerSet(types[i]));
|
|
65
|
-
Object.keys(monomers[i]).forEach(k => {
|
|
66
|
-
if (monomers[i][k].n == checkName){
|
|
67
|
-
flag = true;
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
expect(flag, true);
|
|
72
|
-
});
|
|
73
|
-
|
|
74
49
|
test('parseHelm', async() => {
|
|
75
50
|
const expectedResults = [
|
|
76
51
|
['meI', 'hHis', 'Aca', 'N', 'T', 'dK', 'Thr_PO3H2', 'D-Tyr_Et', 'Aze', 'dV', 'E', 'Phe_4Me'],
|
|
@@ -90,5 +65,4 @@ category('Helm', () => {
|
|
|
90
65
|
expect(JSON.stringify(monomerArray), JSON.stringify(expectedResults[idx]));
|
|
91
66
|
}
|
|
92
67
|
});
|
|
93
|
-
|
|
94
68
|
});
|