@datagrok/bio 2.10.4 → 2.10.6
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 +9 -6
- package/dist/package-test.js +1 -1
- package/dist/package-test.js.map +1 -1
- package/dist/package.js +1 -1
- package/dist/package.js.map +1 -1
- package/package.json +3 -4
- package/src/analysis/sequence-diversity-viewer.ts +1 -1
- package/src/analysis/sequence-search-base-viewer.ts +20 -7
- package/src/analysis/sequence-similarity-viewer.ts +1 -1
- package/src/package.ts +4 -11
- package/src/tests/activity-cliffs-tests.ts +1 -1
- package/src/tests/similarity-diversity-tests.ts +68 -30
- package/src/tests/viewers.ts +8 -1
- package/src/utils/cell-renderer-consts.ts +0 -1
- package/src/utils/cell-renderer.ts +5 -4
- package/src/viewers/vd-regions-viewer.ts +20 -11
- package/src/viewers/web-logo-viewer.ts +4 -4
- package/src/widgets/representations.ts +11 -4
package/package.json
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datagrok/bio",
|
|
3
3
|
"friendlyName": "Bio",
|
|
4
|
-
"skipCI": true,
|
|
5
4
|
"author": {
|
|
6
5
|
"name": "Leonid Stolbov",
|
|
7
6
|
"email": "lstolbov@datagrok.ai"
|
|
8
7
|
},
|
|
9
|
-
"version": "2.10.
|
|
8
|
+
"version": "2.10.6",
|
|
10
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.",
|
|
11
10
|
"repository": {
|
|
12
11
|
"type": "git",
|
|
@@ -35,7 +34,7 @@
|
|
|
35
34
|
],
|
|
36
35
|
"dependencies": {
|
|
37
36
|
"@biowasm/aioli": "^3.1.0",
|
|
38
|
-
"@datagrok-libraries/bio": "^5.38.
|
|
37
|
+
"@datagrok-libraries/bio": "^5.38.4",
|
|
39
38
|
"@datagrok-libraries/chem-meta": "^1.0.1",
|
|
40
39
|
"@datagrok-libraries/ml": "^6.3.39",
|
|
41
40
|
"@datagrok-libraries/tutorials": "^1.3.6",
|
|
@@ -64,7 +63,7 @@
|
|
|
64
63
|
"webpack-bundle-analyzer": "latest",
|
|
65
64
|
"webpack-cli": "^4.9.1",
|
|
66
65
|
"@datagrok/chem": "1.7.2",
|
|
67
|
-
"@datagrok/helm": "2.1.
|
|
66
|
+
"@datagrok/helm": "2.1.17"
|
|
68
67
|
},
|
|
69
68
|
"scripts": {
|
|
70
69
|
"link-api": "npm link datagrok-api",
|
|
@@ -22,7 +22,7 @@ export class SequenceDiversityViewer extends SequenceSearchBaseViewer {
|
|
|
22
22
|
this.diverseColumnLabel = this.string('diverseColumnLabel', null);
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
async
|
|
25
|
+
override async renderInt(computeData: boolean): Promise<void> {
|
|
26
26
|
if (!this.beforeRender())
|
|
27
27
|
return;
|
|
28
28
|
if (this.dataFrame) {
|
|
@@ -6,6 +6,7 @@ import {CHEM_SIMILARITY_METRICS} from '@datagrok-libraries/ml/src/distance-metri
|
|
|
6
6
|
import {TAGS as bioTAGS} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
7
7
|
|
|
8
8
|
const MAX_ROWS_FOR_DISTANCE_MATRIX = 22000;
|
|
9
|
+
|
|
9
10
|
export class SequenceSearchBaseViewer extends DG.JsViewer {
|
|
10
11
|
name: string = '';
|
|
11
12
|
distanceMetric: string;
|
|
@@ -13,11 +14,12 @@ export class SequenceSearchBaseViewer extends DG.JsViewer {
|
|
|
13
14
|
fingerprint: string;
|
|
14
15
|
metricsProperties = ['distanceMetric', 'fingerprint'];
|
|
15
16
|
fingerprintChoices = ['Morgan', 'Pattern'];
|
|
16
|
-
moleculeColumn?: DG.Column|null;
|
|
17
|
+
moleculeColumn?: DG.Column | null;
|
|
17
18
|
moleculeColumnName: string;
|
|
18
19
|
initialized: boolean = false;
|
|
19
20
|
tags = [DG.TAGS.UNITS, bioTAGS.aligned, bioTAGS.separator, bioTAGS.alphabet];
|
|
20
21
|
preComputeDistanceMatrix: boolean = false;
|
|
22
|
+
|
|
21
23
|
constructor(name: string) {
|
|
22
24
|
super();
|
|
23
25
|
this.fingerprint = this.string('fingerprint', this.fingerprintChoices[0], {choices: this.fingerprintChoices});
|
|
@@ -40,19 +42,20 @@ export class SequenceSearchBaseViewer extends DG.JsViewer {
|
|
|
40
42
|
|
|
41
43
|
if (this.dataFrame) {
|
|
42
44
|
this.preComputeDistanceMatrix = this.dataFrame.rowCount <= MAX_ROWS_FOR_DISTANCE_MATRIX;
|
|
43
|
-
this.subs.push(DG.debounce(this.dataFrame.onRowsRemoved, 50)
|
|
45
|
+
this.subs.push(DG.debounce(this.dataFrame.onRowsRemoved, 50)
|
|
46
|
+
.subscribe((_: any) => this.render(true)));
|
|
44
47
|
const compute = this.name !== 'diversity';
|
|
45
48
|
this.subs.push(DG.debounce(this.dataFrame.onCurrentRowChanged, 50)
|
|
46
|
-
.subscribe(
|
|
49
|
+
.subscribe((_: any) => this.render(compute)));
|
|
47
50
|
this.subs.push(DG.debounce(this.dataFrame.selection.onChanged, 50)
|
|
48
|
-
.subscribe(
|
|
51
|
+
.subscribe((_: any) => this.render(false)));
|
|
49
52
|
this.subs.push(DG.debounce(ui.onSizeChanged(this.root), 50)
|
|
50
|
-
.subscribe(
|
|
53
|
+
.subscribe((_: any) => this.render(false)));
|
|
51
54
|
this.moleculeColumn = this.dataFrame.columns.bySemType(DG.SEMTYPE.MACROMOLECULE);
|
|
52
55
|
this.moleculeColumnName = this.moleculeColumn?.name!;
|
|
53
56
|
this.getProperty('limit')!.fromOptions({min: 1, max: this.dataFrame.rowCount});
|
|
54
57
|
}
|
|
55
|
-
|
|
58
|
+
this.render();
|
|
56
59
|
}
|
|
57
60
|
|
|
58
61
|
onPropertyChanged(property: DG.Property): void {
|
|
@@ -67,7 +70,17 @@ export class SequenceSearchBaseViewer extends DG.JsViewer {
|
|
|
67
70
|
this.render();
|
|
68
71
|
}
|
|
69
72
|
|
|
70
|
-
|
|
73
|
+
/** For tests */ public computeRequested: boolean;
|
|
74
|
+
public renderPromise: Promise<void> = Promise.resolve();
|
|
75
|
+
|
|
76
|
+
protected render(computeData = true): void {
|
|
77
|
+
this.renderPromise = this.renderPromise.then(async () => {
|
|
78
|
+
this.computeRequested = this.computeRequested || computeData;
|
|
79
|
+
await this.renderInt(computeData);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async renderInt(_computeData: boolean): Promise<void> {
|
|
71
84
|
|
|
72
85
|
}
|
|
73
86
|
|
|
@@ -39,7 +39,7 @@ export class SequenceSimilarityViewer extends SequenceSearchBaseViewer {
|
|
|
39
39
|
this.initialized = true;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
async
|
|
42
|
+
override async renderInt(computeData: boolean): Promise<void> {
|
|
43
43
|
if (!this.beforeRender())
|
|
44
44
|
return;
|
|
45
45
|
if (this.moleculeColumn) {
|
package/src/package.ts
CHANGED
|
@@ -162,13 +162,6 @@ export function getBioLib(): IMonomerLib {
|
|
|
162
162
|
//input: column seqCol {semType: Macromolecule}
|
|
163
163
|
//output: widget result
|
|
164
164
|
export function getRegionPanel(seqCol: DG.Column<string>): DG.Widget {
|
|
165
|
-
// const host = ui.divV([
|
|
166
|
-
// ui.inputs([
|
|
167
|
-
// ui.stringInput('Region', ''),
|
|
168
|
-
// ]),
|
|
169
|
-
// ui.button('Ok', () => {})
|
|
170
|
-
// ]);
|
|
171
|
-
// return DG.Widget.fromRoot(host);
|
|
172
165
|
const funcName: string = 'getRegionTopMenu';
|
|
173
166
|
const funcList = DG.Func.find({package: _package.name, name: funcName});
|
|
174
167
|
if (funcList.length !== 1) throw new Error(`Package '${_package.name}' func '${funcName}' not found`);
|
|
@@ -357,7 +350,7 @@ export function getRegion(
|
|
|
357
350
|
}
|
|
358
351
|
|
|
359
352
|
//top-menu: Bio | Convert | Get Region...
|
|
360
|
-
//name: Get Region
|
|
353
|
+
//name: Get Region Top Menu
|
|
361
354
|
//description: Get sequences for a region specified from a Macromolecule
|
|
362
355
|
//input: dataframe table [Input data table]
|
|
363
356
|
//input: column sequence {semType: Macromolecule} [Sequence column]
|
|
@@ -784,7 +777,7 @@ export function similaritySearchViewer(): SequenceSimilarityViewer {
|
|
|
784
777
|
return new SequenceSimilarityViewer();
|
|
785
778
|
}
|
|
786
779
|
|
|
787
|
-
//top-menu: Bio | Search | Similarity
|
|
780
|
+
//top-menu: Bio | Search | Similarity Search
|
|
788
781
|
//name: similaritySearch
|
|
789
782
|
//description: Finds similar sequences
|
|
790
783
|
//output: viewer result
|
|
@@ -802,7 +795,7 @@ export function diversitySearchViewer(): SequenceDiversityViewer {
|
|
|
802
795
|
return new SequenceDiversityViewer();
|
|
803
796
|
}
|
|
804
797
|
|
|
805
|
-
//top-menu: Bio | Search | Diversity
|
|
798
|
+
//top-menu: Bio | Search | Diversity Search
|
|
806
799
|
//name: diversitySearch
|
|
807
800
|
//description: Finds the most diverse sequences
|
|
808
801
|
//output: viewer result
|
|
@@ -823,7 +816,7 @@ export function searchSubsequenceEditor(call: DG.FuncCall) {
|
|
|
823
816
|
new SubstructureSearchDialog(columns);
|
|
824
817
|
}
|
|
825
818
|
|
|
826
|
-
//top-menu: Bio | Search | Subsequence...
|
|
819
|
+
//top-menu: Bio | Search | Subsequence Search ...
|
|
827
820
|
//name: Subsequence Search
|
|
828
821
|
//input: column macromolecules
|
|
829
822
|
//editor: Bio:SearchSubsequenceEditor
|
|
@@ -38,7 +38,7 @@ category('activityCliffs', async () => {
|
|
|
38
38
|
const cliffsNum = DG.Test.isInBenchmark ? 6 : 3;
|
|
39
39
|
|
|
40
40
|
await _testActivityCliffsOpen(actCliffsDf, cliffsNum, DimReductionMethods.UMAP, 'sequence');
|
|
41
|
-
});
|
|
41
|
+
}, {skipReason: 'GROK-13952'});
|
|
42
42
|
|
|
43
43
|
test('activityCliffsWithEmptyRows', async () => {
|
|
44
44
|
actCliffsDfWithEmptyRows = await readDataframe('tests/100_3_clustests_empty_vals.csv');
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import {category, test, expect, awaitCheck} from '@datagrok-libraries/utils/src/test';
|
|
1
|
+
import {category, test, expect, awaitCheck, delay} from '@datagrok-libraries/utils/src/test';
|
|
2
2
|
import * as DG from 'datagrok-api/dg';
|
|
3
3
|
import {createTableView} from './utils';
|
|
4
4
|
import * as grok from 'datagrok-api/grok';
|
|
5
5
|
import {SequenceSimilarityViewer} from '../analysis/sequence-similarity-viewer';
|
|
6
|
+
import {SequenceDiversityViewer} from '../analysis/sequence-diversity-viewer';
|
|
6
7
|
|
|
7
8
|
category('similarity/diversity', async () => {
|
|
8
9
|
test('similaritySearchViewer', async () => {
|
|
@@ -15,49 +16,86 @@ category('similarity/diversity', async () => {
|
|
|
15
16
|
});
|
|
16
17
|
|
|
17
18
|
async function _testSimilaritySearchViewer() {
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
'Sequence Similarity Search
|
|
22
|
-
|
|
19
|
+
const moleculesView = await createTableView('tests/sample_MSA_data.csv');
|
|
20
|
+
|
|
21
|
+
const viewer: SequenceSimilarityViewer = (await moleculesView.dataFrame.plot
|
|
22
|
+
.fromType('Sequence Similarity Search')) as SequenceSimilarityViewer;
|
|
23
|
+
let computeCompleted: boolean = false;
|
|
24
|
+
viewer.computeCompleted.subscribe((value) => {
|
|
25
|
+
if (value) computeCompleted = true;
|
|
26
|
+
});
|
|
27
|
+
moleculesView.dockManager.dock(viewer, DG.DOCK_TYPE.RIGHT, null, 'Similarity');
|
|
28
|
+
await viewer.renderPromise; // required to wait for computeCompleted
|
|
29
|
+
|
|
30
|
+
await awaitCheck(() => getSearchViewer(moleculesView, 'Sequence Similarity Search') !== undefined,
|
|
31
|
+
'Sequence Similarity Search viewer has not been created', 100);
|
|
32
|
+
if (!viewer.initialized) throw new Error('The viewer is not initialized.');
|
|
33
|
+
if (!viewer.moleculeColumn) throw new Error('The viewer has not molecule column (onTableAttached).');
|
|
34
|
+
if (!viewer.beforeRender()) throw new Error('The viewer is not able to render.');
|
|
35
|
+
if (!viewer.computeRequested) throw new Error('The viewer has not compute requested even.');
|
|
36
|
+
if (!computeCompleted) throw new Error('The viewer has not compute completed.');
|
|
37
|
+
|
|
38
|
+
const similaritySearchViewer = viewer;
|
|
23
39
|
await awaitCheck(() => similaritySearchViewer.root.getElementsByClassName('d4-grid').length !== 0,
|
|
24
|
-
'Sequence Similarity Search has not been created',
|
|
40
|
+
'Sequence Similarity Search viewer grid has not been created', 100);
|
|
41
|
+
|
|
42
|
+
/* eslint-disable max-len */
|
|
43
|
+
const str0: string = 'D-Tyr_Et/Tyr_ab-dehydroMe/dV/E/N/D-Orn/D-aThr//Phe_4Me';
|
|
44
|
+
const str1: string = 'meI/hHis//Aca/meM/Tyr_ab-dehydroMe/dV/E/N/D-Orn/D-aThr//Phe_4Me';
|
|
45
|
+
const simStr1: string = 'meI/hHis/Aca/Cys_SEt/T/dK/Thr_PO3H2/Aca/Tyr_PO3H2/D-Chg/dV/Phe_ab-dehydro/N/D-Orn/D-aThr//Phe_4Me';
|
|
46
|
+
/* eslint-enable max-len */
|
|
47
|
+
|
|
25
48
|
expect(similaritySearchViewer.fingerprint, 'Morgan');
|
|
26
49
|
expect(similaritySearchViewer.distanceMetric, 'Tanimoto');
|
|
27
50
|
expect(similaritySearchViewer.scores!.get(0), DG.FLOAT_NULL);
|
|
28
51
|
expect(similaritySearchViewer.idxs!.get(0), 0);
|
|
29
|
-
expect(similaritySearchViewer.molCol!.get(0),
|
|
30
|
-
'D-Tyr_Et/Tyr_ab-dehydroMe/dV/E/N/D-Orn/D-aThr//Phe_4Me');
|
|
52
|
+
expect(similaritySearchViewer.molCol!.get(0), str0);
|
|
31
53
|
expect(similaritySearchViewer.scores!.get(1), 0.4722222089767456);
|
|
32
54
|
expect(similaritySearchViewer.idxs!.get(1), 11);
|
|
33
|
-
expect(similaritySearchViewer.molCol!.get(1),
|
|
34
|
-
|
|
35
|
-
molecules.dataFrame.currentRowIdx = 1;
|
|
55
|
+
expect(similaritySearchViewer.molCol!.get(1), str1);
|
|
56
|
+
moleculesView.dataFrame.currentRowIdx = 1;
|
|
36
57
|
await awaitCheck(() => similaritySearchViewer.targetMoleculeIdx === 1,
|
|
37
58
|
'Target molecule has not been changed', 5000);
|
|
38
|
-
await awaitCheck(() => similaritySearchViewer.molCol!.get(0) ===
|
|
39
|
-
|
|
40
|
-
'Incorrect first similar molecule', 5000);
|
|
59
|
+
await awaitCheck(() => similaritySearchViewer.molCol!.get(0) === simStr1,
|
|
60
|
+
'Incorrect first similar molecule', 5000);
|
|
41
61
|
}
|
|
42
62
|
|
|
43
63
|
async function _testDiversitySearchViewer() {
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
'Sequence Diversity Search
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
64
|
+
const moleculesView = await createTableView('tests/sample_MSA_data.csv');
|
|
65
|
+
|
|
66
|
+
const viewer: SequenceDiversityViewer = (await moleculesView.dataFrame.plot
|
|
67
|
+
.fromType('Sequence Diversity Search')) as SequenceDiversityViewer;
|
|
68
|
+
let computeCompleted: boolean = false;
|
|
69
|
+
viewer.computeCompleted.subscribe((value) => {
|
|
70
|
+
if (value) computeCompleted = true;
|
|
71
|
+
});
|
|
72
|
+
moleculesView.dockManager.dock(viewer, DG.DOCK_TYPE.DOWN, null, 'Diversity');
|
|
73
|
+
await viewer.renderPromise;
|
|
74
|
+
|
|
75
|
+
await awaitCheck(() => getSearchViewer(moleculesView, 'Sequence Diversity Search') !== undefined,
|
|
76
|
+
'Sequence Diversity Search viewer has not been created', 100);
|
|
77
|
+
if (!viewer.initialized) throw new Error('The viewer is not initialized.');
|
|
78
|
+
if (!viewer.moleculeColumn) throw new Error('The viewer has not molecule column (onTableAttached).');
|
|
79
|
+
if (!viewer.beforeRender()) throw new Error('The viewer is not able to render.');
|
|
80
|
+
if (!viewer.computeRequested) throw new Error('The viewer has not compute requested even.');
|
|
81
|
+
if (!computeCompleted) throw new Error('The viewer has not compute completed.');
|
|
82
|
+
|
|
83
|
+
//const diversitySearchViewer = getSearchViewer(viewer, 'Sequence Diversity Search');
|
|
84
|
+
const diversitySearchViewer = viewer;
|
|
85
|
+
await awaitCheck(() => diversitySearchViewer.root.getElementsByClassName('d4-grid').length !== 0,
|
|
86
|
+
'Sequence Diversity Search viewer grid has not been created', 100);
|
|
87
|
+
|
|
88
|
+
expect(diversitySearchViewer.fingerprint, 'Morgan');
|
|
89
|
+
expect(diversitySearchViewer.distanceMetric, 'Tanimoto');
|
|
90
|
+
expect(diversitySearchViewer.initialized, true);
|
|
91
|
+
expect(diversitySearchViewer.renderMolIds!.length > 0, true);
|
|
55
92
|
}
|
|
56
93
|
|
|
57
|
-
function getSearchViewer(
|
|
58
|
-
|
|
59
|
-
for (const v of
|
|
94
|
+
function getSearchViewer(tv: DG.TableView, name: string): DG.Viewer | null {
|
|
95
|
+
let res: DG.Viewer | null = null;
|
|
96
|
+
for (const v of tv.viewers) {
|
|
60
97
|
if (v.type === name)
|
|
61
|
-
|
|
98
|
+
res = v;
|
|
62
99
|
}
|
|
100
|
+
return res;
|
|
63
101
|
}
|
package/src/tests/viewers.ts
CHANGED
|
@@ -12,6 +12,13 @@ category('viewers', () => {
|
|
|
12
12
|
test(v, async () => {
|
|
13
13
|
const df = await readDataframe('data/sample_FASTA_DNA.csv');
|
|
14
14
|
await testViewer(v, df, {detectSemanticTypes: true});
|
|
15
|
-
},
|
|
15
|
+
}, {
|
|
16
|
+
skipReason: {
|
|
17
|
+
'Sequence Similarity Search': 'GROK-13162',
|
|
18
|
+
'Sequence Diversity Search': 'GROK-13162',
|
|
19
|
+
'WebLogo': 'GROK-13162',
|
|
20
|
+
'VdRegions': 'GROK-13162',
|
|
21
|
+
}[v],
|
|
22
|
+
});
|
|
16
23
|
}
|
|
17
24
|
});
|
|
@@ -18,7 +18,6 @@ export const rendererSettingsChangedState = {
|
|
|
18
18
|
|
|
19
19
|
export const enum Temps {
|
|
20
20
|
monomerWidth = '.mm.cellRenderer.monomerWidth',
|
|
21
|
-
maxMonomerLength = '.mm.cellRenderer.maxMonomerLength',
|
|
22
21
|
colorCode = '.mm.cellRenderer.colorCode',
|
|
23
22
|
compareWithCurrent = '.mm.cellRenderer.compareWithCurrent',
|
|
24
23
|
highlightDifference = '.mm.cellRenderer.highlightDifference',
|
|
@@ -4,7 +4,7 @@ import * as ui from 'datagrok-api/ui';
|
|
|
4
4
|
|
|
5
5
|
import wu from 'wu';
|
|
6
6
|
|
|
7
|
-
import {printLeftOrCentered, DrawStyle} from '@datagrok-libraries/bio/src/utils/cell-renderer';
|
|
7
|
+
import {printLeftOrCentered, DrawStyle, TAGS as mmcrTAGS} from '@datagrok-libraries/bio/src/utils/cell-renderer';
|
|
8
8
|
import {MonomerPlacer} from '@datagrok-libraries/bio/src/utils/cell-renderer-monomer-placer';
|
|
9
9
|
import {
|
|
10
10
|
getPaletteByType,
|
|
@@ -132,7 +132,7 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
|
132
132
|
): void {
|
|
133
133
|
let gapLength = 0;
|
|
134
134
|
const msaGapLength = 8;
|
|
135
|
-
let maxLengthOfMonomer =
|
|
135
|
+
let maxLengthOfMonomer = 50; // in case of long monomer representation, do not limit max length
|
|
136
136
|
|
|
137
137
|
// TODO: Store temp data to GridColumn
|
|
138
138
|
// Now the renderer requires data frame table Column underlying GridColumn
|
|
@@ -146,10 +146,11 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
|
|
|
146
146
|
if (monomerWidth === 'short') {
|
|
147
147
|
// Renderer can start to work before Bio package initialized, in that time _package.properties is null.
|
|
148
148
|
// TODO: Render function is available but package init method is not completed
|
|
149
|
-
|
|
149
|
+
const tagMaxMonomerLength: number = parseInt(tableCol.getTag(mmcrTAGS.maxMonomerLength));
|
|
150
|
+
maxLengthOfMonomer =
|
|
151
|
+
(!isNaN(tagMaxMonomerLength) ? tagMaxMonomerLength : _package.properties?.MaxMonomerLength) ?? 4;
|
|
150
152
|
}
|
|
151
153
|
|
|
152
|
-
|
|
153
154
|
let seqColTemp: MonomerPlacer = tableCol.temp[tempTAGS.bioSeqCol];
|
|
154
155
|
if (!seqColTemp) {
|
|
155
156
|
seqColTemp = new MonomerPlacer(grid, tableCol,
|
|
@@ -7,6 +7,7 @@ import {fromEvent, Unsubscribable} from 'rxjs';
|
|
|
7
7
|
import {
|
|
8
8
|
IVdRegionsViewer,
|
|
9
9
|
VdRegion, VdRegionType,
|
|
10
|
+
VdRegionsProps, VdRegionsPropsDefault,
|
|
10
11
|
} from '@datagrok-libraries/bio/src/viewers/vd-regions';
|
|
11
12
|
import {FilterSources, IWebLogoViewer, PositionHeight} from '@datagrok-libraries/bio/src/viewers/web-logo';
|
|
12
13
|
|
|
@@ -55,11 +56,14 @@ export enum PROPS {
|
|
|
55
56
|
regionTypes = 'regionTypes',
|
|
56
57
|
chains = 'chains',
|
|
57
58
|
|
|
58
|
-
// --
|
|
59
|
+
// -- Layout --
|
|
60
|
+
fitWidth = 'fitWidth',
|
|
59
61
|
positionWidth = 'positionWidth',
|
|
60
62
|
positionHeight = 'positionHeight',
|
|
61
63
|
}
|
|
62
64
|
|
|
65
|
+
const defaults: VdRegionsProps = VdRegionsPropsDefault;
|
|
66
|
+
|
|
63
67
|
/** Viewer with tabs based on description of chain regions.
|
|
64
68
|
* Used to define regions of an immunoglobulin LC.
|
|
65
69
|
*/
|
|
@@ -80,7 +84,7 @@ export class VdRegionsViewer extends DG.JsViewer implements IVdRegionsViewer {
|
|
|
80
84
|
// public sequenceColumnNamePostfix: string;
|
|
81
85
|
|
|
82
86
|
public skipEmptyPositions: boolean;
|
|
83
|
-
|
|
87
|
+
public fitWidth: boolean;
|
|
84
88
|
public positionWidth: number;
|
|
85
89
|
public positionHeight: PositionHeight;
|
|
86
90
|
|
|
@@ -88,22 +92,24 @@ export class VdRegionsViewer extends DG.JsViewer implements IVdRegionsViewer {
|
|
|
88
92
|
super();
|
|
89
93
|
|
|
90
94
|
// -- Data --
|
|
91
|
-
this.skipEmptyPositions = this.bool(PROPS.skipEmptyPositions,
|
|
95
|
+
this.skipEmptyPositions = this.bool(PROPS.skipEmptyPositions, defaults.skipEmptyPositions,
|
|
92
96
|
{category: PROPS_CATS.DATA});
|
|
93
97
|
|
|
94
98
|
// To prevent ambiguous numbering scheme in MLB
|
|
95
|
-
this.regionTypes = this.stringList(PROPS.regionTypes,
|
|
99
|
+
this.regionTypes = this.stringList(PROPS.regionTypes, defaults.regionTypes, {
|
|
96
100
|
category: PROPS_CATS.DATA, choices: Object.values(vrt).filter((t) => t != vrt.Unknown)
|
|
97
101
|
}) as VdRegionType[];
|
|
98
|
-
this.chains = this.stringList(PROPS.chains,
|
|
102
|
+
this.chains = this.stringList(PROPS.chains, defaults.chains,
|
|
99
103
|
{category: PROPS_CATS.DATA, choices: ['Heavy', 'Light']});
|
|
100
104
|
|
|
101
105
|
// -- Layout --
|
|
102
|
-
this.
|
|
106
|
+
this.fitWidth = this.bool(PROPS.fitWidth, defaults.fitWidth,
|
|
107
|
+
{category: PROPS_CATS.LAYOUT});
|
|
108
|
+
this.positionWidth = this.float(PROPS.positionWidth, defaults.positionWidth, {
|
|
103
109
|
category: PROPS_CATS.LAYOUT, editor: 'slider', min: 0, max: 64,
|
|
104
|
-
description: 'Internal WebLogo viewers property width of position.
|
|
110
|
+
description: 'Internal WebLogo viewers property width of position.'
|
|
105
111
|
});
|
|
106
|
-
this.positionHeight = this.string(PROPS.positionHeight,
|
|
112
|
+
this.positionHeight = this.string(PROPS.positionHeight, defaults.positionHeight,
|
|
107
113
|
{category: PROPS_CATS.LAYOUT, choices: Object.keys(PositionHeight)}) as PositionHeight;
|
|
108
114
|
}
|
|
109
115
|
|
|
@@ -178,6 +184,7 @@ export class VdRegionsViewer extends DG.JsViewer implements IVdRegionsViewer {
|
|
|
178
184
|
this.calcSize();
|
|
179
185
|
break;
|
|
180
186
|
|
|
187
|
+
case PROPS.fitWidth:
|
|
181
188
|
case PROPS.positionWidth:
|
|
182
189
|
this.calcSize();
|
|
183
190
|
break;
|
|
@@ -274,7 +281,7 @@ export class VdRegionsViewer extends DG.JsViewer implements IVdRegionsViewer {
|
|
|
274
281
|
for (const chain of this.chains) {
|
|
275
282
|
const region: VdRegion | undefined = regionsFiltered
|
|
276
283
|
.find((r) => r.order == orderList[orderI] && r.chain == chain);
|
|
277
|
-
logoPromiseList.push((async () => {
|
|
284
|
+
logoPromiseList.push((async (): Promise<[number, string, WebLogoViewer]> => {
|
|
278
285
|
const wl: WebLogoViewer = await this.dataFrame.plot.fromType('WebLogo', {
|
|
279
286
|
sequenceColumnName: region!.sequenceColumnName,
|
|
280
287
|
startPositionName: region!.positionStartName,
|
|
@@ -381,7 +388,7 @@ export class VdRegionsViewer extends DG.JsViewer implements IVdRegionsViewer {
|
|
|
381
388
|
totalPos += Math.max(...this.chains.map((chain) => this.logos[orderI][chain].Length));
|
|
382
389
|
}
|
|
383
390
|
|
|
384
|
-
if (this.
|
|
391
|
+
if (this.fitWidth) {
|
|
385
392
|
if (this.logos.length > 0 && totalPos > 0) {
|
|
386
393
|
const leftPad = 22/* Chain label */;
|
|
387
394
|
const rightPad = 6 + 6 + 1;
|
|
@@ -392,16 +399,18 @@ export class VdRegionsViewer extends DG.JsViewer implements IVdRegionsViewer {
|
|
|
392
399
|
for (let orderI = 0; orderI < this.logos.length; orderI++) {
|
|
393
400
|
for (const chain of this.chains) {
|
|
394
401
|
const wl = this.logos[orderI][chain];
|
|
395
|
-
wl.setOptions({[wlPROPS.positionWidth]: fitPositionWidth});
|
|
402
|
+
wl.setOptions({[wlPROPS.positionWidth]: (fitPositionWidth - wl.positionMarginValue)});
|
|
396
403
|
wl.root.style.width = `${fitPositionWidth * wl.Length}px`;
|
|
397
404
|
}
|
|
398
405
|
}
|
|
399
406
|
}
|
|
407
|
+
this.host.style.setProperty('overflow', 'hidden', 'important');
|
|
400
408
|
} else {
|
|
401
409
|
for (let orderI = 0; orderI < this.logos.length; orderI++) {
|
|
402
410
|
for (const chain of this.chains)
|
|
403
411
|
this.logos[orderI][chain].setOptions({[wlPROPS.positionWidth]: this.positionWidth});
|
|
404
412
|
}
|
|
413
|
+
this.host.style.removeProperty('overflow');
|
|
405
414
|
}
|
|
406
415
|
|
|
407
416
|
if (this.positionWidth === 0)
|
|
@@ -339,7 +339,7 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
|
|
|
339
339
|
return this.startPosition <= this.endPosition ? this.endPosition - this.startPosition + 1 : 0;
|
|
340
340
|
}
|
|
341
341
|
|
|
342
|
-
|
|
342
|
+
public get positionMarginValue(): number {
|
|
343
343
|
if (this.positionMarginState === PositionMarginStates.AUTO && this.unitsHandler!.getAlphabetIsMultichar() === true)
|
|
344
344
|
return this.positionMargin;
|
|
345
345
|
else if (this.positionMarginState === PositionMarginStates.ON)
|
|
@@ -598,12 +598,11 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
|
|
|
598
598
|
}
|
|
599
599
|
}
|
|
600
600
|
|
|
601
|
-
/** Updates {@link host}, {@link canvas}, {@link slider}.
|
|
601
|
+
/** Updates {@link host}, {@link canvas}, {@link slider} .min, .max.
|
|
602
602
|
* Calls {@link render} with {@link WlRenderLevel.Layout}
|
|
603
603
|
*/
|
|
604
604
|
private calcLayout(dpr: number): void {
|
|
605
605
|
if (!this.host || !this.canvas || !this.slider) return;
|
|
606
|
-
if (this.root.clientHeight === 0 || this.root.clientWidth === 0) return;
|
|
607
606
|
|
|
608
607
|
this.host.classList.remove('bio-wl-fixWidth', 'bio-wl-fitArea');
|
|
609
608
|
this.canvas.classList.remove('bio-wl-fixWidth', 'bio-wl-fitArea');
|
|
@@ -892,7 +891,7 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
|
|
|
892
891
|
/** Renders requested repeatedly will be performed once on window.requestAnimationFrame() */
|
|
893
892
|
render(recalcLevel: WlRenderLevel, reason: string): Promise<void> {
|
|
894
893
|
_package.logger.debug(`Bio: WebLogoViewer<${this.viewerId}>` +
|
|
895
|
-
`.render(
|
|
894
|
+
`.render( recalcLevelVal=${recalcLevel}, reason='${reason}' )`);
|
|
896
895
|
|
|
897
896
|
/** Calculate freqs of monomers */
|
|
898
897
|
const calculateFreqsInt = (): void => {
|
|
@@ -989,6 +988,7 @@ export class WebLogoViewer extends DG.JsViewer implements IWebLogoViewer {
|
|
|
989
988
|
/** 0 is for no position labels */
|
|
990
989
|
const positionLabelsHeight = this.showPositionLabels ? POSITION_LABELS_HEIGHT : 0;
|
|
991
990
|
if (recalcLevel >= WlRenderLevel.Freqs) calculateFreqsInt();
|
|
991
|
+
if (this.positions.length === 0) return;
|
|
992
992
|
if (recalcLevel >= WlRenderLevel.Layout) calculateLayoutInt(window.devicePixelRatio, positionLabelsHeight);
|
|
993
993
|
|
|
994
994
|
const length: number = this.Length;
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import * as grok from 'datagrok-api/grok';
|
|
2
2
|
import * as ui from 'datagrok-api/ui';
|
|
3
3
|
import * as DG from 'datagrok-api/dg';
|
|
4
|
+
|
|
4
5
|
import {getMolfilesFromSingleSeq} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
|
|
5
|
-
import {
|
|
6
|
-
|
|
6
|
+
import {TAGS as mmcrTAGS} from '@datagrok-libraries/bio/src/utils/cell-renderer';
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
Tags as mmcrTags, Temps as mmcrTemps, MonomerWidthMode,
|
|
10
|
+
tempTAGS, rendererSettingsChangedState
|
|
11
|
+
} from '../utils/cell-renderer-consts';
|
|
12
|
+
|
|
7
13
|
import {_package} from '../package';
|
|
8
14
|
|
|
9
15
|
|
|
@@ -31,10 +37,11 @@ export function getMacromoleculeColumnPropertyPanel(col: DG.Column): DG.Widget {
|
|
|
31
37
|
`In short mode, only the 'Max monomer length' characters are displayed, followed by .. if there are more`,
|
|
32
38
|
);
|
|
33
39
|
|
|
40
|
+
const tagMaxMonomerLength: number = parseInt(col.getTag(mmcrTAGS.maxMonomerLength));
|
|
34
41
|
const maxMonomerLength: DG.InputBase = ui.intInput('Max monomer length',
|
|
35
|
-
|
|
42
|
+
!isNaN(tagMaxMonomerLength) ? tagMaxMonomerLength : _package.properties.MaxMonomerLength,
|
|
36
43
|
(value: number) => {
|
|
37
|
-
col.
|
|
44
|
+
col.setTag(mmcrTAGS.maxMonomerLength, value.toString());
|
|
38
45
|
col.setTag(mmcrTags.RendererSettingsChanged, rendererSettingsChangedState.true);
|
|
39
46
|
col.dataFrame.fireValuesChanged();
|
|
40
47
|
});
|