@datagrok/bio 2.4.31 → 2.4.39

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.
Files changed (99) hide show
  1. package/.eslintrc.json +6 -8
  2. package/README.md +22 -7
  3. package/detectors.js +21 -12
  4. package/dist/1.js +2 -0
  5. package/dist/1.js.map +1 -0
  6. package/dist/18.js +2 -0
  7. package/dist/18.js.map +1 -0
  8. package/dist/190.js +2 -0
  9. package/dist/190.js.map +1 -0
  10. package/dist/452.js +2 -0
  11. package/dist/452.js.map +1 -0
  12. package/dist/729.js +2 -0
  13. package/dist/729.js.map +1 -0
  14. package/dist/package-test.js +1 -1
  15. package/dist/package-test.js.map +1 -1
  16. package/dist/package.js +1 -1
  17. package/dist/package.js.map +1 -1
  18. package/files/libraries/broken-lib.sdf +136 -0
  19. package/files/libraries/group1/mock-lib-3.json +74 -0
  20. package/files/libraries/mock-lib-2.json +48 -0
  21. package/files/tests/100_3_clustests.csv +100 -0
  22. package/files/tests/100_3_clustests_empty_vals.csv +100 -0
  23. package/files/tests/peptides_motif-with-random_10000.csv +9998 -0
  24. package/package.json +4 -4
  25. package/scripts/sequence_generator.py +164 -48
  26. package/src/analysis/sequence-activity-cliffs.ts +7 -9
  27. package/src/analysis/sequence-diversity-viewer.ts +8 -3
  28. package/src/analysis/sequence-search-base-viewer.ts +4 -3
  29. package/src/analysis/sequence-similarity-viewer.ts +13 -7
  30. package/src/analysis/sequence-space.ts +15 -12
  31. package/src/analysis/workers/mm-distance-array-service.ts +48 -0
  32. package/src/analysis/workers/mm-distance-array-worker.ts +29 -0
  33. package/src/analysis/workers/mm-distance-worker-creator.ts +6 -9
  34. package/src/apps/web-logo-app.ts +34 -0
  35. package/src/calculations/monomerLevelMols.ts +10 -12
  36. package/src/demo/bio01-similarity-diversity.ts +4 -5
  37. package/src/demo/bio01a-hierarchical-clustering-and-sequence-space.ts +6 -7
  38. package/src/demo/bio01b-hierarchical-clustering-and-activity-cliffs.ts +7 -8
  39. package/src/demo/bio03-atomic-level.ts +1 -4
  40. package/src/demo/bio05-helm-msa-sequence-space.ts +6 -4
  41. package/src/demo/utils.ts +3 -4
  42. package/src/package-test.ts +1 -2
  43. package/src/package.ts +135 -82
  44. package/src/seq_align.ts +482 -483
  45. package/src/substructure-search/substructure-search.ts +3 -3
  46. package/src/tests/Palettes-test.ts +1 -1
  47. package/src/tests/WebLogo-positions-test.ts +12 -35
  48. package/src/tests/_first-tests.ts +1 -1
  49. package/src/tests/activity-cliffs-tests.ts +10 -7
  50. package/src/tests/activity-cliffs-utils.ts +6 -5
  51. package/src/tests/bio-tests.ts +20 -25
  52. package/src/tests/checkInputColumn-tests.ts +5 -11
  53. package/src/tests/converters-test.ts +19 -37
  54. package/src/tests/detectors-benchmark-tests.ts +35 -37
  55. package/src/tests/detectors-tests.ts +29 -34
  56. package/src/tests/detectors-weak-and-likely-tests.ts +11 -21
  57. package/src/tests/fasta-export-tests.ts +3 -3
  58. package/src/tests/fasta-handler-test.ts +2 -3
  59. package/src/tests/lib-tests.ts +2 -4
  60. package/src/tests/mm-distance-tests.ts +25 -17
  61. package/src/tests/monomer-libraries-tests.ts +1 -1
  62. package/src/tests/msa-tests.ts +12 -9
  63. package/src/tests/pepsea-tests.ts +6 -3
  64. package/src/tests/renderers-test.ts +13 -11
  65. package/src/tests/sequence-space-test.ts +10 -8
  66. package/src/tests/sequence-space-utils.ts +6 -4
  67. package/src/tests/similarity-diversity-tests.ts +47 -61
  68. package/src/tests/splitters-test.ts +14 -20
  69. package/src/tests/to-atomic-level-tests.ts +9 -17
  70. package/src/tests/units-handler-splitted-tests.ts +106 -0
  71. package/src/tests/units-handler-tests.ts +22 -26
  72. package/src/tests/utils/sequences-generators.ts +6 -2
  73. package/src/tests/utils.ts +10 -4
  74. package/src/tests/viewers.ts +1 -1
  75. package/src/utils/atomic-works.ts +49 -57
  76. package/src/utils/cell-renderer.ts +25 -8
  77. package/src/utils/check-input-column.ts +19 -4
  78. package/src/utils/constants.ts +3 -3
  79. package/src/utils/convert.ts +56 -23
  80. package/src/utils/monomer-lib.ts +83 -64
  81. package/src/utils/multiple-sequence-alignment-ui.ts +24 -21
  82. package/src/utils/multiple-sequence-alignment.ts +2 -2
  83. package/src/utils/pepsea.ts +17 -7
  84. package/src/utils/save-as-fasta.ts +11 -4
  85. package/src/utils/ui-utils.ts +1 -1
  86. package/src/viewers/vd-regions-viewer.ts +21 -22
  87. package/src/viewers/web-logo-viewer.ts +189 -154
  88. package/src/widgets/bio-substructure-filter.ts +9 -6
  89. package/src/widgets/representations.ts +11 -12
  90. package/tsconfig.json +1 -1
  91. package/dist/258.js +0 -2
  92. package/dist/258.js.map +0 -1
  93. package/dist/457.js +0 -2
  94. package/dist/457.js.map +0 -1
  95. package/dist/562.js +0 -2
  96. package/dist/562.js.map +0 -1
  97. package/dist/925.js +0 -2
  98. package/dist/925.js.map +0 -1
  99. package/src/analysis/workers/mm-distance-worker.ts +0 -16
@@ -6,14 +6,18 @@ import {ALIGNMENT, ALPHABET, NOTATION, TAGS as bioTAGS} from '@datagrok-librarie
6
6
 
7
7
  export function generateManySequences(): DG.Column[] {
8
8
  const columns: DG.Column[] = [];
9
- columns.push(DG.Column.fromList('string', 'MSA', new Array(10 ** 6).fill('meI/hHis/Aca/N/T/dE/Thr_PO3H2/Aca/D-Tyr_Et/Tyr_ab-dehydroMe/dV/E/N/D-Orn/D-aThr//Phe_4Me')));
9
+ columns.push(DG.Column.fromList('string', 'MSA',
10
+ new Array(10 ** 6).fill(
11
+ 'meI/hHis/Aca/N/T/dE/Thr_PO3H2/Aca/D-Tyr_Et/Tyr_ab-dehydroMe/dV/E/N/D-Orn/D-aThr//Phe_4Me')),
12
+ );
10
13
  columns.push(DG.Column.fromList('string', 'Activity', new Array(10 ** 6).fill('5.30751')));
11
14
  return columns;
12
15
  }
13
16
 
14
17
  export function generateLongSequence(): DG.Column[] {
15
18
  const columns: DG.Column[] = [];
16
- const longSequence = `meI/hHis/Aca/N/T/dE/Thr_PO3H2/Aca/D-Tyr_Et/Tyr_ab-dehydroMe/dV/E/N/D-Orn/D-aThr`.repeat(10 ** 5);
19
+ const longSequence =
20
+ `meI/hHis/Aca/N/T/dE/Thr_PO3H2/Aca/D-Tyr_Et/Tyr_ab-dehydroMe/dV/E/N/D-Orn/D-aThr`.repeat(10 ** 5);
17
21
  columns.push(DG.Column.fromList('string', 'MSA', new Array(10 ** 2).fill(longSequence)));
18
22
  columns.push(DG.Column.fromList('string', 'Activity', new Array(10 ** 2).fill('7.30751')));
19
23
  return columns;
@@ -2,8 +2,7 @@ import * as DG from 'datagrok-api/dg';
2
2
  import * as grok from 'datagrok-api/grok';
3
3
 
4
4
  import {_package} from '../package-test';
5
- import {expect} from '@datagrok-libraries/utils/src/test';
6
- import {runKalign} from '../utils/multiple-sequence-alignment';
5
+ import {delay, expect} from '@datagrok-libraries/utils/src/test';
7
6
 
8
7
  export async function loadFileAsText(name: string): Promise<string> {
9
8
  return await _package.files.readAsText(name);
@@ -27,8 +26,15 @@ export async function createTableView(tableName: string): Promise<DG.TableView>
27
26
  /**
28
27
  * Tests if a table has non zero rows and columns.
29
28
  *
30
- * @param {DG.DataFrame} table Target table.
31
- */
29
+ * @param {DG.DataFrame} table Target table. */
32
30
  export function _testTableIsNotEmpty(table: DG.DataFrame): void {
33
31
  expect(table.columns.length > 0 && table.rowCount > 0, true);
34
32
  }
33
+
34
+ /** Waits if container is not started
35
+ * @param {number} ms - time to wait in milliseconds */
36
+ export async function awaitContainerStart(ms: number = 10000): Promise<void> {
37
+ const pepseaContainer = await grok.dapi.docker.dockerContainers.filter('bio').first();
38
+ if (pepseaContainer.status !== 'started' && pepseaContainer.status !== 'checking')
39
+ await delay(ms);
40
+ }
@@ -2,7 +2,7 @@ import * as DG from 'datagrok-api/dg';
2
2
  import * as grok from 'datagrok-api/grok';
3
3
  //import * as ui from 'datagrok-api/ui';
4
4
 
5
- import {category, delay, test, testViewer} from '@datagrok-libraries/utils/src/test';
5
+ import {category, delay, test} from '@datagrok-libraries/utils/src/test';
6
6
  import {readDataframe} from './utils';
7
7
 
8
8
 
@@ -1,13 +1,10 @@
1
- import * as OCL from 'openchemlib/full.js';
2
1
  import * as grok from 'datagrok-api/grok';
3
2
 
4
- import {RDModule} from '@datagrok-libraries/chem-meta/src/rdkit-api';
5
-
6
3
  export async function getMacroMol(monomers: any[][]): Promise<string[]> {
7
- let result: string[] = [];
4
+ const result: string[] = [];
8
5
  const moduleRdkit = await grok.functions.call('Chem:getRdKitModule');
9
- for(let i = 0; i < monomers.length; i++) {
10
- for (let j = 0; j < monomers[i].length; j++){
6
+ for (let i = 0; i < monomers.length; i++) {
7
+ for (let j = 0; j < monomers[i].length; j++) {
11
8
  const mol = moduleRdkit.get_mol(monomers[i][j]['molfile']);
12
9
  const a = mol.get_v3Kmolblock();
13
10
  const indices = getIndices(monomers[i][j], a);
@@ -22,17 +19,17 @@ export async function getMacroMol(monomers: any[][]): Promise<string[]> {
22
19
  return result;
23
20
  }
24
21
 
25
- function getIndices(monomer: any, molV3000: string): {first: number, last: number,
26
- remFirst: number, remLast: number,
22
+ function getIndices(monomer: any, molV3000: string): {first: number, last: number,
23
+ remFirst: number, remLast: number,
27
24
  remBondFirst: number, remBondLast: Number} {
28
- const molfile = monomer["molfile"];
25
+ const molfile = monomer['molfile'];
29
26
  let indexStart = molfile.indexOf('M RGP', 0) + 8;
30
27
  let indexEnd = molfile.indexOf('\n', indexStart);
31
28
  const indicesData = molfile.substring(indexStart, indexEnd).replaceAll(' ', ' ').replaceAll(' ', ' ');
32
- let parsedData = indicesData.split(' ')
29
+ let parsedData = indicesData.split(' ');
33
30
  const remFirst = parsedData[2] == '1' ? parseInt(parsedData[1]) : parseInt(parsedData[3]);
34
31
  const remLast = parsedData[2] == '2' ? parseInt(parsedData[1]) : parseInt(parsedData[3]);
35
-
32
+
36
33
  const numbers = extractAtomsBondsNumbersV3000(molV3000);
37
34
  let indexBonds = molV3000.indexOf('M V30 BEGIN BOND'); // V3000 index for bonds
38
35
  indexBonds = molV3000.indexOf('\n', indexBonds);
@@ -45,25 +42,22 @@ function getIndices(monomer: any, molV3000: string): {first: number, last: numbe
45
42
  let remBondLast = 0;
46
43
 
47
44
  for (let j = 0; j < numbers.nbond; j++) {
48
- if(first == 0 || last == 0){
45
+ if (first == 0 || last == 0) {
49
46
  indexStart = molV3000.indexOf('V30', indexStart) + 4;
50
47
  indexEnd = molV3000.indexOf('\n', indexStart);
51
48
  const bondData = molV3000.substring(indexStart, indexEnd).replaceAll(' ', ' ').replaceAll(' ', ' ');
52
- parsedData = bondData.split(' ')
49
+ parsedData = bondData.split(' ');
53
50
 
54
- if(parseInt(parsedData[2]) == remFirst){
51
+ if (parseInt(parsedData[2]) == remFirst) {
55
52
  first = parseInt(parsedData[3]);
56
53
  remBondFirst = parseInt(parsedData[0]);
57
- }
58
- else if(parseInt(parsedData[3]) == remFirst){
54
+ } else if (parseInt(parsedData[3]) == remFirst) {
59
55
  first = parseInt(parsedData[2]);
60
56
  remBondFirst = parseInt(parsedData[0]);
61
- }
62
- else if(parseInt(parsedData[2]) == remLast){
57
+ } else if (parseInt(parsedData[2]) == remLast) {
63
58
  last = parseInt(parsedData[3]);
64
59
  remBondLast = parseInt(parsedData[0]);
65
- }
66
- else if(parseInt(parsedData[3]) == remLast){
60
+ } else if (parseInt(parsedData[3]) == remLast) {
67
61
  last = parseInt(parsedData[2]);
68
62
  remBondLast = parseInt(parsedData[0]);
69
63
  }
@@ -79,8 +73,8 @@ async function rotateBackboneV3000(molBlock: string, indices:any): Promise<strin
79
73
  const first = indices['first'];
80
74
  const last = indices['last'];
81
75
 
82
- const xCenter = (coordinates.x[last] + coordinates.x[first])/2;
83
- const yCenter = (coordinates.y[last] + coordinates.y[first])/2;
76
+ const xCenter = (coordinates.x[last] + coordinates.x[first]) / 2;
77
+ const yCenter = (coordinates.y[last] + coordinates.y[first]) / 2;
84
78
 
85
79
  //place to center
86
80
  for (let i = 0; i < natom; i++) {
@@ -89,13 +83,13 @@ async function rotateBackboneV3000(molBlock: string, indices:any): Promise<strin
89
83
  }
90
84
 
91
85
  let angle = 0;
92
- if (coordinates.x[first] == 0)
93
- angle = coordinates.y[first] > coordinates.y[last] ? Math.PI/2 : 3*Math.PI/2;
94
- else if (coordinates.y[first] == 0)
86
+ if (coordinates.x[first] == 0) {
87
+ angle = coordinates.y[first] > coordinates.y[last] ? Math.PI / 2 : 3 * Math.PI / 2;
88
+ } else if (coordinates.y[first] == 0) {
95
89
  angle = coordinates.x[first] > coordinates.x[last] ? Math.PI : 0;
96
- else {
97
- const derivative = coordinates.y[first]/coordinates.x[first];
98
- if(coordinates.x[first] < coordinates.x[last])
90
+ } else {
91
+ const derivative = coordinates.y[first] / coordinates.x[first];
92
+ if (coordinates.x[first] < coordinates.x[last])
99
93
  angle = derivative > 0 ? Math.PI - Math.atan(derivative) : Math.atan(derivative);
100
94
  else
101
95
  angle = derivative > 0 ? Math.atan(derivative) : Math.PI - Math.atan(derivative);
@@ -106,8 +100,8 @@ async function rotateBackboneV3000(molBlock: string, indices:any): Promise<strin
106
100
 
107
101
  for (let i = 0; i < natom; i++) {
108
102
  const xAdd = coordinates.x[i];
109
- coordinates.x[i] = xAdd*cos - coordinates.y[i]*sin;
110
- coordinates.y[i] = xAdd*sin + coordinates.y[i]*cos;
103
+ coordinates.x[i] = xAdd * cos - coordinates.y[i] * sin;
104
+ coordinates.y[i] = xAdd * sin + coordinates.y[i] * cos;
111
105
  }
112
106
 
113
107
  //place to right
@@ -176,8 +170,6 @@ function linkV3000(monomers: any[]): string {
176
170
  macroMolBlock += 'M V30 BEGIN CTAB\n';
177
171
  let atomBlock = '';
178
172
  let bondBlock = '';
179
- let collectionBlock = '';
180
- const collection: number [] = [];
181
173
  let natom = 0;
182
174
  let nbond = 0;
183
175
  let xShift = 0;
@@ -206,10 +198,10 @@ function linkV3000(monomers: any[]): string {
206
198
  //rewrite atom number
207
199
  index = molfile.indexOf('V30', index) + 4;
208
200
  indexEnd = molfile.indexOf(' ', index);
209
-
210
- let atomNumber = parseInt(molfile.substring(index, indexEnd))
201
+
202
+ let atomNumber = parseInt(molfile.substring(index, indexEnd));
211
203
  atomNumber = (atomNumber > remFirst && atomNumber > remLast) ? atomNumber - 2 :
212
- (atomNumber > remFirst || atomNumber > remLast) ? atomNumber - 1 : atomNumber;
204
+ (atomNumber > remFirst || atomNumber > remLast) ? atomNumber - 1 : atomNumber;
213
205
  atomNumber += natom;
214
206
  molfile = molfile.slice(0, index) + atomNumber + molfile.slice(indexEnd);
215
207
 
@@ -218,12 +210,12 @@ function linkV3000(monomers: any[]): string {
218
210
  index = molfile.indexOf(' ', index) + 1;
219
211
  indexEnd = molfile.indexOf(' ', index);
220
212
 
221
- let coordinate = Math.round(10000*(parseFloat(molfile.substring(index, indexEnd)) + totalShift))/10000;
213
+ let coordinate = Math.round(10000 * (parseFloat(molfile.substring(index, indexEnd)) + totalShift)) / 10000;
222
214
  molfile = molfile.slice(0, index) + coordinate + molfile.slice(indexEnd);
223
215
 
224
216
  index = molfile.indexOf(' ', index) + 1;
225
217
  indexEnd = molfile.indexOf(' ', index);
226
- coordinate = Math.round(10000*(parseFloat(molfile.substring(index, indexEnd))))/10000;
218
+ coordinate = Math.round(10000 * (parseFloat(molfile.substring(index, indexEnd)))) / 10000;
227
219
  molfile = molfile.slice(0, index) + coordinate + molfile.slice(indexEnd);
228
220
 
229
221
  index = molfile.indexOf('\n', index) + 1;
@@ -249,15 +241,15 @@ function linkV3000(monomers: any[]): string {
249
241
  indexEnd = molfile.indexOf(' ', index);
250
242
  bondNumber = parseInt(molfile.substring(index, indexEnd));
251
243
 
252
- if(bondNumber == remBondFirst || bondNumber == remBondLast){
244
+ if (bondNumber == remBondFirst || bondNumber == remBondLast) {
253
245
  indexEnd = molfile.indexOf('\n', index) + 1;
254
- index -=7;
246
+ index -= 7;
255
247
  molfile = molfile.slice(0, index) + molfile.slice(indexEnd);
256
- continue
248
+ continue;
257
249
  }
258
250
 
259
251
  bondNumber = (bondNumber > remBondFirst && bondNumber > remBondLast) ? bondNumber - 2 :
260
- (bondNumber > remBondFirst || bondNumber > remBondLast) ? bondNumber - 1 : bondNumber;
252
+ (bondNumber > remBondFirst || bondNumber > remBondLast) ? bondNumber - 1 : bondNumber;
261
253
  bondNumber += nbond;
262
254
 
263
255
  molfile = molfile.slice(0, index) + bondNumber + molfile.slice(indexEnd);
@@ -266,16 +258,16 @@ function linkV3000(monomers: any[]): string {
266
258
  index = molfile.indexOf(' ', index) + 1;
267
259
  index = molfile.indexOf(' ', index) + 1;
268
260
  indexEnd = molfile.indexOf(' ', index);
269
- let atomNumber = parseInt(molfile.substring(index, indexEnd))
261
+ let atomNumber = parseInt(molfile.substring(index, indexEnd));
270
262
  atomNumber = (atomNumber > remFirst && atomNumber > remLast) ? atomNumber - 2 :
271
- (atomNumber > remFirst || atomNumber > remLast) ? atomNumber - 1 : atomNumber;
263
+ (atomNumber > remFirst || atomNumber > remLast) ? atomNumber - 1 : atomNumber;
272
264
  atomNumber += natom;
273
265
  molfile = molfile.slice(0, index) + atomNumber + molfile.slice(indexEnd);
274
266
  index = molfile.indexOf(' ', index) + 1;
275
267
  indexEnd = Math.min(molfile.indexOf('\n', index), molfile.indexOf(' ', index));
276
- atomNumber = parseInt(molfile.substring(index, indexEnd))
268
+ atomNumber = parseInt(molfile.substring(index, indexEnd));
277
269
  atomNumber = (atomNumber > remFirst && atomNumber > remLast) ? atomNumber - 2 :
278
- (atomNumber > remFirst || atomNumber > remLast) ? atomNumber - 1 : atomNumber;
270
+ (atomNumber > remFirst || atomNumber > remLast) ? atomNumber - 1 : atomNumber;
279
271
  atomNumber += natom;
280
272
  molfile = molfile.slice(0, index) + atomNumber + molfile.slice(indexEnd);
281
273
 
@@ -301,30 +293,30 @@ function linkV3000(monomers: any[]): string {
301
293
  nbond += numbers.nbond - 2;
302
294
  xShift += coordinates.x[last] - coordinates.x[first] + 1;
303
295
 
304
- if(i == monomers.length -1){
296
+ if (i == monomers.length - 1) {
305
297
  natom++;
306
298
  const shift = xShift + 0.2;
307
299
  atomBlock += 'M V30 ' + natom + ' O ' + shift + ' 0 0.000000 0\n';
308
300
  }
309
301
  nbond++;
310
- if(i == monomers.length -1){
311
- const rightTerminal = (last > remFirst && last > remLast) ? last + natom - (numbers.natom - 2) - 3:
312
- (last > remFirst || last > remLast) ? last + natom - (numbers.natom - 2) - 2 :
313
- last + natom - (numbers.natom - 2) - 1;
302
+ if (i == monomers.length - 1) {
303
+ const rightTerminal = (last > remFirst && last > remLast) ? last + natom - (numbers.natom - 2) - 3 :
304
+ (last > remFirst || last > remLast) ? last + natom - (numbers.natom - 2) - 2 :
305
+ last + natom - (numbers.natom - 2) - 1;
314
306
  bondBlock += 'M V30 ' + nbond + ' 1 ' + rightTerminal + ' ' + natom + '\n';
315
- } else{
316
- const rightTerminal = (last > remFirst && last > remLast) ? last + natom - (numbers.natom - 2) - 2:
317
- (last > remFirst || last > remLast) ? last + natom - (numbers.natom - 2) - 1 :
318
- last + natom - (numbers.natom - 2);
319
-
307
+ } else {
308
+ const rightTerminal = (last > remFirst && last > remLast) ? last + natom - (numbers.natom - 2) - 2 :
309
+ (last > remFirst || last > remLast) ? last + natom - (numbers.natom - 2) - 1 :
310
+ last + natom - (numbers.natom - 2);
311
+
320
312
  const next = monomers[i + 1]['indices'];
321
313
  const nextFirst = next['first'];
322
314
  const nextRemFirst = next['remFirst'];
323
315
  const nextRemLast = next['remLast'];
324
316
 
325
317
  const leftTerminal = (nextFirst > nextRemFirst && nextFirst > nextRemLast) ? nextFirst + natom - 2 :
326
- (nextFirst > nextRemFirst || nextFirst > nextRemLast) ? nextFirst + natom - 1 :
327
- nextFirst + natom;
318
+ (nextFirst > nextRemFirst || nextFirst > nextRemLast) ? nextFirst + natom - 1 :
319
+ nextFirst + natom;
328
320
 
329
321
  bondBlock += 'M V30 ' + nbond + ' 1 ' + rightTerminal + ' ' + leftTerminal + '\n';
330
322
  }
@@ -61,7 +61,7 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
61
61
 
62
62
  get defaultWidth(): number | null { return 230; }
63
63
 
64
- onClick(gridCell: DG.GridCell, e: MouseEvent): void {
64
+ onClick(gridCell: DG.GridCell, _e: MouseEvent): void {
65
65
  const colTemp: TempType = gridCell.cell.column.temp;
66
66
  colTemp[tempTAGS.currentWord] = gridCell.cell.value;
67
67
  gridCell.grid.invalidate();
@@ -112,12 +112,12 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
112
112
  * @param {number} w width of the cell.
113
113
  * @param {number} h height of the cell.
114
114
  * @param {DG.GridCell} gridCell Grid cell.
115
- * @param {DG.GridCellStyle} cellStyle Cell style.
115
+ * @param {DG.GridCellStyle} _cellStyle Cell style.
116
116
  * @memberof AlignedSequenceCellRenderer
117
117
  */
118
118
  render(
119
- g: CanvasRenderingContext2D, x: number, y: number, w: number, h: number, gridCell: DG.GridCell,
120
- cellStyle: DG.GridCellStyle
119
+ g: CanvasRenderingContext2D, x: number, y: number, w: number, h: number,
120
+ gridCell: DG.GridCell, _cellStyle: DG.GridCellStyle,
121
121
  ) {
122
122
  const grid = gridCell.gridRow !== -1 ? gridCell.grid : null;
123
123
  const cell = gridCell.cell;
@@ -251,6 +251,21 @@ export class MonomerCellRenderer extends DG.GridCellRenderer {
251
251
  g.fillStyle = color;
252
252
  g.fillText(monomerToShort(s, 3), x + (w / 2), y + (h / 2), w);
253
253
  }
254
+
255
+ svgMolOptions = {autoCrop: true, autoCropMargin: 0, suppressChiralText: true};
256
+
257
+ onMouseEnter(gridCell: DG.GridCell, e: MouseEvent) {
258
+ super.onMouseEnter(gridCell, e);
259
+
260
+ // TODO: Display monomer structure within tooltip
261
+ // const monomerName = gridCell.cell.value;
262
+ // const mw = getMonomerWorksInstance();
263
+ // // TODO: Display monomer structure in Tooltip
264
+ // const nameDiv = ui.div(monomerName);
265
+ // const molDiv = grok.chem.svgMol(monomerMol, undefined, undefined, svgMolOptions);
266
+ //
267
+ // ui.tooltip.show(ui.divV([nameDiv, molEl,]), x, y);
268
+ }
254
269
  }
255
270
 
256
271
  export class MacromoleculeDifferenceCellRenderer extends DG.GridCellRenderer {
@@ -302,7 +317,7 @@ export function drawMoleculeDifferenceOnCanvas(
302
317
  subParts2: string [],
303
318
  units: string,
304
319
  fullStringLength?: boolean,
305
- molDifferences?: { [key: number]: HTMLCanvasElement }
320
+ molDifferences?: { [key: number]: HTMLCanvasElement },
306
321
  ): void {
307
322
  if (subParts1.length !== subParts2.length) {
308
323
  const sequences: IComparedSequences = fillShorterSequence(subParts1, subParts2);
@@ -382,7 +397,7 @@ function fillShorterSequence(subParts1: string[], subParts2: string[]): ICompare
382
397
  let numIdenticalStart = 0;
383
398
  let numIdenticalEnd = 0;
384
399
  const longerSeq = subParts1.length > subParts2.length ? subParts1 : subParts2;
385
- let shorterSeq = subParts1.length > subParts2.length ? subParts2 : subParts1;
400
+ const shorterSeq = subParts1.length > subParts2.length ? subParts2 : subParts1;
386
401
 
387
402
  for (let i = 0; i < shorterSeq.length; i++) {
388
403
  if (longerSeq[i] === shorterSeq[i])
@@ -398,9 +413,11 @@ function fillShorterSequence(subParts1: string[], subParts2: string[]): ICompare
398
413
  const emptyMonomersArray = new Array<string>(Math.abs(subParts1.length - subParts2.length)).fill('');
399
414
 
400
415
  function concatWithEmptyVals(subparts: string[]): string[] {
401
- return numIdenticalStart > numIdenticalEnd ? subparts.concat(emptyMonomersArray) : emptyMonomersArray.concat(subparts);
416
+ return numIdenticalStart > numIdenticalEnd ?
417
+ subparts.concat(emptyMonomersArray) : emptyMonomersArray.concat(subparts);
402
418
  }
403
419
 
404
- subParts1.length > subParts2.length ? subParts2 = concatWithEmptyVals(subParts2) : subParts1 = concatWithEmptyVals(subParts1);
420
+ subParts1.length > subParts2.length ?
421
+ subParts2 = concatWithEmptyVals(subParts2) : subParts1 = concatWithEmptyVals(subParts1);
405
422
  return {subParts1: subParts1, subParts2: subParts2};
406
423
  }
@@ -4,7 +4,15 @@ import * as ui from 'datagrok-api/ui';
4
4
 
5
5
  import {UnitsHandler} from '@datagrok-libraries/bio/src/utils/units-handler';
6
6
 
7
- /** */
7
+ /**
8
+ * Checks if the column is suitable for the analysis.
9
+ * @param {DG.Column} col macromolecule coulumn.
10
+ * @param {string} name column name
11
+ * @param {string[]} allowedNotations allowed notations
12
+ * @param {string[]} allowedAlphabets allowed alphabets
13
+ * @param {boolean} notify show warning message if the column is not suitable for the analysis
14
+ * @return {boolean} True if the column is suitable for the analysis.
15
+ */
8
16
  export function checkInputColumnUI(col: DG.Column, name: string, allowedNotations: string[] = [],
9
17
  allowedAlphabets: string[] = [], notify: boolean = true): boolean {
10
18
  const [res, msg]: [boolean, string] = checkInputColumn(col, name, allowedNotations, allowedAlphabets);
@@ -13,14 +21,21 @@ export function checkInputColumnUI(col: DG.Column, name: string, allowedNotation
13
21
  return res;
14
22
  }
15
23
 
16
- /** */
24
+ /**
25
+ * Checks if the column is suitable for the analysis.
26
+ * @param {DG.Column} col macromolecule coulumn.
27
+ * @param {string} name column name
28
+ * @param {string[]} allowedNotations allowed notations
29
+ * @param {string[]} allowedAlphabets allowed alphabets
30
+ * @return {[boolean, string]} [True if the column is suitable for the analysis, warning message].
31
+ */
17
32
  export function checkInputColumn(
18
- col: DG.Column, name: string, allowedNotations: string[] = [], allowedAlphabets: string[] = []
33
+ col: DG.Column, name: string, allowedNotations: string[] = [], allowedAlphabets: string[] = [],
19
34
  ): [boolean, string] {
20
35
  let res: boolean = true;
21
36
  let msg: string = '';
22
37
 
23
- const uh = new UnitsHandler(col);
38
+ const uh = UnitsHandler.getOrCreate(col);
24
39
  if (col.semType !== DG.SEMTYPE.MACROMOLECULE) {
25
40
  grok.shell.warning(name + ' analysis is allowed for Macromolecules semantic type');
26
41
  res = false;
@@ -70,8 +70,8 @@ export const msaDefaultOptions = {
70
70
  method: pepseaMethods[0],
71
71
  },
72
72
  kalign: {
73
- gapOpen: null,
74
- gapExtend: null,
75
- terminalGap: null,
73
+ gapOpen: -1.0,
74
+ gapExtend: -1.0,
75
+ terminalGap: -1.0,
76
76
  },
77
77
  } as const;
@@ -16,18 +16,56 @@ let convertDialogSubs: Subscription[] = [];
16
16
  *
17
17
  * @param {DG.column} col Column with 'Macromolecule' semantic type
18
18
  */
19
- export function convert(col: DG.Column): void {
20
- const converter = new NotationConverter(col);
21
- const currentNotation: NOTATION = converter.notation;
22
- //TODO: read all notations
19
+ export function convert(col?: DG.Column): void {
20
+
21
+ let tgtCol = col ?? grok.shell.t.columns.bySemType('Macromolecule')!;
22
+ if (!tgtCol)
23
+ throw new Error('No column with Macromolecule semantic type found');
24
+ let converter = new NotationConverter(tgtCol);
25
+ let currentNotation: NOTATION = converter.notation;
26
+ const dialogHeader = ui.divText(
27
+ 'Current notation: ' + currentNotation,
28
+ {
29
+ style: {
30
+ 'text-align': 'center',
31
+ 'font-weight': 'bold',
32
+ 'font-size': '14px',
33
+ 'padding': '5px',
34
+ },
35
+ },
36
+ );
23
37
  const notations = [
24
38
  NOTATION.FASTA,
25
39
  NOTATION.SEPARATOR,
26
- NOTATION.HELM
40
+ NOTATION.HELM,
27
41
  ];
42
+ const toggleColumn = (newCol: DG.Column) => {
43
+ if (newCol.semType !== DG.SEMTYPE.MACROMOLECULE) {
44
+ targetColumnInput.value = tgtCol;
45
+ return;
46
+ }
47
+
48
+ tgtCol = newCol;
49
+ converter = new NotationConverter(tgtCol);
50
+ currentNotation = converter.notation;
51
+ dialogHeader.textContent = 'Current notation: ' + currentNotation;
52
+ filteredNotations = notations.filter((e) => e !== currentNotation);
53
+ targetNotationInput = ui.choiceInput('Convert to', filteredNotations[0], filteredNotations);
54
+ toggleSeparator();
55
+ convertDialog?.clear();
56
+ convertDialog?.add(ui.div([
57
+ dialogHeader,
58
+ targetColumnInput.root,
59
+ targetNotationInput.root,
60
+ separatorInput.root
61
+ ]))
62
+ };
63
+
64
+ const targetColumnInput = ui.columnInput('Column', grok.shell.t, tgtCol, toggleColumn);
65
+
28
66
  const separatorArray = ['-', '.', '/'];
29
- const filteredNotations = notations.filter((e) => e !== currentNotation);
30
- const targetNotationInput = ui.choiceInput('Convert to', filteredNotations[0], filteredNotations);
67
+ let filteredNotations = notations.filter((e) => e !== currentNotation);
68
+ let targetNotationInput = ui.choiceInput('Convert to', filteredNotations[0], filteredNotations);
31
69
 
32
70
  const separatorInput = ui.choiceInput('Separator', separatorArray[0], separatorArray);
33
71
 
@@ -49,29 +87,20 @@ export function convert(col: DG.Column): void {
49
87
  if (convertDialog == null) {
50
88
  convertDialog = ui.dialog('Convert Sequence Notation')
51
89
  .add(ui.div([
52
- ui.divText(
53
- 'Current notation: ' + currentNotation,
54
- {
55
- style: {
56
- 'text-align': 'center',
57
- 'font-weight': 'bold',
58
- 'font-size': '14px',
59
- 'padding': '5px',
60
- }
61
- }
62
- ),
90
+ dialogHeader,
91
+ targetColumnInput.root,
63
92
  targetNotationInput.root,
64
- separatorInput.root
93
+ separatorInput.root,
65
94
  ]))
66
95
  .onOK(async () => {
67
96
  const targetNotation = targetNotationInput.value as NOTATION;
68
97
  const separator: string | null = separatorInput.value;
69
98
 
70
- await convertDo(col, targetNotation, separator);
99
+ await convertDo(tgtCol, targetNotation, separator);
71
100
  })
72
101
  .show({x: 350, y: 100});
73
102
 
74
- convertDialogSubs.push(convertDialog.onClose.subscribe((value) => {
103
+ convertDialogSubs.push(convertDialog.onClose.subscribe((_value) => {
75
104
  convertDialogSubs.forEach((s) => { s.unsubscribe(); });
76
105
  convertDialogSubs = [];
77
106
  convertDialog = null;
@@ -79,9 +108,13 @@ export function convert(col: DG.Column): void {
79
108
  }
80
109
  }
81
110
 
82
- /** Creates a new column with converted sequences and detects its semantic type */
111
+ /** Creates a new column with converted sequences and detects its semantic type
112
+ * @param {DG.Column} srcCol Column with 'Macromolecule' semantic type
113
+ * @param {NOTATION} targetNotation Target notation
114
+ * @param {string | null} separator Separator for SEPARATOR notation
115
+ */
83
116
  export async function convertDo(
84
- srcCol: DG.Column, targetNotation: NOTATION, separator: string | null
117
+ srcCol: DG.Column, targetNotation: NOTATION, separator: string | null,
85
118
  ): Promise<DG.Column> {
86
119
  const converter = new NotationConverter(srcCol);
87
120
  const newColumn = converter.convert(targetNotation, separator);