@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/detectors.js +1 -1
- package/dist/package-test.js +244 -99
- package/dist/package.js +130 -52
- package/files/samples/sample_HELM_empty_vals.csv +541 -0
- package/package.json +3 -3
- package/setup.sh +3 -0
- package/src/package.ts +26 -27
- package/src/tests/activity-cliffs-tests.ts +15 -34
- package/src/tests/activity-cliffs-utils.ts +19 -0
- package/src/tests/renderers-test.ts +6 -5
- package/src/tests/sequence-space-test.ts +17 -12
- package/src/tests/sequence-space-utils.ts +10 -0
- package/src/utils/cell-renderer.ts +75 -21
- package/src/utils/multiple-sequence-alignment.ts +8 -2
- package/src/viewers/vd-regions-viewer.ts +7 -0
- package/{test-Bio-4f0c8bae6479-17115d45.html → test-Bio-dc07f068a0b2-cdad4cfb.html} +6 -6
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
|
|
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) =>
|
|
60
|
+
!allowedAlphabets.some((a) => alphabet.toUpperCase() == (a.toUpperCase()))) ||
|
|
56
61
|
(allowedNotations.length > 0 &&
|
|
57
|
-
!allowedNotations.some((n) =>
|
|
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<
|
|
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
|
|
121
|
-
|
|
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
|
-
|
|
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<
|
|
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.
|
|
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,
|
|
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 {
|
|
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
|
-
|
|
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
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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'), '
|
|
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'), '
|
|
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'), '
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
84
|
-
|
|
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 +
|
|
103
|
-
return x +
|
|
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 +
|
|
107
|
-
return x + dx +
|
|
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,
|
|
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
|
-
|
|
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 (
|
|
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
|
-
|
|
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,
|
|
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=
|
|
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=
|
|
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 (<anonymous>)
|
|
236
237
|
at fulfilled (/home/runner/work/public/public/packages/Bio/src/__jest__/remote.test.ts:31:58)
|
|
237
|
-
at runMicrotasks (<anonymous>)
|
|
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.<anonymous> (/home/runner/work/public/public/packages/Bio/src/__jest__/test-node.ts:63:11)
|
|
239
239
|
at Generator.next (<anonymous>)
|
|
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 (<anonymous>)</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 (<anonymous>)
|
|
250
250
|
at fulfilled (/home/runner/work/public/public/packages/Bio/src/__jest__/remote.test.ts:31:58)
|
|
251
|
-
at runMicrotasks (<anonymous>)
|
|
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
|