@datagrok/peptides 1.9.3 → 1.12.0
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 +78 -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 +275 -234
- package/src/package-test.ts +2 -1
- package/src/package.ts +14 -17
- 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 +48 -18
- package/src/utils/cell-renderer.ts +38 -20
- package/src/utils/constants.ts +3 -0
- package/src/utils/misc.ts +31 -10
- 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 +48 -39
- package/src/widgets/distribution.ts +19 -17
- package/src/widgets/manual-alignment.ts +3 -7
- package/src/widgets/mutation-cliffs.ts +91 -19
- package/src/widgets/peptides.ts +26 -25
- package/src/widgets/selection.ts +31 -0
- package/src/widgets/settings.ts +57 -25
- 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,7 +1,7 @@
|
|
|
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} from '@datagrok-libraries/utils/src/test';
|
|
5
5
|
import {_package} from '../package-test';
|
|
6
6
|
import {PeptidesModel, VIEWER_TYPE} from '../model';
|
|
7
7
|
import {scaleActivity} from '../utils/misc';
|
|
@@ -36,6 +36,16 @@ category('Widgets: Settings', () => {
|
|
|
36
36
|
if (tempModel === null)
|
|
37
37
|
throw new Error('Model is null');
|
|
38
38
|
model = tempModel;
|
|
39
|
+
let overlayInit = false;
|
|
40
|
+
model._analysisView!.grid.onAfterDrawOverlay.subscribe(() => overlayInit = true);
|
|
41
|
+
|
|
42
|
+
// Ensure grid finished initializing to prevent Unhandled exceptions
|
|
43
|
+
let accrodionInit = false;
|
|
44
|
+
grok.events.onAccordionConstructed.subscribe((_) => accrodionInit = true);
|
|
45
|
+
await awaitCheck(() => model!.df.currentRowIdx === 0, 'Grid cell never finished initializing', 2000);
|
|
46
|
+
await awaitCheck(() => grok.shell.o instanceof DG.Column, 'Shell object never changed', 2000);
|
|
47
|
+
await awaitCheck(() => accrodionInit, 'Accordion never finished initializing', 2000);
|
|
48
|
+
await awaitCheck(() => overlayInit, 'Overlay never finished initializing', 2000);
|
|
39
49
|
});
|
|
40
50
|
|
|
41
51
|
test('UI', async () => {
|
|
@@ -77,15 +87,21 @@ category('Widgets: Distribution panel', () => {
|
|
|
77
87
|
if (tempModel === null)
|
|
78
88
|
throw new Error('Model is null');
|
|
79
89
|
model = tempModel;
|
|
90
|
+
let overlayInit = false;
|
|
91
|
+
model._analysisView!.grid.onAfterDrawOverlay.subscribe(() => overlayInit = true);
|
|
92
|
+
|
|
93
|
+
// Ensure grid finished initializing to prevent Unhandled exceptions
|
|
94
|
+
let accrodionInit = false;
|
|
95
|
+
grok.events.onAccordionConstructed.subscribe((_) => accrodionInit = true);
|
|
96
|
+
await awaitCheck(() => model!.df.currentRowIdx === 0, 'Grid cell never finished initializing', 2000);
|
|
97
|
+
await awaitCheck(() => grok.shell.o instanceof DG.Column, 'Shell object never changed', 2000);
|
|
98
|
+
await awaitCheck(() => accrodionInit, 'Accordion never finished initializing', 2000);
|
|
99
|
+
await awaitCheck(() => overlayInit, 'Overlay never finished initializing', 2000);
|
|
80
100
|
});
|
|
81
101
|
|
|
82
102
|
test('UI', async () => {
|
|
83
103
|
getDistributionWidget(model.df, model);
|
|
84
104
|
});
|
|
85
|
-
|
|
86
|
-
test('Split', async () => {
|
|
87
|
-
|
|
88
|
-
}, {skipReason: 'Not implemented yet'});
|
|
89
105
|
});
|
|
90
106
|
|
|
91
107
|
category('Widgets: Mutation cliffs', () => {
|
|
@@ -109,19 +125,21 @@ category('Widgets: Mutation cliffs', () => {
|
|
|
109
125
|
if (tempModel === null)
|
|
110
126
|
throw new Error('Model is null');
|
|
111
127
|
model = tempModel;
|
|
128
|
+
let overlayInit = false;
|
|
129
|
+
model._analysisView!.grid.onAfterDrawOverlay.subscribe(() => overlayInit = true);
|
|
130
|
+
|
|
131
|
+
// Ensure grid finished initializing to prevent Unhandled exceptions
|
|
132
|
+
let accrodionInit = false;
|
|
133
|
+
grok.events.onAccordionConstructed.subscribe((_) => accrodionInit = true);
|
|
134
|
+
await awaitCheck(() => model!.df.currentRowIdx === 0, 'Grid cell never finished initializing', 2000);
|
|
135
|
+
await awaitCheck(() => grok.shell.o instanceof DG.Column, 'Shell object never changed', 2000);
|
|
136
|
+
await awaitCheck(() => accrodionInit, 'Accordion never finished initializing', 2000);
|
|
137
|
+
await awaitCheck(() => overlayInit, 'Overlay never finished initializing', 2000);
|
|
112
138
|
});
|
|
113
139
|
|
|
114
140
|
test('UI', async () => {
|
|
115
141
|
mutationCliffsWidget(model.df, model);
|
|
116
142
|
});
|
|
117
|
-
|
|
118
|
-
test('General', async () => {
|
|
119
|
-
|
|
120
|
-
}, {skipReason: 'Not implemented yet'});
|
|
121
|
-
|
|
122
|
-
test('Filtering', async () => {
|
|
123
|
-
|
|
124
|
-
}, {skipReason: 'Not implemented yet'});
|
|
125
143
|
});
|
|
126
144
|
|
|
127
145
|
category('Widgets: Actions', () => {
|
|
@@ -145,6 +163,16 @@ category('Widgets: Actions', () => {
|
|
|
145
163
|
if (tempModel === null)
|
|
146
164
|
throw new Error('Model is null');
|
|
147
165
|
model = tempModel;
|
|
166
|
+
let overlayInit = false;
|
|
167
|
+
model._analysisView!.grid.onAfterDrawOverlay.subscribe(() => overlayInit = true);
|
|
168
|
+
|
|
169
|
+
// Ensure grid finished initializing to prevent Unhandled exceptions
|
|
170
|
+
let accrodionInit = false;
|
|
171
|
+
grok.events.onAccordionConstructed.subscribe((_) => accrodionInit = true);
|
|
172
|
+
await awaitCheck(() => model!.df.currentRowIdx === 0, 'Grid cell never finished initializing', 2000);
|
|
173
|
+
await awaitCheck(() => grok.shell.o instanceof DG.Column, 'Shell object never changed', 2000);
|
|
174
|
+
await awaitCheck(() => accrodionInit, 'Accordion never finished initializing', 2000);
|
|
175
|
+
await awaitCheck(() => overlayInit, 'Overlay never finished initializing', 2000);
|
|
148
176
|
});
|
|
149
177
|
|
|
150
178
|
test('New view', async () => {
|
|
@@ -164,7 +192,7 @@ category('Widgets: Actions', () => {
|
|
|
164
192
|
expect(currentTable.getTag(C.TAGS.UUID), newViewId, 'Current table is expected to have the same UUID as new view');
|
|
165
193
|
expect(currentTable.rowCount, 1, 'Current table is expected to have 1 row');
|
|
166
194
|
|
|
167
|
-
await
|
|
195
|
+
await awaitCheck(() => currentTable.currentRowIdx === 0, 'Grid never finished initializing', 2000);
|
|
168
196
|
|
|
169
197
|
const currentTableModel = currentTable.temp[PeptidesModel.modelName] as PeptidesModel;
|
|
170
198
|
const lstViewer = currentTableModel.findViewer(VIEWER_TYPE.LOGO_SUMMARY_TABLE);
|
|
@@ -181,13 +209,15 @@ category('Widgets: Actions', () => {
|
|
|
181
209
|
const selection = model.df.selection;
|
|
182
210
|
selection.set(0, true, false);
|
|
183
211
|
|
|
184
|
-
const lstViewer = model.findViewer(VIEWER_TYPE.LOGO_SUMMARY_TABLE) as LogoSummaryTable;
|
|
212
|
+
const lstViewer = model.findViewer(VIEWER_TYPE.LOGO_SUMMARY_TABLE) as LogoSummaryTable | null;
|
|
213
|
+
if (lstViewer === null)
|
|
214
|
+
throw new Error('Logo summary table viewer is not found');
|
|
185
215
|
|
|
186
216
|
// Check that custom clusters are not created yet
|
|
187
217
|
expect(wu(model.customClusters).toArray().length, 0, 'Expected to have 0 custom clusters before creating one');
|
|
188
218
|
|
|
189
219
|
// Create custom cluster
|
|
190
|
-
|
|
220
|
+
lstViewer.clusterFromSelection();
|
|
191
221
|
const customClusterList = wu(model.customClusters).toArray();
|
|
192
222
|
expect(customClusterList.length, 1, 'Expected to have 1 custom cluster');
|
|
193
223
|
const clustName = customClusterList[0].name;
|
|
@@ -198,11 +228,11 @@ category('Widgets: Actions', () => {
|
|
|
198
228
|
|
|
199
229
|
// Remove custom cluster
|
|
200
230
|
model.modifyClusterSelection(clustName);
|
|
201
|
-
|
|
231
|
+
lstViewer.removeCluster();
|
|
202
232
|
expect(wu(model.customClusters).toArray().length, 0, 'Expected to have 0 custom clusters after removing one');
|
|
203
233
|
expect(model.df.col(clustName) === null, true,
|
|
204
234
|
'Expected to have no custom cluster column in the table');
|
|
205
235
|
expect(lstViewer.viewerGrid.table.getCol(C.LST_COLUMN_NAMES.CLUSTER).categories.indexOf(clustName) === -1, true,
|
|
206
236
|
'Expected to have no custom cluster in the Logo Summary Table');
|
|
207
237
|
});
|
|
208
|
-
});
|
|
238
|
+
}, {clear: false});
|
|
@@ -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 {StringDictionary} from '@datagrok-libraries/utils/src/type-declarations';
|
|
7
|
+
import {getSplitter} from '@datagrok-libraries/bio/src/utils/macromolecule/utils';
|
|
8
|
+
import {TAGS as bioTags} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
6
9
|
|
|
7
10
|
export function getTypedArrayConstructor(
|
|
8
11
|
maxNum: number): Uint8ArrayConstructor | Uint16ArrayConstructor | Uint32ArrayConstructor {
|
|
@@ -59,11 +62,6 @@ export function calculateSelected(df: DG.DataFrame): type.MonomerSelectionStats
|
|
|
59
62
|
return selectedObj;
|
|
60
63
|
}
|
|
61
64
|
|
|
62
|
-
// export function isGridCellInvalid(gc: DG.GridCell | null): boolean {
|
|
63
|
-
// return !gc || !gc.cell.value || !gc.tableColumn || gc.tableRowIndex === null || gc.tableRowIndex === -1 ||
|
|
64
|
-
// gc.cell.value === DG.INT_NULL || gc.cell.value === DG.FLOAT_NULL;
|
|
65
|
-
// }
|
|
66
|
-
|
|
67
65
|
export function extractColInfo(col: DG.Column<string>): type.RawColumn {
|
|
68
66
|
return {
|
|
69
67
|
name: col.name,
|
|
@@ -73,10 +71,33 @@ export function extractColInfo(col: DG.Column<string>): type.RawColumn {
|
|
|
73
71
|
}
|
|
74
72
|
|
|
75
73
|
export function getStatsSummary(legend: HTMLDivElement, hist: DG.Viewer<DG.IHistogramLookSettings>,
|
|
76
|
-
statsMap: StringDictionary
|
|
74
|
+
statsMap: StringDictionary): HTMLDivElement {
|
|
77
75
|
const result = ui.divV([legend, hist.root, ui.tableFromMap(statsMap)]);
|
|
78
|
-
|
|
79
|
-
if (isTooltip)
|
|
80
|
-
hist.root.style.maxHeight = '150px';
|
|
76
|
+
hist.root.style.maxHeight = '75px';
|
|
81
77
|
return result;
|
|
82
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
|
+
}
|
|
@@ -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 = {
|