@datagrok/peptides 1.5.1 → 1.7.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/.eslintrc.json +2 -0
- package/dist/package-test.js +5127 -60267
- package/dist/package.js +4838 -60056
- package/dist/vendors-node_modules_datagrok-libraries_ml_src_workers_dimensionality-reducer_js.js +354 -265
- package/files/tests/aligned_5k.d42 +0 -0
- package/package.json +15 -22
- package/src/model.ts +373 -236
- package/src/package-test.ts +1 -0
- package/src/package.ts +23 -50
- package/src/styles.css +7 -0
- package/src/tests/core.ts +54 -13
- package/src/tests/peptide-space-test.ts +5 -53
- package/src/tests/viewers.ts +17 -0
- package/src/utils/cell-renderer.ts +28 -29
- package/src/utils/constants.ts +11 -1
- package/src/utils/misc.ts +16 -4
- package/src/utils/peptide-similarity-space.ts +1 -1
- package/src/utils/types.ts +2 -0
- package/src/viewers/logo-summary.ts +239 -74
- package/src/viewers/sar-viewer.ts +63 -49
- package/src/widgets/distribution.ts +74 -29
- package/src/widgets/manual-alignment.ts +2 -2
- package/src/widgets/mutation-cliffs.ts +6 -2
- package/src/widgets/peptides.ts +17 -10
- package/jest.config.js +0 -33
- package/src/__jest__/remote.test.ts +0 -76
- package/src/__jest__/test-node.ts +0 -97
- package/test-Peptides-4775b69ad08a-1bc1a2b4.html +0 -277
package/src/package-test.ts
CHANGED
package/src/package.ts
CHANGED
|
@@ -10,19 +10,23 @@ import {MonomerPosition, MostPotentResiduesViewer} from './viewers/sar-viewer';
|
|
|
10
10
|
|
|
11
11
|
import {PeptideSpaceViewer} from './viewers/peptide-space-viewer';
|
|
12
12
|
import {LogoSummary} from './viewers/logo-summary';
|
|
13
|
-
import {MonomerWorks} from '@datagrok-libraries/bio';
|
|
13
|
+
import {MonomerWorks} from '@datagrok-libraries/bio/src/monomer-works/monomer-works';
|
|
14
|
+
import {PeptidesModel} from './model';
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
let monomerWorks: MonomerWorks | null = null;
|
|
16
17
|
|
|
17
18
|
export const _package = new DG.Package();
|
|
18
|
-
let currentTable: DG.DataFrame;
|
|
19
|
-
let alignedSequenceColumn: DG.Column;
|
|
20
19
|
|
|
21
20
|
export function getMonomerWorks(): MonomerWorks | null {
|
|
22
21
|
return monomerWorks;
|
|
23
|
-
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
//tags: init
|
|
25
|
+
export async function initPeptides(): Promise<void> {
|
|
26
|
+
monomerWorks ??= new MonomerWorks(await grok.functions.call('Bio:getBioLib'));
|
|
27
|
+
}
|
|
24
28
|
|
|
25
|
-
async function
|
|
29
|
+
async function openDemoData(chosenFile: string): Promise<void> {
|
|
26
30
|
const pi = DG.TaskBarProgressIndicator.create('Loading Peptides');
|
|
27
31
|
const path = _package.webRoot + 'files/' + chosenFile;
|
|
28
32
|
const peptides = await grok.data.loadTable(path);
|
|
@@ -36,13 +40,10 @@ async function main(chosenFile: string): Promise<void> {
|
|
|
36
40
|
|
|
37
41
|
//name: Peptides
|
|
38
42
|
//tags: app
|
|
39
|
-
export
|
|
43
|
+
export function Peptides(): void {
|
|
40
44
|
const wikiLink = ui.link('wiki', 'https://github.com/datagrok-ai/public/blob/master/help/domains/bio/peptides.md');
|
|
41
45
|
const textLink = ui.inlineText(['For more details, see our ', wikiLink, '.']);
|
|
42
|
-
|
|
43
|
-
const lib = await grok.functions.call('Bio:getBioLib');
|
|
44
|
-
monomerWorks = new MonomerWorks(lib);
|
|
45
|
-
}
|
|
46
|
+
|
|
46
47
|
const appDescription = ui.info(
|
|
47
48
|
[
|
|
48
49
|
ui.list([
|
|
@@ -72,9 +73,9 @@ export async function Peptides(): Promise<void> {
|
|
|
72
73
|
appDescription,
|
|
73
74
|
ui.info([textLink]),
|
|
74
75
|
ui.divH([
|
|
75
|
-
ui.button('Simple demo', () =>
|
|
76
|
-
ui.button('Complex demo', () =>
|
|
77
|
-
ui.button('HELM demo', () =>
|
|
76
|
+
ui.button('Simple demo', () => openDemoData('aligned.csv'), ''),
|
|
77
|
+
ui.button('Complex demo', () => openDemoData('aligned_2.csv'), ''),
|
|
78
|
+
ui.button('HELM demo', () => openDemoData('aligned_3.csv'), ''),
|
|
78
79
|
]),
|
|
79
80
|
]);
|
|
80
81
|
}
|
|
@@ -96,8 +97,7 @@ export function peptidesDialog(): DG.Dialog {
|
|
|
96
97
|
//input: column col {semType: Macromolecule}
|
|
97
98
|
//output: widget result
|
|
98
99
|
export function peptidesPanel(col: DG.Column): DG.Widget {
|
|
99
|
-
|
|
100
|
-
const analyzeObject = analyzePeptidesUI(currentTable, alignedSequenceColumn);
|
|
100
|
+
const analyzeObject = analyzePeptidesUI(col.dataFrame, col);
|
|
101
101
|
return new DG.Widget(analyzeObject.host);
|
|
102
102
|
}
|
|
103
103
|
|
|
@@ -137,9 +137,14 @@ export function peptideSpace(): PeptideSpaceViewer {
|
|
|
137
137
|
//input: string _monomer {semType: Monomer}
|
|
138
138
|
//output: widget result
|
|
139
139
|
export function manualAlignment(_monomer: string): DG.Widget {
|
|
140
|
-
[currentTable, alignedSequenceColumn] = getOrDefine();
|
|
141
140
|
//TODO: recalculate Molfile and Molecule panels on sequence update
|
|
142
|
-
|
|
141
|
+
const df = grok.shell.t;
|
|
142
|
+
const model: PeptidesModel | null = df?.temp[PeptidesModel.modelName];
|
|
143
|
+
if (!model)
|
|
144
|
+
return new DG.Widget(ui.divText('Manual alignment works with peptides analysis'));
|
|
145
|
+
|
|
146
|
+
const col = df.getCol(model.settings.sequenceColumnName!);
|
|
147
|
+
return manualAlignmentWidget(col, df);
|
|
143
148
|
}
|
|
144
149
|
|
|
145
150
|
//name: Peptide Space
|
|
@@ -147,38 +152,6 @@ export function manualAlignment(_monomer: string): DG.Widget {
|
|
|
147
152
|
//input: column col {semType: Macromolecule}
|
|
148
153
|
//output: widget result
|
|
149
154
|
export async function peptideSpacePanel(col: DG.Column): Promise<DG.Widget> {
|
|
150
|
-
[currentTable, alignedSequenceColumn] = getOrDefine(col.dataFrame, col);
|
|
151
155
|
const widget = new PeptideSimilaritySpaceWidget(col, grok.shell.v as DG.TableView);
|
|
152
156
|
return widget.draw();
|
|
153
157
|
}
|
|
154
|
-
|
|
155
|
-
//name: Get Peptides Structure
|
|
156
|
-
//tags: panel, widgets
|
|
157
|
-
//input: column col {semType: Macromolecule}
|
|
158
|
-
//output: widget result
|
|
159
|
-
export function getPeptidesStructure(col: DG.Column): DG.Widget {
|
|
160
|
-
const getButtonTooltip = 'Retrieves peptides structure from customer database by special id column';
|
|
161
|
-
const getButton = ui.button('Get structure', async () => {
|
|
162
|
-
const progress = DG.TaskBarProgressIndicator.create('Getting structure...');
|
|
163
|
-
try {
|
|
164
|
-
const params = {peptidesTable: col.dataFrame};
|
|
165
|
-
const result = await grok.functions.call('Customerextensions:getPeptidesStructure', params);
|
|
166
|
-
const text = result ? 'Structure retreived' : 'Structure retreivial is not possible';
|
|
167
|
-
grok.shell.info(text);
|
|
168
|
-
} catch (e) {
|
|
169
|
-
console.warn(e);
|
|
170
|
-
} finally {
|
|
171
|
-
progress.close();
|
|
172
|
-
}
|
|
173
|
-
}, getButtonTooltip);
|
|
174
|
-
return new DG.Widget(getButton);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
function getOrDefine(dataframe?: DG.DataFrame, column?: DG.Column | null): [DG.DataFrame, DG.Column] {
|
|
178
|
-
dataframe ??= grok.shell.t;
|
|
179
|
-
column ??= dataframe.columns.bySemType(DG.SEMTYPE.MACROMOLECULE)!;
|
|
180
|
-
if (column === null)
|
|
181
|
-
throw new Error('Table does not contain aligned sequence columns');
|
|
182
|
-
|
|
183
|
-
return [dataframe, column];
|
|
184
|
-
}
|
package/src/styles.css
CHANGED
package/src/tests/core.ts
CHANGED
|
@@ -8,7 +8,7 @@ import {startAnalysis} from '../widgets/peptides';
|
|
|
8
8
|
import {PeptidesModel} from '../model';
|
|
9
9
|
import * as C from '../utils/constants';
|
|
10
10
|
import {scaleActivity} from '../utils/misc';
|
|
11
|
-
import {
|
|
11
|
+
import {ALIGNMENT, ALPHABET, NOTATION, TAGS as bioTAGS} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
12
12
|
|
|
13
13
|
category('Core', () => {
|
|
14
14
|
let simpleTable: DG.DataFrame;
|
|
@@ -32,16 +32,14 @@ category('Core', () => {
|
|
|
32
32
|
simpleAlignedSeqCol.semType = DG.SEMTYPE.MACROMOLECULE;
|
|
33
33
|
simpleAlignedSeqCol.setTag(C.TAGS.ALPHABET, ALPHABET.PT);
|
|
34
34
|
simpleAlignedSeqCol.setTag(DG.TAGS.UNITS, NOTATION.FASTA);
|
|
35
|
-
simpleAlignedSeqCol.setTag(
|
|
35
|
+
simpleAlignedSeqCol.setTag(bioTAGS.aligned, ALIGNMENT.SEQ_MSA);
|
|
36
36
|
simpleScaledCol = scaleActivity(simpleActivityCol, '-lg');
|
|
37
37
|
|
|
38
38
|
model = await startAnalysis(simpleActivityCol, simpleAlignedSeqCol, null, simpleTable, simpleScaledCol, '-lg');
|
|
39
39
|
expect(model instanceof PeptidesModel, true);
|
|
40
40
|
|
|
41
|
-
if (model != null)
|
|
41
|
+
if (model != null)
|
|
42
42
|
model.mutationCliffsSelection = {'11': ['D']};
|
|
43
|
-
grok.shell.closeTable(model.df);
|
|
44
|
-
}
|
|
45
43
|
});
|
|
46
44
|
|
|
47
45
|
test('Start analysis: сomplex', async () => {
|
|
@@ -52,18 +50,16 @@ category('Core', () => {
|
|
|
52
50
|
complexAlignedSeqCol.semType = DG.SEMTYPE.MACROMOLECULE;
|
|
53
51
|
complexAlignedSeqCol.setTag(C.TAGS.ALPHABET, ALPHABET.UN);
|
|
54
52
|
complexAlignedSeqCol.setTag(DG.TAGS.UNITS, NOTATION.SEPARATOR);
|
|
55
|
-
complexAlignedSeqCol.setTag(
|
|
56
|
-
complexAlignedSeqCol.
|
|
53
|
+
complexAlignedSeqCol.setTag(bioTAGS.aligned, ALIGNMENT.SEQ_MSA);
|
|
54
|
+
complexAlignedSeqCol.setTag(C.TAGS.SEPARATOR, '/');
|
|
57
55
|
complexScaledCol = scaleActivity(complexActivityCol, '-lg');
|
|
58
56
|
|
|
59
57
|
model = await startAnalysis(
|
|
60
58
|
complexActivityCol, complexAlignedSeqCol, null, complexTable, complexScaledCol, '-lg');
|
|
61
59
|
expect(model instanceof PeptidesModel, true);
|
|
62
60
|
|
|
63
|
-
if (model != null)
|
|
61
|
+
if (model != null)
|
|
64
62
|
model.mutationCliffsSelection = {'13': ['-']};
|
|
65
|
-
grok.shell.closeTable(model.df);
|
|
66
|
-
}
|
|
67
63
|
});
|
|
68
64
|
|
|
69
65
|
test('Save and load project', async () => {
|
|
@@ -74,7 +70,7 @@ category('Core', () => {
|
|
|
74
70
|
simpleAlignedSeqCol.semType = DG.SEMTYPE.MACROMOLECULE;
|
|
75
71
|
simpleAlignedSeqCol.setTag(C.TAGS.ALPHABET, ALPHABET.PT);
|
|
76
72
|
simpleAlignedSeqCol.setTag(DG.TAGS.UNITS, NOTATION.FASTA);
|
|
77
|
-
simpleAlignedSeqCol.setTag(
|
|
73
|
+
simpleAlignedSeqCol.setTag(bioTAGS.aligned, ALIGNMENT.SEQ_MSA);
|
|
78
74
|
simpleScaledCol = scaleActivity(simpleActivityCol, '-lg');
|
|
79
75
|
|
|
80
76
|
model = await startAnalysis(simpleActivityCol, simpleAlignedSeqCol, null, simpleTable, simpleScaledCol, '-lg');
|
|
@@ -95,12 +91,57 @@ category('Core', () => {
|
|
|
95
91
|
grok.shell.closeTable(d);
|
|
96
92
|
await delay(500);
|
|
97
93
|
|
|
98
|
-
await
|
|
94
|
+
await sp.open();
|
|
99
95
|
v = grok.shell.getTableView('Peptides analysis');
|
|
100
|
-
grok.shell.closeTable(v.dataFrame);
|
|
101
96
|
|
|
102
97
|
await grok.dapi.layouts.delete(sl);
|
|
103
98
|
await grok.dapi.tables.delete(sti);
|
|
104
99
|
await grok.dapi.projects.delete(sp);
|
|
105
100
|
});
|
|
101
|
+
|
|
102
|
+
test('Cluster stats - Benchmark HELM 5k', async () => {
|
|
103
|
+
const df = (await _package.files.readBinaryDataFrames('tests/aligned_5k_2.d42'))[0];
|
|
104
|
+
const activityCol = df.getCol('Activity');
|
|
105
|
+
const scaledActivityCol = scaleActivity(activityCol, 'none');
|
|
106
|
+
const clustersCol = df.getCol('Cluster');
|
|
107
|
+
const sequenceCol = df.getCol('HELM');
|
|
108
|
+
sequenceCol.semType = DG.SEMTYPE.MACROMOLECULE;
|
|
109
|
+
sequenceCol.setTag(DG.TAGS.UNITS, NOTATION.HELM);
|
|
110
|
+
const model = await startAnalysis(activityCol, sequenceCol, clustersCol, df, scaledActivityCol, 'none');
|
|
111
|
+
|
|
112
|
+
for (let i = 0; i < 5; ++i)
|
|
113
|
+
DG.time('Cluster stats', () => model?.calculateClusterStatistics());
|
|
114
|
+
}, {skipReason: 'Benchmark'});
|
|
115
|
+
|
|
116
|
+
test('Monomer Position stats - Benchmark HELM 5k', async () => {
|
|
117
|
+
const df = (await _package.files.readBinaryDataFrames('tests/aligned_5k.d42'))[0];
|
|
118
|
+
const activityCol = df.getCol('Activity');
|
|
119
|
+
const scaledActivityCol = scaleActivity(activityCol, 'none');
|
|
120
|
+
const clustersCol = df.getCol('Cluster');
|
|
121
|
+
const sequenceCol = df.getCol('HELM');
|
|
122
|
+
sequenceCol.semType = DG.SEMTYPE.MACROMOLECULE;
|
|
123
|
+
sequenceCol.setTag(DG.TAGS.UNITS, NOTATION.HELM);
|
|
124
|
+
const model = await startAnalysis(activityCol, sequenceCol, clustersCol, df, scaledActivityCol, 'none');
|
|
125
|
+
|
|
126
|
+
for (let i = 0; i < 5; ++i)
|
|
127
|
+
DG.time('Monomer position stats', () => model?.calculateMonomerPositionStatistics());
|
|
128
|
+
}, {skipReason: 'Benchmark'});
|
|
129
|
+
|
|
130
|
+
test('Analysis start - Benchmark HELM 5k', async () => {
|
|
131
|
+
const df = (await _package.files.readBinaryDataFrames('tests/aligned_5k.d42'))[0];
|
|
132
|
+
const activityCol = df.getCol('Activity');
|
|
133
|
+
const scaledActivityCol = scaleActivity(activityCol, 'none');
|
|
134
|
+
const clustersCol = df.getCol('Cluster');
|
|
135
|
+
const sequenceCol = df.getCol('HELM');
|
|
136
|
+
sequenceCol.semType = DG.SEMTYPE.MACROMOLECULE;
|
|
137
|
+
sequenceCol.setTag(DG.TAGS.UNITS, NOTATION.HELM);
|
|
138
|
+
|
|
139
|
+
for (let i = 0; i < 5; ++i) {
|
|
140
|
+
await DG.timeAsync('Analysis start', async () => {
|
|
141
|
+
const model = await startAnalysis(activityCol, sequenceCol, clustersCol, df, scaledActivityCol, 'none');
|
|
142
|
+
if (model)
|
|
143
|
+
grok.shell.closeTable(model.df);
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}, {skipReason: 'Benchmark'});
|
|
106
147
|
});
|
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
import {/*before, after, */after, category, test} from '@datagrok-libraries/utils/src/test';
|
|
2
|
-
import
|
|
3
|
-
_testViewerIsDrawing,
|
|
4
|
-
_testDimensionalityReducer,
|
|
5
|
-
_testPeptideSimilaritySpaceViewer,
|
|
6
|
-
_testTableIsNotEmpty,
|
|
7
|
-
} from './utils';
|
|
2
|
+
import * as utils from './utils';
|
|
8
3
|
import {DimensionalityReducer} from '@datagrok-libraries/ml/src/reduce-dimensionality';
|
|
9
4
|
import {cleanAlignedSequencesColumn} from '../utils/peptide-similarity-space';
|
|
10
5
|
import {aligned1} from './test-data';
|
|
@@ -12,7 +7,6 @@ import {aligned1} from './test-data';
|
|
|
12
7
|
import * as DG from 'datagrok-api/dg';
|
|
13
8
|
import * as grok from 'datagrok-api/grok';
|
|
14
9
|
import {StringMetrics} from '@datagrok-libraries/ml/src/typed-metrics';
|
|
15
|
-
import {computeWeights} from '../viewers/peptide-space-viewer';
|
|
16
10
|
import {_package} from '../package-test';
|
|
17
11
|
|
|
18
12
|
let table: DG.DataFrame;
|
|
@@ -22,12 +16,12 @@ category('Peptide space', async () => {
|
|
|
22
16
|
table = DG.DataFrame.fromCsv(aligned1);
|
|
23
17
|
|
|
24
18
|
test('test_table.is_not_empty', async () => {
|
|
25
|
-
_testTableIsNotEmpty(table);
|
|
19
|
+
utils._testTableIsNotEmpty(table);
|
|
26
20
|
});
|
|
27
21
|
|
|
28
22
|
test('PeptideSimilaritySpaceWidget.is_drawing', async () => {
|
|
29
23
|
view = grok.shell.addTableView(table);
|
|
30
|
-
await _testViewerIsDrawing(table, view);
|
|
24
|
+
await utils._testViewerIsDrawing(table, view);
|
|
31
25
|
});
|
|
32
26
|
|
|
33
27
|
const alignedSequencesColumn = table.getCol('AlignedSequence');
|
|
@@ -37,7 +31,7 @@ category('Peptide space', async () => {
|
|
|
37
31
|
for (const method of DimensionalityReducer.availableMethods) {
|
|
38
32
|
for (const measure of DimensionalityReducer.availableMetricsByType('String')) {
|
|
39
33
|
test(`peptide_space.DimensinalityReducer.${method}.${measure}.is_numeric`, async () => {
|
|
40
|
-
await _testDimensionalityReducer(columnData, method as StringMetrics, measure);
|
|
34
|
+
await utils._testDimensionalityReducer(columnData, method as StringMetrics, measure);
|
|
41
35
|
});
|
|
42
36
|
}
|
|
43
37
|
}
|
|
@@ -47,51 +41,9 @@ category('Peptide space', async () => {
|
|
|
47
41
|
for (const method of DimensionalityReducer.availableMethods) {
|
|
48
42
|
for (const measure of DimensionalityReducer.availableMetricsByType('String')) {
|
|
49
43
|
test(`peptide_space.PeptideSimilaritySpaceViewer.${method}.${measure}.is_proper`, async () => {
|
|
50
|
-
await _testPeptideSimilaritySpaceViewer(table, alignedSequencesColumn, method, measure, 100);//, view);
|
|
44
|
+
await utils._testPeptideSimilaritySpaceViewer(table, alignedSequencesColumn, method, measure, 100);//, view);
|
|
51
45
|
});
|
|
52
46
|
}
|
|
53
47
|
}
|
|
54
48
|
});
|
|
55
|
-
|
|
56
|
-
after(async () => {
|
|
57
|
-
view?.close();
|
|
58
|
-
});
|
|
59
49
|
});
|
|
60
|
-
|
|
61
|
-
// category('Peptide Space Performance', () => {
|
|
62
|
-
// test('test_compute_weights_performance', async () => {
|
|
63
|
-
// const table = DG.DataFrame.fromCsv(await _package.files.readAsText('peptides_large.csv'));
|
|
64
|
-
// const results: {[key: string]: {[key: string]: {[key: string]: number}}} = {};
|
|
65
|
-
// const sliceVolumes = [1, 2, 3, 4, 5, 7, 10];
|
|
66
|
-
// const methods = DimensionalityReducer.availableMethods;
|
|
67
|
-
// const metrics = DimensionalityReducer.availableMetricsByType('String');
|
|
68
|
-
// const totalRuns = sliceVolumes.length * methods.length * metrics.length;
|
|
69
|
-
// console.log('Started Peptide Space Performance benchmark...');
|
|
70
|
-
|
|
71
|
-
// let run = 0;
|
|
72
|
-
// for (const slice of sliceVolumes) {
|
|
73
|
-
// const bitset = DG.BitSet.create(table.rowCount, (i) => i < slice * 1000);
|
|
74
|
-
// const tableSlice = table.clone(bitset);
|
|
75
|
-
// const col = tableSlice.getCol('sequence');
|
|
76
|
-
// const methodObj: {[key: string]: {[key: string]: number}} = {};
|
|
77
|
-
|
|
78
|
-
// for (const method of methods) {
|
|
79
|
-
// const measureObj: {[key: string]: number} = {};
|
|
80
|
-
|
|
81
|
-
// for (const metric of metrics) {
|
|
82
|
-
// console.log(`Run ${run++}/${totalRuns}`);
|
|
83
|
-
|
|
84
|
-
// const start = new Date();
|
|
85
|
-
// await computeWeights(tableSlice, method, metric, 100, col);
|
|
86
|
-
// const stop = new Date();
|
|
87
|
-
|
|
88
|
-
// measureObj[metric] = stop.getTime() - start.getTime();
|
|
89
|
-
// }
|
|
90
|
-
// methodObj[method] = measureObj;
|
|
91
|
-
// }
|
|
92
|
-
// results[`${slice}k`] = methodObj;
|
|
93
|
-
// }
|
|
94
|
-
// console.log('Peptide Space Performance benchmark finished...');
|
|
95
|
-
// console.log(results);
|
|
96
|
-
// });
|
|
97
|
-
// });
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as DG from 'datagrok-api/dg';
|
|
2
|
+
import * as grok from 'datagrok-api/grok';
|
|
3
|
+
//import * as ui from 'datagrok-api/ui';
|
|
4
|
+
|
|
5
|
+
import {category, test, testViewer} from '@datagrok-libraries/utils/src/test';
|
|
6
|
+
import {aligned1} from './test-data';
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
category('Viewers', () => {
|
|
10
|
+
const df = DG.DataFrame.fromCsv(aligned1);
|
|
11
|
+
const viewers = DG.Func.find({package: 'Peptides', tags: ['viewer']}).map((f) => f.friendlyName);
|
|
12
|
+
for (const v of viewers) {
|
|
13
|
+
test(v, async () => {
|
|
14
|
+
await testViewer(v, df.clone(), true);
|
|
15
|
+
}, {skipReason: 'GROK-11534'});
|
|
16
|
+
}
|
|
17
|
+
});
|
|
@@ -2,7 +2,9 @@ import * as DG from 'datagrok-api/dg';
|
|
|
2
2
|
|
|
3
3
|
import * as C from './constants';
|
|
4
4
|
import * as types from './types';
|
|
5
|
-
import
|
|
5
|
+
import {PositionStats, SummaryStats, MonomerPositionStats} from '../model';
|
|
6
|
+
import {SeqPalette} from '@datagrok-libraries/bio/src/seq-palettes';
|
|
7
|
+
import {monomerToShort} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
6
8
|
|
|
7
9
|
function renderCellSelection(canvasContext: CanvasRenderingContext2D, bound: DG.Rect): void {
|
|
8
10
|
canvasContext.strokeStyle = '#000';
|
|
@@ -18,34 +20,32 @@ export function setAARRenderer(col: DG.Column, alphabet: string): void {
|
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
export function renderMutationCliffCell(canvasContext: CanvasRenderingContext2D, currentAAR: string,
|
|
21
|
-
currentPosition: string,
|
|
23
|
+
currentPosition: string, monomerPositionStats: MonomerPositionStats, bound: DG.Rect,
|
|
22
24
|
mutationCliffsSelection: types.PositionToAARList, substitutionsInfo: types.SubstitutionsInfo,
|
|
23
25
|
twoColorMode: boolean = false): void {
|
|
24
|
-
const
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
.groupBy([C.COLUMNS_NAMES.P_VALUE])
|
|
28
|
-
.where(query)
|
|
29
|
-
.aggregate()
|
|
30
|
-
.get(C.COLUMNS_NAMES.P_VALUE, 0);
|
|
26
|
+
const positionStats = monomerPositionStats[currentPosition];
|
|
27
|
+
const pVal: number = positionStats[currentAAR].pValue;
|
|
28
|
+
const currentMeanDiff = positionStats[currentAAR].meanDifference;
|
|
31
29
|
|
|
32
30
|
let coef: string;
|
|
33
|
-
const
|
|
31
|
+
const isMeanDeltaNegative = currentMeanDiff < 0;
|
|
34
32
|
if (pVal < 0.01)
|
|
35
|
-
coef =
|
|
33
|
+
coef = isMeanDeltaNegative && twoColorMode ? '#FF7900' : '#299617';
|
|
36
34
|
else if (pVal < 0.05)
|
|
37
|
-
coef =
|
|
35
|
+
coef = isMeanDeltaNegative && twoColorMode ? '#FFA500' : '#32CD32';
|
|
38
36
|
else if (pVal < 0.1)
|
|
39
|
-
coef =
|
|
37
|
+
coef = isMeanDeltaNegative && twoColorMode ? '#FBCEB1' : '#98FF98';
|
|
40
38
|
else
|
|
41
39
|
coef = DG.Color.toHtml(DG.Color.lightLightGray);
|
|
42
40
|
|
|
43
41
|
|
|
44
|
-
const
|
|
45
|
-
const
|
|
46
|
-
|
|
42
|
+
const minMeanDifference = twoColorMode ? 0 : monomerPositionStats.general.minMeanDifference;
|
|
43
|
+
const maxMeanDifference = twoColorMode ?
|
|
44
|
+
Math.max(Math.abs(monomerPositionStats.general.minMeanDifference), monomerPositionStats.general.maxMeanDifference) :
|
|
45
|
+
monomerPositionStats.general.maxMeanDifference;
|
|
46
|
+
const currentMeanDifference = twoColorMode ? Math.abs(currentMeanDiff) : currentMeanDiff;
|
|
47
47
|
|
|
48
|
-
const rCoef = (
|
|
48
|
+
const rCoef = (currentMeanDifference - minMeanDifference) / (maxMeanDifference - minMeanDifference);
|
|
49
49
|
|
|
50
50
|
const maxRadius = 0.9 * (bound.width > bound.height ? bound.height : bound.width) / 2;
|
|
51
51
|
const radius = Math.floor(maxRadius * rCoef);
|
|
@@ -92,22 +92,22 @@ export function renderInvaraintMapCell(canvasContext: CanvasRenderingContext2D,
|
|
|
92
92
|
renderCellSelection(canvasContext, bound);
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
export function renderLogoSummaryCell(canvasContext: CanvasRenderingContext2D, cellValue: string,
|
|
96
|
-
clusterSelection:
|
|
95
|
+
export function renderLogoSummaryCell(canvasContext: CanvasRenderingContext2D, cellValue: string,
|
|
96
|
+
clusterSelection: string[], bound: DG.Rect): void {
|
|
97
97
|
canvasContext.font = '13px Roboto, Roboto Local, sans-serif';
|
|
98
98
|
canvasContext.textAlign = 'center';
|
|
99
99
|
canvasContext.textBaseline = 'middle';
|
|
100
100
|
canvasContext.fillStyle = '#000';
|
|
101
101
|
canvasContext.fillText(cellValue.toString(), bound.x + (bound.width / 2), bound.y + (bound.height / 2), bound.width);
|
|
102
102
|
|
|
103
|
-
if (clusterSelection.includes(
|
|
103
|
+
if (clusterSelection.includes(cellValue))
|
|
104
104
|
renderCellSelection(canvasContext, bound);
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
|
|
108
|
-
export function drawLogoInBounds(ctx: CanvasRenderingContext2D, bounds: DG.Rect,
|
|
109
|
-
rowCount: number, cp:
|
|
110
|
-
drawOptions: types.DrawOptions = {}): {[monomer: string]: DG.Rect} {
|
|
108
|
+
export function drawLogoInBounds(ctx: CanvasRenderingContext2D, bounds: DG.Rect, stats: PositionStats,
|
|
109
|
+
sortedOrder: string[], rowCount: number, cp: SeqPalette, monomerSelectionStats: { [monomer: string]: number } = {},
|
|
110
|
+
drawOptions: types.DrawOptions = {}): { [monomer: string]: DG.Rect } {
|
|
111
111
|
drawOptions.fontStyle ??= '16px Roboto, Roboto Local, sans-serif';
|
|
112
112
|
drawOptions.upperLetterHeight ??= 12.2;
|
|
113
113
|
drawOptions.upperLetterAscent ??= 0.25;
|
|
@@ -115,7 +115,7 @@ export function drawLogoInBounds(ctx: CanvasRenderingContext2D, bounds: DG.Rect,
|
|
|
115
115
|
drawOptions.marginHorizontal ??= 5;
|
|
116
116
|
|
|
117
117
|
const pr = window.devicePixelRatio;
|
|
118
|
-
const totalSpaceBetweenLetters = (
|
|
118
|
+
const totalSpaceBetweenLetters = (sortedOrder.length - 1) * drawOptions.upperLetterAscent;
|
|
119
119
|
const barHeight = (bounds.height - 2 * drawOptions.marginVertical - totalSpaceBetweenLetters) * pr;
|
|
120
120
|
const leftShift = drawOptions.marginHorizontal * 2;
|
|
121
121
|
const barWidth = (bounds.width - leftShift * 2) * pr;
|
|
@@ -124,17 +124,16 @@ export function drawLogoInBounds(ctx: CanvasRenderingContext2D, bounds: DG.Rect,
|
|
|
124
124
|
const xSelection = (bounds.x + 3) * pr;
|
|
125
125
|
let currentY = (bounds.y + drawOptions.marginVertical) * pr;
|
|
126
126
|
|
|
127
|
-
const monomerBounds: {[monomer: string]: DG.Rect} = {};
|
|
128
|
-
for (const
|
|
129
|
-
const
|
|
130
|
-
const monomerHeight = barHeight * (statsInfo.countCol.get(index)! / rowCount);
|
|
127
|
+
const monomerBounds: { [monomer: string]: DG.Rect } = {};
|
|
128
|
+
for (const monomer of sortedOrder) {
|
|
129
|
+
const monomerHeight = barHeight * (stats[monomer].count / rowCount);
|
|
131
130
|
const selectionHeight = barHeight * ((monomerSelectionStats[monomer] ?? 0) / rowCount);
|
|
132
131
|
const currentBound = new DG.Rect(xStart / pr, currentY / pr, barWidth / pr, monomerHeight / pr);
|
|
133
132
|
monomerBounds[monomer] = currentBound;
|
|
134
133
|
|
|
135
134
|
ctx.resetTransform();
|
|
136
135
|
if (monomer !== '-' && monomer !== '') {
|
|
137
|
-
const monomerTxt =
|
|
136
|
+
const monomerTxt = monomerToShort(monomer, 5);
|
|
138
137
|
const mTm: TextMetrics = ctx.measureText(monomerTxt);
|
|
139
138
|
|
|
140
139
|
// Filling selection
|
package/src/utils/constants.ts
CHANGED
|
@@ -7,7 +7,15 @@ export enum COLUMNS_NAMES {
|
|
|
7
7
|
MEAN_DIFFERENCE = 'Mean difference',
|
|
8
8
|
COUNT = 'Count',
|
|
9
9
|
RATIO = 'Ratio',
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export enum LST_COLUMN_NAMES {
|
|
10
13
|
MEMBERS = 'Members',
|
|
14
|
+
WEB_LOGO = 'WebLogo',
|
|
15
|
+
DISTRIBUTION = 'Distribution',
|
|
16
|
+
MEAN_DIFFERENCE = 'Mean difference',
|
|
17
|
+
P_VALUE = 'P-Value',
|
|
18
|
+
RATIO = 'Ratio',
|
|
11
19
|
}
|
|
12
20
|
|
|
13
21
|
export enum CATEGORIES {
|
|
@@ -26,6 +34,8 @@ export enum TAGS {
|
|
|
26
34
|
CLUSTER_SELECTION = 'clusterSelection',
|
|
27
35
|
VISIBLE = 'visible',
|
|
28
36
|
SETTINGS = 'settings',
|
|
37
|
+
CUSTOM_CLUSTER = 'customCluster',
|
|
38
|
+
UUID = 'pep-uuid',
|
|
29
39
|
}
|
|
30
40
|
|
|
31
41
|
export enum SEM_TYPES {
|
|
@@ -35,4 +45,4 @@ export enum SEM_TYPES {
|
|
|
35
45
|
|
|
36
46
|
export const EMBEDDING_STATUS = 'embeddingStatus';
|
|
37
47
|
|
|
38
|
-
export const
|
|
48
|
+
export const MULTIPLE_VIEWS = 'isMultipleViews';
|
package/src/utils/misc.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import {StringDictionary} from '@datagrok-libraries/utils/src/type-declarations';
|
|
2
|
+
import * as ui from 'datagrok-api/ui';
|
|
1
3
|
import * as DG from 'datagrok-api/dg';
|
|
2
4
|
import * as C from './constants';
|
|
3
5
|
import * as type from './types';
|
|
@@ -36,6 +38,7 @@ export function scaleActivity(activityCol: DG.Column<number>, scaling: string =
|
|
|
36
38
|
return scaledCol;
|
|
37
39
|
}
|
|
38
40
|
|
|
41
|
+
//TODO: optimize
|
|
39
42
|
export function calculateSelected(df: DG.DataFrame): type.MonomerSelectionStats {
|
|
40
43
|
const monomerColumns: DG.Column<string>[] = df.columns.bySemTypeAll(C.SEM_TYPES.MONOMER);
|
|
41
44
|
const selectedObj: type.MonomerSelectionStats = {};
|
|
@@ -54,10 +57,10 @@ export function calculateSelected(df: DG.DataFrame): type.MonomerSelectionStats
|
|
|
54
57
|
return selectedObj;
|
|
55
58
|
}
|
|
56
59
|
|
|
57
|
-
export function isGridCellInvalid(gc: DG.GridCell | null): boolean {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
60
|
+
// export function isGridCellInvalid(gc: DG.GridCell | null): boolean {
|
|
61
|
+
// return !gc || !gc.cell.value || !gc.tableColumn || gc.tableRowIndex == null || gc.tableRowIndex == -1 ||
|
|
62
|
+
// gc.cell.value == DG.INT_NULL || gc.cell.value == DG.FLOAT_NULL;
|
|
63
|
+
// }
|
|
61
64
|
|
|
62
65
|
export function extractMonomerInfo(col: DG.Column<string>): type.RawColumn {
|
|
63
66
|
return {
|
|
@@ -66,3 +69,12 @@ export function extractMonomerInfo(col: DG.Column<string>): type.RawColumn {
|
|
|
66
69
|
rawData: col.getRawData(),
|
|
67
70
|
};
|
|
68
71
|
}
|
|
72
|
+
|
|
73
|
+
export function wrapDistroAndStatsDefault(labels: HTMLDivElement, histRoot: HTMLElement, tableMap: StringDictionary,
|
|
74
|
+
isTooltip: boolean = false): HTMLDivElement {
|
|
75
|
+
const result = ui.divV([labels, histRoot, ui.tableFromMap(tableMap)]);
|
|
76
|
+
result.style.minWidth = '200px';
|
|
77
|
+
if (isTooltip)
|
|
78
|
+
histRoot.style.maxHeight = '150px';
|
|
79
|
+
return result;
|
|
80
|
+
}
|
|
@@ -188,7 +188,7 @@ export class PeptideSimilaritySpaceWidget {
|
|
|
188
188
|
}
|
|
189
189
|
|
|
190
190
|
/**
|
|
191
|
-
* Draws a viewer on
|
|
191
|
+
* Draws a viewer on context panel.
|
|
192
192
|
*
|
|
193
193
|
* @return {Promise<DG.Widget>} The corresponding widget.
|
|
194
194
|
* @memberof PeptideSimilaritySpaceWidget
|