@datagrok/peptides 0.8.10 → 0.8.12
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 -1
- package/dist/package-test.js +22626 -0
- package/dist/package.js +21429 -0
- package/dist/vendors-node_modules_datagrok-libraries_ml_src_workers_dimensionality-reducer_js.js +8840 -0
- package/jest.config.js +33 -0
- package/package.json +70 -62
- package/src/__jest__/remote.test.ts +50 -0
- package/src/__jest__/test-node.ts +96 -0
- package/src/model.ts +849 -442
- package/src/package-test.ts +2 -1
- package/src/package.ts +36 -22
- package/src/peptides.ts +152 -116
- package/src/styles.css +8 -0
- package/src/tests/peptides-tests.ts +7 -7
- package/src/tests/utils.ts +1 -7
- package/src/utils/SAR-multiple-filter.ts +439 -0
- package/src/utils/SAR-multiple-selection.ts +177 -0
- package/src/utils/cell-renderer.ts +38 -37
- package/src/utils/chem-palette.ts +1 -0
- package/src/utils/constants.ts +56 -0
- package/src/utils/filtering-statistics.ts +62 -0
- package/src/utils/multivariate-analysis.ts +5 -3
- package/src/utils/peptide-similarity-space.ts +12 -31
- package/src/utils/types.ts +10 -0
- package/src/viewers/logo-viewer.ts +2 -1
- package/src/viewers/peptide-space-viewer.ts +121 -0
- package/src/viewers/sar-viewer.ts +109 -293
- package/src/viewers/stacked-barchart-viewer.ts +100 -136
- package/src/widgets/analyze-peptides.ts +34 -31
- package/src/widgets/distribution.ts +61 -0
- package/src/widgets/manual-alignment.ts +1 -0
- package/src/widgets/subst-table.ts +30 -20
- package/test-Peptides-414a1874a71a-2f1c6575.html +256 -0
- package/src/viewers/subst-viewer.ts +0 -312
|
@@ -4,22 +4,29 @@ import * as ui from 'datagrok-api/ui';
|
|
|
4
4
|
import {MonomerLibrary} from '../monomer-library';
|
|
5
5
|
import {PeptidesController} from '../peptides';
|
|
6
6
|
|
|
7
|
+
import * as C from '../utils/constants';
|
|
8
|
+
import * as type from '../utils/types';
|
|
9
|
+
|
|
7
10
|
export function addViewerToHeader(grid: DG.Grid, barchart: StackedBarChart) {
|
|
8
11
|
if (grid.temp['containsBarchart'])
|
|
9
12
|
return;
|
|
13
|
+
|
|
14
|
+
const compareBarParts = (bar1: type.BarChart.BarPart | null, bar2: type.BarChart.BarPart | null) =>
|
|
15
|
+
bar1 && bar2 && bar1.aaName === bar2.aaName && bar1.colName === bar2.colName;
|
|
10
16
|
|
|
11
|
-
|
|
17
|
+
const eventAction = (mouseMove: MouseEvent) => {
|
|
12
18
|
const cell = grid.hitTest(mouseMove.offsetX, mouseMove.offsetY);
|
|
13
|
-
if (cell
|
|
14
|
-
barchart.
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
barchart.
|
|
22
|
-
|
|
19
|
+
if (cell?.isColHeader && cell.tableColumn?.semType == C.SEM_TYPES.AMINO_ACIDS) {
|
|
20
|
+
const newBarPart = barchart.findAARandPosition(cell, mouseMove);
|
|
21
|
+
const previousClickedBarPart = barchart._previousClickedBarPart;
|
|
22
|
+
if (mouseMove.type === 'click' && compareBarParts(newBarPart, previousClickedBarPart))
|
|
23
|
+
barchart.isSameBarClicked = true;
|
|
24
|
+
else
|
|
25
|
+
barchart.currentBarPart = newBarPart;
|
|
26
|
+
barchart.requestAction(mouseMove);
|
|
27
|
+
barchart.computeData();
|
|
28
|
+
}
|
|
29
|
+
};
|
|
23
30
|
|
|
24
31
|
// The following events makes the barchart interactive
|
|
25
32
|
rxjs.fromEvent<MouseEvent>(grid.overlay, 'mousemove').subscribe((mouseMove: MouseEvent) => eventAction(mouseMove));
|
|
@@ -32,16 +39,17 @@ export function addViewerToHeader(grid: DG.Grid, barchart: StackedBarChart) {
|
|
|
32
39
|
grid.setOptions({'colHeaderHeight': 130});
|
|
33
40
|
|
|
34
41
|
grid.onCellTooltip((cell, x, y) => {
|
|
35
|
-
if (
|
|
42
|
+
if (
|
|
43
|
+
cell.tableColumn &&
|
|
44
|
+
[C.SEM_TYPES.AMINO_ACIDS, C.SEM_TYPES.ALIGNED_SEQUENCE].includes(cell.tableColumn.semType as C.SEM_TYPES)
|
|
45
|
+
) {
|
|
36
46
|
if (!cell.isColHeader) {
|
|
37
47
|
const monomerLib = cell.cell.dataFrame.temp[MonomerLibrary.id];
|
|
38
48
|
PeptidesController.chemPalette.showTooltip(cell, x, y, monomerLib);
|
|
39
|
-
} else {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
ui.tooltip.show(ui.divV(elements), x, y);
|
|
44
|
-
}
|
|
49
|
+
} else if (barchart.currentBarPart) {
|
|
50
|
+
let elements: HTMLElement[] = [];
|
|
51
|
+
elements = elements.concat([ui.divText(barchart.currentBarPart.aaName)]);
|
|
52
|
+
ui.tooltip.show(ui.divV(elements), x, y);
|
|
45
53
|
}
|
|
46
54
|
}
|
|
47
55
|
return true;
|
|
@@ -72,36 +80,33 @@ export function addViewerToHeader(grid: DG.Grid, barchart: StackedBarChart) {
|
|
|
72
80
|
barchart.unhighlight();
|
|
73
81
|
}
|
|
74
82
|
|
|
75
|
-
type stackedBarChartDatatype = {
|
|
76
|
-
'name': string,
|
|
77
|
-
'data': {'name': string, 'count': number, 'selectedCount': number, 'fixedSelectedCount': number}[],
|
|
78
|
-
}[];
|
|
79
|
-
|
|
80
|
-
type bartStatsType = {
|
|
81
|
-
[Key: string]: {'name': string, 'count': number, 'selectedCount': number, 'fixedSelectedCount': number}[],
|
|
82
|
-
};
|
|
83
|
-
|
|
84
83
|
export class StackedBarChart extends DG.JsViewer {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
84
|
+
dataEmptyAA: string;
|
|
85
|
+
_currentBarPart: type.BarChart.BarPart | null = null;
|
|
86
|
+
tableCanvas: HTMLCanvasElement | undefined;
|
|
87
|
+
aminoColumnNames: string[] = [];
|
|
88
|
+
ord: { [Key: string]: number; } = {};
|
|
89
|
+
aminoColumnIndices: {[Key: string]: number} = {};
|
|
90
|
+
aggregatedFilterTables: type.DataFrameDict = {};
|
|
91
|
+
max = 0;
|
|
92
|
+
barStats: {[Key: string]: type.BarChart.BarStatsObject[]} = {};
|
|
93
|
+
selected: type.BarChart.BarPart[] = [];
|
|
94
|
+
aggregatedSelectedTables: type.DataFrameDict = {};
|
|
95
|
+
controller!: PeptidesController;
|
|
96
|
+
isSameBarClicked: boolean = false;
|
|
97
|
+
_previousClickedBarPart: type.BarChart.BarPart | null = null;
|
|
99
98
|
|
|
100
99
|
constructor() {
|
|
101
100
|
super();
|
|
102
101
|
this.dataEmptyAA = this.string('dataEmptyAA', '-');
|
|
103
102
|
}
|
|
104
103
|
|
|
104
|
+
get currentBarPart() { return this._currentBarPart; }
|
|
105
|
+
set currentBarPart(barPart: type.BarChart.BarPart | null) {
|
|
106
|
+
this._currentBarPart = barPart;
|
|
107
|
+
this.isSameBarClicked = false;
|
|
108
|
+
}
|
|
109
|
+
|
|
105
110
|
init() {
|
|
106
111
|
const groups: {[key: string]: string[]} = {
|
|
107
112
|
'yellow': ['C', 'U'],
|
|
@@ -122,12 +127,14 @@ export class StackedBarChart extends DG.JsViewer {
|
|
|
122
127
|
}
|
|
123
128
|
|
|
124
129
|
// Stream subscriptions
|
|
125
|
-
onTableAttached() {
|
|
130
|
+
async onTableAttached() {
|
|
126
131
|
this.init();
|
|
132
|
+
this.controller = await PeptidesController.getInstance(this.dataFrame);
|
|
133
|
+
this.controller.init(this.dataFrame);
|
|
127
134
|
if (this.dataFrame) {
|
|
128
135
|
this.subs.push(DG.debounce(this.dataFrame.selection.onChanged, 50).subscribe((_) => this.computeData()));
|
|
129
136
|
this.subs.push(DG.debounce(this.dataFrame.filter.onChanged, 50).subscribe((_) => this.computeData()));
|
|
130
|
-
this.
|
|
137
|
+
this.subs.push(DG.debounce(this.dataFrame.onValuesChanged, 50).subscribe(() => this.computeData()));
|
|
131
138
|
}
|
|
132
139
|
}
|
|
133
140
|
|
|
@@ -141,7 +148,7 @@ export class StackedBarChart extends DG.JsViewer {
|
|
|
141
148
|
this.aminoColumnIndices = {};
|
|
142
149
|
|
|
143
150
|
this.dataFrame!.columns.names().forEach((name: string) => {
|
|
144
|
-
if (this.dataFrame!.getCol(name).semType ===
|
|
151
|
+
if (this.dataFrame!.getCol(name).semType === C.SEM_TYPES.AMINO_ACIDS &&
|
|
145
152
|
!this.dataFrame!.getCol(name).categories.includes('COOH') &&
|
|
146
153
|
!this.dataFrame!.getCol(name).categories.includes('NH2')) {
|
|
147
154
|
this.aminoColumnIndices[name] = this.aminoColumnNames.length + 1;
|
|
@@ -149,23 +156,16 @@ export class StackedBarChart extends DG.JsViewer {
|
|
|
149
156
|
}
|
|
150
157
|
});
|
|
151
158
|
|
|
152
|
-
this.
|
|
153
|
-
this.aggregatedHighlightedTables = {};
|
|
159
|
+
this.aggregatedFilterTables = {};
|
|
154
160
|
this.aggregatedSelectedTables = {};
|
|
155
161
|
//TODO: optimize it, why store so many tables?
|
|
156
162
|
this.aminoColumnNames.forEach((name) => {
|
|
157
|
-
this.
|
|
163
|
+
this.aggregatedFilterTables[name] = this.dataFrame!
|
|
158
164
|
.groupBy([name])
|
|
159
165
|
.whereRowMask(this.dataFrame!.filter)
|
|
160
166
|
.add('count', name, `${name}_count`)
|
|
161
167
|
.aggregate();
|
|
162
168
|
|
|
163
|
-
this.aggregatedHighlightedTables[name] = this.dataFrame!
|
|
164
|
-
.groupBy([name])
|
|
165
|
-
.whereRowMask(this.highlightedMask!)
|
|
166
|
-
.add('count', name, `${name}_count`)
|
|
167
|
-
.aggregate();
|
|
168
|
-
|
|
169
169
|
this.aggregatedSelectedTables[name] = this.dataFrame!
|
|
170
170
|
.groupBy([name])
|
|
171
171
|
.whereRowMask(this.dataFrame!.selection)
|
|
@@ -175,43 +175,35 @@ export class StackedBarChart extends DG.JsViewer {
|
|
|
175
175
|
|
|
176
176
|
this.barStats = {};
|
|
177
177
|
|
|
178
|
-
for (const [name, df] of Object.entries(this.
|
|
179
|
-
const
|
|
180
|
-
'name': string,
|
|
181
|
-
'data': { 'name': string, 'count': number, 'highlightedCount': number, 'selectedCount': number}[],
|
|
182
|
-
} = {'name': name, 'data': []};
|
|
178
|
+
for (const [name, df] of Object.entries(this.aggregatedFilterTables)) {
|
|
179
|
+
const colData: {'name': string, 'count': number, 'selectedCount': number}[] = [];
|
|
183
180
|
const aminoCol = df.getCol(name);
|
|
184
181
|
const aminoCountCol = df.getCol(`${name}_count`);
|
|
185
|
-
this.barStats[
|
|
182
|
+
this.barStats[name] = colData;
|
|
186
183
|
|
|
187
184
|
for (let i = 0; i < df.rowCount; i++) {
|
|
188
185
|
const amino = aminoCol.get(i);
|
|
189
186
|
const aminoCount = aminoCountCol.get(i);
|
|
190
|
-
const aminoObj = {'name': amino, 'count': aminoCount, '
|
|
191
|
-
const aggHighlightedAminoCol = this.aggregatedHighlightedTables[name].getCol(`${name}`);
|
|
192
|
-
const aggHighlightedCountCol = this.aggregatedHighlightedTables[name].getCol(`${name}_count`);
|
|
187
|
+
const aminoObj = {'name': amino, 'count': aminoCount, 'selectedCount': 0};
|
|
193
188
|
const aggSelectedAminoCol = this.aggregatedSelectedTables[name].getCol(`${name}`);
|
|
194
189
|
const aggSelectedCountCol = this.aggregatedSelectedTables[name].getCol(`${name}_count`);
|
|
195
190
|
|
|
196
191
|
if (!amino || amino === this.dataEmptyAA)
|
|
197
192
|
continue;
|
|
198
193
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
for (
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
aminoObj[col == aggHighlightedCountCol ? 'highlightedCount' : 'selectedCount'] = col.get(j);
|
|
208
|
-
break;
|
|
209
|
-
}
|
|
194
|
+
colData.push(aminoObj);
|
|
195
|
+
|
|
196
|
+
for (let j = 0; j < aggSelectedCountCol.length; j++) {
|
|
197
|
+
const selectedAmino = aggSelectedAminoCol.get(j);
|
|
198
|
+
const curAmino = (selectedAmino);
|
|
199
|
+
if (curAmino == amino) {
|
|
200
|
+
aminoObj['selectedCount'] = aggSelectedCountCol.get(j);
|
|
201
|
+
break;
|
|
210
202
|
}
|
|
211
203
|
}
|
|
212
204
|
}
|
|
213
205
|
|
|
214
|
-
|
|
206
|
+
colData.sort((o1, o2) => this.ord[o2['name']] - this.ord[o1['name']]);
|
|
215
207
|
}
|
|
216
208
|
|
|
217
209
|
this.max = this.dataFrame!.filter.trueCount;
|
|
@@ -291,24 +283,16 @@ export class StackedBarChart extends DG.JsViewer {
|
|
|
291
283
|
);
|
|
292
284
|
}
|
|
293
285
|
|
|
294
|
-
if (obj['highlightedCount'] > eps && obj['highlightedCount'] > obj['selectedCount']) {
|
|
295
|
-
g.fillStyle = 'rgb(209,242,251)';
|
|
296
|
-
g.fillRect(
|
|
297
|
-
x + xStart - w * selectLineRatio * 2,
|
|
298
|
-
y + yStart + h * obj['selectedCount'] / this.max - gapSize,
|
|
299
|
-
barWidth * selectLineRatio,
|
|
300
|
-
h * (obj['highlightedCount'] - obj['selectedCount']) / this.max - gapSize,
|
|
301
|
-
);
|
|
302
|
-
}
|
|
303
|
-
|
|
304
286
|
sum -= obj['count'];
|
|
305
287
|
});
|
|
306
288
|
}
|
|
307
289
|
|
|
308
|
-
|
|
290
|
+
findAARandPosition(cell: DG.GridCell, mouseEvent: MouseEvent) {
|
|
309
291
|
if (!cell.tableColumn?.name || !this.aminoColumnNames.includes(cell.tableColumn.name))
|
|
310
|
-
return;
|
|
292
|
+
return null;
|
|
311
293
|
|
|
294
|
+
const offsetX = mouseEvent.offsetX;
|
|
295
|
+
const offsetY = mouseEvent.offsetY;
|
|
312
296
|
const colName = cell.tableColumn?.name;
|
|
313
297
|
const innerMargin = 0.02;
|
|
314
298
|
const margin = 0.2;
|
|
@@ -326,73 +310,53 @@ export class StackedBarChart extends DG.JsViewer {
|
|
|
326
310
|
sum += obj['count'];
|
|
327
311
|
});
|
|
328
312
|
|
|
329
|
-
|
|
330
|
-
|
|
313
|
+
const xStart = x + (w - barWidth) / 2;
|
|
314
|
+
for (const obj of barData) {
|
|
331
315
|
const sBarHeight = h * obj['count'] / this.max;
|
|
332
316
|
const gapSize = sBarHeight * innerMargin;
|
|
333
317
|
const verticalShift = (this.max - sum) / this.max;
|
|
334
318
|
const subBartHeight = sBarHeight - gapSize;
|
|
335
|
-
const yStart = h * verticalShift + gapSize / 2;
|
|
336
|
-
const xStart = (w - barWidth) / 2;
|
|
319
|
+
const yStart = y + h * verticalShift + gapSize / 2;
|
|
337
320
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
offsetX <= x + xStart + barWidth &&
|
|
341
|
-
offsetY <= y + yStart + subBartHeight)
|
|
342
|
-
this.highlighted = {'colName': colName, 'aaName': obj['name']};
|
|
321
|
+
const isIntersectingX = offsetX >= xStart && offsetX <= xStart + barWidth;
|
|
322
|
+
const isIntersectingY = offsetY >= yStart && offsetY <= yStart + subBartHeight;
|
|
343
323
|
|
|
324
|
+
if (isIntersectingX && isIntersectingY)
|
|
325
|
+
return {'colName': colName, 'aaName': obj['name']};
|
|
344
326
|
|
|
345
327
|
sum -= obj['count'];
|
|
346
|
-
});
|
|
347
|
-
|
|
348
|
-
if (!this.highlighted)
|
|
349
|
-
return;
|
|
350
|
-
|
|
351
|
-
if (mouseEvent.type == 'click') {
|
|
352
|
-
let idx = -1;
|
|
353
|
-
|
|
354
|
-
for (let i = 0; i < this.selected.length; ++i) {
|
|
355
|
-
if (JSON.stringify(this.selected[i]) == JSON.stringify(this.highlighted))
|
|
356
|
-
idx = i;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
if (mouseEvent.shiftKey && idx == -1)
|
|
360
|
-
this.selected.push(this.highlighted);
|
|
361
|
-
|
|
362
|
-
if (mouseEvent.shiftKey && (mouseEvent.ctrlKey || mouseEvent.metaKey) && idx != -1)
|
|
363
|
-
this.selected.splice(idx, 1);
|
|
364
328
|
}
|
|
329
|
+
|
|
330
|
+
return null;
|
|
365
331
|
}
|
|
366
332
|
|
|
367
333
|
unhighlight() {
|
|
368
|
-
|
|
369
|
-
this.highlightedMask!.setAll(false);
|
|
334
|
+
ui.tooltip.hide();
|
|
370
335
|
this.computeData();
|
|
371
336
|
}
|
|
372
337
|
|
|
373
|
-
|
|
374
|
-
|
|
338
|
+
/**
|
|
339
|
+
* Requests highlight/select/filter action based on currentBarPart
|
|
340
|
+
* @param event
|
|
341
|
+
* @returns
|
|
342
|
+
*/
|
|
343
|
+
requestAction(event: MouseEvent) {
|
|
344
|
+
if (!this._currentBarPart)
|
|
375
345
|
return;
|
|
376
|
-
|
|
377
|
-
this.
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
return true;
|
|
346
|
+
let aar = this._currentBarPart!['aaName'];
|
|
347
|
+
let position = this._currentBarPart!['colName'];
|
|
348
|
+
if (event.type === 'click') {
|
|
349
|
+
if (this.isSameBarClicked) {
|
|
350
|
+
aar = position = C.CATEGORIES.ALL;
|
|
351
|
+
this.currentBarPart = null;
|
|
383
352
|
}
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
return true;
|
|
392
|
-
return false;
|
|
393
|
-
}, event);
|
|
353
|
+
this.controller.setSARGridCellAt(aar, position);
|
|
354
|
+
this._previousClickedBarPart = this._currentBarPart;
|
|
355
|
+
} else {
|
|
356
|
+
ui.tooltip.showRowGroup(this.dataFrame, (i) => {
|
|
357
|
+
const currentAAR = this.dataFrame.get(position, i);
|
|
358
|
+
return currentAAR === aar;
|
|
359
|
+
}, event.offsetX, event.offsetY);
|
|
394
360
|
}
|
|
395
|
-
|
|
396
|
-
this.computeData();
|
|
397
361
|
}
|
|
398
362
|
}
|
|
@@ -5,6 +5,8 @@ import {callMVA} from '../utils/multivariate-analysis';
|
|
|
5
5
|
import {PeptidesController} from '../peptides';
|
|
6
6
|
import '../styles.css';
|
|
7
7
|
import {StringDictionary} from '@datagrok-libraries/utils/src/type-declarations';
|
|
8
|
+
import * as C from '../utils/constants';
|
|
9
|
+
import {FilteringStatistics} from '../utils/filtering-statistics';
|
|
8
10
|
|
|
9
11
|
/**
|
|
10
12
|
* Peptide analysis widget.
|
|
@@ -16,9 +18,7 @@ import {StringDictionary} from '@datagrok-libraries/utils/src/type-declarations'
|
|
|
16
18
|
* @param {DG.DataFrame} currentDf Working table.
|
|
17
19
|
* @return {Promise<DG.Widget>} Widget containing peptide analysis.
|
|
18
20
|
*/
|
|
19
|
-
export async function analyzePeptidesWidget(
|
|
20
|
-
col: DG.Column, view: DG.TableView, tableGrid: DG.Grid, currentDf: DG.DataFrame,
|
|
21
|
-
): Promise<DG.Widget> {
|
|
21
|
+
export async function analyzePeptidesWidget(currentDf: DG.DataFrame, col: DG.Column): Promise<DG.Widget> {
|
|
22
22
|
let tempCol = null;
|
|
23
23
|
let tempDf: DG.DataFrame;
|
|
24
24
|
let newScaledColName: string;
|
|
@@ -33,13 +33,14 @@ export async function analyzePeptidesWidget(
|
|
|
33
33
|
'Scaling', 'none', ['none', 'lg', '-lg'],
|
|
34
34
|
async (currentMethod: string) => {
|
|
35
35
|
const currentActivityCol = activityColumnChoice.value.name;
|
|
36
|
+
|
|
36
37
|
|
|
37
38
|
[tempDf, newScaledColName] = await PeptidesController.scaleActivity(
|
|
38
|
-
currentMethod,
|
|
39
|
+
currentMethod, currentDf, currentActivityCol, true);
|
|
39
40
|
|
|
40
41
|
const hist = tempDf.plot.histogram({
|
|
41
42
|
filteringEnabled: false,
|
|
42
|
-
valueColumnName:
|
|
43
|
+
valueColumnName: C.COLUMNS_NAMES.ACTIVITY_SCALED,
|
|
43
44
|
legendVisibility: 'Never',
|
|
44
45
|
showXAxis: true,
|
|
45
46
|
showColumnSelector: false,
|
|
@@ -69,45 +70,47 @@ export async function analyzePeptidesWidget(
|
|
|
69
70
|
const startBtn = ui.button('Launch SAR', async () => {
|
|
70
71
|
const progress = DG.TaskBarProgressIndicator.create('Loading SAR...');
|
|
71
72
|
if (activityColumnChoice.value.type === DG.TYPE.FLOAT) {
|
|
72
|
-
const activityColumn = activityColumnChoice.value.name;
|
|
73
|
-
const activityColumnScaled = `${activityColumn}Scaled`;
|
|
74
|
-
const originalDfColumns = (currentDf.columns as DG.ColumnList).names();
|
|
73
|
+
const activityColumn: string = activityColumnChoice.value.name;
|
|
74
|
+
// const activityColumnScaled = `${activityColumn}Scaled`;
|
|
75
|
+
// const originalDfColumns = (currentDf.columns as DG.ColumnList).names();
|
|
75
76
|
const options: StringDictionary = {
|
|
76
|
-
'activityColumnName': activityColumn,
|
|
77
77
|
'scaling': activityScalingMethod.value,
|
|
78
78
|
};
|
|
79
79
|
|
|
80
|
-
|
|
81
|
-
(currentDf.
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
80
|
+
//prepare new DF
|
|
81
|
+
const newDf = currentDf.clone(currentDf.filter, [col.name, activityColumn]);
|
|
82
|
+
newDf.getCol(activityColumn).name = C.COLUMNS_NAMES.ACTIVITY;
|
|
83
|
+
newDf.getCol(col.name).name = C.COLUMNS_NAMES.ALIGNED_SEQUENCE;
|
|
84
|
+
const activityScaledCol = tempDf.getCol(C.COLUMNS_NAMES.ACTIVITY_SCALED);
|
|
85
|
+
(newDf.columns as DG.ColumnList).add(activityScaledCol);
|
|
86
|
+
// newDf.temp[C.COLUMNS_NAMES.ACTIVITY] = activityColumn;
|
|
87
|
+
newDf.name = 'Peptides analysis';
|
|
88
|
+
newDf.temp[C.COLUMNS_NAMES.ACTIVITY_SCALED] = newScaledColName;
|
|
89
|
+
newDf.tags['isPeptidesAnalysis'] = 'true';
|
|
90
|
+
|
|
91
|
+
const peptides = await PeptidesController.getInstance(newDf);
|
|
92
|
+
await peptides.init(newDf);
|
|
90
93
|
} else
|
|
91
94
|
grok.shell.error('The activity column must be of floating point number type!');
|
|
92
95
|
progress.close();
|
|
93
96
|
});
|
|
94
97
|
startBtn.style.alignSelf = 'center';
|
|
95
98
|
|
|
96
|
-
const startMVABtn = ui.button('Launch MVA', async () => {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
+
// const startMVABtn = ui.button('Launch MVA', async () => {
|
|
100
|
+
// if (activityColumnChoice.value.type === DG.TYPE.FLOAT) {
|
|
101
|
+
// const progress = DG.TaskBarProgressIndicator.create('Loading MVA...');
|
|
99
102
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
103
|
+
// const options: {[key: string]: string} = {
|
|
104
|
+
// 'activityColumnName': activityColumnChoice.value.name,
|
|
105
|
+
// 'scaling': activityScalingMethod.value,
|
|
106
|
+
// };
|
|
104
107
|
|
|
105
|
-
|
|
108
|
+
// await callMVA(tableGrid, view, currentDf, options, col);
|
|
106
109
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
});
|
|
110
|
+
// progress.close();
|
|
111
|
+
// } else
|
|
112
|
+
// grok.shell.error('The activity column must be of floating point number type!');
|
|
113
|
+
// });
|
|
111
114
|
|
|
112
115
|
|
|
113
116
|
const viewer = await currentDf.plot.fromType('peptide-logo-viewer');
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import * as ui from 'datagrok-api/ui';
|
|
2
|
+
import * as DG from 'datagrok-api/dg';
|
|
3
|
+
|
|
4
|
+
import * as C from '../utils/constants';
|
|
5
|
+
import {StringDictionary} from '@datagrok-libraries/utils/src/type-declarations';
|
|
6
|
+
import {FilteringStatistics} from '../utils/filtering-statistics';
|
|
7
|
+
|
|
8
|
+
export function getDistributionPlot(df: DG.DataFrame, valueCol: string, splitCol: string) {
|
|
9
|
+
return df.plot.histogram({
|
|
10
|
+
// const hist = originalDf.plot.histogram({
|
|
11
|
+
filteringEnabled: false,
|
|
12
|
+
valueColumnName: valueCol,
|
|
13
|
+
splitColumnName: splitCol,
|
|
14
|
+
legendVisibility: 'Never',
|
|
15
|
+
showXAxis: true,
|
|
16
|
+
showColumnSelector: false,
|
|
17
|
+
showRangeSlider: false,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function getDistributionWidget(table: DG.DataFrame): DG.Widget {
|
|
22
|
+
// const labelStr = this.multipleFilter.filterLabel;
|
|
23
|
+
const splitCol = table.col(C.COLUMNS_NAMES.SPLIT_COL);
|
|
24
|
+
if (!splitCol)
|
|
25
|
+
return new DG.Widget(ui.divText('No distribution'));
|
|
26
|
+
let [aarStr, otherStr] = splitCol.categories;
|
|
27
|
+
if (typeof otherStr === 'undefined')
|
|
28
|
+
[aarStr, otherStr] = [otherStr, aarStr];
|
|
29
|
+
// const currentColor = DG.Color.toHtml(DG.Color.orange);
|
|
30
|
+
// const otherColor = DG.Color.toHtml(DG.Color.blue);
|
|
31
|
+
const currentColor = DG.Color.toHtml(DG.Color.getCategoryColor(splitCol, aarStr));
|
|
32
|
+
const otherColor = DG.Color.toHtml(DG.Color.getCategoryColor(splitCol, otherStr));
|
|
33
|
+
|
|
34
|
+
const currentLabel = ui.label(aarStr, {style: {color: currentColor}});
|
|
35
|
+
const otherLabel = ui.label(otherStr, {style: {color: otherColor}});
|
|
36
|
+
const elements: (HTMLLabelElement | HTMLElement)[] = [currentLabel, otherLabel];
|
|
37
|
+
|
|
38
|
+
const getContent = () => {
|
|
39
|
+
// const processedDf =
|
|
40
|
+
// table.clone(null, [C.COLUMNS_NAMES.ACTIVITY_SCALED, C.COLUMNS_NAMES.SPLIT_COL]);
|
|
41
|
+
const hist = getDistributionPlot(table, C.COLUMNS_NAMES.ACTIVITY_SCALED, C.COLUMNS_NAMES.SPLIT_COL).root;
|
|
42
|
+
|
|
43
|
+
hist.style.width = 'auto';
|
|
44
|
+
elements.push(hist);
|
|
45
|
+
|
|
46
|
+
const stats = (table.temp[C.STATS] as FilteringStatistics).result;
|
|
47
|
+
if (stats) {
|
|
48
|
+
const tableMap: StringDictionary = {
|
|
49
|
+
'Statistics:': '',
|
|
50
|
+
'Count': stats.count.toString(),
|
|
51
|
+
'p-value': stats.pValue < 0.01 ? '<0.01' : stats.pValue.toFixed(2),
|
|
52
|
+
'Mean difference': stats.meanDifference.toFixed(2),
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
elements.push(ui.tableFromMap(tableMap));
|
|
56
|
+
}
|
|
57
|
+
return ui.divV(elements);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
return new DG.Widget(getContent());
|
|
61
|
+
}
|
|
@@ -34,6 +34,7 @@ export function manualAlignmentWidget(alignedSequenceCol: DG.Column, currentDf:
|
|
|
34
34
|
grok.shell.o = temp;
|
|
35
35
|
|
|
36
36
|
const peptidesController = await PeptidesController.getInstance(currentDf);
|
|
37
|
+
peptidesController.init(currentDf);
|
|
37
38
|
peptidesController.updateDefault();
|
|
38
39
|
});
|
|
39
40
|
|
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
import * as ui from 'datagrok-api/ui';
|
|
2
2
|
import * as DG from 'datagrok-api/dg';
|
|
3
|
+
import { PeptidesController } from '../peptides';
|
|
3
4
|
|
|
4
|
-
export function
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
export async function substitutionsWidget(table: DG.DataFrame): Promise<DG.Widget> {
|
|
6
|
+
const controller = await PeptidesController.getInstance(table);
|
|
7
|
+
controller.init(table);
|
|
8
|
+
const substTable = controller.getSubstitutions();
|
|
7
9
|
|
|
8
|
-
|
|
10
|
+
if (!substTable)
|
|
11
|
+
return new DG.Widget(ui.label('No substitution table generated'));
|
|
12
|
+
|
|
13
|
+
const dfRowCount = substTable.rowCount;
|
|
9
14
|
const aminoInputFrom = ui.stringInput('from', '');
|
|
10
15
|
const aminoInputTo = ui.stringInput('to', '');
|
|
11
16
|
const fromToMap: {[key: string]: DG.BitSet} = {};
|
|
12
17
|
let aminoFrom = '';
|
|
13
18
|
let aminoTo = '';
|
|
14
|
-
const initialCol: DG.Column =
|
|
15
|
-
const substitutedCol: DG.Column =
|
|
16
|
-
|
|
17
|
-
for (let i = 0; i < initialCol.length; ++i) {
|
|
18
|
-
const sequenceDifference = `${initialCol.get(i)}#${substitutedCol.get(i)}`;
|
|
19
|
-
initialCol.set(i, sequenceDifference);
|
|
20
|
-
}
|
|
19
|
+
const initialCol: DG.Column = substTable.getCol('Initial');
|
|
20
|
+
const substitutedCol: DG.Column = substTable.getCol('Substituted');
|
|
21
21
|
|
|
22
22
|
initialCol.semType = 'alignedSequenceDifference';
|
|
23
23
|
initialCol.name = 'Substitution';
|
|
24
|
-
|
|
24
|
+
// substTable.columns.remove('Substituted');
|
|
25
25
|
// const substCol = table.getCol('Substitution');
|
|
26
26
|
|
|
27
27
|
for (let i = 0; i < dfRowCount; ++i) {
|
|
@@ -33,7 +33,7 @@ export function substTableWidget(table: DG.DataFrame): DG.Widget {
|
|
|
33
33
|
|
|
34
34
|
for (let j = 0; j < aminosFrom.length; ++j) {
|
|
35
35
|
if (aminosFrom[j] != aminosTo[j]) {
|
|
36
|
-
const idx = (aminosFrom[j]
|
|
36
|
+
const idx = `${getAmino(aminosFrom[j])}#${getAmino(aminosTo[j])}`;
|
|
37
37
|
|
|
38
38
|
if (!(idx in fromToMap))
|
|
39
39
|
fromToMap[idx] = DG.BitSet.create(dfRowCount);
|
|
@@ -42,22 +42,32 @@ export function substTableWidget(table: DG.DataFrame): DG.Widget {
|
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
for (let i = 0; i < initialCol.length; ++i) {
|
|
46
|
+
const sequenceDifference = `${initialCol.get(i)}#${substitutedCol.get(i)}`;
|
|
47
|
+
initialCol.set(i, sequenceDifference);
|
|
48
|
+
}
|
|
49
|
+
|
|
45
50
|
aminoInputFrom.onInput(() => {
|
|
46
|
-
aminoFrom = aminoInputFrom.value;
|
|
47
|
-
const fromKey = aminoFrom
|
|
51
|
+
aminoFrom = getAmino(aminoInputFrom.value);
|
|
52
|
+
const fromKey = `${aminoFrom}#${aminoTo}`;
|
|
48
53
|
if (fromKey in fromToMap)
|
|
49
|
-
|
|
54
|
+
substTable.selection.copyFrom(fromToMap[fromKey]);
|
|
50
55
|
});
|
|
51
56
|
|
|
52
57
|
aminoInputTo.onInput(() => {
|
|
53
|
-
aminoTo = aminoInputTo.value;
|
|
54
|
-
const toKey = aminoFrom
|
|
58
|
+
aminoTo = getAmino(aminoInputTo.value);
|
|
59
|
+
const toKey = `${aminoFrom}#${aminoTo}`;
|
|
55
60
|
if (toKey in fromToMap)
|
|
56
|
-
|
|
61
|
+
substTable.selection.copyFrom(fromToMap[toKey]);
|
|
57
62
|
});
|
|
58
63
|
|
|
59
|
-
const grid =
|
|
64
|
+
const grid = substTable.plot.grid();
|
|
60
65
|
grid.props.allowEdit = false;
|
|
61
66
|
grid.root.style.width = 'auto';
|
|
67
|
+
grid.root.style.height = '150px';
|
|
62
68
|
return new DG.Widget(ui.divV([aminoInputFrom.root, aminoInputTo.root, grid.root]));
|
|
63
69
|
}
|
|
70
|
+
|
|
71
|
+
function getAmino(amino: string): string {
|
|
72
|
+
return amino === '' ? '-' : amino;
|
|
73
|
+
}
|