@datagrok/bio 2.12.17 → 2.12.19
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/CHANGELOG.md +21 -2
- package/dist/79.js.map +1 -1
- package/dist/package-test.js +3 -3
- package/dist/package-test.js.map +1 -1
- package/dist/package.js +3 -3
- package/dist/package.js.map +1 -1
- package/package.json +4 -4
- package/src/package.ts +56 -12
- package/src/tests/monomer-libraries-tests.ts +1 -4
- package/src/tests/renderers-monomer-placer-tests.ts +59 -12
- package/src/tests/renderers-test.ts +3 -5
- package/src/tests/scoring.ts +2 -2
- package/src/tests/substructure-filters-tests.ts +2 -0
- package/src/tests/to-atomic-level-tests.ts +1 -1
- package/src/tests/utils/sequences-generators.ts +0 -20
- package/src/tests/utils.ts +15 -0
- package/src/utils/cell-renderer.ts +39 -46
- package/src/utils/helm-to-molfile/converter/converter.ts +10 -5
- package/src/utils/helm-to-molfile/converter/monomer-wrapper.ts +9 -9
- package/src/utils/helm-to-molfile/converter/polymer.ts +10 -3
- package/src/utils/macromolecule-column-widget.ts +2 -0
- package/src/utils/monomer-cell-renderer.ts +18 -8
- package/src/utils/monomer-lib/lib-manager.ts +56 -18
- package/src/utils/monomer-lib/library-file-manager/event-manager.ts +15 -9
- package/src/utils/monomer-lib/library-file-manager/file-manager.ts +78 -59
- package/src/utils/monomer-lib/library-file-manager/file-validator.ts +3 -1
- package/src/utils/monomer-lib/library-file-manager/ui.ts +52 -47
- package/src/utils/monomer-lib/monomer-lib.ts +78 -9
- package/src/utils/multiple-sequence-alignment-ui.ts +31 -18
- package/src/utils/sequence-to-mol.ts +7 -7
- package/src/viewers/web-logo-viewer.ts +14 -4
- package/src/widgets/bio-substructure-filter-helm.ts +9 -3
- package/src/widgets/bio-substructure-filter.ts +2 -2
- package/webpack.config.js +1 -0
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"name": "Aleksandr Tanas",
|
|
6
6
|
"email": "atanas@datagrok.ai"
|
|
7
7
|
},
|
|
8
|
-
"version": "2.12.
|
|
8
|
+
"version": "2.12.19",
|
|
9
9
|
"description": "Bioinformatics support (import/export of sequences, conversion, visualization, analysis). [See more](https://github.com/datagrok-ai/public/blob/master/packages/Bio/README.md) for details.",
|
|
10
10
|
"repository": {
|
|
11
11
|
"type": "git",
|
|
@@ -34,12 +34,12 @@
|
|
|
34
34
|
],
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@biowasm/aioli": "^3.1.0",
|
|
37
|
-
"@datagrok-libraries/bio": "^5.41.
|
|
37
|
+
"@datagrok-libraries/bio": "^5.41.5",
|
|
38
38
|
"@datagrok-libraries/chem-meta": "^1.2.5",
|
|
39
39
|
"@datagrok-libraries/math": "^1.1.5",
|
|
40
40
|
"@datagrok-libraries/ml": "^6.6.5",
|
|
41
41
|
"@datagrok-libraries/tutorials": "^1.3.12",
|
|
42
|
-
"@datagrok-libraries/utils": "^4.2.
|
|
42
|
+
"@datagrok-libraries/utils": "^4.2.5",
|
|
43
43
|
"@webgpu/types": "^0.1.40",
|
|
44
44
|
"ajv": "^8.12.0",
|
|
45
45
|
"ajv-errors": "^3.0.0",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"devDependencies": {
|
|
58
58
|
"@datagrok/chem": "^1.9.2",
|
|
59
59
|
"@datagrok/dendrogram": "^1.2.29",
|
|
60
|
-
"@datagrok/helm": "^2.1
|
|
60
|
+
"@datagrok/helm": "^2.2.1",
|
|
61
61
|
"@types/node": "^17.0.24",
|
|
62
62
|
"@types/wu": "latest",
|
|
63
63
|
"@typescript-eslint/eslint-plugin": "latest",
|
package/src/package.ts
CHANGED
|
@@ -11,9 +11,7 @@ import {DimReductionBaseEditor, PreprocessFunctionReturnType}
|
|
|
11
11
|
import {getActivityCliffs} from '@datagrok-libraries/ml/src/viewers/activity-cliffs';
|
|
12
12
|
import {MmDistanceFunctionsNames} from '@datagrok-libraries/ml/src/macromolecule-distance-functions';
|
|
13
13
|
import {BitArrayMetrics, KnownMetrics} from '@datagrok-libraries/ml/src/typed-metrics';
|
|
14
|
-
import {
|
|
15
|
-
TAGS as bioTAGS,
|
|
16
|
-
} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
14
|
+
import {NOTATION, TAGS as bioTAGS} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
17
15
|
import {SeqHandler, SeqTemps} from '@datagrok-libraries/bio/src/utils/seq-handler';
|
|
18
16
|
import {IMonomerLib} from '@datagrok-libraries/bio/src/types';
|
|
19
17
|
import {SeqPalette} from '@datagrok-libraries/bio/src/seq-palettes';
|
|
@@ -51,7 +49,7 @@ import {demoBio01bUI} from './demo/bio01b-hierarchical-clustering-and-activity-c
|
|
|
51
49
|
import {demoBio03UI} from './demo/bio03-atomic-level';
|
|
52
50
|
import {demoBio05UI} from './demo/bio05-helm-msa-sequence-space';
|
|
53
51
|
import {checkInputColumnUI} from './utils/check-input-column';
|
|
54
|
-
import {multipleSequenceAlignmentUI} from './utils/multiple-sequence-alignment-ui';
|
|
52
|
+
import {MsaWarning, multipleSequenceAlignmentUI} from './utils/multiple-sequence-alignment-ui';
|
|
55
53
|
import {WebLogoApp} from './apps/web-logo-app';
|
|
56
54
|
import {SplitToMonomersFunctionEditor} from './function-edtiors/split-to-monomers-editor';
|
|
57
55
|
import {splitToMonomersUI} from './utils/split-to-monomers';
|
|
@@ -75,6 +73,8 @@ import {DimReductionMethods} from '@datagrok-libraries/ml/src/multi-column-dimen
|
|
|
75
73
|
import {
|
|
76
74
|
ITSNEOptions, IUMAPOptions
|
|
77
75
|
} from '@datagrok-libraries/ml/src/multi-column-dimensionality-reduction/multi-column-dim-reducer';
|
|
76
|
+
import {generateLongSequence, generateLongSequence2} from '@datagrok-libraries/bio/src/utils/generator';
|
|
77
|
+
|
|
78
78
|
import {CyclizedNotationProvider} from './utils/cyclized';
|
|
79
79
|
import {getMolColumnFromHelm} from './utils/helm-to-molfile/utils';
|
|
80
80
|
|
|
@@ -86,8 +86,8 @@ export const _package = new BioPackage();
|
|
|
86
86
|
//name: getMonomerLibHelper
|
|
87
87
|
//description:
|
|
88
88
|
//output: object result
|
|
89
|
-
export function getMonomerLibHelper(): IMonomerLibHelper {
|
|
90
|
-
return MonomerLibManager.
|
|
89
|
+
export async function getMonomerLibHelper(): Promise<IMonomerLibHelper> {
|
|
90
|
+
return await MonomerLibManager.getInstance();
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
export let hydrophobPalette: SeqPaletteCustom | null = null;
|
|
@@ -104,12 +104,20 @@ export class SeqPaletteCustom implements SeqPalette {
|
|
|
104
104
|
}
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
+
let monomerLib: IMonomerLib | null = null;
|
|
108
|
+
|
|
107
109
|
//tags: init
|
|
108
110
|
export async function initBio() {
|
|
109
|
-
|
|
111
|
+
const logPrefix = 'Bio: initBio()';
|
|
112
|
+
_package.logger.debug(`${logPrefix}, start`);
|
|
110
113
|
const module = await grok.functions.call('Chem:getRdKitModule');
|
|
114
|
+
const t1: number = window.performance.now();
|
|
111
115
|
await Promise.all([
|
|
112
|
-
(async () => {
|
|
116
|
+
(async () => {
|
|
117
|
+
const monomerLibManager = await MonomerLibManager.getInstance();
|
|
118
|
+
await monomerLibManager.loadLibraries();
|
|
119
|
+
monomerLib = monomerLibManager.getBioLib();
|
|
120
|
+
})(),
|
|
113
121
|
(async () => {
|
|
114
122
|
const pkgProps = await _package.getProperties();
|
|
115
123
|
const bioPkgProps = new BioPackageProperties(pkgProps);
|
|
@@ -117,9 +125,10 @@ export async function initBio() {
|
|
|
117
125
|
})(),
|
|
118
126
|
]).finally(() => {
|
|
119
127
|
_package.completeInit();
|
|
128
|
+
const t2: number = window.performance.now();
|
|
129
|
+
_package.logger.debug(`${logPrefix}, loading ET: ${t2 - t1} ms`);
|
|
120
130
|
});
|
|
121
131
|
|
|
122
|
-
const monomerLib = MonomerLibManager.instance.getBioLib();
|
|
123
132
|
const monomers: string[] = [];
|
|
124
133
|
const logPs: number[] = [];
|
|
125
134
|
|
|
@@ -159,10 +168,16 @@ export function sequenceTooltip(col: DG.Column): DG.Widget<any> {
|
|
|
159
168
|
return resWidget;
|
|
160
169
|
}
|
|
161
170
|
|
|
171
|
+
// Keep for backward compatibility
|
|
162
172
|
//name: getBioLib
|
|
163
173
|
//output: object monomerLib
|
|
164
174
|
export function getBioLib(): IMonomerLib {
|
|
165
|
-
return
|
|
175
|
+
return monomerLib!;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// For sync internal use, on initialized package
|
|
179
|
+
export function getMonomerLib(): IMonomerLib | null {
|
|
180
|
+
return monomerLib!;
|
|
166
181
|
}
|
|
167
182
|
|
|
168
183
|
//name: getSeqHandler
|
|
@@ -571,7 +586,8 @@ export async function sequenceSpaceTopMenu(table: DG.DataFrame, molecules: DG.Co
|
|
|
571
586
|
export async function toAtomicLevel(table: DG.DataFrame, seqCol: DG.Column, nonlinear: boolean): Promise<void> {
|
|
572
587
|
const pi = DG.TaskBarProgressIndicator.create('Converting to atomic level ...');
|
|
573
588
|
try {
|
|
574
|
-
await
|
|
589
|
+
const monomerLib = (await getMonomerLibHelper()).getBioLib();
|
|
590
|
+
await sequenceToMolfile(table, seqCol, nonlinear, monomerLib);
|
|
575
591
|
} finally {
|
|
576
592
|
pi.close();
|
|
577
593
|
}
|
|
@@ -582,7 +598,15 @@ export async function toAtomicLevel(table: DG.DataFrame, seqCol: DG.Column, nonl
|
|
|
582
598
|
//description: Performs multiple sequence alignment
|
|
583
599
|
//tags: bio, panel
|
|
584
600
|
export function multipleSequenceAlignmentDialog(): void {
|
|
585
|
-
multipleSequenceAlignmentUI()
|
|
601
|
+
multipleSequenceAlignmentUI()
|
|
602
|
+
.catch((err: any) => {
|
|
603
|
+
const [errMsg, _errStack] = errInfo(err);
|
|
604
|
+
if (err instanceof MsaWarning) {
|
|
605
|
+
_package.logger.warning(errMsg);
|
|
606
|
+
return;
|
|
607
|
+
}
|
|
608
|
+
throw err;
|
|
609
|
+
});
|
|
586
610
|
}
|
|
587
611
|
|
|
588
612
|
//name: Multiple Sequence Alignment
|
|
@@ -930,6 +954,26 @@ export async function getRegionHelmApp(): Promise<void> {
|
|
|
930
954
|
}
|
|
931
955
|
}
|
|
932
956
|
|
|
957
|
+
// -- Tests long seq --
|
|
958
|
+
|
|
959
|
+
//name: longSeqTableSeparator
|
|
960
|
+
export function longSeqTableSeparator(): void {
|
|
961
|
+
const df = DG.DataFrame.fromColumns(generateLongSequence());
|
|
962
|
+
grok.shell.addTableView(df);
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
//name: longSeqTableFasta
|
|
966
|
+
export function longSeqTableFasta(): void {
|
|
967
|
+
const df = DG.DataFrame.fromColumns([generateLongSequence2(NOTATION.FASTA)]);
|
|
968
|
+
grok.shell.addTableView(df);
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
//name: longSeqTableHelm
|
|
972
|
+
export function longSeqTableHelm(): void {
|
|
973
|
+
const df = DG.DataFrame.fromColumns([generateLongSequence2(NOTATION.HELM)]);
|
|
974
|
+
grok.shell.addTableView(df);
|
|
975
|
+
}
|
|
976
|
+
|
|
933
977
|
// -- Handle context menu --
|
|
934
978
|
|
|
935
979
|
///name: addCopyMenu
|
|
@@ -8,8 +8,6 @@ import {getMonomerLibHelper, IMonomerLibHelper} from '@datagrok-libraries/bio/sr
|
|
|
8
8
|
import {
|
|
9
9
|
getUserLibSettings, setUserLibSettings, setUserLibSettingsForTests
|
|
10
10
|
} from '@datagrok-libraries/bio/src/monomer-works/lib-settings';
|
|
11
|
-
import {MonomerLibFileManager} from '../utils/monomer-lib/library-file-manager/file-manager';
|
|
12
|
-
import {MonomerLibFileEventManager} from '../utils/monomer-lib/library-file-manager/event-manager';
|
|
13
11
|
|
|
14
12
|
|
|
15
13
|
category('monomerLibraries', () => {
|
|
@@ -51,8 +49,7 @@ category('monomerLibraries', () => {
|
|
|
51
49
|
test('empty', async () => {
|
|
52
50
|
// exclude all monomer libraries for empty set
|
|
53
51
|
const libSettings = await getUserLibSettings();
|
|
54
|
-
const
|
|
55
|
-
const libFileManager = await MonomerLibFileManager.getInstance(libFileEventManager);
|
|
52
|
+
const libFileManager = await monomerLibHelper.getFileManager();
|
|
56
53
|
|
|
57
54
|
let libFnList = libFileManager.getValidLibraryPaths();
|
|
58
55
|
if (libFnList.length === 0)
|
|
@@ -4,16 +4,36 @@ import * as ui from 'datagrok-api/ui';
|
|
|
4
4
|
|
|
5
5
|
import wu from 'wu';
|
|
6
6
|
|
|
7
|
-
import {category, test} from '@datagrok-libraries/utils/src/test';
|
|
8
|
-
import {MonomerPlacer} from '@datagrok-libraries/bio/src/utils/cell-renderer-monomer-placer';
|
|
7
|
+
import {after, before, category, expect, test} from '@datagrok-libraries/utils/src/test';
|
|
8
|
+
import {MonomerPlacer, hitBounds} from '@datagrok-libraries/bio/src/utils/cell-renderer-monomer-placer';
|
|
9
9
|
import {monomerToShort} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
10
10
|
import {SeqHandler} from '@datagrok-libraries/bio/src/utils/seq-handler';
|
|
11
|
-
|
|
12
|
-
import {
|
|
11
|
+
import {getMonomerLibHelper, IMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
|
|
12
|
+
import {
|
|
13
|
+
getUserLibSettings, setUserLibSettings, setUserLibSettingsForTests
|
|
14
|
+
} from '@datagrok-libraries/bio/src/monomer-works/lib-settings';
|
|
15
|
+
import {UserLibSettings} from '@datagrok-libraries/bio/src/monomer-works/types';
|
|
13
16
|
|
|
14
17
|
import {_package} from '../package-test';
|
|
15
18
|
|
|
16
19
|
category('renderers: monomerPlacer', () => {
|
|
20
|
+
let libHelper: IMonomerLibHelper;
|
|
21
|
+
let libSettings: UserLibSettings;
|
|
22
|
+
|
|
23
|
+
before(async () => {
|
|
24
|
+
libHelper = await getMonomerLibHelper();
|
|
25
|
+
libSettings = await getUserLibSettings();
|
|
26
|
+
|
|
27
|
+
await setUserLibSettingsForTests();
|
|
28
|
+
await libHelper.awaitLoaded();
|
|
29
|
+
await libHelper.loadLibraries(true);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
after(async () => {
|
|
33
|
+
await setUserLibSettings(libSettings);
|
|
34
|
+
await libHelper.loadLibraries(true);
|
|
35
|
+
});
|
|
36
|
+
|
|
17
37
|
const tests = {
|
|
18
38
|
splitter: {
|
|
19
39
|
/**
|
|
@@ -45,7 +65,7 @@ category('renderers: monomerPlacer', () => {
|
|
|
45
65
|
'id1,m1-M-m3-mon4-mon5-N-T-MON8-N9\n' +
|
|
46
66
|
'id2,m1-mon2-m3-mon4-mon5-Num--MON8-N9\n' +
|
|
47
67
|
'id3,\n' + // empty
|
|
48
|
-
'id4,mon1-M-mon3-mon4-mon5---MON8-N9\n',
|
|
68
|
+
'id4,mon1-M-mon3-mon4-mon5---MON8-N9\n', // [ 5, 38, 71, 104, 137, 170, 203, 236, 269, 295 ]
|
|
49
69
|
testList: [
|
|
50
70
|
{src: {row: 0, x: -1}, tgt: {pos: null}},
|
|
51
71
|
{src: {row: 1, x: 0}, tgt: {pos: null}},
|
|
@@ -54,12 +74,12 @@ category('renderers: monomerPlacer', () => {
|
|
|
54
74
|
{src: {row: 1, x: 5}, tgt: {pos: 0}},
|
|
55
75
|
{src: {row: 1, x: 37}, tgt: {pos: 0}},
|
|
56
76
|
{src: {row: 1, x: 38}, tgt: {pos: 1}},
|
|
57
|
-
{src: {row: 1, x: 170}, tgt: {pos:
|
|
77
|
+
{src: {row: 1, x: 170}, tgt: {pos: 5}},
|
|
58
78
|
{src: {row: 1, x: 200}, tgt: {pos: 5}},
|
|
59
79
|
{src: {row: 2, x: 20}, tgt: {pos: null}}, // empty value
|
|
60
|
-
{src: {row: 3, x: 170}, tgt: {pos:
|
|
80
|
+
{src: {row: 3, x: 170}, tgt: {pos: 5}},
|
|
61
81
|
{src: {row: 3, x: 200}, tgt: {pos: 5}},
|
|
62
|
-
{src: {row: 3, x:
|
|
82
|
+
{src: {row: 3, x: 297}, tgt: {pos: null}},
|
|
63
83
|
]
|
|
64
84
|
},
|
|
65
85
|
fastaMsa: {
|
|
@@ -88,6 +108,8 @@ id3,QHIRE--LT
|
|
|
88
108
|
|
|
89
109
|
for (const [testName, testData] of Object.entries(tests)) {
|
|
90
110
|
test(`getPosition-${testName}`, async () => {
|
|
111
|
+
const libHelper = await getMonomerLibHelper();
|
|
112
|
+
const monomerLib = libHelper.getBioLib();
|
|
91
113
|
const df: DG.DataFrame = DG.DataFrame.fromCsv(testData.csv);
|
|
92
114
|
await grok.data.detectSemanticTypes(df);
|
|
93
115
|
const seqCol: DG.Column = df.getCol('seq');
|
|
@@ -103,25 +125,50 @@ id3,QHIRE--LT
|
|
|
103
125
|
separatorWidth: sepWidth,
|
|
104
126
|
monomerToShort: monomerToShort,
|
|
105
127
|
monomerLengthLimit: monLength,
|
|
106
|
-
monomerLib: MonomerLibManager.instance.getBioLib(),
|
|
107
128
|
};
|
|
108
129
|
});
|
|
109
130
|
|
|
131
|
+
const width: number = 10000;
|
|
110
132
|
const testList = testData.testList;
|
|
111
133
|
// simulate rendering
|
|
112
134
|
for (let rowI: number = 0; rowI < seqCol.length; ++rowI)
|
|
113
|
-
colTemp.getCellMonomerLengths(rowI);
|
|
135
|
+
colTemp.getCellMonomerLengths(rowI, 10000);
|
|
114
136
|
|
|
115
137
|
const errorList: string[] = [];
|
|
116
138
|
for (const [test, _testI] of wu.enumerate(testList)) {
|
|
117
|
-
const res = {pos: colTemp.getPosition(test.src.row, test.src.x)};
|
|
139
|
+
const res = {pos: colTemp.getPosition(test.src.row, test.src.x, width)};
|
|
118
140
|
if (test.tgt.pos != res.pos) {
|
|
119
141
|
errorList.push(`Test src ${JSON.stringify(test.src)} expected tgt ${JSON.stringify(test.tgt)},` +
|
|
120
142
|
` but get ${JSON.stringify({res})}`);
|
|
121
143
|
}
|
|
122
144
|
}
|
|
123
145
|
if (errorList.length > 0)
|
|
124
|
-
throw new Error('Test failed error(s):\n' + errorList.join(', n'));
|
|
146
|
+
throw new Error('Test failed error(s):\n' + errorList.join(', \n'));
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
category('renderers: monomerPlacer', () => {
|
|
152
|
+
const boundsTestData = {
|
|
153
|
+
bounds: [10, 20, 30, 40, 50, 60],
|
|
154
|
+
tests: {
|
|
155
|
+
left: {x: 3, tgt: null},
|
|
156
|
+
c0left: {x: 10, tgt: 0},
|
|
157
|
+
c0mid: {x: 12, tgt: 0},
|
|
158
|
+
c0right: {x: 19, tgt: 0},
|
|
159
|
+
c1left: {x: 20, tgt: 1},
|
|
160
|
+
c2right: {x: 39, tgt: 2},
|
|
161
|
+
c4left: {x: 50, tgt: 4},
|
|
162
|
+
c4right: {x: 59, tgt: 4},
|
|
163
|
+
max: {x: 60, tgt: null},
|
|
164
|
+
right: {x: 65, tgt: null},
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
for (const [testName, testData] of Object.entries(boundsTestData.tests)) {
|
|
169
|
+
test('hitBounds-' + testName, async () => {
|
|
170
|
+
const res = hitBounds(boundsTestData.bounds, testData.x);
|
|
171
|
+
expect(res, testData.tgt);
|
|
125
172
|
});
|
|
126
173
|
}
|
|
127
174
|
});
|
|
@@ -8,10 +8,11 @@ import {fromEvent} from 'rxjs';
|
|
|
8
8
|
import {category, expect, test, delay, testEvent} from '@datagrok-libraries/utils/src/test';
|
|
9
9
|
import {ALIGNMENT, ALPHABET, NOTATION, TAGS as bioTAGS} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
10
10
|
import {SeqHandler} from '@datagrok-libraries/bio/src/utils/seq-handler';
|
|
11
|
+
import {generateLongSequence, generateManySequences} from '@datagrok-libraries/bio/src/utils/generator';
|
|
11
12
|
|
|
12
13
|
import {importFasta} from '../package';
|
|
13
14
|
import {convertDo} from '../utils/convert';
|
|
14
|
-
import {
|
|
15
|
+
import {performanceTest} from './utils/sequences-generators';
|
|
15
16
|
import {multipleSequenceAlignmentUI} from '../utils/multiple-sequence-alignment-ui';
|
|
16
17
|
import {awaitGrid} from './utils';
|
|
17
18
|
import * as C from '../utils/constants';
|
|
@@ -23,9 +24,6 @@ category('renderers', () => {
|
|
|
23
24
|
await performanceTest(generateLongSequence, 'Long sequences');
|
|
24
25
|
});
|
|
25
26
|
|
|
26
|
-
test('many sequence performance', async () => {
|
|
27
|
-
await performanceTest(generateManySequences, 'Many sequences');
|
|
28
|
-
});
|
|
29
27
|
test('many sequence performance', async () => {
|
|
30
28
|
await performanceTest(generateManySequences, 'Many sequences');
|
|
31
29
|
});
|
|
@@ -56,7 +54,7 @@ category('renderers', () => {
|
|
|
56
54
|
|
|
57
55
|
test('scatterPlotTooltip', async () => {
|
|
58
56
|
await _testScatterPlotTooltip();
|
|
59
|
-
});
|
|
57
|
+
}, {skipReason: 'GROK-15679'});
|
|
60
58
|
|
|
61
59
|
async function _rendererMacromoleculeFasta() {
|
|
62
60
|
const csv: string = await grok.dapi.files.readAsText('System:AppData/Bio/samples/FASTA.csv');
|
package/src/tests/scoring.ts
CHANGED
|
@@ -4,9 +4,9 @@ import * as DG from 'datagrok-api/dg';
|
|
|
4
4
|
|
|
5
5
|
import {category, test, expectFloat, before, after} from '@datagrok-libraries/utils/src/test';
|
|
6
6
|
import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
7
|
-
import {
|
|
7
|
+
import {IMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
|
|
8
8
|
|
|
9
|
-
import {sequenceIdentityScoring, sequenceSimilarityScoring} from '../package';
|
|
9
|
+
import {getMonomerLibHelper, sequenceIdentityScoring, sequenceSimilarityScoring} from '../package';
|
|
10
10
|
import {
|
|
11
11
|
getUserLibSettings, setUserLibSettings, setUserLibSettingsForTests
|
|
12
12
|
} from '@datagrok-libraries/bio/src/monomer-works/lib-settings';
|
|
@@ -185,6 +185,7 @@ category('bio-substructure-filters', async () => {
|
|
|
185
185
|
dlg.close();
|
|
186
186
|
}
|
|
187
187
|
await filter.awaitRendered();
|
|
188
|
+
await delay(3000); //TODO: await for grid.onLookChanged
|
|
188
189
|
});
|
|
189
190
|
|
|
190
191
|
// Generates unhandled exception accessing isFiltering before bioFilter created
|
|
@@ -308,6 +309,7 @@ category('bio-substructure-filters', async () => {
|
|
|
308
309
|
}
|
|
309
310
|
await Promise.all([f1.awaitRendered(), f2.awaitRendered()]);
|
|
310
311
|
await awaitGrid(view.grid);
|
|
312
|
+
await delay(3000); //TODO: await for grid.onLookChanged
|
|
311
313
|
});
|
|
312
314
|
|
|
313
315
|
// two seq columns
|
|
@@ -7,7 +7,7 @@ import wu from 'wu';
|
|
|
7
7
|
|
|
8
8
|
import {before, after, category, test, expectArray, expect} from '@datagrok-libraries/utils/src/test';
|
|
9
9
|
import {_toAtomicLevel} from '@datagrok-libraries/bio/src/monomer-works/to-atomic-level';
|
|
10
|
-
import {IMonomerLib} from '@datagrok-libraries/bio/src/types
|
|
10
|
+
import {IMonomerLib} from '@datagrok-libraries/bio/src/types';
|
|
11
11
|
import {ALPHABET, NOTATION, TAGS as bioTAGS} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
12
12
|
import {getMonomerLibHelper, IMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
|
|
13
13
|
import {
|
|
@@ -7,26 +7,6 @@ import {expect} from '@datagrok-libraries/utils/src/test';
|
|
|
7
7
|
|
|
8
8
|
import {awaitGrid} from '../utils';
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
export function generateManySequences(): DG.Column[] {
|
|
12
|
-
const columns: DG.Column[] = [];
|
|
13
|
-
columns.push(DG.Column.fromList('string', 'MSA',
|
|
14
|
-
new Array(10 ** 6).fill(
|
|
15
|
-
'meI/hHis/Aca/N/T/dE/Thr_PO3H2/Aca/D-Tyr_Et/Tyr_ab-dehydroMe/dV/E/N/D-Orn/D-aThr//Phe_4Me')),
|
|
16
|
-
);
|
|
17
|
-
columns.push(DG.Column.fromList('string', 'Activity', new Array(10 ** 6).fill('5.30751')));
|
|
18
|
-
return columns;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export function generateLongSequence(): DG.Column[] {
|
|
22
|
-
const columns: DG.Column[] = [];
|
|
23
|
-
const longSequence =
|
|
24
|
-
`meI/hHis/Aca/N/T/dE/Thr_PO3H2/Aca/D-Tyr_Et/Tyr_ab-dehydroMe/dV/E/N/D-Orn/D-aThr`.repeat(10 ** 5);
|
|
25
|
-
columns.push(DG.Column.fromList('string', 'MSA', new Array(10 ** 2).fill(longSequence)));
|
|
26
|
-
columns.push(DG.Column.fromList('string', 'Activity', new Array(10 ** 2).fill('7.30751')));
|
|
27
|
-
return columns;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
10
|
export async function performanceTest(generateFunc: () => DG.Column[], testName: string) {
|
|
31
11
|
const columns = generateFunc();
|
|
32
12
|
const df: DG.DataFrame = DG.DataFrame.fromColumns(columns);
|
package/src/tests/utils.ts
CHANGED
|
@@ -2,10 +2,12 @@ import * as DG from 'datagrok-api/dg';
|
|
|
2
2
|
import * as grok from 'datagrok-api/grok';
|
|
3
3
|
|
|
4
4
|
import {delay, expect, testEvent} from '@datagrok-libraries/utils/src/test';
|
|
5
|
+
import {asRenderer, IRenderer, isRenderer} from '@datagrok-libraries/bio/src/types/renderer';
|
|
5
6
|
|
|
6
7
|
import {startDockerContainer} from '../utils/docker';
|
|
7
8
|
|
|
8
9
|
import {_package} from '../package-test';
|
|
10
|
+
import {CellRendererBackBase, getGridCellRendererBack} from '@datagrok-libraries/bio/src/utils/cell-renderer-back-base';
|
|
9
11
|
|
|
10
12
|
export async function loadFileAsText(name: string): Promise<string> {
|
|
11
13
|
return await _package.files.readAsText(name);
|
|
@@ -38,4 +40,17 @@ export async function awaitGrid(grid: DG.Grid, timeout: number = 5000): Promise<
|
|
|
38
40
|
await delay(0);
|
|
39
41
|
await testEvent(grid.onAfterDrawContent, () => {},
|
|
40
42
|
() => { grid.invalidate(); }, timeout);
|
|
43
|
+
|
|
44
|
+
const colCount = grid.columns.length;
|
|
45
|
+
for (let colI = 0; colI < colCount; ++colI) {
|
|
46
|
+
const gridCol = grid.columns.byIndex(colI);
|
|
47
|
+
if (gridCol) {
|
|
48
|
+
const gridCell = grid.cell(gridCol.name, 0);
|
|
49
|
+
const [_gridCol, _tableCol, temp] =
|
|
50
|
+
getGridCellRendererBack<void, CellRendererBackBase<void>>(gridCell);
|
|
51
|
+
|
|
52
|
+
const renderer = asRenderer(temp.rendererBack);
|
|
53
|
+
if (renderer) await renderer.awaitRendered();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
41
56
|
}
|
|
@@ -3,7 +3,6 @@ import * as DG from 'datagrok-api/dg';
|
|
|
3
3
|
import * as ui from 'datagrok-api/ui';
|
|
4
4
|
|
|
5
5
|
import wu from 'wu';
|
|
6
|
-
import {Unsubscribable} from 'rxjs';
|
|
7
6
|
|
|
8
7
|
import {printLeftOrCentered, DrawStyle, TAGS as mmcrTAGS} from '@datagrok-libraries/bio/src/utils/cell-renderer';
|
|
9
8
|
import {MonomerPlacer} from '@datagrok-libraries/bio/src/utils/cell-renderer-monomer-placer';
|
|
@@ -22,7 +21,7 @@ import {GapOriginals, SeqHandler} from '@datagrok-libraries/bio/src/utils/seq-ha
|
|
|
22
21
|
import {ISeqSplitted, SeqSplittedBase} from '@datagrok-libraries/bio/src/utils/macromolecule/types';
|
|
23
22
|
import {getSplitter} from '@datagrok-libraries/bio/src/utils/macromolecule/utils';
|
|
24
23
|
import {errInfo} from '@datagrok-libraries/bio/src/utils/err-info';
|
|
25
|
-
import {alphabetPolymerTypes, IMonomerLib} from '@datagrok-libraries/bio/src/types
|
|
24
|
+
import {alphabetPolymerTypes, IMonomerLib} from '@datagrok-libraries/bio/src/types';
|
|
26
25
|
import {getGridCellRendererBack} from '@datagrok-libraries/bio/src/utils/cell-renderer-back-base';
|
|
27
26
|
|
|
28
27
|
import {
|
|
@@ -31,14 +30,16 @@ import {
|
|
|
31
30
|
} from '../utils/cell-renderer-consts';
|
|
32
31
|
import * as C from './constants';
|
|
33
32
|
|
|
34
|
-
import {_package,
|
|
33
|
+
import {_package, getMonomerLib} from '../package';
|
|
35
34
|
|
|
36
35
|
type TempType = { [tagName: string]: any };
|
|
37
36
|
|
|
38
37
|
const undefinedColor = 'rgb(100,100,100)';
|
|
39
38
|
const monomerToShortFunction: MonomerToShortFunc = monomerToShort;
|
|
40
39
|
|
|
41
|
-
function getUpdatedWidth(
|
|
40
|
+
function getUpdatedWidth(
|
|
41
|
+
grid: DG.Grid | null | undefined, g: CanvasRenderingContext2D, x: number, w: number, dpr: number
|
|
42
|
+
): number {
|
|
42
43
|
return !!grid ? Math.max(Math.min(grid.canvas.width / dpr - x, w)) : Math.max(g.canvas.width / dpr - x, 0);
|
|
43
44
|
}
|
|
44
45
|
|
|
@@ -99,7 +100,7 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
|
99
100
|
// maxLengthWordsSum[posI] = maxLengthWordsSum[posI - 1] + maxLengthWords[posI];
|
|
100
101
|
// const maxIndex = maxLengthWords.length;
|
|
101
102
|
const argsX = e.offsetX - gridCell.gridColumn.left + (gridCell.gridColumn.left - gridCellBounds.x);
|
|
102
|
-
const left: number | null = seqColTemp.getPosition(gridCell.tableRowIndex!, argsX);
|
|
103
|
+
const left: number | null = seqColTemp.getPosition(gridCell.tableRowIndex!, argsX, gridCellBounds.width);
|
|
103
104
|
|
|
104
105
|
const seqCList: SeqSplittedBase = SeqHandler.forColumn(tableCol)
|
|
105
106
|
.getSplitted(gridCell.tableRowIndex!).canonicals;
|
|
@@ -113,8 +114,8 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
|
113
114
|
const alphabet = sh.alphabet ?? ALPHABET.UN;
|
|
114
115
|
const polymerType = alphabetPolymerTypes[alphabet as ALPHABET];
|
|
115
116
|
|
|
116
|
-
const lib: IMonomerLib =
|
|
117
|
-
return lib.getTooltip(polymerType, monomerSymbol);
|
|
117
|
+
const lib: IMonomerLib | null = getMonomerLib();
|
|
118
|
+
return lib ? lib.getTooltip(polymerType, monomerSymbol) : ui.divText('Monomer library is not available');
|
|
118
119
|
})();
|
|
119
120
|
}
|
|
120
121
|
tooltipElements.push(monomerDiv);
|
|
@@ -142,23 +143,17 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
|
142
143
|
_cellStyle: DG.GridCellStyle
|
|
143
144
|
): void {
|
|
144
145
|
const logPrefix: string = 'MacromoleculeSequenceCellRenderer.render()';
|
|
146
|
+
|
|
147
|
+
const dpr = window.devicePixelRatio;
|
|
148
|
+
const [gridCol, tableCol, _temp] =
|
|
149
|
+
getGridCellRendererBack<string, MonomerPlacer>(gridCell);
|
|
150
|
+
if (!tableCol) return;
|
|
151
|
+
const tableColTemp: TempType = tableCol.temp;
|
|
152
|
+
|
|
145
153
|
let gapLength = 0;
|
|
146
154
|
const msaGapLength = 8;
|
|
147
155
|
let maxLengthOfMonomer = 50; // in case of long monomer representation, do not limit max length
|
|
148
156
|
|
|
149
|
-
// TODO: Store temp data to GridColumn
|
|
150
|
-
// Now the renderer requires data frame table Column underlying GridColumn
|
|
151
|
-
let grid: DG.Grid | undefined = undefined;
|
|
152
|
-
try { grid = gridCell.grid; } catch (err: any) {
|
|
153
|
-
grid = undefined;
|
|
154
|
-
const [errMsg, errStack] = errInfo(err);
|
|
155
|
-
_package.logger.error(errMsg, undefined, errStack);
|
|
156
|
-
}
|
|
157
|
-
const tableCol: DG.Column = gridCell.cell.column;
|
|
158
|
-
if (!grid || !tableCol) return;
|
|
159
|
-
|
|
160
|
-
const tableColTemp: TempType = tableCol.temp;
|
|
161
|
-
|
|
162
157
|
// Cell renderer settings
|
|
163
158
|
const tempMonomerWidth: string | null = tableColTemp[tempTAGS.monomerWidth];
|
|
164
159
|
const monomerWidth: string = (tempMonomerWidth != null) ? tempMonomerWidth : 'short';
|
|
@@ -170,46 +165,41 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
|
170
165
|
(!isNaN(tagMaxMonomerLength) ? tagMaxMonomerLength : _package.properties?.MaxMonomerLength) ?? 4;
|
|
171
166
|
}
|
|
172
167
|
|
|
173
|
-
const [
|
|
168
|
+
const [_gc, _tc, temp] =
|
|
174
169
|
getGridCellRendererBack<string, MonomerPlacer>(gridCell);
|
|
175
|
-
let seqColTemp: MonomerPlacer = temp
|
|
170
|
+
let seqColTemp: MonomerPlacer = temp.rendererBack;
|
|
176
171
|
if (!seqColTemp) {
|
|
177
|
-
seqColTemp = new MonomerPlacer(gridCol, tableCol, _package.logger,
|
|
172
|
+
seqColTemp = temp.rendererBack = new MonomerPlacer(gridCol, tableCol, _package.logger,
|
|
178
173
|
() => {
|
|
179
174
|
const sh = SeqHandler.forColumn(tableCol);
|
|
180
175
|
return {
|
|
181
176
|
seqHandler: sh,
|
|
182
177
|
monomerCharWidth: 7, separatorWidth: !sh.isMsa() ? gapLength : msaGapLength,
|
|
183
178
|
monomerToShort: monomerToShortFunction, monomerLengthLimit: maxLengthOfMonomer,
|
|
184
|
-
monomerLib: getBioLib()
|
|
185
179
|
};
|
|
186
180
|
});
|
|
187
181
|
}
|
|
188
182
|
|
|
189
|
-
if (tableCol.tags[mmcrTags.RendererSettingsChanged] === rendererSettingsChangedState.true) {
|
|
190
|
-
gapLength = tableColTemp[mmcrTemps.gapLength] as number ?? gapLength;
|
|
191
|
-
// this event means that the mm renderer settings have changed, particularly monomer representation and max width.
|
|
192
|
-
seqColTemp.setMonomerLengthLimit(maxLengthOfMonomer);
|
|
193
|
-
seqColTemp.setSeparatorWidth(seqColTemp.isMsa() ? msaGapLength : gapLength);
|
|
194
|
-
tableCol.setTag(mmcrTags.RendererSettingsChanged, rendererSettingsChangedState.false);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
const [maxLengthWords, maxLengthWordsSum]: [number[], number[]] =
|
|
198
|
-
seqColTemp.getCellMonomerLengths(gridCell.tableRowIndex!);
|
|
199
|
-
const _maxIndex = maxLengthWords.length;
|
|
200
|
-
|
|
201
|
-
// Store updated seqColTemp to the col temp
|
|
202
|
-
if (seqColTemp.updated) temp['rendererBack'] = seqColTemp;
|
|
203
|
-
|
|
204
183
|
g.save();
|
|
205
184
|
try {
|
|
206
|
-
|
|
207
|
-
|
|
185
|
+
if (tableCol.tags[mmcrTags.RendererSettingsChanged] === rendererSettingsChangedState.true) {
|
|
186
|
+
gapLength = tableColTemp[mmcrTemps.gapLength] as number ?? gapLength;
|
|
187
|
+
// this event means that the mm renderer settings have changed,
|
|
188
|
+
// particularly monomer representation and max width.
|
|
189
|
+
seqColTemp.setMonomerLengthLimit(maxLengthOfMonomer);
|
|
190
|
+
seqColTemp.setSeparatorWidth(seqColTemp.isMsa() ? msaGapLength : gapLength);
|
|
191
|
+
tableCol.setTag(mmcrTags.RendererSettingsChanged, rendererSettingsChangedState.false);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const [maxLengthWords, maxLengthWordsSum]: [number[], number[]] =
|
|
195
|
+
seqColTemp.getCellMonomerLengths(gridCell.tableRowIndex!, w);
|
|
196
|
+
const _maxIndex = maxLengthWords.length;
|
|
197
|
+
|
|
208
198
|
const value: any = gridCell.cell.value;
|
|
209
199
|
const rowIdx = gridCell.cell.rowIndex;
|
|
210
200
|
const paletteType = tableCol.getTag(bioTAGS.alphabet);
|
|
211
201
|
const minDistanceRenderer = 50;
|
|
212
|
-
w = getUpdatedWidth(grid, g, x, w, dpr);
|
|
202
|
+
w = getUpdatedWidth(gridCol?.grid, g, x, w, dpr);
|
|
213
203
|
g.beginPath();
|
|
214
204
|
g.rect(x + this.padding, y + this.padding, w - this.padding - 1, h - this.padding * 2);
|
|
215
205
|
g.clip();
|
|
@@ -223,7 +213,8 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
|
223
213
|
const palette = getPaletteByType(paletteType);
|
|
224
214
|
|
|
225
215
|
const separator = tableCol.getTag(bioTAGS.separator) ?? '';
|
|
226
|
-
const
|
|
216
|
+
const minMonWidth = seqColTemp.props.separatorWidth + 1 * seqColTemp.props.monomerCharWidth;
|
|
217
|
+
const splitLimit = Math.ceil(w / minMonWidth);
|
|
227
218
|
const sh = SeqHandler.forColumn(tableCol);
|
|
228
219
|
|
|
229
220
|
const tempReferenceSequence: string | null = tableColTemp[tempTAGS.referenceSequence];
|
|
@@ -247,7 +238,8 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
|
247
238
|
if (aligned && aligned.includes('MSA') && units == NOTATION.SEPARATOR)
|
|
248
239
|
drawStyle = DrawStyle.MSA;
|
|
249
240
|
|
|
250
|
-
|
|
241
|
+
const visibleSeqLength = Math.min(subParts.length, splitLimit);
|
|
242
|
+
for (let posIdx: number = 0; posIdx < visibleSeqLength; ++posIdx) {
|
|
251
243
|
const amino: string = subParts.getOriginal(posIdx);
|
|
252
244
|
color = palette.get(amino);
|
|
253
245
|
g.fillStyle = undefinedColor;
|
|
@@ -259,8 +251,9 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
|
259
251
|
if (minDistanceRenderer > w) break;
|
|
260
252
|
}
|
|
261
253
|
} catch (err: any) {
|
|
262
|
-
const errMsg
|
|
263
|
-
|
|
254
|
+
const [errMsg, errStack] = errInfo(err);
|
|
255
|
+
seqColTemp.logger.error(errMsg, undefined, errStack);
|
|
256
|
+
seqColTemp.errors.push(err);
|
|
264
257
|
//throw err; // Do not throw to prevent disabling renderer
|
|
265
258
|
} finally {
|
|
266
259
|
g.restore();
|