@datagrok/bio 1.5.7 → 1.5.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/css/helm.css +3 -0
- package/detectors.js +9 -10
- package/dist/package-test.js +1095 -416
- package/dist/package.js +898 -250
- package/files/samples/sample_FASTA.csv +66 -66
- package/helm/JSDraw/Pistoia.HELM-uncompressed.js +9694 -0
- package/helm/JSDraw/Pistoia.HELM.js +27 -0
- package/helm/JSDraw/ReadMe.txt +8 -0
- package/helm/JSDraw/Scilligence.JSDraw2.Lite-uncompressed.js +31126 -0
- package/helm/JSDraw/Scilligence.JSDraw2.Lite.js +12 -0
- package/helm/JSDraw/Scilligence.JSDraw2.Resources.js +762 -0
- package/helm/JSDraw/dojo.js +250 -0
- package/helm/JSDraw/test.html +21 -0
- package/package.json +8 -1
- package/src/monomer-library.ts +199 -0
- package/src/package-test.ts +2 -0
- package/src/package.ts +41 -13
- package/src/tests/convert-test.ts +143 -22
- package/src/tests/detectors-test.ts +97 -156
- package/src/tests/renderer-test.ts +36 -0
- package/src/tests/splitter-test.ts +22 -0
- package/src/tests/types.ts +7 -0
- package/src/utils/atomic-works.ts +218 -97
- package/src/utils/cell-renderer.ts +214 -0
- package/src/utils/chem-palette.ts +280 -0
- package/src/utils/convert.ts +25 -16
- package/src/utils/misc.ts +29 -0
- package/src/utils/multiple-sequence-alignment.ts +1 -1
- package/src/utils/notation-converter.ts +120 -84
- package/src/utils/sequence-activity-cliffs.ts +2 -2
- package/src/utils/types.ts +13 -0
- package/src/utils/utils.ts +35 -30
- package/test-Bio-34f75e5127b8-c4c5a3dc.html +259 -0
- package/files/sample_FASTA.csv +0 -66
- package/files/sample_FASTA_with_activities.csv +0 -66
- package/files/sample_MSA.csv +0 -541
|
@@ -1,22 +1,84 @@
|
|
|
1
1
|
import * as OCL from 'openchemlib/full.js';
|
|
2
|
+
import * as grok from 'datagrok-api/grok';
|
|
3
|
+
|
|
4
|
+
export async function getMacroMol(monomers: any[][]): Promise<string[]> {
|
|
5
|
+
let result: string[] = [];
|
|
6
|
+
const moduleRdkit = await grok.functions.call('Chem:getRdKitModule');
|
|
7
|
+
for(let i = 0; i < monomers.length; i++) {
|
|
8
|
+
for (let j = 0; j < monomers[i].length; j++){
|
|
9
|
+
const mol = moduleRdkit.get_mol(monomers[i][j]['molfile']);
|
|
10
|
+
const a = mol.get_v3Kmolblock();
|
|
11
|
+
const indices = getIndices(monomers[i][j], a);
|
|
12
|
+
monomers[i][j]['indices'] = indices;
|
|
13
|
+
|
|
14
|
+
monomers[i][j]['molfile'] = await rotateBackboneV3000(a, indices);
|
|
15
|
+
mol?.delete();
|
|
16
|
+
}
|
|
17
|
+
result.push(linkV3000(monomers[i]));
|
|
18
|
+
}
|
|
2
19
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
20
|
+
return result;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function getIndices(monomer: any, molV3000: string): {first: number, last: number,
|
|
24
|
+
remFirst: number, remLast: number,
|
|
25
|
+
remBondFirst: number, remBondLast: Number} {
|
|
26
|
+
const molfile = monomer["molfile"];
|
|
27
|
+
let indexStart = molfile.indexOf('M RGP', 0) + 8;
|
|
28
|
+
let indexEnd = molfile.indexOf('\n', indexStart);
|
|
29
|
+
const indicesData = molfile.substring(indexStart, indexEnd).replaceAll(' ', ' ').replaceAll(' ', ' ');
|
|
30
|
+
let parsedData = indicesData.split(' ')
|
|
31
|
+
const remFirst = parsedData[2] == '1' ? parseInt(parsedData[1]) : parseInt(parsedData[3]);
|
|
32
|
+
const remLast = parsedData[2] == '2' ? parseInt(parsedData[1]) : parseInt(parsedData[3]);
|
|
33
|
+
|
|
34
|
+
const numbers = extractAtomsBondsNumbersV3000(molV3000);
|
|
35
|
+
let indexBonds = molV3000.indexOf('M V30 BEGIN BOND'); // V3000 index for bonds
|
|
36
|
+
indexBonds = molV3000.indexOf('\n', indexBonds);
|
|
37
|
+
indexStart = indexBonds;
|
|
38
|
+
indexEnd = indexBonds;
|
|
39
|
+
|
|
40
|
+
let first = 0;
|
|
41
|
+
let last = 0;
|
|
42
|
+
let remBondFirst = 0;
|
|
43
|
+
let remBondLast = 0;
|
|
44
|
+
|
|
45
|
+
for (let j = 0; j < numbers.nbond; j++) {
|
|
46
|
+
if(first == 0 || last == 0){
|
|
47
|
+
indexStart = molV3000.indexOf('V30', indexStart) + 4;
|
|
48
|
+
indexEnd = molV3000.indexOf('\n', indexStart);
|
|
49
|
+
const bondData = molV3000.substring(indexStart, indexEnd).replaceAll(' ', ' ').replaceAll(' ', ' ');
|
|
50
|
+
parsedData = bondData.split(' ')
|
|
51
|
+
|
|
52
|
+
if(parseInt(parsedData[2]) == remFirst){
|
|
53
|
+
first = parseInt(parsedData[3]);
|
|
54
|
+
remBondFirst = parseInt(parsedData[0]);
|
|
55
|
+
}
|
|
56
|
+
else if(parseInt(parsedData[3]) == remFirst){
|
|
57
|
+
first = parseInt(parsedData[2]);
|
|
58
|
+
remBondFirst = parseInt(parsedData[0]);
|
|
59
|
+
}
|
|
60
|
+
else if(parseInt(parsedData[2]) == remLast){
|
|
61
|
+
last = parseInt(parsedData[3]);
|
|
62
|
+
remBondLast = parseInt(parsedData[0]);
|
|
63
|
+
}
|
|
64
|
+
else if(parseInt(parsedData[3]) == remLast){
|
|
65
|
+
last = parseInt(parsedData[2]);
|
|
66
|
+
remBondLast = parseInt(parsedData[0]);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
6
70
|
|
|
7
|
-
return
|
|
71
|
+
return {first, last, remFirst, remLast, remBondFirst, remBondLast};
|
|
8
72
|
}
|
|
9
73
|
|
|
10
|
-
function rotateBackboneV3000(
|
|
11
|
-
let molBlock = OCL.Molecule.fromMolfile(molecule).toMolfileV3();
|
|
74
|
+
async function rotateBackboneV3000(molBlock: string, indices:any): Promise<string> {
|
|
12
75
|
const coordinates = extractAtomDataV3000(molBlock);
|
|
13
76
|
const natom = coordinates.atomIndex.length;
|
|
77
|
+
const first = indices['first'];
|
|
78
|
+
const last = indices['last'];
|
|
14
79
|
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
const xCenter = (coordinates.x[indexThreePrime] + coordinates.x[indexFivePrime])/2;
|
|
19
|
-
const yCenter = (coordinates.y[indexThreePrime] + coordinates.y[indexFivePrime])/2;
|
|
80
|
+
const xCenter = (coordinates.x[last] + coordinates.x[first])/2;
|
|
81
|
+
const yCenter = (coordinates.y[last] + coordinates.y[first])/2;
|
|
20
82
|
|
|
21
83
|
//place to center
|
|
22
84
|
for (let i = 0; i < natom; i++) {
|
|
@@ -25,13 +87,16 @@ function rotateBackboneV3000(molecule: string): string {
|
|
|
25
87
|
}
|
|
26
88
|
|
|
27
89
|
let angle = 0;
|
|
28
|
-
if (coordinates.x[
|
|
29
|
-
angle = coordinates.y[
|
|
30
|
-
else if (coordinates.y[
|
|
31
|
-
angle = coordinates.x[
|
|
90
|
+
if (coordinates.x[first] == 0)
|
|
91
|
+
angle = coordinates.y[first] > coordinates.y[last] ? Math.PI/2 : 3*Math.PI/2;
|
|
92
|
+
else if (coordinates.y[first] == 0)
|
|
93
|
+
angle = coordinates.x[first] > coordinates.x[last] ? Math.PI : 0;
|
|
32
94
|
else {
|
|
33
|
-
const derivative = coordinates.y[
|
|
34
|
-
|
|
95
|
+
const derivative = coordinates.y[first]/coordinates.x[first];
|
|
96
|
+
if(coordinates.x[first] < coordinates.x[last])
|
|
97
|
+
angle = derivative > 0 ? Math.PI - Math.atan(derivative) : Math.atan(derivative);
|
|
98
|
+
else
|
|
99
|
+
angle = derivative > 0 ? Math.atan(derivative) : Math.PI - Math.atan(derivative);
|
|
35
100
|
}
|
|
36
101
|
|
|
37
102
|
const cos = Math.cos(angle);
|
|
@@ -44,7 +109,7 @@ function rotateBackboneV3000(molecule: string): string {
|
|
|
44
109
|
}
|
|
45
110
|
|
|
46
111
|
//place to right
|
|
47
|
-
const xShift = coordinates.x[
|
|
112
|
+
const xShift = coordinates.x[first];
|
|
48
113
|
for (let i = 0; i < natom; i++)
|
|
49
114
|
coordinates.x[i] -= xShift;
|
|
50
115
|
|
|
@@ -103,7 +168,7 @@ function extractAtomDataV3000(molBlock: string) {
|
|
|
103
168
|
return {atomIndex: indexes, atomType: types, x: x, y: y};
|
|
104
169
|
}
|
|
105
170
|
|
|
106
|
-
function linkV3000(
|
|
171
|
+
function linkV3000(monomers: any[]): string {
|
|
107
172
|
let macroMolBlock = '\nDatagrok macromolecule handler\n\n';
|
|
108
173
|
macroMolBlock += ' 0 0 0 0 0 0 999 V3000\n';
|
|
109
174
|
macroMolBlock += 'M V30 BEGIN CTAB\n';
|
|
@@ -115,112 +180,168 @@ function linkV3000(molBlocks: string[]): string {
|
|
|
115
180
|
let nbond = 0;
|
|
116
181
|
let xShift = 0;
|
|
117
182
|
|
|
118
|
-
for (let i = 0; i <
|
|
119
|
-
|
|
183
|
+
for (let i = 0; i < monomers.length; i++) {
|
|
184
|
+
let molfile = monomers[i]['molfile'];
|
|
185
|
+
const first = monomers[i]['indices']['first'];
|
|
186
|
+
const last = monomers[i]['indices']['last'];
|
|
187
|
+
const remFirst = monomers[i]['indices']['remFirst'];
|
|
188
|
+
const remLast = monomers[i]['indices']['remLast'];
|
|
189
|
+
const remBondFirst = monomers[i]['indices']['remBondFirst'];
|
|
190
|
+
const remBondLast = monomers[i]['indices']['remBondLast'];
|
|
191
|
+
molfile = molfile.replaceAll('(-\nM V30 ', '(')
|
|
120
192
|
.replaceAll('-\nM V30 ', '').replaceAll(' )', ')');
|
|
121
|
-
const numbers = extractAtomsBondsNumbersV3000(
|
|
122
|
-
const coordinates = extractAtomDataV3000(
|
|
193
|
+
const numbers = extractAtomsBondsNumbersV3000(molfile);
|
|
194
|
+
const coordinates = extractAtomDataV3000(molfile);
|
|
123
195
|
|
|
124
|
-
let indexAtoms =
|
|
125
|
-
indexAtoms =
|
|
196
|
+
let indexAtoms = molfile.indexOf('M V30 BEGIN ATOM'); // V3000 index for atoms coordinates
|
|
197
|
+
indexAtoms = molfile.indexOf('\n', indexAtoms);
|
|
126
198
|
let index = indexAtoms;
|
|
127
199
|
let indexEnd = indexAtoms;
|
|
200
|
+
const totalShift = xShift - coordinates.x[first - 1];
|
|
128
201
|
|
|
129
202
|
for (let j = 0; j < numbers.natom; j++) {
|
|
130
|
-
if (coordinates.atomIndex[j] !=
|
|
203
|
+
if (coordinates.atomIndex[j] != remFirst && coordinates.atomIndex[j] != remLast) { //|| i == 0) {
|
|
131
204
|
//rewrite atom number
|
|
132
|
-
index =
|
|
133
|
-
indexEnd =
|
|
134
|
-
|
|
135
|
-
|
|
205
|
+
index = molfile.indexOf('V30', index) + 4;
|
|
206
|
+
indexEnd = molfile.indexOf(' ', index);
|
|
207
|
+
|
|
208
|
+
let atomNumber = parseInt(molfile.substring(index, indexEnd))
|
|
209
|
+
atomNumber = (atomNumber > remFirst && atomNumber > remLast) ? atomNumber - 2 :
|
|
210
|
+
(atomNumber > remFirst || atomNumber > remLast) ? atomNumber - 1 : atomNumber;
|
|
211
|
+
atomNumber += natom;
|
|
212
|
+
molfile = molfile.slice(0, index) + atomNumber + molfile.slice(indexEnd);
|
|
136
213
|
|
|
137
214
|
//rewrite coordinates
|
|
138
|
-
index =
|
|
139
|
-
index =
|
|
140
|
-
indexEnd =
|
|
215
|
+
index = molfile.indexOf(' ', index) + 1;
|
|
216
|
+
index = molfile.indexOf(' ', index) + 1;
|
|
217
|
+
indexEnd = molfile.indexOf(' ', index);
|
|
141
218
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
molBlocks[i] = molBlocks[i].slice(0, index) + coordinate + molBlocks[i].slice(indexEnd);
|
|
219
|
+
let coordinate = Math.round(10000*(parseFloat(molfile.substring(index, indexEnd)) + totalShift))/10000;
|
|
220
|
+
molfile = molfile.slice(0, index) + coordinate + molfile.slice(indexEnd);
|
|
145
221
|
|
|
146
|
-
index =
|
|
147
|
-
indexEnd =
|
|
148
|
-
coordinate = Math.round(10000*(parseFloat(
|
|
149
|
-
|
|
222
|
+
index = molfile.indexOf(' ', index) + 1;
|
|
223
|
+
indexEnd = molfile.indexOf(' ', index);
|
|
224
|
+
coordinate = Math.round(10000*(parseFloat(molfile.substring(index, indexEnd))))/10000;
|
|
225
|
+
molfile = molfile.slice(0, index) + coordinate + molfile.slice(indexEnd);
|
|
150
226
|
|
|
151
|
-
index =
|
|
227
|
+
index = molfile.indexOf('\n', index) + 1;
|
|
152
228
|
} else {
|
|
153
|
-
index =
|
|
154
|
-
indexEnd =
|
|
155
|
-
|
|
229
|
+
index = molfile.indexOf('M V30', index) - 1;
|
|
230
|
+
indexEnd = molfile.indexOf('\n', index + 1);
|
|
231
|
+
molfile = molfile.slice(0, index) + molfile.slice(indexEnd);
|
|
156
232
|
}
|
|
157
233
|
}
|
|
158
234
|
|
|
159
|
-
const indexAtomsEnd =
|
|
160
|
-
atomBlock +=
|
|
235
|
+
const indexAtomsEnd = molfile.indexOf('M V30 END ATOM');
|
|
236
|
+
atomBlock += molfile.substring(indexAtoms + 1, indexAtomsEnd);
|
|
161
237
|
|
|
162
|
-
let indexBonds =
|
|
163
|
-
indexBonds =
|
|
238
|
+
let indexBonds = molfile.indexOf('M V30 BEGIN BOND'); // V3000 index for bonds
|
|
239
|
+
indexBonds = molfile.indexOf('\n', indexBonds);
|
|
164
240
|
index = indexBonds;
|
|
165
241
|
indexEnd = indexBonds;
|
|
242
|
+
let bondNumber = 0;
|
|
166
243
|
|
|
167
244
|
for (let j = 0; j < numbers.nbond; j++) {
|
|
168
245
|
//rewrite bond number
|
|
169
|
-
index =
|
|
170
|
-
indexEnd =
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
molBlocks[i] = molBlocks[i].slice(0, index) + atomNumber + molBlocks[i].slice(indexEnd);
|
|
180
|
-
index = molBlocks[i].indexOf(' ', index) + 1;
|
|
181
|
-
indexEnd = Math.min(molBlocks[i].indexOf('\n', index), molBlocks[i].indexOf(' ', index));
|
|
182
|
-
atomNumber = parseInt(molBlocks[i].substring(index, indexEnd)) + natom;
|
|
183
|
-
molBlocks[i] = molBlocks[i].slice(0, index) + atomNumber + molBlocks[i].slice(indexEnd);
|
|
184
|
-
|
|
185
|
-
index = molBlocks[i].indexOf('\n', index) + 1;
|
|
186
|
-
}
|
|
246
|
+
index = molfile.indexOf('V30', index) + 4;
|
|
247
|
+
indexEnd = molfile.indexOf(' ', index);
|
|
248
|
+
bondNumber = parseInt(molfile.substring(index, indexEnd));
|
|
249
|
+
|
|
250
|
+
if(bondNumber == remBondFirst || bondNumber == remBondLast){
|
|
251
|
+
indexEnd = molfile.indexOf('\n', index) + 1;
|
|
252
|
+
index -=7;
|
|
253
|
+
molfile = molfile.slice(0, index) + molfile.slice(indexEnd);
|
|
254
|
+
continue
|
|
255
|
+
}
|
|
187
256
|
|
|
188
|
-
|
|
189
|
-
|
|
257
|
+
bondNumber = (bondNumber > remBondFirst && bondNumber > remBondLast) ? bondNumber - 2 :
|
|
258
|
+
(bondNumber > remBondFirst || bondNumber > remBondLast) ? bondNumber - 1 : bondNumber;
|
|
259
|
+
bondNumber += nbond;
|
|
190
260
|
|
|
191
|
-
|
|
261
|
+
molfile = molfile.slice(0, index) + bondNumber + molfile.slice(indexEnd);
|
|
192
262
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
263
|
+
//rewrite atom pair in bond
|
|
264
|
+
index = molfile.indexOf(' ', index) + 1;
|
|
265
|
+
index = molfile.indexOf(' ', index) + 1;
|
|
266
|
+
indexEnd = molfile.indexOf(' ', index);
|
|
267
|
+
let atomNumber = parseInt(molfile.substring(index, indexEnd))
|
|
268
|
+
atomNumber = (atomNumber > remFirst && atomNumber > remLast) ? atomNumber - 2 :
|
|
269
|
+
(atomNumber > remFirst || atomNumber > remLast) ? atomNumber - 1 : atomNumber;
|
|
270
|
+
atomNumber += natom;
|
|
271
|
+
molfile = molfile.slice(0, index) + atomNumber + molfile.slice(indexEnd);
|
|
272
|
+
index = molfile.indexOf(' ', index) + 1;
|
|
273
|
+
indexEnd = Math.min(molfile.indexOf('\n', index), molfile.indexOf(' ', index));
|
|
274
|
+
atomNumber = parseInt(molfile.substring(index, indexEnd))
|
|
275
|
+
atomNumber = (atomNumber > remFirst && atomNumber > remLast) ? atomNumber - 2 :
|
|
276
|
+
(atomNumber > remFirst || atomNumber > remLast) ? atomNumber - 1 : atomNumber;
|
|
277
|
+
atomNumber += natom;
|
|
278
|
+
molfile = molfile.slice(0, index) + atomNumber + molfile.slice(indexEnd);
|
|
279
|
+
|
|
280
|
+
index = molfile.indexOf('\n', index) + 1;
|
|
202
281
|
}
|
|
203
282
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
283
|
+
const indexBondEnd = molfile.indexOf('M V30 END BOND');
|
|
284
|
+
bondBlock += molfile.substring(indexBonds + 1, indexBondEnd);
|
|
285
|
+
//let indexCollection = molfile.indexOf('M V30 MDLV30/STEABS ATOMS=('); // V3000 index for collections
|
|
286
|
+
|
|
287
|
+
// while (indexCollection != -1) {
|
|
288
|
+
// indexCollection += 28;
|
|
289
|
+
// const collectionEnd = molfile.indexOf(')', indexCollection);
|
|
290
|
+
// const collectionEntries = molfile.substring(indexCollection, collectionEnd).split(' ').slice(1);
|
|
291
|
+
// collectionEntries.forEach((e: string) => {
|
|
292
|
+
// collection.push(parseInt(e) + natom);
|
|
293
|
+
// });
|
|
294
|
+
// indexCollection = collectionEnd;
|
|
295
|
+
// indexCollection = molfile.indexOf('M V30 MDLV30/STEABS ATOMS=(', indexCollection);
|
|
296
|
+
// }
|
|
297
|
+
|
|
298
|
+
natom += numbers.natom - 2;
|
|
299
|
+
nbond += numbers.nbond - 2;
|
|
300
|
+
xShift += coordinates.x[last] - coordinates.x[first] + 1;
|
|
301
|
+
|
|
302
|
+
if(i == monomers.length -1){
|
|
303
|
+
natom++;
|
|
304
|
+
const shift = xShift + 0.2;
|
|
305
|
+
atomBlock += 'M V30 ' + natom + ' O ' + shift + ' 0 0.000000 0\n';
|
|
306
|
+
}
|
|
307
|
+
nbond++;
|
|
308
|
+
if(i == monomers.length -1){
|
|
309
|
+
const rightTerminal = (last > remFirst && last > remLast) ? last + natom - (numbers.natom - 2) - 3:
|
|
310
|
+
(last > remFirst || last > remLast) ? last + natom - (numbers.natom - 2) - 2 :
|
|
311
|
+
last + natom - (numbers.natom - 2) - 1;
|
|
312
|
+
bondBlock += 'M V30 ' + nbond + ' 1 ' + rightTerminal + ' ' + natom + '\n';
|
|
313
|
+
} else{
|
|
314
|
+
const rightTerminal = (last > remFirst && last > remLast) ? last + natom - (numbers.natom - 2) - 2:
|
|
315
|
+
(last > remFirst || last > remLast) ? last + natom - (numbers.natom - 2) - 1 :
|
|
316
|
+
last + natom - (numbers.natom - 2);
|
|
317
|
+
|
|
318
|
+
const next = monomers[i + 1]['indices'];
|
|
319
|
+
const nextFirst = next['first'];
|
|
320
|
+
const nextRemFirst = next['remFirst'];
|
|
321
|
+
const nextRemLast = next['remLast'];
|
|
322
|
+
|
|
323
|
+
const leftTerminal = (nextFirst > nextRemFirst && nextFirst > nextRemLast) ? nextFirst + natom - 2 :
|
|
324
|
+
(nextFirst > nextRemFirst || nextFirst > nextRemLast) ? nextFirst + natom - 1 :
|
|
325
|
+
nextFirst + natom;
|
|
326
|
+
|
|
327
|
+
bondBlock += 'M V30 ' + nbond + ' 1 ' + rightTerminal + ' ' + leftTerminal + '\n';
|
|
219
328
|
}
|
|
220
329
|
}
|
|
221
330
|
|
|
331
|
+
// const entries = 4;
|
|
332
|
+
// const collNumber = Math.ceil(collection.length / entries);
|
|
333
|
+
// collectionBlock += 'M V30 MDLV30/STEABS ATOMS=(' + collection.length + ' -\n';
|
|
334
|
+
// for (let i = 0; i < collNumber; i++) {
|
|
335
|
+
// collectionBlock += 'M V30 ';
|
|
336
|
+
// const entriesCurrent = i + 1 == collNumber ? collection.length - (collNumber - 1)*entries : entries;
|
|
337
|
+
// for (let j = 0; j < entriesCurrent; j++) {
|
|
338
|
+
// collectionBlock += (j + 1 == entriesCurrent) ?
|
|
339
|
+
// (i == collNumber - 1 ? collection[entries*i + j] + ')\n' : collection[entries*i + j] + ' -\n') :
|
|
340
|
+
// collection[entries*i + j] + ' ';
|
|
341
|
+
// }
|
|
342
|
+
// }
|
|
343
|
+
|
|
222
344
|
//generate file
|
|
223
|
-
natom++;
|
|
224
345
|
macroMolBlock += 'M V30 COUNTS ' + natom + ' ' + nbond + ' 0 0 0\n';
|
|
225
346
|
macroMolBlock += 'M V30 BEGIN ATOM\n';
|
|
226
347
|
macroMolBlock += atomBlock;
|
|
@@ -228,9 +349,9 @@ function linkV3000(molBlocks: string[]): string {
|
|
|
228
349
|
macroMolBlock += 'M V30 BEGIN BOND\n';
|
|
229
350
|
macroMolBlock += bondBlock;
|
|
230
351
|
macroMolBlock += 'M V30 END BOND\n';
|
|
231
|
-
macroMolBlock += 'M V30 BEGIN COLLECTION\n';
|
|
232
|
-
macroMolBlock += collectionBlock;
|
|
233
|
-
macroMolBlock += 'M V30 END COLLECTION\n';
|
|
352
|
+
//macroMolBlock += 'M V30 BEGIN COLLECTION\n';
|
|
353
|
+
//macroMolBlock += collectionBlock;
|
|
354
|
+
//macroMolBlock += 'M V30 END COLLECTION\n';
|
|
234
355
|
macroMolBlock += 'M V30 END CTAB\n';
|
|
235
356
|
macroMolBlock += 'M END\n';
|
|
236
357
|
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import * as C from "./constants";
|
|
2
|
+
import {getSeparator} from "./misc";
|
|
3
|
+
import {ChemPalette} from "./chem-palette";
|
|
4
|
+
import * as DG from 'datagrok-api/dg';
|
|
5
|
+
import {AminoacidsPalettes} from "@datagrok-libraries/bio/src/aminoacids";
|
|
6
|
+
import {NucleotidesPalettes} from "@datagrok-libraries/bio/src/nucleotides";
|
|
7
|
+
import {UnknownSeqPalettes} from "@datagrok-libraries/bio/src/unknown";
|
|
8
|
+
import {SplitterFunc, WebLogo} from "@datagrok-libraries/bio/src/viewers/web-logo";
|
|
9
|
+
import {SeqPalette} from "@datagrok-libraries/bio/src/seq-palettes";
|
|
10
|
+
import * as ui from 'datagrok-api/ui';
|
|
11
|
+
|
|
12
|
+
const lru = new DG.LruCache<any, any>();
|
|
13
|
+
|
|
14
|
+
function getPalleteByType(paletteType: string): SeqPalette {
|
|
15
|
+
switch (paletteType) {
|
|
16
|
+
case 'PT':
|
|
17
|
+
return AminoacidsPalettes.GrokGroups;
|
|
18
|
+
case 'NT':
|
|
19
|
+
return NucleotidesPalettes.Chromatogram
|
|
20
|
+
// other
|
|
21
|
+
default:
|
|
22
|
+
return UnknownSeqPalettes.Color;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function processSequence(subParts: string[]): [string[], boolean] {
|
|
27
|
+
const simplified = !subParts.some((amino, index) =>
|
|
28
|
+
amino.length > 1 &&
|
|
29
|
+
index != 0 &&
|
|
30
|
+
index != subParts.length - 1);
|
|
31
|
+
|
|
32
|
+
const text: string[] = [];
|
|
33
|
+
const gap = simplified ? '' : ' ';
|
|
34
|
+
subParts.forEach((amino: string, index) => {
|
|
35
|
+
if (index < subParts.length)
|
|
36
|
+
amino += `${amino ? '' : '-'}${gap}`;
|
|
37
|
+
|
|
38
|
+
text.push(amino);
|
|
39
|
+
});
|
|
40
|
+
return [text, simplified];
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* A function that prints a string aligned to left or centered.
|
|
44
|
+
*
|
|
45
|
+
* @param {number} x x coordinate.
|
|
46
|
+
* @param {number} y y coordinate.
|
|
47
|
+
* @param {number} w Width.
|
|
48
|
+
* @param {number} h Height.
|
|
49
|
+
* @param {CanvasRenderingContext2D} g Canvas rendering context.
|
|
50
|
+
* @param {string} s String to print.
|
|
51
|
+
* @param {string} [color=ChemPalette.undefinedColor] String color.
|
|
52
|
+
* @param {number} [pivot=0] Pirvot.
|
|
53
|
+
* @param {boolean} [left=false] Is left aligned.
|
|
54
|
+
* @param {boolean} [hideMod=false] Hide amino acid redidue modifications.
|
|
55
|
+
* @param {number} [transparencyRate=0.0] Transparency rate where 1.0 is fully transparent
|
|
56
|
+
* @return {number} x coordinate to start printing at.
|
|
57
|
+
*/
|
|
58
|
+
function printLeftOrCentered(
|
|
59
|
+
x: number, y: number, w: number, h: number,
|
|
60
|
+
g: CanvasRenderingContext2D, s: string, color = ChemPalette.undefinedColor,
|
|
61
|
+
pivot: number = 0, left = false, hideMod = false, transparencyRate: number = 1.0,
|
|
62
|
+
separator: string = ''): number {
|
|
63
|
+
g.textAlign = 'start';
|
|
64
|
+
let colorPart = s.substring(0);
|
|
65
|
+
let grayPart = separator;
|
|
66
|
+
const textSize = g.measureText(colorPart + grayPart);
|
|
67
|
+
const indent = 5;
|
|
68
|
+
|
|
69
|
+
const colorTextSize = g.measureText(colorPart);
|
|
70
|
+
const dy = (textSize.fontBoundingBoxAscent + textSize.fontBoundingBoxDescent) / 2;
|
|
71
|
+
|
|
72
|
+
function draw(dx1: number, dx2: number): void {
|
|
73
|
+
g.fillStyle = color;
|
|
74
|
+
g.globalAlpha = transparencyRate;
|
|
75
|
+
g.fillText(colorPart, x + dx1, y + dy);
|
|
76
|
+
g.fillStyle = '#808080';
|
|
77
|
+
g.fillText(grayPart, x + dx2, y + dy);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
if (left || textSize.width > w) {
|
|
82
|
+
draw(indent, indent + colorTextSize.width);
|
|
83
|
+
return x + colorTextSize.width + g.measureText(grayPart).width;
|
|
84
|
+
} else {
|
|
85
|
+
const dx = (w - textSize.width) / 2;
|
|
86
|
+
draw(dx, dx + colorTextSize.width);
|
|
87
|
+
return x + dx + colorTextSize.width;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function renderSequense(
|
|
91
|
+
g: CanvasRenderingContext2D, x: number, y: number, w: number, h: number, gridCell: DG.GridCell,
|
|
92
|
+
cellStyle: DG.GridCellStyle,
|
|
93
|
+
): void {
|
|
94
|
+
const grid = gridCell.grid;
|
|
95
|
+
const cell = gridCell.cell;
|
|
96
|
+
const [type, subtype, paletteType] = gridCell.cell.column.getTag(DG.TAGS.UNITS).split(":");
|
|
97
|
+
w = grid ? Math.min(grid.canvas.width - x, w) : g.canvas.width - x;
|
|
98
|
+
g.save();
|
|
99
|
+
g.beginPath();
|
|
100
|
+
g.rect(x, y, w, h);
|
|
101
|
+
g.clip();
|
|
102
|
+
g.font = '12px monospace';
|
|
103
|
+
g.textBaseline = 'top';
|
|
104
|
+
const s: string = cell.value ?? '';
|
|
105
|
+
|
|
106
|
+
//TODO: can this be replaced/merged with splitSequence?
|
|
107
|
+
const units = gridCell.cell.column.getTag(DG.TAGS.UNITS);
|
|
108
|
+
|
|
109
|
+
const palette = getPalleteByType(paletteType);
|
|
110
|
+
|
|
111
|
+
const separator = gridCell.cell.column.getTag('separator') ?? '';
|
|
112
|
+
const splitterFunc: SplitterFunc = WebLogo.getSplitter(units, gridCell.cell.column.getTag('separator') );// splitter,
|
|
113
|
+
|
|
114
|
+
const subParts:string[] = splitterFunc(cell.value);
|
|
115
|
+
|
|
116
|
+
const textSize = g.measureText(subParts.join(''));
|
|
117
|
+
let x1 = Math.max(x, x + (w - textSize.width) / 2);
|
|
118
|
+
|
|
119
|
+
subParts.forEach((amino, index) => {
|
|
120
|
+
let [color, outerAmino,, pivot] = ChemPalette.getColorAAPivot(amino);
|
|
121
|
+
color = palette.get(amino);
|
|
122
|
+
g.fillStyle = ChemPalette.undefinedColor;
|
|
123
|
+
x1 = printLeftOrCentered(x1, y, w, h, g, amino, color, pivot, true, false, 1.0, separator);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
g.restore();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
130
|
+
constructor() {
|
|
131
|
+
super();
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
get name(): string {return 'macromoleculeSequence';}
|
|
135
|
+
|
|
136
|
+
get cellType(): string {return C.SEM_TYPES.Macro_Molecule;}
|
|
137
|
+
|
|
138
|
+
get defaultHeight(): number {return 30;}
|
|
139
|
+
|
|
140
|
+
get defaultWidth(): number {return 230;}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Cell renderer function.
|
|
144
|
+
*
|
|
145
|
+
* @param {CanvasRenderingContext2D} g Canvas rendering context.
|
|
146
|
+
* @param {number} x x coordinate on the canvas.
|
|
147
|
+
* @param {number} y y coordinate on the canvas.
|
|
148
|
+
* @param {number} w width of the cell.
|
|
149
|
+
* @param {number} h height of the cell.
|
|
150
|
+
* @param {DG.GridCell} gridCell Grid cell.
|
|
151
|
+
* @param {DG.GridCellStyle} cellStyle Cell style.
|
|
152
|
+
* @memberof AlignedSequenceCellRenderer
|
|
153
|
+
*/
|
|
154
|
+
render(
|
|
155
|
+
g: CanvasRenderingContext2D, x: number, y: number, w: number, h: number, gridCell: DG.GridCell,
|
|
156
|
+
cellStyle: DG.GridCellStyle,
|
|
157
|
+
): void {
|
|
158
|
+
const grid = gridCell.grid;
|
|
159
|
+
const cell = gridCell.cell;
|
|
160
|
+
const tag = gridCell.cell.column.getTag(DG.TAGS.UNITS);
|
|
161
|
+
if (tag === 'HELM') {
|
|
162
|
+
let host = ui.div([], { style: { width: `${w}px`, height: `${h}px`}});
|
|
163
|
+
host.setAttribute('dataformat', 'helm');
|
|
164
|
+
host.setAttribute('data', gridCell.cell.value);
|
|
165
|
+
|
|
166
|
+
//@ts-ignore
|
|
167
|
+
var canvas = new JSDraw2.Editor(host, { width: w, height: h, skin: "w8", viewonly: true });
|
|
168
|
+
var formula = canvas.getFormula(true);
|
|
169
|
+
if (!formula) {
|
|
170
|
+
gridCell.element = ui.divText(gridCell.cell.value, {style: {color: 'red'}});
|
|
171
|
+
} else {
|
|
172
|
+
gridCell.element = host;
|
|
173
|
+
var molWeight = Math.round(canvas.getMolWeight() * 100) / 100;
|
|
174
|
+
var coef = Math.round(canvas.getExtinctionCoefficient(true) * 100) / 100;
|
|
175
|
+
var molfile = canvas.getMolfile();
|
|
176
|
+
var result = formula + ', ' + molWeight + ', ' + coef + ', ' + molfile;
|
|
177
|
+
lru.set(gridCell.cell.value, result);
|
|
178
|
+
}
|
|
179
|
+
} else {
|
|
180
|
+
const [type, subtype, paletteType] = gridCell.cell.column.getTag(DG.TAGS.UNITS).split(":");
|
|
181
|
+
w = grid ? Math.min(grid.canvas.width - x, w) : g.canvas.width - x;
|
|
182
|
+
g.save();
|
|
183
|
+
g.beginPath();
|
|
184
|
+
g.rect(x, y, w, h);
|
|
185
|
+
g.clip();
|
|
186
|
+
g.font = '12px monospace';
|
|
187
|
+
g.textBaseline = 'top';
|
|
188
|
+
const s: string = cell.value ?? '';
|
|
189
|
+
|
|
190
|
+
//TODO: can this be replaced/merged with splitSequence?
|
|
191
|
+
const units = gridCell.cell.column.getTag(DG.TAGS.UNITS);
|
|
192
|
+
|
|
193
|
+
const palette = getPalleteByType(paletteType);
|
|
194
|
+
|
|
195
|
+
const separator = gridCell.cell.column.getTag('separator') ?? '';
|
|
196
|
+
const splitterFunc: SplitterFunc = WebLogo.getSplitter(units, gridCell.cell.column.getTag('separator') );// splitter,
|
|
197
|
+
|
|
198
|
+
const subParts:string[] = splitterFunc(cell.value);
|
|
199
|
+
console.log(subParts);
|
|
200
|
+
|
|
201
|
+
const textSize = g.measureText(subParts.join(''));
|
|
202
|
+
let x1 = Math.max(x, x + (w - textSize.width) / 2);
|
|
203
|
+
|
|
204
|
+
subParts.forEach((amino, index) => {
|
|
205
|
+
let [color, outerAmino,, pivot] = ChemPalette.getColorAAPivot(amino);
|
|
206
|
+
color = palette.get(amino);
|
|
207
|
+
g.fillStyle = ChemPalette.undefinedColor;
|
|
208
|
+
x1 = printLeftOrCentered(x1, y, w, h, g, amino, color, pivot, true, false, 1.0, separator);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
g.restore();
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|