@datagrok/bio 1.7.22 → 1.7.23

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/package.json CHANGED
@@ -2,7 +2,11 @@
2
2
  "name": "@datagrok/bio",
3
3
  "beta": false,
4
4
  "friendlyName": "Bio",
5
- "version": "1.7.22",
5
+ "author": {
6
+ "name": "Leonid Stolbov",
7
+ "email": "lstolbov@datagrok.ai"
8
+ },
9
+ "version": "1.7.23",
6
10
  "description": "Bio is a [package](https://datagrok.ai/help/develop/develop#packages) for the [Datagrok](https://datagrok.ai) platform",
7
11
  "repository": {
8
12
  "type": "git",
@@ -11,7 +15,7 @@
11
15
  },
12
16
  "dependencies": {
13
17
  "@biowasm/aioli": ">=2.4.0",
14
- "@datagrok-libraries/bio": "^3.0.0",
18
+ "@datagrok-libraries/bio": "^3.0.2",
15
19
  "@datagrok-libraries/ml": "^3.0.0",
16
20
  "@datagrok-libraries/utils": "^1.4.0",
17
21
  "cash-dom": "latest",
@@ -11,6 +11,7 @@ import './tests/activity-cliffs-tests';
11
11
  import './tests/splitters-test';
12
12
  import './tests/renderers-test';
13
13
  import './tests/convert-test';
14
+ import './tests/fasta-handler-test';
14
15
  import './tests/WebLogo-positions-test';
15
16
 
16
17
  export const _package = new DG.Package();
package/src/package.ts CHANGED
@@ -5,7 +5,7 @@ import * as DG from 'datagrok-api/dg';
5
5
 
6
6
  export const _package = new DG.Package();
7
7
 
8
- import {AlignedSequenceDifferenceCellRenderer, AminoAcidsCellRenderer} from './utils/cell-renderer';
8
+ import {MacromoleculeDifferenceCellRenderer, MonomerCellRenderer} from './utils/cell-renderer';
9
9
  import {WebLogo, SeqColStats} from '@datagrok-libraries/bio/src/viewers/web-logo';
10
10
  import {VdRegionsViewer} from './viewers/vd-regions-viewer';
11
11
  import {runKalign, testMSAEnoughMemory} from './utils/multiple-sequence-alignment';
@@ -241,6 +241,14 @@ export async function multipleSequenceAlignmentAny(table: DG.DataFrame, col: DG.
241
241
  return msaCol;
242
242
  }
243
243
 
244
+ //name: Bio | MSA
245
+ //tags: bio, panel
246
+ //input: column sequence { semType: Macromolecule }
247
+ //output: column result
248
+ export async function panelMSA(col: DG.Column): Promise<DG.Column | null> {
249
+ return multipleSequenceAlignmentAny(col.dataFrame, col);
250
+ }
251
+
244
252
  //name: Composition Analysis
245
253
  //top-menu: Bio | Composition Analysis
246
254
  //output: viewer result
@@ -334,20 +342,20 @@ export function convertPanel(col: DG.Column): void {
334
342
  convert(col);
335
343
  }
336
344
 
337
- //name: aminoAcidsCellRenderer
345
+ //name: monomerCellRenderer
338
346
  //tags: cellRenderer
339
- //meta.cellType: aminoAcids
347
+ //meta.cellType: Monomer
340
348
  //output: grid_cell_renderer result
341
- export function aminoAcidsCellRenderer(): AminoAcidsCellRenderer {
342
- return new AminoAcidsCellRenderer();
349
+ export function monomerCellRenderer(): MonomerCellRenderer {
350
+ return new MonomerCellRenderer();
343
351
  }
344
352
 
345
- //name: alignedSequenceDifferenceCellRenderer
353
+ //name: MacromoleculeDifferenceCellRenderer
346
354
  //tags: cellRenderer
347
- //meta.cellType: alignedSequenceDifference
355
+ //meta.cellType: MacromoleculeDifference
348
356
  //output: grid_cell_renderer result
349
- export function alignedSequenceDifferenceCellRenderer(): AlignedSequenceDifferenceCellRenderer {
350
- return new AlignedSequenceDifferenceCellRenderer();
357
+ export function macromoleculeDifferenceCellRenderer(): MacromoleculeDifferenceCellRenderer {
358
+ return new MacromoleculeDifferenceCellRenderer();
351
359
  }
352
360
 
353
361
  //name: testDetectMacromolecule
@@ -1,13 +1,14 @@
1
+
1
2
  import {after, before, category, test, expect, expectObject} from '@datagrok-libraries/utils/src/test';
2
3
 
3
4
  import * as grok from 'datagrok-api/grok';
4
5
  import * as ui from 'datagrok-api/ui';
5
6
  import * as DG from 'datagrok-api/dg';
6
7
  import {PositionInfo, PositionMonomerInfo, WebLogo} from '@datagrok-libraries/bio/src/viewers/web-logo';
7
-
8
8
  category('WebLogo-positions', () => {
9
9
  let tvList: DG.TableView[];
10
10
  let dfList: DG.DataFrame[];
11
+ let currentView: DG.View;
11
12
 
12
13
  const csvDf1 = `seq
13
14
  ATC-G-TTGC--
@@ -22,13 +23,14 @@ category('WebLogo-positions', () => {
22
23
  before(async () => {
23
24
  tvList = [];
24
25
  dfList = [];
26
+ currentView = grok.shell.tv;
25
27
  });
26
28
 
27
29
  after(async () => {
28
- dfList.forEach((df: DG.DataFrame) => { grok.shell.closeTable(df); });
30
+ dfList.forEach((df: DG.DataFrame) => { grok.shell.closeTable(df);});
29
31
  tvList.forEach((tv: DG.TableView) => tv.close());
32
+ currentView = grok.shell.tv;
30
33
  });
31
-
32
34
  test('allPositions', async () => {
33
35
  const df: DG.DataFrame = DG.DataFrame.fromCsv(csvDf1);
34
36
  const tv: DG.TableView = grok.shell.addTableView(df);
@@ -55,12 +57,82 @@ category('WebLogo-positions', () => {
55
57
  new PositionInfo('11', {'-': new PositionMonomerInfo(5)}),
56
58
  new PositionInfo('12', {'-': new PositionMonomerInfo(5)})
57
59
  ];
60
+ console.log(positions);
61
+ expect(positions.length,resAllDf1.length);
58
62
  // check all positions are equal resAllDf1
59
63
  for (let i = 0; i < positions.length; i++) {
60
64
  expect(positions[i].name, resAllDf1[i].name);
61
- for (const key in positions[i].freq) {
62
- expect(positions[i].freq[key].count, resAllDf1[i].freq[key].count);
63
- }
65
+ for (const key in positions[i].freq) {
66
+ expect(positions[i].freq[key].count, resAllDf1[i].freq[key].count);
67
+ }
68
+ }
69
+
70
+ });
71
+ test('positions with shrinkEmptyTail option', async () => {
72
+ const df: DG.DataFrame = DG.DataFrame.fromCsv(csvDf1);
73
+ const tv: DG.TableView = grok.shell.addTableView(df);
74
+
75
+ const wlViewer: WebLogo = await df.plot.fromType('WebLogo', {'shrinkEmptyTail': true}) as unknown as WebLogo;
76
+ tv.dockManager.dock(wlViewer.root, DG.DOCK_TYPE.DOWN);
77
+
78
+ tvList.push(tv);
79
+ dfList.push(df);
80
+
81
+ const positions: PositionInfo[] = wlViewer['positions'];
82
+
83
+ const resAllDf1: PositionInfo[] = [
84
+ new PositionInfo('1', {'A': new PositionMonomerInfo(2), '-': new PositionMonomerInfo(3)}),
85
+ new PositionInfo('2', {'T': new PositionMonomerInfo(5)}),
86
+ new PositionInfo('3', {'C': new PositionMonomerInfo(5)}),
87
+ new PositionInfo('4', {'-': new PositionMonomerInfo(5)}),
88
+ new PositionInfo('5', {'G': new PositionMonomerInfo(5)}),
89
+ new PositionInfo('6', {'-': new PositionMonomerInfo(3), 'C': new PositionMonomerInfo(2)}),
90
+ new PositionInfo('7', {'T': new PositionMonomerInfo(5)}),
91
+ new PositionInfo('8', {'T': new PositionMonomerInfo(5)}),
92
+ new PositionInfo('9', {'G': new PositionMonomerInfo(5)}),
93
+ new PositionInfo('10', {'C': new PositionMonomerInfo(5)})
94
+ ];
95
+
96
+ console.log(positions);
97
+ for (let i = 0; i < positions.length; i++) {
98
+ expect(positions[i].name, resAllDf1[i].name);
99
+ for (const key in positions[i].freq) {
100
+ expect(positions[i].freq[key].count, resAllDf1[i].freq[key].count);
101
+ }
102
+ }
103
+
104
+ });
105
+
106
+ test('positions with skipEmptyPositions option', async () => {
107
+ const df: DG.DataFrame = DG.DataFrame.fromCsv(csvDf1);
108
+ const tv: DG.TableView = grok.shell.addTableView(df);
109
+
110
+ const wlViewer: WebLogo = await df.plot.fromType('WebLogo', {'skipEmptyPositions': false}) as unknown as WebLogo;
111
+ tv.dockManager.dock(wlViewer.root, DG.DOCK_TYPE.DOWN);
112
+
113
+ tvList.push(tv);
114
+ dfList.push(df);
115
+
116
+ const positions: PositionInfo[] = wlViewer['positions'];
117
+
118
+ const resAllDf1: PositionInfo[] = [
119
+ new PositionInfo('1', {'A': new PositionMonomerInfo(2), '-': new PositionMonomerInfo(3)}),
120
+ new PositionInfo('2', {'T': new PositionMonomerInfo(5)}),
121
+ new PositionInfo('3', {'C': new PositionMonomerInfo(5)}),
122
+ new PositionInfo('5', {'G': new PositionMonomerInfo(5)}),
123
+ new PositionInfo('6', {'-': new PositionMonomerInfo(3), 'C': new PositionMonomerInfo(2)}),
124
+ new PositionInfo('7', {'T': new PositionMonomerInfo(5)}),
125
+ new PositionInfo('8', {'T': new PositionMonomerInfo(5)}),
126
+ new PositionInfo('9', {'G': new PositionMonomerInfo(5)}),
127
+ new PositionInfo('10', {'C': new PositionMonomerInfo(5)})
128
+ ];
129
+ console.log(positions);
130
+
131
+ for (let i = 0; i < positions.length; i++) {
132
+ expect(positions[i].name, resAllDf1[i].name);
133
+ for (const key in positions[i].freq) {
134
+ expect(positions[i].freq[key].count, resAllDf1[i].freq[key].count);
135
+ }
64
136
  }
65
137
 
66
138
  });
@@ -146,3 +146,4 @@ export async function _testPickupPaletteAA2(dfAA2: DG.DataFrame) {
146
146
 
147
147
  expect(cp instanceof AminoacidsPalettes, true);
148
148
  }
149
+
@@ -0,0 +1,141 @@
1
+ /* Do not change these import lines to match external modules in webpack configuration */
2
+ import * as grok from 'datagrok-api/grok';
3
+ import * as ui from 'datagrok-api/ui';
4
+ import * as DG from 'datagrok-api/dg';
5
+
6
+ import {category, expectArray, test} from '@datagrok-libraries/utils/src/test';
7
+ import {FastaFileHandler} from '@datagrok-libraries/bio/src/utils/fasta-handler';
8
+ import {UnitsHandler} from '@datagrok-libraries/bio/src/utils/units-handler';
9
+
10
+
11
+ category('fastaFileHandler', () => {
12
+ const fastaNormalFormatting = `>description:1
13
+ MDYKETLLMPKTDFPMRGGLPNKEPQIQEKW
14
+
15
+ >description:2
16
+ MIEVFLFGIVLGLIPITLAGLFVTAYLQYRRGDQLDL
17
+
18
+ >description:3
19
+ MMELVLKTIIGPIVVGVVLRIVDKWLNKDK
20
+
21
+ >description:4
22
+ MDRTDEVSNHTHDKPTLTWFEEIFEEYHSPFHN
23
+ `;
24
+
25
+ const fastaExtraSpaces = `>description:1
26
+ MDYKETLLMPKTDFPMRGGLPNKEPQIQEKW
27
+
28
+ >description:2
29
+ MI EVF LFGIVLGLI PITLAGLFVTAY LQYRRGDQLDL
30
+
31
+ >description:3
32
+ M MELVLKTI IGPI VVGVVLR IVDKWLNKDK
33
+
34
+ >description:4
35
+ MDR TDEVSNHTHDKP TLTWFEEIFEEYHSPFHN
36
+ `;
37
+
38
+ const fastaExtraNewlines = `>description:1
39
+
40
+ MDYKETLLMPKTDFPMRGGLPNKEPQIQEKW
41
+
42
+ >description:2
43
+ MIEVF
44
+ LFGIVLGLI
45
+ PITLAGLFVTA
46
+ YLQYRRGDQLDL
47
+
48
+ >description:3
49
+ M
50
+ ME
51
+
52
+ LVLKTIIG
53
+
54
+ PIVVGVVLRI
55
+ VDKWLNKDK
56
+
57
+
58
+ >description:4
59
+
60
+ MDRT
61
+
62
+ DEVSNHTHDKP
63
+
64
+ TLTWFEEIFEE
65
+
66
+
67
+
68
+ YHSPFHN
69
+ `;
70
+ // a "broken" fasta file
71
+ // const fastaBroken = `
72
+
73
+ // >description:1
74
+ // MDYKETLLM
75
+ // PKTDFPMRGGLPN
76
+ // KEPQIQEKW
77
+
78
+
79
+
80
+ // >description:2
81
+ // MIEVFL FGIVLGLIPI TLAGLFVTAYLQYRRGDQLDL
82
+
83
+ // >description:3
84
+
85
+ // M
86
+ // MELVLKTIIGP
87
+ // IVVGVVLR
88
+ // IVDKWLNKD
89
+
90
+ // K
91
+
92
+ // >description:4
93
+ // MDRTDEV
94
+
95
+ // SNHTHDKP
96
+ // TLTWFEEI
97
+ // FEE
98
+
99
+ // YHSPFHN
100
+
101
+
102
+ // `;
103
+
104
+ const descriptionsArray = [
105
+ 'description:1', 'description:2', 'description:3', 'description:4',
106
+ ];
107
+ const descriptionCol = DG.Column.fromStrings('description', descriptionsArray);
108
+
109
+ const sequencesArray = [
110
+ 'MDYKETLLMPKTDFPMRGGLPNKEPQIQEKW',
111
+ 'MIEVFLFGIVLGLIPITLAGLFVTAYLQYRRGDQLDL',
112
+ 'MMELVLKTIIGPIVVGVVLRIVDKWLNKDK',
113
+ 'MDRTDEVSNHTHDKPTLTWFEEIFEEYHSPFHN',
114
+ ];
115
+ const sequencesCol = DG.Column.fromStrings('sequence', sequencesArray);
116
+ sequencesCol.semType = DG.SEMTYPE.MACROMOLECULE;
117
+ UnitsHandler.setUnitsToFastaColumn(sequencesCol);
118
+
119
+ const fastaDf = DG.DataFrame.fromColumns([descriptionCol, sequencesCol]);
120
+
121
+ function _testColumnsParser(inputFasta: string) {
122
+ const ffh = new FastaFileHandler(inputFasta);
123
+ const parsedDescriptionsArray = ffh.descriptionsArray;
124
+ const parsedSequencesArray = ffh.sequencesArray;
125
+ expectArray(
126
+ [parsedDescriptionsArray, parsedSequencesArray],
127
+ [descriptionsArray, sequencesArray]
128
+ );
129
+ }
130
+
131
+ // test parser
132
+ test('testNormalFormatting', async () => {
133
+ _testColumnsParser(fastaNormalFormatting);
134
+ });
135
+ test('testExtraSpaces', async () => {
136
+ _testColumnsParser(fastaExtraSpaces);
137
+ });
138
+ test('testExtraNewlines', async () => {
139
+ _testColumnsParser(fastaExtraNewlines);
140
+ });
141
+ });
@@ -2,7 +2,7 @@ import * as C from './constants';
2
2
  import * as DG from 'datagrok-api/dg';
3
3
  import {AminoacidsPalettes} from '@datagrok-libraries/bio/src/aminoacids';
4
4
  import {NucleotidesPalettes} from '@datagrok-libraries/bio/src/nucleotides';
5
- import {UnknownSeqPalettes} from '@datagrok-libraries/bio/src/unknown';
5
+ import {UnknownSeqPalette, UnknownSeqPalettes} from '@datagrok-libraries/bio/src/unknown';
6
6
  import {SplitterFunc, WebLogo} from '@datagrok-libraries/bio/src/viewers/web-logo';
7
7
  import {SeqPalette} from '@datagrok-libraries/bio/src/seq-palettes';
8
8
  import * as ui from 'datagrok-api/ui';
@@ -44,6 +44,7 @@ export function processSequence(subParts: string[]): [string[], boolean] {
44
44
  return [text, simplified];
45
45
  }
46
46
 
47
+
47
48
  /**
48
49
  * A function that prints a string aligned to left or centered.
49
50
  *
@@ -65,33 +66,46 @@ function printLeftOrCentered(
65
66
  x: number, y: number, w: number, h: number,
66
67
  g: CanvasRenderingContext2D, s: string, color = undefinedColor,
67
68
  pivot: number = 0, left = false, transparencyRate: number = 1.0,
68
- separator: string = '', last: boolean = false): number {
69
+ separator: string = '', last: boolean = false, drawStyle: string = 'classic', maxWord:any={}, maxWordIdx:number=0, gridCell:any = {}): number {
69
70
  g.textAlign = 'start';
70
71
  const colorPart = s.substring(0);
71
- let grayPart = last ? '' : separator;
72
+ let grayPart = last ? '' : separator;
73
+ if (drawStyle === 'msa') {
74
+ grayPart = ' ';
75
+ }
72
76
 
73
- const textSize = g.measureText(colorPart + grayPart);
77
+ let textSize: any = g.measureText(colorPart + grayPart);
74
78
  const indent = 5;
75
79
 
76
- const colorTextSize = g.measureText(colorPart);
80
+ let colorTextSize = g.measureText(colorPart).width;
77
81
  const dy = (textSize.fontBoundingBoxAscent + textSize.fontBoundingBoxDescent) / 2;
82
+ textSize = textSize.width;
83
+ if (drawStyle === 'msa') {
84
+ if (colorTextSize > maxWord) {
85
+ maxWord[maxWordIdx] = colorTextSize;
86
+ gridCell.cell.column.temp = maxWord;
87
+ }
88
+ colorTextSize = maxWord[maxWordIdx];
89
+ textSize = maxWord[maxWordIdx];
90
+ }
78
91
 
79
92
  function draw(dx1: number, dx2: number): void {
80
93
  g.fillStyle = color;
81
94
  g.globalAlpha = transparencyRate;
82
95
  g.fillText(colorPart, x + dx1, y + dy);
83
- g.fillStyle = grayColor;
84
- g.fillText(grayPart, x + dx2, y + dy);
96
+ if (drawStyle === 'classic') {
97
+ g.fillStyle = grayColor;
98
+ g.fillText(grayPart, x + dx2, y + dy);
99
+ }
85
100
  }
86
101
 
87
-
88
- if (left || textSize.width > w) {
89
- draw(indent, indent + colorTextSize.width);
90
- return x + colorTextSize.width + g.measureText(grayPart).width;
102
+ if (left || textSize > w) {
103
+ draw(indent, indent + colorTextSize);
104
+ return x + colorTextSize + g.measureText(grayPart).width;
91
105
  } else {
92
- const dx = (w - textSize.width) / 2;
93
- draw(dx, dx + colorTextSize.width);
94
- return x + dx + colorTextSize.width;
106
+ const dx = (w - textSize) / 2;
107
+ draw(dx, dx + colorTextSize);
108
+ return x + dx + colorTextSize;
95
109
  }
96
110
  }
97
111
 
@@ -114,7 +128,7 @@ function findMonomers(helmString: string) {
114
128
  export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
115
129
  get name(): string { return 'macromoleculeSequence'; }
116
130
 
117
- get cellType(): string { return C.SEM_TYPES.Macro_Molecule; }
131
+ get cellType(): string { return C.SEM_TYPES.MACROMOLECULE; }
118
132
 
119
133
  get defaultHeight(): number { return 30; }
120
134
 
@@ -198,15 +212,51 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
198
212
  const separator = gridCell.cell.column.getTag('separator') ?? '';
199
213
  const splitterFunc: SplitterFunc = WebLogo.getSplitter(units, gridCell.cell.column.getTag('separator'));
200
214
 
215
+ // обработка новых елементов
216
+ const columns = gridCell.cell.column.categories;
217
+ let maxLengthWords = {};
218
+ // check if gridCell.cell.column.temp is array
219
+ if (gridCell.cell.column.getTag('.calculatedCellRender') !== 'exist') {
220
+ for (let i = 0; i < columns.length; i++) {
221
+ let subParts: string[] = splitterFunc(columns[i]);
222
+ subParts.forEach((amino, index) => {
223
+ //@ts-ignore
224
+ let textSizeWidth = g.measureText(WebLogo.monomerToText(amino) + ' ');
225
+ //@ts-ignore
226
+ if (textSizeWidth.width > (maxLengthWords[index] ?? 0)) {
227
+ //@ts-ignore
228
+ maxLengthWords[index] = textSizeWidth.width;
229
+ }
230
+ });
231
+ }
232
+ gridCell.cell.column.temp = maxLengthWords;
233
+ gridCell.cell.column.setTag('.calculatedCellRender', 'exist');
234
+ } else {
235
+ maxLengthWords = gridCell.cell.column.temp;
236
+ }
237
+
201
238
  const subParts: string[] = splitterFunc(cell.value);
202
- // console.log(subParts);
203
239
  let x1 = x;
204
240
  let color = undefinedColor;
241
+ // get max length word in subParts
242
+ let tagUnits = gridCell.cell.column.getTag(DG.TAGS.UNITS);
243
+ let maxLength = 0;
244
+ let maxWord = '';
245
+ let drawStyle = 'classic';
246
+ if (tagUnits.includes('MSA')) {
247
+ subParts.forEach(part => {
248
+ if (part.length > maxLength) {
249
+ maxLength = part.length;
250
+ maxWord = part;
251
+ drawStyle = 'msa';
252
+ }
253
+ });
254
+ }
205
255
  subParts.forEach((amino, index) => {
206
256
  color = palette.get(amino);
207
257
  g.fillStyle = undefinedColor;
208
258
  let last = index === subParts.length - 1;
209
- x1 = printLeftOrCentered(x1, y, w, h, g, amino, color, 0, true, 1.0, separator, last);
259
+ x1 = printLeftOrCentered(x1, y, w, h, g, WebLogo.monomerToText(amino), color, 0, true, 1.0, separator, last, drawStyle, maxLengthWords, index, gridCell);
210
260
  });
211
261
 
212
262
  g.restore();
@@ -215,11 +265,10 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
215
265
  }
216
266
  }
217
267
 
268
+ export class MonomerCellRenderer extends DG.GridCellRenderer {
269
+ get name(): string {return 'MonomerCR';}
218
270
 
219
- export class AminoAcidsCellRenderer extends DG.GridCellRenderer {
220
- get name(): string {return 'aminoAcidsCR';}
221
-
222
- get cellType(): string {return C.SEM_TYPES.AMINO_ACIDS;}
271
+ get cellType(): string {return C.SEM_TYPES.MONOMER;}
223
272
 
224
273
  get defaultHeight(): number {return 15;}
225
274
 
@@ -256,10 +305,10 @@ export class AminoAcidsCellRenderer extends DG.GridCellRenderer {
256
305
  }
257
306
  }
258
307
 
259
- export class AlignedSequenceDifferenceCellRenderer extends DG.GridCellRenderer {
260
- get name(): string {return 'alignedSequenceDifferenceCR';}
308
+ export class MacromoleculeDifferenceCellRenderer extends DG.GridCellRenderer {
309
+ get name(): string {return 'MacromoleculeDifferenceCR';}
261
310
 
262
- get cellType(): string {return C.SEM_TYPES.ALIGNED_SEQUENCE_DIFFERENCE;}
311
+ get cellType(): string {return C.SEM_TYPES.MACROMOLECULE_DIFFERENCE;}
263
312
 
264
313
  get defaultHeight(): number {return 30;}
265
314
 
@@ -295,23 +344,28 @@ export class AlignedSequenceDifferenceCellRenderer extends DG.GridCellRenderer {
295
344
  //TODO: can this be replaced/merged with splitSequence?
296
345
  const [s1, s2] = s.split('#');
297
346
  const separator = gridCell.tableColumn!.tags[C.TAGS.SEPARATOR];
298
- const subParts1 = s1.split(separator);
299
- const subParts2 = s2.split(separator);
347
+ const units: string = gridCell.tableColumn!.tags[DG.TAGS.UNITS];
348
+ const splitter = WebLogo.getSplitter(units, separator);
349
+ const subParts1 = splitter(s1);
350
+ const subParts2 = splitter(s2);
300
351
  const [text] = processSequence(subParts1);
301
352
  const textSize = g.measureText(text.join(''));
302
353
  let updatedX = Math.max(x, x + (w - (textSize.width + subParts1.length * 4)) / 2);
303
354
  // 28 is the height of the two substitutions on top of each other + space
304
355
  const updatedY = Math.max(y, y + (h - 28) / 2);
305
356
 
306
- const palette = getPalleteByType(gridCell.tableColumn!.tags[C.TAGS.ALPHABET]);
357
+ let palette: SeqPalette = UnknownSeqPalettes.Color;
358
+ if (units != 'HELM')
359
+ palette = getPalleteByType(units.substring(units.length - 2));
360
+
361
+ const vShift = 7;
307
362
  for (let i = 0; i < subParts1.length; i++) {
308
363
  const amino1 = subParts1[i];
309
364
  const amino2 = subParts2[i];
310
365
  const color1 = palette.get(amino1);
311
- const color2 = palette.get(amino2);
312
366
 
313
367
  if (amino1 != amino2) {
314
- const vShift = 7;
368
+ const color2 = palette.get(amino2);
315
369
  const subX0 = printLeftOrCentered(updatedX, updatedY - vShift, w, h, g, amino1, color1, 0, true);
316
370
  const subX1 = printLeftOrCentered(updatedX, updatedY + vShift, w, h, g, amino2, color2, 0, true);
317
371
  updatedX = Math.max(subX1, subX0);
@@ -23,12 +23,11 @@ export enum TAGS {
23
23
  }
24
24
 
25
25
  export enum SEM_TYPES {
26
- AMINO_ACIDS = 'aminoAcids',
27
- ALIGNED_SEQUENCE = 'alignedSequence',
28
- ALIGNED_SEQUENCE_DIFFERENCE = 'alignedSequenceDifference',
26
+ MONOMER = 'Monomer',
27
+ MACROMOLECULE_DIFFERENCE = 'MacromoleculeDifference',
29
28
  ACTIVITY = 'activity',
30
29
  ACTIVITY_SCALED = 'activityScaled',
31
- Macro_Molecule = 'Macromolecule',
30
+ MACROMOLECULE = 'Macromolecule',
32
31
  }
33
32
 
34
33
  export const STATS = 'stats';
@@ -50,6 +50,9 @@ export class VdRegionsViewer extends DG.JsViewer {
50
50
  public chains: string[];
51
51
  public sequenceColumnNamePostfix: string;
52
52
 
53
+ public skipEmptyPositions: boolean;
54
+
55
+
53
56
  public get df(): DG.DataFrame {
54
57
  return this.dataFrame;
55
58
  }
@@ -72,6 +75,8 @@ export class VdRegionsViewer extends DG.JsViewer {
72
75
  this.chains = this.stringList('chains', ['Heavy', 'Light'],
73
76
  {choices: ['Heavy', 'Light']});
74
77
  this.sequenceColumnNamePostfix = this.string('sequenceColumnNamePostfix', 'chain sequence');
78
+
79
+ this.skipEmptyPositions = this.bool('skipEmptyPositions', false);
75
80
  }
76
81
 
77
82
  public async init() {
@@ -119,6 +124,17 @@ export class VdRegionsViewer extends DG.JsViewer {
119
124
  break;
120
125
  case 'sequenceColumnNamePostfix':
121
126
  break;
127
+ case 'skipEmptyPositions':
128
+ // for (let orderI = 0; orderI < this.logos.length; orderI++) {
129
+ // for (let chainI = 0; chainI < this.chains.length; chainI++) {
130
+ // const chain: string = this.chains[chainI];
131
+ // this.logos[orderI][chain].setOptions({skipEmptyPositions: this.skipEmptyPositions});
132
+ // }
133
+ // }
134
+ // this.calcSize();
135
+ await this.destroyView();
136
+ await this.buildView();
137
+ break;
122
138
  }
123
139
  }
124
140
  }
@@ -188,6 +204,7 @@ export class VdRegionsViewer extends DG.JsViewer {
188
204
  startPositionName: region!.positionStartName,
189
205
  endPositionName: region!.positionEndName,
190
206
  fixWidth: true,
207
+ skipEmptyPositions: this.skipEmptyPositions,
191
208
  })) as unknown as WebLogo;
192
209
  }
193
210
  // 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 dd77efbc.</title><style type="text/css">html,
1
+ <html><head><meta charset="utf-8"/><title>Bio Test Report. Datagrok version datagrok/datagrok:latest SHA=4f0c8bae6479. Commit 5b129baa.</title><style type="text/css">html,
2
2
  body {
3
3
  font-family: Arial, Helvetica, sans-serif;
4
4
  font-size: 1rem;
@@ -229,7 +229,13 @@ 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 dd77efbc.</h1></header><div id="metadata-container"><div id="timestamp">Started: 2022-08-01 14:54:31</div><div id="summary"><div id="suite-summary"><div class="summary-total">Suites (1)</div><div class="summary-passed">1 passed</div><div class="summary-failed summary-empty">0 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">1 passed</div><div class="summary-failed summary-empty">0 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">230.253s</div></div><div class="suite-tests"><div class="test-result passed"><div class="test-info"><div class="test-suitename"> </div><div class="test-title">TEST</div><div class="test-status">passed</div><div class="test-duration">213.793s</div></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)
232
+ </style></head><body><div id="jesthtml-content"><header><h1 id="title">Bio Test Report. Datagrok version datagrok/datagrok:latest SHA=4f0c8bae6479. Commit 5b129baa.</h1></header><div id="metadata-container"><div id="timestamp">Started: 2022-08-04 11:48:50</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">247.467s</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">224.086s</div></div><div class="failureMessages"> <pre class="failureMsg">Error: Test result : Bio.WebLogo-positions.allPositions : Error: Expected "12", got "0"
233
+
234
+ at /home/runner/work/public/public/packages/Bio/src/__jest__/remote.test.ts:67:20
235
+ at Generator.next (&lt;anonymous&gt;)
236
+ at fulfilled (/home/runner/work/public/public/packages/Bio/src/__jest__/remote.test.ts:31:58)
237
+ at runMicrotasks (&lt;anonymous&gt;)
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)
233
239
  at Generator.next (&lt;anonymous&gt;)
234
240
  at fulfilled (/home/runner/work/public/public/packages/Bio/src/__jest__/test-node.ts:28:58)
235
241
  at processTicksAndRejections (internal/process/task_queues.js:97:5)</pre><pre class="suite-consolelog-item-message">Using web root: http://localhost:8080</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:40:11
@@ -344,5 +350,9 @@ Test result : Bio.converters.testHelmPtToSeparator : OK
344
350
  Test result : Bio.converters.testHelmLoneRibose : OK
345
351
  Test result : Bio.converters.testHelmLoneDeoxyribose : OK
346
352
  Test result : Bio.converters.testHelmLonePhosphorus : OK
347
- Test result : Bio.WebLogo-positions.allPositions : OK
353
+ Test result : Bio.fastaFileHandler.testNormalFormatting : OK
354
+ Test result : Bio.fastaFileHandler.testExtraSpaces : OK
355
+ Test result : Bio.fastaFileHandler.testExtraNewlines : OK
356
+ Test result : Bio.WebLogo-positions.positions with shrinkEmptyTail option : OK
357
+ Test result : Bio.WebLogo-positions.positions with skipEmptyPositions option : OK
348
358
  </pre></div></div></div></div></body></html>