@datagrok/bio 1.7.25 → 1.8.1

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/src/package.ts CHANGED
@@ -26,6 +26,10 @@ import {FastaFileHandler} from '@datagrok-libraries/bio/src/utils/fasta-handler'
26
26
  import {removeEmptyStringRows} from '@datagrok-libraries/utils/src/dataframe-utils'
27
27
 
28
28
 
29
+ //tags: init
30
+ export async function initBio() {
31
+ }
32
+
29
33
  //name: fastaSequenceCellRenderer
30
34
  //tags: cellRenderer
31
35
  //meta.cellType: Sequence
@@ -46,15 +50,16 @@ export function separatorSequenceCellRenderer(): MacromoleculeSequenceCellRender
46
50
 
47
51
  function checkInputColumn(col: DG.Column, name: string,
48
52
  allowedNotations: string[] = [], allowedAlphabets: string[] = []): boolean {
49
- const units: string = col.getTag(DG.TAGS.UNITS);
53
+ const notation: string = col.getTag(DG.TAGS.UNITS);
54
+ const alphabet: string = col.getTag('alphabet')
50
55
  if (col.semType !== DG.SEMTYPE.MACROMOLECULE) {
51
56
  grok.shell.warning(name + ' analysis is allowed for Macromolecules semantic type');
52
57
  return false;
53
58
  } else if (
54
59
  (allowedAlphabets.length > 0 &&
55
- !allowedAlphabets.some((a) => units.toUpperCase().endsWith(a.toUpperCase()))) ||
60
+ !allowedAlphabets.some((a) => alphabet.toUpperCase() == (a.toUpperCase()))) ||
56
61
  (allowedNotations.length > 0 &&
57
- !allowedNotations.some((n) => units.toUpperCase().startsWith(n.toUpperCase())))
62
+ !allowedNotations.some((n) => notation.toUpperCase() == (n.toUpperCase())))
58
63
  ) {
59
64
  const notationAdd = allowedNotations.length == 0 ? 'any notation' :
60
65
  (`notation${allowedNotations.length > 1 ? 's' : ''} ${allowedNotations.map((n) => `"${n}"`).join(', ')} `);
@@ -107,7 +112,7 @@ export function vdRegionViewer() {
107
112
  //input: double similarity = 80 [Similarity cutoff]
108
113
  //input: string methodName { choices:["UMAP", "t-SNE", "SPE"] }
109
114
  export async function activityCliffs(df: DG.DataFrame, macroMolecule: DG.Column, activities: DG.Column,
110
- similarity: number, methodName: string): Promise<void> {
115
+ similarity: number, methodName: string): Promise<DG.Viewer | undefined> {
111
116
  if (!checkInputColumn(macroMolecule, 'Activity Cliffs'))
112
117
  return;
113
118
  const encodedCol = encodeMonomers(macroMolecule);
@@ -117,8 +122,13 @@ export async function activityCliffs(df: DG.DataFrame, macroMolecule: DG.Column,
117
122
  const options = {
118
123
  'SPE': {cycles: 2000, lambda: 1.0, dlambda: 0.0005},
119
124
  };
120
- const units = macroMolecule!.tags[DG.TAGS.UNITS];
121
- await getActivityCliffs(
125
+ const tags = {
126
+ 'units': macroMolecule.tags['units'],
127
+ 'aligned': macroMolecule.tags['aligned'],
128
+ 'separator': macroMolecule.tags['separator'],
129
+ 'alphabet': macroMolecule.tags['alphabet'],
130
+ }
131
+ const sp = await getActivityCliffs(
122
132
  df,
123
133
  macroMolecule,
124
134
  encodedCol,
@@ -129,11 +139,12 @@ export async function activityCliffs(df: DG.DataFrame, macroMolecule: DG.Column,
129
139
  'Levenshtein',
130
140
  methodName,
131
141
  DG.SEMTYPE.MACROMOLECULE,
132
- units,
142
+ tags,
133
143
  sequenceSpace,
134
144
  sequenceGetSimilarities,
135
145
  drawTooltip,
136
146
  (options as any)[methodName]);
147
+ return sp;
137
148
  }
138
149
 
139
150
  //top-menu: Bio | Sequence Space...
@@ -144,7 +155,7 @@ export async function activityCliffs(df: DG.DataFrame, macroMolecule: DG.Column,
144
155
  //input: string similarityMetric { choices:["Levenshtein", "Tanimoto"] }
145
156
  //input: bool plotEmbeddings = true
146
157
  export async function sequenceSpaceTopMenu(table: DG.DataFrame, macroMolecule: DG.Column, methodName: string,
147
- similarityMetric: string = 'Levenshtein', plotEmbeddings: boolean): Promise<void> {
158
+ similarityMetric: string = 'Levenshtein', plotEmbeddings: boolean): Promise<DG.Viewer|undefined> {
148
159
  if (!checkInputColumn(macroMolecule, 'Activity Cliffs'))
149
160
  return;
150
161
  const encodedCol = encodeMonomers(macroMolecule);
@@ -165,14 +176,16 @@ export async function sequenceSpaceTopMenu(table: DG.DataFrame, macroMolecule: D
165
176
  for (const col of embeddings) {
166
177
  const listValues = col.toList();
167
178
  emptyValsIdxs.forEach((ind: number) => listValues.splice(ind, 0, null));
168
- table.columns.add(DG.Column.fromFloat32Array(col.name, listValues));
169
- }
179
+ table.columns.add(DG.Column.fromList('double', col.name, listValues));
180
+ }
181
+ let sp;
170
182
  if (plotEmbeddings) {
171
183
  for (const v of grok.shell.views) {
172
184
  if (v.name === table.name)
173
- (v as DG.TableView).scatterPlot({x: embedColsNames[0], y: embedColsNames[1], title: 'Sequence space'});
185
+ sp = (v as DG.TableView).scatterPlot({x: embedColsNames[0], y: embedColsNames[1], title: 'Sequence space'});
174
186
  }
175
187
  }
188
+ return sp;
176
189
  };
177
190
 
178
191
  //top-menu: Bio | To Atomic Level...
@@ -188,22 +201,6 @@ export async function toAtomicLevel(df: DG.DataFrame, macroMolecule: DG.Column):
188
201
  if (!checkInputColumn(macroMolecule, 'To Atomic Level'))
189
202
  return;
190
203
 
191
- let currentView: DG.TableView;
192
- for (const view of grok.shell.tableViews) {
193
- if (df.name === view.name)
194
- currentView = view;
195
- }
196
-
197
- // Some hack to activate Chem Molecule rendering
198
- const file2 = await _package.files.readAsText('tests/sar-small.csv');
199
- const df2 = DG.DataFrame.fromCsv(file2);
200
- const v2 = grok.shell.addTableView(df2);
201
- setTimeout(() => {
202
- grok.shell.closeTable(df2);
203
- v2.close();
204
- grok.shell.v = currentView;
205
- }, 100);
206
-
207
204
  const monomersLibFile = await _package.files.readAsText(HELM_CORE_LIB_FILENAME);
208
205
  const monomersLibObject: any[] = JSON.parse(monomersLibFile);
209
206
  const atomicCodes = getMolfilesFromSeq(macroMolecule, monomersLibObject);
@@ -213,6 +210,7 @@ export async function toAtomicLevel(df: DG.DataFrame, macroMolecule: DG.Column):
213
210
  col.semType = DG.SEMTYPE.MOLECULE;
214
211
  col.tags[DG.TAGS.UNITS] = 'molblock';
215
212
  df.columns.add(col, true);
213
+ await grok.data.detectSemanticTypes(df);
216
214
  }
217
215
 
218
216
 
@@ -404,3 +402,4 @@ export async function testDetectMacromolecule(path: string): Promise<DG.DataFram
404
402
  resDf.name = `datasets_detectMacromolecule_${path}`;
405
403
  return resDf;
406
404
  }
405
+
@@ -1,58 +1,39 @@
1
- import {after, before, category, expect, expectFloat, test} from '@datagrok-libraries/utils/src/test';
1
+ import {after, before, category, test} from '@datagrok-libraries/utils/src/test';
2
2
 
3
3
  import * as DG from 'datagrok-api/dg';
4
4
  import * as grok from 'datagrok-api/grok';
5
5
 
6
6
  import {readDataframe} from './utils';
7
- import {getEmbeddingColsNames, sequenceSpace} from '../utils/sequence-space';
8
- import {drawTooltip, sequenceGetSimilarities} from '../utils/sequence-activity-cliffs';
9
- import {getActivityCliffs} from '@datagrok-libraries/ml/src/viewers/activity-cliffs';
10
- import {encodeMonomers} from '../utils/utils';
7
+ import { _testActivityCliffsOpen } from './activity-cliffs-utils';
11
8
 
12
9
 
13
10
  category('activityCliffs', async () => {
14
11
  let actCliffsTableView: DG.TableView;
15
12
  let actCliffsDf: DG.DataFrame;
13
+ let actCliffsTableViewWithEmptyRows: DG.TableView;
14
+ let actCliffsDfWithEmptyRows: DG.DataFrame;
15
+
16
16
 
17
17
  before(async () => {
18
18
  actCliffsDf = await readDataframe('samples/sample_MSA.csv');
19
19
  actCliffsTableView = grok.shell.addTableView(actCliffsDf);
20
-
21
- actCliffsDf = actCliffsTableView.dataFrame;
20
+ actCliffsDfWithEmptyRows = await readDataframe('samples/sample_HELM_empty_vals.csv');
21
+ actCliffsTableViewWithEmptyRows = grok.shell.addTableView(actCliffsDfWithEmptyRows);
22
22
  });
23
23
 
24
24
  after(async () => {
25
25
  grok.shell.closeTable(actCliffsDf);
26
26
  actCliffsTableView.close();
27
+ grok.shell.closeTable(actCliffsDfWithEmptyRows);
28
+ actCliffsTableViewWithEmptyRows.close();
27
29
  });
28
30
 
29
31
  test('activityCliffsOpen', async () => {
30
- const axesNames = getEmbeddingColsNames(actCliffsDf);
31
- const units = actCliffsDf.col('MSA')!.tags[DG.TAGS.UNITS];
32
- const options = {
33
- 'SPE': {cycles: 2000, lambda: 1.0, dlambda: 0.0005},
34
- };
35
- const encodedCol = encodeMonomers(actCliffsDf.col('MSA')!) as DG.Column;
36
- const scatterPlot = await getActivityCliffs(
37
- actCliffsDf,
38
- actCliffsDf.col('MSA')!,
39
- encodedCol,
40
- axesNames,
41
- 'Activity cliffs',
42
- actCliffsDf.col('Activity')!,
43
- 50,
44
- 'Levenshtein',
45
- 't-SNE',
46
- DG.SEMTYPE.MACROMOLECULE,
47
- units,
48
- sequenceSpace,
49
- sequenceGetSimilarities,
50
- drawTooltip);
51
-
52
- expect(scatterPlot != null, true);
53
-
54
- const cliffsLink = (Array.from(scatterPlot.root.children) as Element[])
55
- .filter((it) => it.className === 'ui-btn ui-btn-ok');
56
- expect((cliffsLink[0] as HTMLElement).innerText, '2362 cliffs');
32
+ await _testActivityCliffsOpen(actCliffsDf, 53, 'UMAP', 'MSA');
33
+ });
34
+
35
+ test('activityCliffsOpenWithEmptyRows', async () => {
36
+ await _testActivityCliffsOpen(actCliffsDfWithEmptyRows, 53, 'UMAP', 'HELM');
57
37
  });
38
+
58
39
  });
@@ -0,0 +1,19 @@
1
+ import * as DG from 'datagrok-api/dg';
2
+ import {delay, expect} from '@datagrok-libraries/utils/src/test';
3
+ import {_package} from '../package-test';
4
+ import { activityCliffs } from '../package';
5
+
6
+
7
+ export async function _testActivityCliffsOpen(df: DG.DataFrame, numberCliffs: number, method: string, colName: string) {
8
+ const scatterPlot = await activityCliffs(
9
+ df,
10
+ df.col(colName)!,
11
+ df.col('Activity')!,
12
+ 80,
13
+ method);
14
+
15
+ expect(scatterPlot != null, true);
16
+
17
+ const cliffsLink = Array.from(scatterPlot!.root.children).filter(it => it.className === 'ui-btn ui-btn-ok');
18
+ expect((cliffsLink[0] as HTMLElement).innerText, `${numberCliffs} cliffs`);
19
+ }
@@ -1,4 +1,4 @@
1
- import {after, before, category, expect, test} from '@datagrok-libraries/utils/src/test';
1
+ import {after, before, category, delay, expect, test} from '@datagrok-libraries/utils/src/test';
2
2
 
3
3
  import * as grok from 'datagrok-api/grok';
4
4
  import * as DG from 'datagrok-api/dg';
@@ -12,6 +12,7 @@ category('renderers', () => {
12
12
  let dfList: DG.DataFrame[];
13
13
 
14
14
  before(async () => {
15
+ await grok.functions.call('Bio:initBio');
15
16
  tvList = [];
16
17
  dfList = [];
17
18
  });
@@ -46,16 +47,16 @@ category('renderers', () => {
46
47
  expect(srcSeqCol!.getTag(DG.TAGS.UNITS), 'fasta');
47
48
  expect(srcSeqCol!.getTag('aligned'), 'SEQ');
48
49
  expect(srcSeqCol!.getTag('alphabet'), 'PT');
49
- expect(srcSeqCol!.getTag('cell.renderer'), 'Macromolecule');
50
+ expect(srcSeqCol!.getTag('cell.renderer'), 'sequence');
50
51
 
51
52
  const msaSeqCol: DG.Column | null = await multipleSequenceAlignmentAny(df, srcSeqCol!);
52
53
  tv.grid.invalidate();
53
-
54
+
54
55
  expect(msaSeqCol!.semType, DG.SEMTYPE.MACROMOLECULE);
55
56
  expect(msaSeqCol!.getTag(DG.TAGS.UNITS), 'fasta');
56
57
  expect(msaSeqCol!.getTag('aligned'), 'SEQ.MSA');
57
58
  expect(msaSeqCol!.getTag('alphabet'), 'PT');
58
- expect(msaSeqCol!.getTag('cell.renderer'), 'Macromolecule');
59
+ expect(msaSeqCol!.getTag('cell.renderer'), 'sequence');
59
60
 
60
61
  dfList.push(df);
61
62
  tvList.push(tv);
@@ -69,7 +70,7 @@ category('renderers', () => {
69
70
 
70
71
  const srcCol: DG.Column = df.col('sequence')!;
71
72
  const tgtCol: DG.Column = await convertDo(srcCol, NOTATION.SEPARATOR, '/');
72
- expect(tgtCol.getTag('cell.renderer'), 'Macromolecule');
73
+ expect(tgtCol.getTag('cell.renderer'), 'sequence');
73
74
 
74
75
  tvList.push(tv);
75
76
  dfList.push(df);
@@ -1,30 +1,35 @@
1
- import {after, before, category, test, expect} from '@datagrok-libraries/utils/src/test';
1
+ import {after, before, category, test, expect, delay} from '@datagrok-libraries/utils/src/test';
2
2
  import * as DG from 'datagrok-api/dg';
3
- import {sequenceSpace} from '../utils/sequence-space';
4
3
  import {readDataframe} from './utils';
5
4
  import * as grok from 'datagrok-api/grok';
5
+ import { _testSequenceSpaceReturnsResult } from './sequence-space-utils';
6
6
 
7
7
  category('sequenceSpace', async () => {
8
8
  let testFastaDf: DG.DataFrame;
9
+ let testFastaTableView: DG.TableView;
10
+ let testHelmWithEmptyRows: DG.DataFrame;
11
+ let testHelmWithEmptyRowsTableView: DG.TableView;
9
12
 
10
13
  before(async () => {
11
14
  testFastaDf = await readDataframe('samples/sample_FASTA.csv');
12
- // await grok.data.detectSemanticTypes(testFastaDf);
15
+ testFastaTableView = grok.shell.addTableView(testFastaDf);
16
+ testHelmWithEmptyRows = await readDataframe('samples/sample_HELM_empty_vals.csv');
17
+ testHelmWithEmptyRowsTableView = grok.shell.addTableView(testHelmWithEmptyRows);
13
18
  });
14
19
 
15
20
  after(async () => {
16
21
  grok.shell.closeTable(testFastaDf);
22
+ testFastaTableView.close();
23
+ grok.shell.closeTable(testHelmWithEmptyRows);
24
+ testHelmWithEmptyRowsTableView.close();
17
25
  });
18
26
 
19
27
  test('sequenceSpaceOpens', async () => {
20
- const sequenceSpaceParams = {
21
- seqCol: testFastaDf.col('Sequence')!,
22
- methodName: 't-SNE',
23
- similarityMetric: 'Levenshtein',
24
- embedAxesNames: ['Embed_X', 'Embed_Y']
25
- };
26
- const res = await sequenceSpace(sequenceSpaceParams);
27
- expect(res.coordinates != undefined, true);
28
- expect(res.distance != undefined, true);
28
+ await _testSequenceSpaceReturnsResult(testFastaDf, 'UMAP', 'Sequence');
29
29
  });
30
+
31
+ test('sequenceSpaceOpensWithEmptyRows', async () => {
32
+ await _testSequenceSpaceReturnsResult(testHelmWithEmptyRows, 'UMAP', 'HELM');
33
+ });
34
+
30
35
  });
@@ -0,0 +1,10 @@
1
+ import * as DG from 'datagrok-api/dg';
2
+ import * as grok from 'datagrok-api/grok';
3
+ import { expect } from '@datagrok-libraries/utils/src/test';
4
+ import { sequenceSpaceTopMenu } from '../package';
5
+
6
+ export async function _testSequenceSpaceReturnsResult(df: DG.DataFrame, algorithm: string, colName: string) {
7
+ await grok.data.detectSemanticTypes(df);
8
+ const sp = await sequenceSpaceTopMenu(df, df.col(colName)!, algorithm, 'Levenshtein', true);
9
+ expect(sp != null, true);
10
+ }
@@ -76,35 +76,45 @@ export function printLeftOrCentered(
76
76
  let textSize: any = g.measureText(colorPart + grayPart);
77
77
  const indent = 5;
78
78
 
79
+ let maxColorTextSize = g.measureText(colorPart).width;
79
80
  let colorTextSize = g.measureText(colorPart).width;
80
81
  const dy = (textSize.fontBoundingBoxAscent + textSize.fontBoundingBoxDescent) / 2;
81
82
  textSize = textSize.width;
82
83
  if (drawStyle === 'msa') {
83
- if (colorTextSize > maxWord) {
84
- maxWord[maxWordIdx] = colorTextSize;
84
+ maxColorTextSize = maxWord[maxWordIdx];
85
+ textSize = maxWord[maxWordIdx];
86
+ if (maxColorTextSize > maxWord) {
87
+ maxWord[maxWordIdx] = maxColorTextSize;
88
+ gridCell.cell.column.temp = maxWord;
89
+ }
90
+ if (maxWordIdx > (maxWord['bio-maxIndex'] ?? 0)) {
91
+ maxWord['bio-maxIndex'] = maxWordIdx;
85
92
  gridCell.cell.column.temp = maxWord;
86
93
  }
87
- colorTextSize = maxWord[maxWordIdx];
88
- textSize = maxWord[maxWordIdx];
89
94
  }
90
95
 
91
96
  function draw(dx1: number, dx2: number): void {
92
97
  g.fillStyle = color;
93
98
  g.globalAlpha = transparencyRate;
94
- g.fillText(colorPart, x + dx1, y + dy);
95
99
  if (drawStyle === 'classic') {
100
+ g.fillText(colorPart, x + dx1, y + dy);
96
101
  g.fillStyle = grayColor;
97
102
  g.fillText(grayPart, x + dx2, y + dy);
98
103
  }
104
+ if (drawStyle === 'msa') {
105
+ g.fillStyle = color;
106
+ g.fillText(colorPart, x + dx1 + ((maxWord[maxWordIdx] - colorTextSize) / 2), y + dy);
107
+ }
99
108
  }
100
109
 
101
110
  if (left || textSize > w) {
102
- draw(indent, indent + colorTextSize);
103
- return x + colorTextSize + g.measureText(grayPart).width;
111
+ draw(indent, indent + maxColorTextSize);
112
+ return x + maxColorTextSize + g.measureText(grayPart).width;
113
+
104
114
  } else {
105
115
  const dx = (w - textSize) / 2;
106
- draw(dx, dx + colorTextSize);
107
- return x + dx + colorTextSize;
116
+ draw(dx, dx + maxColorTextSize);
117
+ return x + dx + maxColorTextSize;
108
118
  }
109
119
  }
110
120
 
@@ -118,6 +128,45 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
118
128
 
119
129
  get defaultWidth(): number { return 230; }
120
130
 
131
+ onMouseMove(gridCell: DG.GridCell, e: MouseEvent): void {
132
+ if (gridCell.cell.column.getTag('aligned') !== 'SEQ.MSA') {
133
+ return;
134
+ }
135
+ const maxLengthWordsSum = gridCell.cell.column.temp['bio-sum-maxLengthWords'];
136
+ if (maxLengthWordsSum == null) {
137
+ gridCell.cell.column.setTag('.calculatedCellRender', 'unexist');
138
+ }
139
+ const maxIndex = gridCell.cell.column.temp['bio-maxIndex'];
140
+ //@ts-ignore
141
+ const argsX = e.layerX - gridCell.gridColumn.left - ((gridCell.bounds.x<0) ? gridCell.bounds.x : 0);
142
+ let left = 0;
143
+ let right = maxIndex;
144
+ let found = false;
145
+ maxLengthWordsSum[maxIndex + 1] = argsX + 1;
146
+ let mid = 0;
147
+ if (argsX > maxLengthWordsSum[0]) {
148
+ while (!found) {
149
+ mid = Math.floor((right + left) / 2);
150
+ if (argsX >= maxLengthWordsSum[mid] && argsX <= maxLengthWordsSum[mid + 1]) {
151
+ left = mid;
152
+ found = true;
153
+ } else if (argsX < maxLengthWordsSum[mid]) {
154
+ right = mid - 1;
155
+ } else if (argsX > maxLengthWordsSum[mid + 1]) {
156
+ left = mid + 1;
157
+ }
158
+ if (left == right) {
159
+ found = true;
160
+ }
161
+ }
162
+ }
163
+ left = (argsX >= maxLengthWordsSum[left]) ? left + 1 : left;
164
+ const separator = gridCell.cell.column.getTag('separator') ?? '';
165
+ const splitterFunc: SplitterFunc = WebLogo.getSplitter('separator', separator);
166
+ const subParts: string[] = splitterFunc(gridCell.cell.value);
167
+ ui.tooltip.show(ui.div(subParts[left]), e.x + 16, e.y + 16);
168
+ }
169
+
121
170
  /**
122
171
  * Cell renderer function.
123
172
  *
@@ -136,7 +185,6 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
136
185
  ): void {
137
186
  const grid = gridCell.gridRow !== -1 ? gridCell.grid : undefined;
138
187
  const cell = gridCell.cell;
139
- const tag = gridCell.cell.column.getTag(DG.TAGS.UNITS);
140
188
  const [type, subtype, paletteType] = gridCell.cell.column.getTag(DG.TAGS.UNITS).split(':');
141
189
  w = grid ? Math.min(grid.canvas.width - x, w) : g.canvas.width - x;
142
190
  g.save();
@@ -153,40 +201,46 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
153
201
  const palette = getPalleteByType(paletteType);
154
202
 
155
203
  const separator = gridCell.cell.column.getTag('separator') ?? '';
156
- const splitterFunc: SplitterFunc = WebLogo.getSplitter(units, gridCell.cell.column.getTag('separator'));
204
+ const splitterFunc: SplitterFunc = WebLogo.getSplitter(units, separator);
157
205
 
158
206
  const columns = gridCell.cell.column.categories;
159
207
  let monomerToShortFunction: (amino: string, maxLengthOfMonomer: number) => string = WebLogo.monomerToShort;
160
208
  let maxLengthOfMonomer = 8;
161
209
 
162
- let maxLengthWords = {};
163
- // check if gridCell.cell.column.temp is array
210
+ let maxLengthWords: any = {};
164
211
  if (gridCell.cell.column.getTag('.calculatedCellRender') !== 'exist') {
165
212
  for (let i = 0; i < columns.length; i++) {
166
213
  let subParts: string[] = splitterFunc(columns[i]);
167
214
  subParts.forEach((amino, index) => {
168
- //@ts-ignore
169
215
  let textSizeWidth = g.measureText(monomerToShortFunction(amino, maxLengthOfMonomer));
170
- //@ts-ignore
171
216
  if (textSizeWidth.width > (maxLengthWords[index] ?? 0)) {
172
- //@ts-ignore
173
217
  maxLengthWords[index] = textSizeWidth.width;
174
218
  }
219
+ if (index > (maxLengthWords['bio-maxIndex'] ?? 0)) {
220
+ maxLengthWords['bio-maxIndex'] = index;
221
+ }
175
222
  });
176
223
  }
177
- gridCell.cell.column.temp = maxLengthWords;
224
+ let maxLengthWordSum: any = {};
225
+ maxLengthWordSum[0] = maxLengthWords[0];
226
+ for (let i = 1; i <= maxLengthWords['bio-maxIndex']; i++) {
227
+ maxLengthWordSum[i] = maxLengthWordSum[i - 1] + maxLengthWords[i];
228
+ }
229
+ gridCell.cell.column.temp = {
230
+ 'bio-sum-maxLengthWords': maxLengthWordSum,
231
+ 'bio-maxIndex': maxLengthWords['bio-maxIndex'],
232
+ 'bio-maxLengthWords': maxLengthWords
233
+ };
178
234
  gridCell.cell.column.setTag('.calculatedCellRender', 'exist');
179
235
  } else {
180
- maxLengthWords = gridCell.cell.column.temp;
236
+ maxLengthWords = gridCell.cell.column.temp['bio-maxLengthWords'];
181
237
  }
182
238
 
183
239
  const subParts: string[] = splitterFunc(cell.value);
184
240
  let x1 = x;
185
241
  let color = undefinedColor;
186
- // get max length word in subParts
187
- let tagUnits = gridCell.cell.column.getTag(DG.TAGS.UNITS);
188
242
  let drawStyle = 'classic';
189
- if (tagUnits.includes('MSA')) {
243
+ if (gridCell.cell.column.getTag('aligned').includes('MSA')) {
190
244
  drawStyle = 'msa';
191
245
  }
192
246
  subParts.forEach((amino, index) => {
@@ -57,9 +57,15 @@ export async function runKalign(srcCol: DG.Column, isAligned = false, unUsedName
57
57
 
58
58
  // units
59
59
  const srcUnits = srcCol.getTag(DG.TAGS.UNITS);
60
- const tgtUnits = srcUnits.split(':').map((p, i) => i == 1 ? p + '.MSA' : p).join(':');
60
+ //aligned
61
+ const srcAligned = srcCol.getTag('aligned');
62
+ const tgtAligned = srcAligned + '.MSA';
63
+ //alphabet
64
+ const srcAlphabet = srcCol.getTag('alphabet');
61
65
 
62
- tgtCol.setTag(DG.TAGS.UNITS, tgtUnits);
66
+ tgtCol.setTag(DG.TAGS.UNITS, srcUnits);
67
+ tgtCol.setTag('aligned', tgtAligned);
68
+ tgtCol.setTag('alphabet', srcAlphabet);
63
69
  tgtCol.semType = DG.SEMTYPE.MACROMOLECULE;
64
70
  return tgtCol;
65
71
  }
@@ -51,6 +51,7 @@ export class VdRegionsViewer extends DG.JsViewer {
51
51
  public sequenceColumnNamePostfix: string;
52
52
 
53
53
  public skipEmptyPositions: boolean;
54
+ public positionWidth: number;
54
55
 
55
56
 
56
57
  public get df(): DG.DataFrame {
@@ -77,6 +78,7 @@ export class VdRegionsViewer extends DG.JsViewer {
77
78
  this.sequenceColumnNamePostfix = this.string('sequenceColumnNamePostfix', 'chain sequence');
78
79
 
79
80
  this.skipEmptyPositions = this.bool('skipEmptyPositions', false);
81
+ this.positionWidth = this.float('positionWidth', 16);
80
82
  }
81
83
 
82
84
  public async init() {
@@ -135,6 +137,10 @@ export class VdRegionsViewer extends DG.JsViewer {
135
137
  await this.destroyView();
136
138
  await this.buildView();
137
139
  break;
140
+ case 'positionWidth':
141
+ await this.destroyView();
142
+ await this.buildView();
143
+ break;
138
144
  }
139
145
  }
140
146
  }
@@ -205,6 +211,7 @@ export class VdRegionsViewer extends DG.JsViewer {
205
211
  endPositionName: region!.positionEndName,
206
212
  fixWidth: true,
207
213
  skipEmptyPositions: this.skipEmptyPositions,
214
+ positionWidth: this.positionWidth,
208
215
  })) as unknown as WebLogo;
209
216
  }
210
217
  // WebLogo creation fires onRootSizeChanged event even before control being added to this.logos
@@ -1,4 +1,4 @@
1
- <html><head><meta charset="utf-8"/><title>Bio Test Report. Datagrok version datagrok/datagrok:latest SHA=4f0c8bae6479. Commit 17115d45.</title><style type="text/css">html,
1
+ <html><head><meta charset="utf-8"/><title>Bio Test Report. Datagrok version datagrok/datagrok:latest SHA=dc07f068a0b2. Commit cdad4cfb.</title><style type="text/css">html,
2
2
  body {
3
3
  font-family: Arial, Helvetica, sans-serif;
4
4
  font-size: 1rem;
@@ -229,12 +229,12 @@ header {
229
229
  font-size: 1rem;
230
230
  padding: 0 0.5rem;
231
231
  }
232
- </style></head><body><div id="jesthtml-content"><header><h1 id="title">Bio Test Report. Datagrok version datagrok/datagrok:latest SHA=4f0c8bae6479. Commit 17115d45.</h1></header><div id="metadata-container"><div id="timestamp">Started: 2022-08-10 09:26:20</div><div id="summary"><div id="suite-summary"><div class="summary-total">Suites (1)</div><div class="summary-passed summary-empty">0 passed</div><div class="summary-failed">1 failed</div><div class="summary-pending summary-empty">0 pending</div></div><div id="test-summary"><div class="summary-total">Tests (1)</div><div class="summary-passed summary-empty">0 passed</div><div class="summary-failed">1 failed</div><div class="summary-pending summary-empty">0 pending</div></div></div></div><div id="suite-1" class="suite-container"><div class="suite-info"><div class="suite-path">/home/runner/work/public/public/packages/Bio/src/__jest__/remote.test.ts</div><div class="suite-time warn">239.746s</div></div><div class="suite-tests"><div class="test-result failed"><div class="test-info"><div class="test-suitename"> </div><div class="test-title">TEST</div><div class="test-status">failed</div><div class="test-duration">222.193s</div></div><div class="failureMessages"> <pre class="failureMsg">Error: Test result : Failed : Bio.renderers.afterMsa : Error: Expected "Macromolecule", got "null"
232
+ </style></head><body><div id="jesthtml-content"><header><h1 id="title">Bio Test Report. Datagrok version datagrok/datagrok:latest SHA=dc07f068a0b2. Commit cdad4cfb.</h1></header><div id="metadata-container"><div id="timestamp">Started: 2022-08-22 08:54:42</div><div id="summary"><div id="suite-summary"><div class="summary-total">Suites (1)</div><div class="summary-passed summary-empty">0 passed</div><div class="summary-failed">1 failed</div><div class="summary-pending summary-empty">0 pending</div></div><div id="test-summary"><div class="summary-total">Tests (1)</div><div class="summary-passed summary-empty">0 passed</div><div class="summary-failed">1 failed</div><div class="summary-pending summary-empty">0 pending</div></div></div></div><div id="suite-1" class="suite-container"><div class="suite-info"><div class="suite-path">/home/runner/work/public/public/packages/Bio/src/__jest__/remote.test.ts</div><div class="suite-time warn">251.573s</div></div><div class="suite-tests"><div class="test-result failed"><div class="test-info"><div class="test-suitename"> </div><div class="test-title">TEST</div><div class="test-status">failed</div><div class="test-duration">237.85s</div></div><div class="failureMessages"> <pre class="failureMsg">Error: Test result : Failed : Bio.detectors.samplesHelmCsvHELM : Error: Expected "HELM", got "helm"
233
+ Test result : Failed : Bio.detectors.samplesTestHelmPositiveHelmString : Error: Expected "HELM", got "helm"
233
234
 
234
235
  at /home/runner/work/public/public/packages/Bio/src/__jest__/remote.test.ts:67:20
235
236
  at Generator.next (&lt;anonymous&gt;)
236
237
  at fulfilled (/home/runner/work/public/public/packages/Bio/src/__jest__/remote.test.ts:31:58)
237
- at runMicrotasks (&lt;anonymous&gt;)
238
238
  at processTicksAndRejections (internal/process/task_queues.js:97:5)</pre></div></div></div><div class="suite-consolelog"><div class="suite-consolelog-header">Console Log</div><div class="suite-consolelog-item"><pre class="suite-consolelog-item-origin"> at Object.&lt;anonymous&gt; (/home/runner/work/public/public/packages/Bio/src/__jest__/test-node.ts:63:11)
239
239
  at Generator.next (&lt;anonymous&gt;)
240
240
  at fulfilled (/home/runner/work/public/public/packages/Bio/src/__jest__/test-node.ts:28:58)
@@ -248,7 +248,6 @@ header {
248
248
  at new Promise (&lt;anonymous&gt;)</pre><pre class="suite-consolelog-item-message">Testing Bio package</pre></div><div class="suite-consolelog-item"><pre class="suite-consolelog-item-origin"> at /home/runner/work/public/public/packages/Bio/src/__jest__/remote.test.ts:65:11
249
249
  at Generator.next (&lt;anonymous&gt;)
250
250
  at fulfilled (/home/runner/work/public/public/packages/Bio/src/__jest__/remote.test.ts:31:58)
251
- at runMicrotasks (&lt;anonymous&gt;)
252
251
  at processTicksAndRejections (internal/process/task_queues.js:97:5)</pre><pre class="suite-consolelog-item-message">Test result : Success : Bio.WebLogo.testGetStats : OK
253
252
  Test result : Success : Bio.WebLogo.testGetAlphabetSimilarity : OK
254
253
  Test result : Success : Bio.WebLogo.testPickupPaletteN1 : OK
@@ -290,11 +289,9 @@ Test result : Success : Bio.detectors.samplesMsaComplexUn : OK
290
289
  Test result : Success : Bio.detectors.samplesMsaComplexNegativeActivity : OK
291
290
  Test result : Success : Bio.detectors.samplesIdCsvNegativeID : OK
292
291
  Test result : Success : Bio.detectors.samplesSarSmallCsvNegativeSmiles : OK
293
- Test result : Success : Bio.detectors.samplesHelmCsvHELM : OK
294
292
  Test result : Success : Bio.detectors.samplesHelmCsvNegativeActivity : OK
295
293
  Test result : Success : Bio.detectors.samplesTestHelmNegativeID : OK
296
294
  Test result : Success : Bio.detectors.samplesTestHelmNegativeTestType : OK
297
- Test result : Success : Bio.detectors.samplesTestHelmPositiveHelmString : OK
298
295
  Test result : Success : Bio.detectors.samplesTestHelmNegativeValid : OK
299
296
  Test result : Success : Bio.detectors.samplesTestHelmNegativeMolWeight : OK
300
297
  Test result : Success : Bio.detectors.samplesTestHelmNegativeMolFormula : OK
@@ -316,13 +313,16 @@ Test result : Success : Bio.detectors.samplesTestAlertCollectionNegativeSmarts :
316
313
  Test result : Success : Bio.MSA.isCorrect : OK
317
314
  Test result : Success : Bio.MSA.isCorrectLong : OK
318
315
  Test result : Success : Bio.sequenceSpace.sequenceSpaceOpens : OK
316
+ Test result : Success : Bio.sequenceSpace.sequenceSpaceOpensWithEmptyRows : OK
319
317
  Test result : Success : Bio.activityCliffs.activityCliffsOpen : OK
318
+ Test result : Success : Bio.activityCliffs.activityCliffsOpenWithEmptyRows : OK
320
319
  Test result : Success : Bio.splitters.helm1 : OK
321
320
  Test result : Success : Bio.splitters.helm2 : OK
322
321
  Test result : Success : Bio.splitters.helm3-multichar : OK
323
322
  Test result : Success : Bio.splitters.testHelm1 : OK
324
323
  Test result : Success : Bio.splitters.testHelm2 : OK
325
324
  Test result : Success : Bio.splitters.testHelm3 : OK
325
+ Test result : Success : Bio.renderers.afterMsa : OK
326
326
  Test result : Success : Bio.renderers.afterConvert : OK
327
327
  Test result : Success : Bio.converters.testFastaPtToSeparator : OK
328
328
  Test result : Success : Bio.converters.testFastaDnaToSeparator : OK