@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/dist/package-test.js +349 -46
- package/dist/package.js +147 -45
- package/package.json +6 -2
- package/src/package-test.ts +1 -0
- package/src/package.ts +17 -9
- package/src/tests/WebLogo-positions-test.ts +78 -6
- package/src/tests/WebLogo-test.ts +1 -0
- package/src/tests/fasta-handler-test.ts +141 -0
- package/src/utils/cell-renderer.ts +83 -29
- package/src/utils/constants.ts +3 -4
- package/src/viewers/vd-regions-viewer.ts +17 -0
- package/{test-Bio-4f0c8bae6479-dd77efbc.html → test-Bio-4f0c8bae6479-5b129baa.html} +13 -3
package/package.json
CHANGED
|
@@ -2,7 +2,11 @@
|
|
|
2
2
|
"name": "@datagrok/bio",
|
|
3
3
|
"beta": false,
|
|
4
4
|
"friendlyName": "Bio",
|
|
5
|
-
"
|
|
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.
|
|
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",
|
package/src/package-test.ts
CHANGED
|
@@ -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 {
|
|
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:
|
|
345
|
+
//name: monomerCellRenderer
|
|
338
346
|
//tags: cellRenderer
|
|
339
|
-
//meta.cellType:
|
|
347
|
+
//meta.cellType: Monomer
|
|
340
348
|
//output: grid_cell_renderer result
|
|
341
|
-
export function
|
|
342
|
-
return new
|
|
349
|
+
export function monomerCellRenderer(): MonomerCellRenderer {
|
|
350
|
+
return new MonomerCellRenderer();
|
|
343
351
|
}
|
|
344
352
|
|
|
345
|
-
//name:
|
|
353
|
+
//name: MacromoleculeDifferenceCellRenderer
|
|
346
354
|
//tags: cellRenderer
|
|
347
|
-
//meta.cellType:
|
|
355
|
+
//meta.cellType: MacromoleculeDifference
|
|
348
356
|
//output: grid_cell_renderer result
|
|
349
|
-
export function
|
|
350
|
-
return new
|
|
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
|
-
|
|
62
|
-
|
|
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
|
});
|
|
@@ -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 =
|
|
72
|
+
let grayPart = last ? '' : separator;
|
|
73
|
+
if (drawStyle === 'msa') {
|
|
74
|
+
grayPart = ' ';
|
|
75
|
+
}
|
|
72
76
|
|
|
73
|
-
|
|
77
|
+
let textSize: any = g.measureText(colorPart + grayPart);
|
|
74
78
|
const indent = 5;
|
|
75
79
|
|
|
76
|
-
|
|
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
|
-
|
|
84
|
-
|
|
96
|
+
if (drawStyle === 'classic') {
|
|
97
|
+
g.fillStyle = grayColor;
|
|
98
|
+
g.fillText(grayPart, x + dx2, y + dy);
|
|
99
|
+
}
|
|
85
100
|
}
|
|
86
101
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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
|
|
93
|
-
draw(dx, dx + colorTextSize
|
|
94
|
-
return x + dx + colorTextSize
|
|
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.
|
|
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
|
-
|
|
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
|
|
260
|
-
get name(): string {return '
|
|
308
|
+
export class MacromoleculeDifferenceCellRenderer extends DG.GridCellRenderer {
|
|
309
|
+
get name(): string {return 'MacromoleculeDifferenceCR';}
|
|
261
310
|
|
|
262
|
-
get cellType(): string {return C.SEM_TYPES.
|
|
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
|
|
299
|
-
const
|
|
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
|
-
|
|
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
|
|
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);
|
package/src/utils/constants.ts
CHANGED
|
@@ -23,12 +23,11 @@ export enum TAGS {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
export enum SEM_TYPES {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
ALIGNED_SEQUENCE_DIFFERENCE = 'alignedSequenceDifference',
|
|
26
|
+
MONOMER = 'Monomer',
|
|
27
|
+
MACROMOLECULE_DIFFERENCE = 'MacromoleculeDifference',
|
|
29
28
|
ACTIVITY = 'activity',
|
|
30
29
|
ACTIVITY_SCALED = 'activityScaled',
|
|
31
|
-
|
|
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
|
|
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
|
|
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 (<anonymous>)
|
|
236
|
+
at fulfilled (/home/runner/work/public/public/packages/Bio/src/__jest__/remote.test.ts:31:58)
|
|
237
|
+
at runMicrotasks (<anonymous>)
|
|
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.<anonymous> (/home/runner/work/public/public/packages/Bio/src/__jest__/test-node.ts:63:11)
|
|
233
239
|
at Generator.next (<anonymous>)
|
|
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.
|
|
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>
|