@datagrok/peptides 1.9.2 → 1.11.3
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 +81 -0
- package/dist/209.js +2 -0
- package/dist/521.js +2 -0
- package/dist/535.js +2 -0
- package/dist/729.js +2 -0
- package/dist/959.js +2 -0
- package/dist/package-test.js +2 -2
- package/dist/package.js +2 -2
- package/package.json +13 -11
- package/setup-unlink-clean.sh +0 -0
- package/src/model.ts +302 -232
- package/src/package-test.ts +2 -1
- package/src/package.ts +14 -16
- package/src/tests/algorithms.ts +4 -1
- package/src/tests/core.ts +100 -14
- package/src/tests/model.ts +16 -14
- package/src/tests/peptide-space-test.ts +7 -7
- package/src/tests/table-view.ts +63 -54
- package/src/tests/utils.ts +1 -1
- package/src/tests/viewers.ts +40 -6
- package/src/tests/widgets.ts +100 -18
- package/src/utils/cell-renderer.ts +38 -20
- package/src/utils/constants.ts +3 -0
- package/src/utils/misc.ts +44 -12
- package/src/utils/peptide-similarity-space.ts +3 -4
- package/src/utils/statistics.ts +2 -2
- package/src/utils/types.ts +3 -1
- package/src/viewers/logo-summary.ts +132 -140
- package/src/viewers/peptide-space-viewer.ts +2 -1
- package/src/viewers/sar-viewer.ts +46 -39
- package/src/widgets/distribution.ts +17 -17
- package/src/widgets/mutation-cliffs.ts +91 -19
- package/src/widgets/peptides.ts +12 -13
- package/src/widgets/settings.ts +47 -25
- package/src/widgets/similarity.ts +39 -0
- package/dist/168.js +0 -2
- package/dist/478.js +0 -2
- package/dist/802.js +0 -2
- package/dist/951.js +0 -2
package/src/tests/viewers.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
+
import * as grok from 'datagrok-api/grok';
|
|
1
2
|
import * as DG from 'datagrok-api/dg';
|
|
2
3
|
|
|
3
|
-
import {before, category, expect, test, testViewer} from '@datagrok-libraries/utils/src/test';
|
|
4
|
+
import {awaitCheck, before, category, expect, test, testViewer} from '@datagrok-libraries/utils/src/test';
|
|
4
5
|
import {aligned1} from './test-data';
|
|
5
6
|
import {PeptidesModel, VIEWER_TYPE} from '../model';
|
|
6
7
|
import {_package} from '../package-test';
|
|
7
8
|
import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
8
9
|
import {scaleActivity} from '../utils/misc';
|
|
9
10
|
import {startAnalysis} from '../widgets/peptides';
|
|
10
|
-
import {MONOMER_POSITION_MODE, MonomerPosition,
|
|
11
|
+
import {MONOMER_POSITION_MODE, MonomerPosition, MostPotentResidues, showTooltip} from '../viewers/sar-viewer';
|
|
11
12
|
import {SCALING_METHODS} from '../utils/constants';
|
|
12
13
|
import {LST_PROPERTIES, LogoSummaryTable} from '../viewers/logo-summary';
|
|
13
14
|
import {PositionHeight} from '@datagrok-libraries/bio/src/viewers/web-logo';
|
|
@@ -45,7 +46,18 @@ category('Viewers: Monomer-Position', () => {
|
|
|
45
46
|
if (tempModel === null)
|
|
46
47
|
throw new Error('Model is null');
|
|
47
48
|
model = tempModel;
|
|
49
|
+
let overlayInit = false;
|
|
50
|
+
model._analysisView!.grid.onAfterDrawOverlay.subscribe(() => overlayInit = true);
|
|
51
|
+
|
|
48
52
|
mpViewer = model.findViewer(VIEWER_TYPE.MONOMER_POSITION) as MonomerPosition;
|
|
53
|
+
|
|
54
|
+
// Ensure grid finished initializing to prevent Unhandled exceptions
|
|
55
|
+
let accrodionInit = false;
|
|
56
|
+
grok.events.onAccordionConstructed.subscribe((_) => accrodionInit = true);
|
|
57
|
+
await awaitCheck(() => model!.df.currentRowIdx === 0, 'Grid cell never finished initializing', 2000);
|
|
58
|
+
await awaitCheck(() => grok.shell.o instanceof DG.Column, 'Shell object never changed', 2000);
|
|
59
|
+
await awaitCheck(() => accrodionInit, 'Accordion never finished initializing', 2000);
|
|
60
|
+
await awaitCheck(() => overlayInit, 'Overlay never finished initializing', 2000);
|
|
49
61
|
});
|
|
50
62
|
|
|
51
63
|
test('Tooltip', async () => {
|
|
@@ -70,7 +82,7 @@ category('Viewers: Monomer-Position', () => {
|
|
|
70
82
|
expect(mpViewer.mode, MONOMER_POSITION_MODE.MUTATION_CLIFFS,
|
|
71
83
|
`Monomer-Position mode is not ${MONOMER_POSITION_MODE.MUTATION_CLIFFS} after switching`);
|
|
72
84
|
});
|
|
73
|
-
});
|
|
85
|
+
}, {clear: false});
|
|
74
86
|
|
|
75
87
|
category('Viewers: Most Potent Residues', () => {
|
|
76
88
|
let df: DG.DataFrame;
|
|
@@ -79,7 +91,7 @@ category('Viewers: Most Potent Residues', () => {
|
|
|
79
91
|
let sequenceCol: DG.Column<string>;
|
|
80
92
|
let clusterCol: DG.Column<any>;
|
|
81
93
|
let scaledActivityCol: DG.Column<number>;
|
|
82
|
-
let mprViewer:
|
|
94
|
+
let mprViewer: MostPotentResidues;
|
|
83
95
|
|
|
84
96
|
before(async () => {
|
|
85
97
|
df = DG.DataFrame.fromCsv(await _package.files.readAsText('tests/HELM_small.csv'));
|
|
@@ -94,7 +106,18 @@ category('Viewers: Most Potent Residues', () => {
|
|
|
94
106
|
if (tempModel === null)
|
|
95
107
|
throw new Error('Model is null');
|
|
96
108
|
model = tempModel;
|
|
97
|
-
|
|
109
|
+
let overlayInit = false;
|
|
110
|
+
model._analysisView!.grid.onAfterDrawOverlay.subscribe(() => overlayInit = true);
|
|
111
|
+
|
|
112
|
+
mprViewer = model.findViewer(VIEWER_TYPE.MOST_POTENT_RESIDUES) as MostPotentResidues;
|
|
113
|
+
|
|
114
|
+
// Ensure grid finished initializing to prevent Unhandled exceptions
|
|
115
|
+
let accrodionInit = false;
|
|
116
|
+
grok.events.onAccordionConstructed.subscribe((_) => accrodionInit = true);
|
|
117
|
+
await awaitCheck(() => model!.df.currentRowIdx === 0, 'Grid cell never finished initializing', 2000);
|
|
118
|
+
await awaitCheck(() => grok.shell.o instanceof DG.Column, 'Shell object never changed', 2000);
|
|
119
|
+
await awaitCheck(() => accrodionInit, 'Accordion never finished initializing', 2000);
|
|
120
|
+
await awaitCheck(() => overlayInit, 'Overlay never finished initializing', 2000);
|
|
98
121
|
});
|
|
99
122
|
|
|
100
123
|
test('Tooltip', async () => {
|
|
@@ -127,7 +150,18 @@ category('Viewers: Logo Summary Table', () => {
|
|
|
127
150
|
if (tempModel === null)
|
|
128
151
|
throw new Error('Model is null');
|
|
129
152
|
model = tempModel;
|
|
153
|
+
let overlayInit = false;
|
|
154
|
+
model._analysisView!.grid.onAfterDrawOverlay.subscribe(() => overlayInit = true);
|
|
155
|
+
|
|
130
156
|
lstViewer = model.findViewer(VIEWER_TYPE.LOGO_SUMMARY_TABLE) as LogoSummaryTable;
|
|
157
|
+
|
|
158
|
+
// Ensure grid finished initializing to prevent Unhandled exceptions
|
|
159
|
+
let accrodionInit = false;
|
|
160
|
+
grok.events.onAccordionConstructed.subscribe((_) => accrodionInit = true);
|
|
161
|
+
await awaitCheck(() => model!.df.currentRowIdx === 0, 'Grid cell never finished initializing', 2000);
|
|
162
|
+
await awaitCheck(() => grok.shell.o instanceof DG.Column, 'Shell object never changed', 2000);
|
|
163
|
+
await awaitCheck(() => accrodionInit, 'Accordion never finished initializing', 2000);
|
|
164
|
+
await awaitCheck(() => overlayInit, 'Overlay never finished initializing', 2000);
|
|
131
165
|
});
|
|
132
166
|
|
|
133
167
|
test('Properties', async () => {
|
|
@@ -152,4 +186,4 @@ category('Viewers: Logo Summary Table', () => {
|
|
|
152
186
|
const tooltipElement = lstViewer.showTooltip(cluster, 0, 0);
|
|
153
187
|
expect(tooltipElement !== null, true, `Tooltip is not shown for cluster '${cluster}'`);
|
|
154
188
|
});
|
|
155
|
-
});
|
|
189
|
+
}, {clear: false});
|
package/src/tests/widgets.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import * as grok from 'datagrok-api/grok';
|
|
2
2
|
import * as DG from 'datagrok-api/dg';
|
|
3
3
|
|
|
4
|
-
import {category, test, before, expect,
|
|
4
|
+
import {category, test, before, expect, awaitCheck, expectFloat} from '@datagrok-libraries/utils/src/test';
|
|
5
5
|
import {_package} from '../package-test';
|
|
6
6
|
import {PeptidesModel, VIEWER_TYPE} from '../model';
|
|
7
|
-
import {scaleActivity} from '../utils/misc';
|
|
7
|
+
import {getTemplate, scaleActivity} from '../utils/misc';
|
|
8
8
|
import {startAnalysis} from '../widgets/peptides';
|
|
9
9
|
import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
10
10
|
import * as C from '../utils/constants';
|
|
@@ -14,6 +14,7 @@ import {mutationCliffsWidget} from '../widgets/mutation-cliffs';
|
|
|
14
14
|
import {TEST_COLUMN_NAMES} from './utils';
|
|
15
15
|
import wu from 'wu';
|
|
16
16
|
import {LogoSummaryTable} from '../viewers/logo-summary';
|
|
17
|
+
import {calculateIdentity, calculateSimilarity} from '../widgets/similarity';
|
|
17
18
|
|
|
18
19
|
category('Widgets: Settings', () => {
|
|
19
20
|
let df: DG.DataFrame;
|
|
@@ -36,6 +37,16 @@ category('Widgets: Settings', () => {
|
|
|
36
37
|
if (tempModel === null)
|
|
37
38
|
throw new Error('Model is null');
|
|
38
39
|
model = tempModel;
|
|
40
|
+
let overlayInit = false;
|
|
41
|
+
model._analysisView!.grid.onAfterDrawOverlay.subscribe(() => overlayInit = true);
|
|
42
|
+
|
|
43
|
+
// Ensure grid finished initializing to prevent Unhandled exceptions
|
|
44
|
+
let accrodionInit = false;
|
|
45
|
+
grok.events.onAccordionConstructed.subscribe((_) => accrodionInit = true);
|
|
46
|
+
await awaitCheck(() => model!.df.currentRowIdx === 0, 'Grid cell never finished initializing', 2000);
|
|
47
|
+
await awaitCheck(() => grok.shell.o instanceof DG.Column, 'Shell object never changed', 2000);
|
|
48
|
+
await awaitCheck(() => accrodionInit, 'Accordion never finished initializing', 2000);
|
|
49
|
+
await awaitCheck(() => overlayInit, 'Overlay never finished initializing', 2000);
|
|
39
50
|
});
|
|
40
51
|
|
|
41
52
|
test('UI', async () => {
|
|
@@ -77,15 +88,21 @@ category('Widgets: Distribution panel', () => {
|
|
|
77
88
|
if (tempModel === null)
|
|
78
89
|
throw new Error('Model is null');
|
|
79
90
|
model = tempModel;
|
|
91
|
+
let overlayInit = false;
|
|
92
|
+
model._analysisView!.grid.onAfterDrawOverlay.subscribe(() => overlayInit = true);
|
|
93
|
+
|
|
94
|
+
// Ensure grid finished initializing to prevent Unhandled exceptions
|
|
95
|
+
let accrodionInit = false;
|
|
96
|
+
grok.events.onAccordionConstructed.subscribe((_) => accrodionInit = true);
|
|
97
|
+
await awaitCheck(() => model!.df.currentRowIdx === 0, 'Grid cell never finished initializing', 2000);
|
|
98
|
+
await awaitCheck(() => grok.shell.o instanceof DG.Column, 'Shell object never changed', 2000);
|
|
99
|
+
await awaitCheck(() => accrodionInit, 'Accordion never finished initializing', 2000);
|
|
100
|
+
await awaitCheck(() => overlayInit, 'Overlay never finished initializing', 2000);
|
|
80
101
|
});
|
|
81
102
|
|
|
82
103
|
test('UI', async () => {
|
|
83
104
|
getDistributionWidget(model.df, model);
|
|
84
105
|
});
|
|
85
|
-
|
|
86
|
-
test('Split', async () => {
|
|
87
|
-
|
|
88
|
-
}, {skipReason: 'Not implemented yet'});
|
|
89
106
|
});
|
|
90
107
|
|
|
91
108
|
category('Widgets: Mutation cliffs', () => {
|
|
@@ -109,19 +126,21 @@ category('Widgets: Mutation cliffs', () => {
|
|
|
109
126
|
if (tempModel === null)
|
|
110
127
|
throw new Error('Model is null');
|
|
111
128
|
model = tempModel;
|
|
129
|
+
let overlayInit = false;
|
|
130
|
+
model._analysisView!.grid.onAfterDrawOverlay.subscribe(() => overlayInit = true);
|
|
131
|
+
|
|
132
|
+
// Ensure grid finished initializing to prevent Unhandled exceptions
|
|
133
|
+
let accrodionInit = false;
|
|
134
|
+
grok.events.onAccordionConstructed.subscribe((_) => accrodionInit = true);
|
|
135
|
+
await awaitCheck(() => model!.df.currentRowIdx === 0, 'Grid cell never finished initializing', 2000);
|
|
136
|
+
await awaitCheck(() => grok.shell.o instanceof DG.Column, 'Shell object never changed', 2000);
|
|
137
|
+
await awaitCheck(() => accrodionInit, 'Accordion never finished initializing', 2000);
|
|
138
|
+
await awaitCheck(() => overlayInit, 'Overlay never finished initializing', 2000);
|
|
112
139
|
});
|
|
113
140
|
|
|
114
141
|
test('UI', async () => {
|
|
115
142
|
mutationCliffsWidget(model.df, model);
|
|
116
143
|
});
|
|
117
|
-
|
|
118
|
-
test('General', async () => {
|
|
119
|
-
|
|
120
|
-
}, {skipReason: 'Not implemented yet'});
|
|
121
|
-
|
|
122
|
-
test('Filtering', async () => {
|
|
123
|
-
|
|
124
|
-
}, {skipReason: 'Not implemented yet'});
|
|
125
144
|
});
|
|
126
145
|
|
|
127
146
|
category('Widgets: Actions', () => {
|
|
@@ -145,6 +164,16 @@ category('Widgets: Actions', () => {
|
|
|
145
164
|
if (tempModel === null)
|
|
146
165
|
throw new Error('Model is null');
|
|
147
166
|
model = tempModel;
|
|
167
|
+
let overlayInit = false;
|
|
168
|
+
model._analysisView!.grid.onAfterDrawOverlay.subscribe(() => overlayInit = true);
|
|
169
|
+
|
|
170
|
+
// Ensure grid finished initializing to prevent Unhandled exceptions
|
|
171
|
+
let accrodionInit = false;
|
|
172
|
+
grok.events.onAccordionConstructed.subscribe((_) => accrodionInit = true);
|
|
173
|
+
await awaitCheck(() => model!.df.currentRowIdx === 0, 'Grid cell never finished initializing', 2000);
|
|
174
|
+
await awaitCheck(() => grok.shell.o instanceof DG.Column, 'Shell object never changed', 2000);
|
|
175
|
+
await awaitCheck(() => accrodionInit, 'Accordion never finished initializing', 2000);
|
|
176
|
+
await awaitCheck(() => overlayInit, 'Overlay never finished initializing', 2000);
|
|
148
177
|
});
|
|
149
178
|
|
|
150
179
|
test('New view', async () => {
|
|
@@ -164,7 +193,7 @@ category('Widgets: Actions', () => {
|
|
|
164
193
|
expect(currentTable.getTag(C.TAGS.UUID), newViewId, 'Current table is expected to have the same UUID as new view');
|
|
165
194
|
expect(currentTable.rowCount, 1, 'Current table is expected to have 1 row');
|
|
166
195
|
|
|
167
|
-
await
|
|
196
|
+
await awaitCheck(() => currentTable.currentRowIdx === 0, 'Grid never finished initializing', 2000);
|
|
168
197
|
|
|
169
198
|
const currentTableModel = currentTable.temp[PeptidesModel.modelName] as PeptidesModel;
|
|
170
199
|
const lstViewer = currentTableModel.findViewer(VIEWER_TYPE.LOGO_SUMMARY_TABLE);
|
|
@@ -181,13 +210,15 @@ category('Widgets: Actions', () => {
|
|
|
181
210
|
const selection = model.df.selection;
|
|
182
211
|
selection.set(0, true, false);
|
|
183
212
|
|
|
184
|
-
const lstViewer = model.findViewer(VIEWER_TYPE.LOGO_SUMMARY_TABLE) as LogoSummaryTable;
|
|
213
|
+
const lstViewer = model.findViewer(VIEWER_TYPE.LOGO_SUMMARY_TABLE) as LogoSummaryTable | null;
|
|
214
|
+
if (lstViewer === null)
|
|
215
|
+
throw new Error('Logo summary table viewer is not found');
|
|
185
216
|
|
|
186
217
|
// Check that custom clusters are not created yet
|
|
187
218
|
expect(wu(model.customClusters).toArray().length, 0, 'Expected to have 0 custom clusters before creating one');
|
|
188
219
|
|
|
189
220
|
// Create custom cluster
|
|
190
|
-
|
|
221
|
+
lstViewer.clusterFromSelection();
|
|
191
222
|
const customClusterList = wu(model.customClusters).toArray();
|
|
192
223
|
expect(customClusterList.length, 1, 'Expected to have 1 custom cluster');
|
|
193
224
|
const clustName = customClusterList[0].name;
|
|
@@ -198,11 +229,62 @@ category('Widgets: Actions', () => {
|
|
|
198
229
|
|
|
199
230
|
// Remove custom cluster
|
|
200
231
|
model.modifyClusterSelection(clustName);
|
|
201
|
-
|
|
232
|
+
lstViewer.removeCluster();
|
|
202
233
|
expect(wu(model.customClusters).toArray().length, 0, 'Expected to have 0 custom clusters after removing one');
|
|
203
234
|
expect(model.df.col(clustName) === null, true,
|
|
204
235
|
'Expected to have no custom cluster column in the table');
|
|
205
236
|
expect(lstViewer.viewerGrid.table.getCol(C.LST_COLUMN_NAMES.CLUSTER).categories.indexOf(clustName) === -1, true,
|
|
206
237
|
'Expected to have no custom cluster in the Logo Summary Table');
|
|
207
238
|
});
|
|
239
|
+
}, {clear: false});
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
category('Widgets: Identity', () => {
|
|
243
|
+
let df: DG.DataFrame;
|
|
244
|
+
let model: PeptidesModel;
|
|
245
|
+
let activityCol: DG.Column<number>;
|
|
246
|
+
let sequenceCol: DG.Column<string>;
|
|
247
|
+
let clusterCol: DG.Column<any>;
|
|
248
|
+
let scaledActivityCol: DG.Column<number>;
|
|
249
|
+
|
|
250
|
+
before(async () => {
|
|
251
|
+
df = DG.DataFrame.fromCsv(await _package.files.readAsText('tests/HELM_small.csv'));
|
|
252
|
+
activityCol = df.getCol(TEST_COLUMN_NAMES.ACTIVITY);
|
|
253
|
+
sequenceCol = df.getCol(TEST_COLUMN_NAMES.SEQUENCE);
|
|
254
|
+
sequenceCol.semType = DG.SEMTYPE.MACROMOLECULE;
|
|
255
|
+
sequenceCol.setTag(DG.TAGS.UNITS, NOTATION.HELM);
|
|
256
|
+
scaledActivityCol = scaleActivity(activityCol, C.SCALING_METHODS.NONE);
|
|
257
|
+
clusterCol = df.getCol(TEST_COLUMN_NAMES.CLUSTER);
|
|
258
|
+
const tempModel = await startAnalysis(activityCol, sequenceCol, clusterCol, df, scaledActivityCol,
|
|
259
|
+
C.SCALING_METHODS.NONE);
|
|
260
|
+
if (tempModel === null)
|
|
261
|
+
throw new Error('Model is null');
|
|
262
|
+
model = tempModel;
|
|
263
|
+
let overlayInit = false;
|
|
264
|
+
model._analysisView!.grid.onAfterDrawOverlay.subscribe(() => overlayInit = true);
|
|
265
|
+
|
|
266
|
+
// Ensure grid finished initializing to prevent Unhandled exceptions
|
|
267
|
+
let accrodionInit = false;
|
|
268
|
+
grok.events.onAccordionConstructed.subscribe((_) => accrodionInit = true);
|
|
269
|
+
await awaitCheck(() => model!.df.currentRowIdx === 0, 'Grid cell never finished initializing', 2000);
|
|
270
|
+
await awaitCheck(() => grok.shell.o instanceof DG.Column, 'Shell object never changed', 2000);
|
|
271
|
+
await awaitCheck(() => accrodionInit, 'Accordion never finished initializing', 2000);
|
|
272
|
+
await awaitCheck(() => overlayInit, 'Overlay never finished initializing', 2000);
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
test('Identity', async () => {
|
|
276
|
+
const seq = 'PEPTIDE1{meI.hHis.Aca.N.T.dE.Thr_PO3H2.Aca.D-Tyr_Et.Tyr_ab-dehydroMe.dV.E.N.D-Orn.D-aThr.Phe_4Me}$$$$';
|
|
277
|
+
const template = await getTemplate(seq);
|
|
278
|
+
const identityCol = calculateIdentity(template, model.splitSeqDf);
|
|
279
|
+
expect(identityCol.get(0), 1, 'Expected 1 identity score when sequence is matching template');
|
|
280
|
+
expectFloat(identityCol.get(3)!, 0.5625, 0.01, 'Expected 0.5625 identity score agains sequence at position 3');
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
test('Similarity', async () => {
|
|
284
|
+
const seq = 'PEPTIDE1{meI.hHis.Aca.N.T.dE.Thr_PO3H2.Aca.D-Tyr_Et.Tyr_ab-dehydroMe.dV.E.N.D-Orn.D-aThr.Phe_4Me}$$$$';
|
|
285
|
+
const template = await getTemplate(seq);
|
|
286
|
+
const identityCol = await calculateSimilarity(template, model.splitSeqDf);
|
|
287
|
+
expect(identityCol.get(0), 1, 'Expected 1 identity score when sequence is matching template');
|
|
288
|
+
expectFloat(identityCol.get(3)!, 0, 0.001, 'Expected 7 identity score agains sequence at position 3');
|
|
289
|
+
})
|
|
208
290
|
});
|
|
@@ -6,7 +6,7 @@ import {PositionStats, MonomerPositionStats} from '../model';
|
|
|
6
6
|
import {SeqPalette} from '@datagrok-libraries/bio/src/seq-palettes';
|
|
7
7
|
import {monomerToShort} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
8
8
|
|
|
9
|
-
function renderCellSelection(canvasContext: CanvasRenderingContext2D, bound: DG.Rect): void {
|
|
9
|
+
export function renderCellSelection(canvasContext: CanvasRenderingContext2D, bound: DG.Rect): void {
|
|
10
10
|
canvasContext.strokeStyle = '#000';
|
|
11
11
|
canvasContext.lineWidth = 1;
|
|
12
12
|
canvasContext.strokeRect(bound.x + 1, bound.y + 1, bound.width - 1, bound.height - 1);
|
|
@@ -22,7 +22,7 @@ export function setAARRenderer(col: DG.Column, alphabet: string): void {
|
|
|
22
22
|
export function renderMutationCliffCell(canvasContext: CanvasRenderingContext2D, currentAAR: string,
|
|
23
23
|
currentPosition: string, monomerPositionStats: MonomerPositionStats, bound: DG.Rect,
|
|
24
24
|
mutationCliffsSelection: types.PositionToAARList, substitutionsInfo: types.MutationCliffs | null = null,
|
|
25
|
-
twoColorMode: boolean = false): void {
|
|
25
|
+
twoColorMode: boolean = false, renderNums: boolean = true): void {
|
|
26
26
|
const positionStats = monomerPositionStats[currentPosition];
|
|
27
27
|
const pVal: number = positionStats[currentAAR].pValue;
|
|
28
28
|
const currentMeanDiff = positionStats[currentAAR].meanDifference;
|
|
@@ -56,19 +56,27 @@ export function renderMutationCliffCell(canvasContext: CanvasRenderingContext2D,
|
|
|
56
56
|
canvasContext.fillStyle = coef;
|
|
57
57
|
canvasContext.arc(midX, midY, radius < 3 ? 3 : radius, 0, Math.PI * 2, true);
|
|
58
58
|
canvasContext.closePath();
|
|
59
|
-
|
|
60
59
|
canvasContext.fill();
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
60
|
+
|
|
61
|
+
if (renderNums) {
|
|
62
|
+
const substitutions = substitutionsInfo?.get(currentAAR)?.get(currentPosition)?.entries() ?? null;
|
|
63
|
+
if (substitutions !== null) {
|
|
64
|
+
canvasContext.textBaseline = 'middle';
|
|
65
|
+
canvasContext.textAlign = 'center';
|
|
66
|
+
canvasContext.fillStyle = DG.Color.toHtml(DG.Color.black);
|
|
67
|
+
canvasContext.font = '13px Roboto, Roboto Local, sans-serif';
|
|
68
|
+
canvasContext.shadowBlur = 5;
|
|
69
|
+
canvasContext.shadowColor = DG.Color.toHtml(DG.Color.white);
|
|
70
|
+
const uniqueValues = new Set<number>();
|
|
71
|
+
|
|
72
|
+
for (const [key, value] of substitutions) {
|
|
73
|
+
uniqueValues.add(key);
|
|
74
|
+
for (const val of value)
|
|
75
|
+
uniqueValues.add(val);
|
|
76
|
+
}
|
|
77
|
+
if (uniqueValues.size !== 0)
|
|
78
|
+
canvasContext.fillText(uniqueValues.size.toString(), midX, midY);
|
|
79
|
+
}
|
|
72
80
|
}
|
|
73
81
|
|
|
74
82
|
const aarSelection = mutationCliffsSelection[currentPosition];
|
|
@@ -105,18 +113,20 @@ export function renderLogoSummaryCell(canvasContext: CanvasRenderingContext2D, c
|
|
|
105
113
|
}
|
|
106
114
|
|
|
107
115
|
|
|
108
|
-
export function drawLogoInBounds(ctx: CanvasRenderingContext2D, bounds: DG.Rect, stats: PositionStats,
|
|
116
|
+
export function drawLogoInBounds(ctx: CanvasRenderingContext2D, bounds: DG.Rect, stats: PositionStats, position: string,
|
|
109
117
|
sortedOrder: string[], rowCount: number, cp: SeqPalette, monomerSelectionStats: { [monomer: string]: number } = {},
|
|
110
118
|
drawOptions: types.DrawOptions = {}): { [monomer: string]: DG.Rect } {
|
|
111
|
-
|
|
119
|
+
const pr = window.devicePixelRatio;
|
|
120
|
+
drawOptions.symbolStyle ??= '16px Roboto, Roboto Local, sans-serif';
|
|
112
121
|
drawOptions.upperLetterHeight ??= 12.2;
|
|
113
122
|
drawOptions.upperLetterAscent ??= 0.25;
|
|
114
123
|
drawOptions.marginVertical ??= 5;
|
|
115
124
|
drawOptions.marginHorizontal ??= 5;
|
|
125
|
+
drawOptions.textHeight ??= 13;
|
|
126
|
+
drawOptions.headerStyle ??= `bold ${drawOptions.textHeight * pr}px Roboto, Roboto Local, sans-serif`;
|
|
116
127
|
|
|
117
|
-
const
|
|
118
|
-
const
|
|
119
|
-
const barHeight = (bounds.height - 2 * drawOptions.marginVertical - totalSpaceBetweenLetters) * pr;
|
|
128
|
+
const totalSpace = (sortedOrder.length - 1) * drawOptions.upperLetterAscent; // Total space between letters
|
|
129
|
+
const barHeight = (bounds.height - 2 * drawOptions.marginVertical - totalSpace - 1.25 * drawOptions.textHeight) * pr;
|
|
120
130
|
const leftShift = drawOptions.marginHorizontal * 2;
|
|
121
131
|
const barWidth = (bounds.width - leftShift * 2) * pr;
|
|
122
132
|
const xStart = (bounds.x + leftShift) * pr;
|
|
@@ -143,7 +153,7 @@ export function drawLogoInBounds(ctx: CanvasRenderingContext2D, bounds: DG.Rect,
|
|
|
143
153
|
ctx.fillStyle = cp.get(monomer) ?? cp.get('other');
|
|
144
154
|
ctx.textAlign = 'left';
|
|
145
155
|
ctx.textBaseline = 'top';
|
|
146
|
-
ctx.font = drawOptions.
|
|
156
|
+
ctx.font = drawOptions.symbolStyle;
|
|
147
157
|
// Hacks to scale uppercase characters to target rectangle
|
|
148
158
|
const widthTransform = barWidth / mTm.width;
|
|
149
159
|
const heightTransfrom = monomerHeight / drawOptions.upperLetterHeight;
|
|
@@ -153,5 +163,13 @@ export function drawLogoInBounds(ctx: CanvasRenderingContext2D, bounds: DG.Rect,
|
|
|
153
163
|
currentY += monomerHeight + drawOptions.upperLetterAscent * pr;
|
|
154
164
|
}
|
|
155
165
|
|
|
166
|
+
// Drawing column header
|
|
167
|
+
ctx.resetTransform();
|
|
168
|
+
ctx.fillStyle = DG.Color.toHtml(DG.Color.black);
|
|
169
|
+
ctx.textAlign = 'center';
|
|
170
|
+
ctx.textBaseline = 'top';
|
|
171
|
+
ctx.font = drawOptions.headerStyle;
|
|
172
|
+
ctx.fillText(position, (bounds.x + bounds.width / 2) * pr, (bounds.y + bounds.height - drawOptions.textHeight) * pr);
|
|
173
|
+
|
|
156
174
|
return monomerBounds;
|
|
157
175
|
}
|
package/src/utils/constants.ts
CHANGED
|
@@ -31,6 +31,7 @@ export enum TAGS {
|
|
|
31
31
|
SELECTION = 'selection',
|
|
32
32
|
ALPHABET = 'alphabet',
|
|
33
33
|
FILTER = 'filter',
|
|
34
|
+
INVARIANT_MAP_SELECTION = 'invariantMapSelection',
|
|
34
35
|
SAR_MODE = 'sarMode',
|
|
35
36
|
CLUSTER_SELECTION = 'clusterSelection',
|
|
36
37
|
VISIBLE = 'visible',
|
|
@@ -39,6 +40,8 @@ export enum TAGS {
|
|
|
39
40
|
UUID = 'pep-uuid',
|
|
40
41
|
MONOMER_POSITION_MODE = 'monomerPositionMode',
|
|
41
42
|
MULTIPLE_VIEWS = 'isMultipleViews',
|
|
43
|
+
IDENTITY_TEMPLATE = 'Identity template',
|
|
44
|
+
SIMILARITY_TEMPLATE = 'Similarity template',
|
|
42
45
|
}
|
|
43
46
|
|
|
44
47
|
export enum SEM_TYPES {
|
package/src/utils/misc.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import
|
|
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
|
import * as C from './constants';
|
|
5
5
|
import * as type from './types';
|
|
6
|
+
import {getSplitterForColumn} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
7
|
+
import {StringDictionary} from '@datagrok-libraries/utils/src/type-declarations';
|
|
8
|
+
import {ISeqSplitted} from '@datagrok-libraries/bio/src/utils/macromolecule/types';
|
|
6
9
|
|
|
7
10
|
export function getTypedArrayConstructor(
|
|
8
11
|
maxNum: number): Uint8ArrayConstructor | Uint16ArrayConstructor | Uint32ArrayConstructor {
|
|
@@ -30,10 +33,11 @@ export function scaleActivity(activityCol: DG.Column<number>, scaling: C.SCALING
|
|
|
30
33
|
default:
|
|
31
34
|
throw new Error(`ScalingError: method \`${scaling}\` is not available.`);
|
|
32
35
|
}
|
|
36
|
+
const activityColData = activityCol.getRawData();
|
|
33
37
|
const scaledCol: DG.Column<number> = DG.Column.float(C.COLUMNS_NAMES.ACTIVITY_SCALED, activityCol.length)
|
|
34
38
|
.init((i) => {
|
|
35
|
-
const val =
|
|
36
|
-
return val ?
|
|
39
|
+
const val = activityColData[i];
|
|
40
|
+
return val === DG.FLOAT_NULL || val === DG.INT_NULL ? val : formula(val);
|
|
37
41
|
});
|
|
38
42
|
|
|
39
43
|
return scaledCol;
|
|
@@ -58,11 +62,6 @@ export function calculateSelected(df: DG.DataFrame): type.MonomerSelectionStats
|
|
|
58
62
|
return selectedObj;
|
|
59
63
|
}
|
|
60
64
|
|
|
61
|
-
// export function isGridCellInvalid(gc: DG.GridCell | null): boolean {
|
|
62
|
-
// return !gc || !gc.cell.value || !gc.tableColumn || gc.tableRowIndex === null || gc.tableRowIndex === -1 ||
|
|
63
|
-
// gc.cell.value === DG.INT_NULL || gc.cell.value === DG.FLOAT_NULL;
|
|
64
|
-
// }
|
|
65
|
-
|
|
66
65
|
export function extractColInfo(col: DG.Column<string>): type.RawColumn {
|
|
67
66
|
return {
|
|
68
67
|
name: col.name,
|
|
@@ -72,10 +71,43 @@ export function extractColInfo(col: DG.Column<string>): type.RawColumn {
|
|
|
72
71
|
}
|
|
73
72
|
|
|
74
73
|
export function getStatsSummary(legend: HTMLDivElement, hist: DG.Viewer<DG.IHistogramLookSettings>,
|
|
75
|
-
statsMap: StringDictionary
|
|
74
|
+
statsMap: StringDictionary): HTMLDivElement {
|
|
76
75
|
const result = ui.divV([legend, hist.root, ui.tableFromMap(statsMap)]);
|
|
77
|
-
|
|
78
|
-
if (isTooltip)
|
|
79
|
-
hist.root.style.maxHeight = '150px';
|
|
76
|
+
hist.root.style.maxHeight = '75px';
|
|
80
77
|
return result;
|
|
81
78
|
}
|
|
79
|
+
|
|
80
|
+
export function prepareTableForHistogram(table: DG.DataFrame): DG.DataFrame {
|
|
81
|
+
const activityCol: DG.Column<number> = table.getCol(C.COLUMNS_NAMES.ACTIVITY_SCALED);
|
|
82
|
+
const splitCol: DG.Column<boolean> = table.getCol(C.COLUMNS_NAMES.SPLIT_COL);
|
|
83
|
+
|
|
84
|
+
const rowCount = activityCol.length;
|
|
85
|
+
const activityColData = activityCol.getRawData();
|
|
86
|
+
const expandedData: number[] = new Array(rowCount + splitCol.stats.sum);
|
|
87
|
+
const expandedMasks: boolean[] = new Array(expandedData.length);
|
|
88
|
+
for (let i = 0, j = 0; i < rowCount; ++i) {
|
|
89
|
+
const isSplit = splitCol.get(i)!;
|
|
90
|
+
expandedData[i] = activityColData[i];
|
|
91
|
+
expandedMasks[i] = isSplit;
|
|
92
|
+
if (isSplit) {
|
|
93
|
+
expandedData[rowCount + j] = activityColData[i];
|
|
94
|
+
expandedMasks[rowCount + j] = false;
|
|
95
|
+
++j;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return DG.DataFrame.fromColumns([
|
|
100
|
+
DG.Column.fromList(DG.TYPE.FLOAT, activityCol.name, expandedData),
|
|
101
|
+
DG.Column.fromList(DG.TYPE.BOOL, C.COLUMNS_NAMES.SPLIT_COL, expandedMasks),
|
|
102
|
+
]);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export async function getTemplate(sequence: string, seqCol?: DG.Column<string>): Promise<ISeqSplitted> {
|
|
106
|
+
if (typeof seqCol === 'undefined') {
|
|
107
|
+
const tempDf = DG.DataFrame.fromCsv(`sequence\n${new Array(10).fill(sequence).join('\n')}`);
|
|
108
|
+
await grok.data.detectSemanticTypes(tempDf);
|
|
109
|
+
seqCol = tempDf.getCol('sequence');
|
|
110
|
+
}
|
|
111
|
+
const splitter = getSplitterForColumn(seqCol);
|
|
112
|
+
return splitter(sequence);
|
|
113
|
+
}
|
|
@@ -4,12 +4,11 @@ import * as DG from 'datagrok-api/dg';
|
|
|
4
4
|
|
|
5
5
|
import {getSequenceMolecularWeight} from './molecular-measure';
|
|
6
6
|
import {AlignedSequenceEncoder} from '@datagrok-libraries/bio/src/sequence-encoder';
|
|
7
|
-
import {DimensionalityReducer} from '@datagrok-libraries/ml/src/reduce-dimensionality';
|
|
7
|
+
import {DimensionalityReducer, IReduceDimensionalityResult} from '@datagrok-libraries/ml/src/reduce-dimensionality';
|
|
8
8
|
import {
|
|
9
9
|
createDimensinalityReducingWorker,
|
|
10
|
-
IReduceDimensionalityResult,
|
|
11
10
|
} from '@datagrok-libraries/ml/src/workers/dimensionality-reducing-worker-creator';
|
|
12
|
-
import {Measure, StringMetrics} from '@datagrok-libraries/ml/src/typed-metrics';
|
|
11
|
+
import {DistanceMetricsSubjects, Measure, StringMetrics} from '@datagrok-libraries/ml/src/typed-metrics';
|
|
13
12
|
import {Coordinates} from '@datagrok-libraries/utils/src/type-declarations';
|
|
14
13
|
|
|
15
14
|
/**
|
|
@@ -115,7 +114,7 @@ export class PeptideSimilaritySpaceWidget {
|
|
|
115
114
|
*/
|
|
116
115
|
constructor(alignedSequencesColumn: DG.Column, view: DG.TableView) {
|
|
117
116
|
this.availableMethods = DimensionalityReducer.availableMethods;
|
|
118
|
-
this.availableMetrics = Measure.getMetricByDataType(
|
|
117
|
+
this.availableMetrics = Measure.getMetricByDataType(DistanceMetricsSubjects.String);
|
|
119
118
|
this.method = this.availableMethods[0];
|
|
120
119
|
this.metrics = this.availableMetrics[0];
|
|
121
120
|
const df = alignedSequencesColumn.dataFrame;
|
package/src/utils/statistics.ts
CHANGED
|
@@ -16,7 +16,7 @@ export function getStats(data: RawData | number[], bitArray: BitArray): Stats {
|
|
|
16
16
|
|
|
17
17
|
let selectedIndex = 0;
|
|
18
18
|
let restIndex = 0;
|
|
19
|
-
for (let i = 0; i <
|
|
19
|
+
for (let i = 0; i < bitArray.length; ++i) {
|
|
20
20
|
if (bitArray.getBit(i))
|
|
21
21
|
selected[selectedIndex++] = data[i];
|
|
22
22
|
else
|
|
@@ -29,7 +29,7 @@ export function getStats(data: RawData | number[], bitArray: BitArray): Stats {
|
|
|
29
29
|
count: selected.length,
|
|
30
30
|
pValue: testResult[currentMeanDiff >= 0 ? 'p-value more' : 'p-value less'] || 0,
|
|
31
31
|
meanDifference: currentMeanDiff || 0,
|
|
32
|
-
ratio: selected.length /
|
|
32
|
+
ratio: selected.length / (bitArray.length),
|
|
33
33
|
};
|
|
34
34
|
}
|
|
35
35
|
|
package/src/utils/types.ts
CHANGED
|
@@ -28,7 +28,7 @@ export type PeptidesSettings = {
|
|
|
28
28
|
};
|
|
29
29
|
|
|
30
30
|
export type DrawOptions = {
|
|
31
|
-
|
|
31
|
+
symbolStyle?: string,
|
|
32
32
|
upperLetterHeight?: number,
|
|
33
33
|
upperLetterAscent?: number,
|
|
34
34
|
bounds?: DG.Rect,
|
|
@@ -36,6 +36,8 @@ export type DrawOptions = {
|
|
|
36
36
|
textBaseline?: CanvasTextBaseline,
|
|
37
37
|
marginVertical?: number,
|
|
38
38
|
marginHorizontal?: number,
|
|
39
|
+
headerStyle?: string,
|
|
40
|
+
textHeight?: number,
|
|
39
41
|
};
|
|
40
42
|
|
|
41
43
|
export type StatsInfo = {
|