@datagrok/peptides 1.16.0 → 1.17.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 +33 -8
- package/README.md +12 -7
- package/dist/209.js +2 -2
- package/dist/361.js +2 -2
- package/dist/381.js +2 -2
- package/dist/770.js +2 -0
- package/dist/831.js +2 -2
- package/dist/868.js +2 -2
- package/dist/931.js +3 -0
- package/dist/932.js +2 -0
- package/dist/package-test.js +2 -2
- package/dist/package.js +2 -2
- package/package.json +7 -7
- package/setup-unlink-clean.cmd +6 -0
- package/setup.cmd +2 -2
- package/src/model.ts +161 -113
- package/src/package.ts +13 -22
- package/src/tests/model.ts +1 -1
- package/src/tests/table-view.ts +1 -1
- package/src/utils/algorithms.ts +2 -2
- package/src/utils/cell-renderer.ts +54 -42
- package/src/utils/constants.ts +4 -0
- package/src/utils/misc.ts +49 -28
- package/src/utils/statistics.ts +1 -0
- package/src/utils/tooltips.ts +6 -10
- package/src/viewers/logo-summary.ts +14 -13
- package/src/viewers/peptide-space-viewer.ts +1 -1
- package/src/viewers/sar-viewer.ts +80 -37
- package/src/widgets/distribution.ts +52 -198
- package/src/widgets/mutation-cliffs.ts +2 -4
- package/src/widgets/peptides.ts +3 -3
- package/src/widgets/selection.ts +3 -3
- package/src/widgets/settings.ts +2 -2
- package/dist/196.js +0 -3
- package/dist/694.js +0 -2
- /package/dist/{196.js.LICENSE.txt → 931.js.LICENSE.txt} +0 -0
|
@@ -21,11 +21,14 @@ export enum MONOMER_POSITION_PROPERTIES {
|
|
|
21
21
|
COLOR_COLUMN_NAME = 'color',
|
|
22
22
|
AGGREGATION = 'aggregation',
|
|
23
23
|
TARGET = 'target',
|
|
24
|
-
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const MUTATION_CLIFFS_CELL_WIDTH = 40;
|
|
27
|
+
const AAR_CELL_WIDTH = 30;
|
|
25
28
|
|
|
26
29
|
/** Structure-activity relationship viewer */
|
|
27
30
|
export class MonomerPosition extends DG.JsViewer {
|
|
28
|
-
_titleHost = ui.divText(SELECTION_MODE.MUTATION_CLIFFS, {id: 'pep-viewer-title'});
|
|
31
|
+
// _titleHost = ui.divText(SELECTION_MODE.MUTATION_CLIFFS, {id: 'pep-viewer-title'});
|
|
29
32
|
_viewerGrid!: DG.Grid;
|
|
30
33
|
_model!: PeptidesModel;
|
|
31
34
|
color: string;
|
|
@@ -38,13 +41,11 @@ export class MonomerPosition extends DG.JsViewer {
|
|
|
38
41
|
super();
|
|
39
42
|
this.target = this.string(MONOMER_POSITION_PROPERTIES.TARGET, null,
|
|
40
43
|
{category: SELECTION_MODE.MUTATION_CLIFFS, choices: []});
|
|
41
|
-
this.color = this.string(MONOMER_POSITION_PROPERTIES.COLOR_COLUMN_NAME, C.COLUMNS_NAMES.
|
|
42
|
-
{category: SELECTION_MODE.INVARIANT_MAP,
|
|
43
|
-
choices: wu(grok.shell.t.columns.numerical).toArray().map((col) => col.name)});
|
|
44
|
+
this.color = this.string(MONOMER_POSITION_PROPERTIES.COLOR_COLUMN_NAME, C.COLUMNS_NAMES.ACTIVITY,
|
|
45
|
+
{category: SELECTION_MODE.INVARIANT_MAP, choices: wu(grok.shell.t.columns.numerical).toArray().map((col) => col.name)});
|
|
44
46
|
this.aggregation = this.string(MONOMER_POSITION_PROPERTIES.AGGREGATION, DG.AGG.AVG,
|
|
45
47
|
{category: SELECTION_MODE.INVARIANT_MAP,
|
|
46
|
-
choices: Object.values(DG.AGG)
|
|
47
|
-
.filter((agg) => ![DG.AGG.KEY, DG.AGG.PIVOT, DG.AGG.SELECTED_ROWS_COUNT].includes(agg))});
|
|
48
|
+
choices: Object.values(DG.AGG).filter((agg) => ![DG.AGG.KEY, DG.AGG.PIVOT, DG.AGG.SELECTED_ROWS_COUNT].includes(agg))});
|
|
48
49
|
}
|
|
49
50
|
|
|
50
51
|
get name(): string {return VIEWER_TYPE.MONOMER_POSITION;}
|
|
@@ -84,6 +85,10 @@ export class MonomerPosition extends DG.JsViewer {
|
|
|
84
85
|
super.onPropertyChanged(property);
|
|
85
86
|
if (property.name === MONOMER_POSITION_PROPERTIES.TARGET)
|
|
86
87
|
this.model.updateMutationCliffs().then(() => this.render(true));
|
|
88
|
+
// this will cause colors to recalculate
|
|
89
|
+
this.model.df.columns.toList().forEach((col) => {
|
|
90
|
+
col.temp[C.TAGS.INVARIANT_MAP_COLOR_CACHE] = null;
|
|
91
|
+
});
|
|
87
92
|
|
|
88
93
|
this.render(true);
|
|
89
94
|
}
|
|
@@ -113,7 +118,8 @@ export class MonomerPosition extends DG.JsViewer {
|
|
|
113
118
|
const monomerPositionDf = this.createMonomerPositionDf();
|
|
114
119
|
this.viewerGrid = monomerPositionDf.plot.grid();
|
|
115
120
|
this.viewerGrid.sort([C.COLUMNS_NAMES.MONOMER]);
|
|
116
|
-
|
|
121
|
+
const positionColumns = this.model.positionColumns.toArray().map((col) => col.name);
|
|
122
|
+
this.viewerGrid.columns.setOrder([C.COLUMNS_NAMES.MONOMER, ...positionColumns]);
|
|
117
123
|
const monomerCol = monomerPositionDf.getCol(C.COLUMNS_NAMES.MONOMER);
|
|
118
124
|
CR.setMonomerRenderer(monomerCol, this.model.alphabet);
|
|
119
125
|
this.viewerGrid.onCellRender.subscribe((args: DG.GridCellRenderArgs) => renderCell(args, this.model,
|
|
@@ -175,6 +181,8 @@ export class MonomerPosition extends DG.JsViewer {
|
|
|
175
181
|
this.model.modifyMutationCliffsSelection(monomerPosition, {shiftPressed: true, ctrlPressed: false}, false);
|
|
176
182
|
}
|
|
177
183
|
}
|
|
184
|
+
} else {
|
|
185
|
+
return;
|
|
178
186
|
}
|
|
179
187
|
this.model.fireBitsetChanged();
|
|
180
188
|
this.viewerGrid.invalidate();
|
|
@@ -197,7 +205,21 @@ export class MonomerPosition extends DG.JsViewer {
|
|
|
197
205
|
this.showHelp();
|
|
198
206
|
});
|
|
199
207
|
|
|
200
|
-
setViewerGridProps(this.viewerGrid
|
|
208
|
+
setViewerGridProps(this.viewerGrid);
|
|
209
|
+
|
|
210
|
+
// Monomer cell renderer overrides width settings. This way I ensure is "initially" set.
|
|
211
|
+
const afterDraw = this.viewerGrid.onAfterDrawContent.subscribe(() => {
|
|
212
|
+
const monomerGCol = this.viewerGrid.col(C.COLUMNS_NAMES.MONOMER)!;
|
|
213
|
+
if (monomerGCol.width === AAR_CELL_WIDTH) {
|
|
214
|
+
afterDraw.unsubscribe();
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
monomerGCol.width = AAR_CELL_WIDTH;
|
|
218
|
+
for (const posCol of positionColumns) {
|
|
219
|
+
const gcCol = this.viewerGrid.col(posCol)!;
|
|
220
|
+
gcCol.width = MUTATION_CLIFFS_CELL_WIDTH;
|
|
221
|
+
}
|
|
222
|
+
});
|
|
201
223
|
}
|
|
202
224
|
|
|
203
225
|
showHelp(): void {
|
|
@@ -212,6 +234,14 @@ export class MonomerPosition extends DG.JsViewer {
|
|
|
212
234
|
}
|
|
213
235
|
|
|
214
236
|
render(refreshOnly = false): void {
|
|
237
|
+
// Backward compatability with 1.16.0
|
|
238
|
+
const columnProperty = this.getProperty(MONOMER_POSITION_PROPERTIES.COLOR_COLUMN_NAME);
|
|
239
|
+
if (columnProperty) {
|
|
240
|
+
columnProperty.choices = wu(grok.shell.t.columns.numerical).toArray().map((col) => col.name);
|
|
241
|
+
if (columnProperty.get(this) === C.COLUMNS_NAMES.ACTIVITY_SCALED)
|
|
242
|
+
columnProperty.set(this, C.COLUMNS_NAMES.ACTIVITY);
|
|
243
|
+
}
|
|
244
|
+
|
|
215
245
|
if (!refreshOnly) {
|
|
216
246
|
$(this.root).empty();
|
|
217
247
|
let switchHost = ui.divText(VIEWER_TYPE.MOST_POTENT_RESIDUES, {id: 'pep-viewer-title'});
|
|
@@ -254,7 +284,7 @@ export class MonomerPosition extends DG.JsViewer {
|
|
|
254
284
|
|
|
255
285
|
/** Vertical structure activity relationship viewer */
|
|
256
286
|
export class MostPotentResidues extends DG.JsViewer {
|
|
257
|
-
_titleHost = ui.divText(VIEWER_TYPE.MOST_POTENT_RESIDUES, {id: 'pep-viewer-title'});
|
|
287
|
+
// _titleHost = ui.divText(VIEWER_TYPE.MOST_POTENT_RESIDUES, {id: 'pep-viewer-title'});
|
|
258
288
|
_viewerGrid!: DG.Grid;
|
|
259
289
|
_model!: PeptidesModel;
|
|
260
290
|
keyPressed: boolean = false;
|
|
@@ -350,6 +380,7 @@ export class MostPotentResidues extends DG.JsViewer {
|
|
|
350
380
|
pValData.length = i;
|
|
351
381
|
countData.length = i;
|
|
352
382
|
ratioData.length = i;
|
|
383
|
+
meanData.length = i;
|
|
353
384
|
|
|
354
385
|
const mprDf = DG.DataFrame.create(i); // Subtract 'general' entry from mp-stats
|
|
355
386
|
const mprDfCols = mprDf.columns;
|
|
@@ -420,6 +451,8 @@ export class MostPotentResidues extends DG.JsViewer {
|
|
|
420
451
|
const monomerPosition = this.getMonomerPosition(this.viewerGrid.cell('Diff', rowIdx));
|
|
421
452
|
this.model.modifyMutationCliffsSelection(monomerPosition, {shiftPressed: true, ctrlPressed: false}, false);
|
|
422
453
|
}
|
|
454
|
+
} else {
|
|
455
|
+
return;
|
|
423
456
|
}
|
|
424
457
|
this.model.fireBitsetChanged();
|
|
425
458
|
this.viewerGrid.invalidate();
|
|
@@ -440,9 +473,19 @@ export class MostPotentResidues extends DG.JsViewer {
|
|
|
440
473
|
grok.shell.windows.help.showHelp(ui.markdown(text));
|
|
441
474
|
}).catch((e) => grok.log.error(e));
|
|
442
475
|
});
|
|
476
|
+
setViewerGridProps(this.viewerGrid);
|
|
443
477
|
const mdCol: DG.GridColumn = this.viewerGrid.col(C.COLUMNS_NAMES.MEAN_DIFFERENCE)!;
|
|
444
478
|
mdCol.name = 'Diff';
|
|
445
|
-
|
|
479
|
+
// Monomer cell renderer overrides width settings. This way I ensure is "initially" set.
|
|
480
|
+
const afterDraw = this.viewerGrid.onAfterDrawContent.subscribe(() => {
|
|
481
|
+
const monomerGCol = this.viewerGrid.col(C.COLUMNS_NAMES.MONOMER)!;
|
|
482
|
+
if (monomerGCol.width === AAR_CELL_WIDTH) {
|
|
483
|
+
afterDraw.unsubscribe();
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
monomerGCol.width = AAR_CELL_WIDTH;
|
|
487
|
+
mdCol.width = MUTATION_CLIFFS_CELL_WIDTH;
|
|
488
|
+
});
|
|
446
489
|
}
|
|
447
490
|
|
|
448
491
|
getMonomerPosition(gridCell: DG.GridCell): SelectionItem {
|
|
@@ -464,7 +507,7 @@ export class MostPotentResidues extends DG.JsViewer {
|
|
|
464
507
|
}
|
|
465
508
|
|
|
466
509
|
function renderCell(args: DG.GridCellRenderArgs, model: PeptidesModel, isInvariantMap?: boolean,
|
|
467
|
-
|
|
510
|
+
colorCol?: DG.Column<number>, colorAgg?: DG.AGG): void {
|
|
468
511
|
const renderColNames = [...model.positionColumns.toArray().map((col) => col.name), C.COLUMNS_NAMES.MEAN_DIFFERENCE];
|
|
469
512
|
const canvasContext = args.g;
|
|
470
513
|
const bound = args.bounds;
|
|
@@ -505,31 +548,38 @@ function renderCell(args: DG.GridCellRenderArgs, model: PeptidesModel, isInvaria
|
|
|
505
548
|
if (isInvariantMap) {
|
|
506
549
|
const value = currentPosStats![currentMonomer]!.count;
|
|
507
550
|
const positionCol = model.df.getCol(currentPosition);
|
|
508
|
-
const
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
551
|
+
const colorCache: {[_: string]: number} = positionCol.temp[C.TAGS.INVARIANT_MAP_COLOR_CACHE] ?? {};
|
|
552
|
+
let color: number | null = null;
|
|
553
|
+
if (colorCache[currentMonomer])
|
|
554
|
+
color = colorCache[currentMonomer];
|
|
555
|
+
else {
|
|
556
|
+
const positionColData = positionCol.getRawData();
|
|
557
|
+
const positionColCategories = positionCol.categories;
|
|
558
|
+
|
|
559
|
+
const colorColData = colorCol!.getRawData();
|
|
560
|
+
const colorValuesIndexes: number[] = [];
|
|
561
|
+
for (let i = 0; i < positionCol.length; ++i) {
|
|
562
|
+
if (positionColCategories[positionColData[i]] === currentMonomer)
|
|
563
|
+
colorValuesIndexes.push(i);
|
|
564
|
+
}
|
|
565
|
+
const cellColorDataCol = DG.Column.float('color', colorValuesIndexes.length)
|
|
566
|
+
.init((i) => colorColData[colorValuesIndexes[i]]);
|
|
567
|
+
const colorColStats = colorCol!.stats;
|
|
520
568
|
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
569
|
+
color = DG.Color.scaleColor(cellColorDataCol.aggregate(colorAgg!), colorColStats.min, colorColStats.max);
|
|
570
|
+
colorCache[currentMonomer] = color;
|
|
571
|
+
positionCol.temp[C.TAGS.INVARIANT_MAP_COLOR_CACHE] = colorCache;
|
|
572
|
+
}
|
|
573
|
+
CR.renderInvariantMapCell(canvasContext, currentMonomer, currentPosition, model.invariantMapSelection, value, bound, color);
|
|
524
574
|
} else {
|
|
525
575
|
CR.renderMutationCliffCell(canvasContext, currentMonomer, currentPosition, model.monomerPositionStats, bound,
|
|
526
|
-
model.mutationCliffsSelection, model.mutationCliffs
|
|
576
|
+
model.mutationCliffsSelection, model.mutationCliffs);
|
|
527
577
|
}
|
|
528
578
|
args.preventDefault();
|
|
529
579
|
canvasContext.restore();
|
|
530
580
|
}
|
|
531
581
|
|
|
532
|
-
function setViewerGridProps(grid: DG.Grid
|
|
582
|
+
function setViewerGridProps(grid: DG.Grid): void {
|
|
533
583
|
const gridProps = grid.props;
|
|
534
584
|
gridProps.allowEdit = false;
|
|
535
585
|
gridProps.allowRowSelection = false;
|
|
@@ -539,12 +589,5 @@ function setViewerGridProps(grid: DG.Grid, isMostPotentResiduesGrid: boolean): v
|
|
|
539
589
|
gridProps.showCurrentRowIndicator = false;
|
|
540
590
|
|
|
541
591
|
gridProps.rowHeight = 20;
|
|
542
|
-
|
|
543
|
-
const colNum = girdCols.length;
|
|
544
|
-
for (let i = 0; i < colNum; ++i) {
|
|
545
|
-
const col = girdCols.byIndex(i)!;
|
|
546
|
-
const colName = col.name;
|
|
547
|
-
col.width = isMostPotentResiduesGrid && colName !== 'Diff' && colName !== C.COLUMNS_NAMES.MONOMER ? 50 :
|
|
548
|
-
gridProps.rowHeight + 10;
|
|
549
|
-
}
|
|
592
|
+
|
|
550
593
|
}
|
|
@@ -1,227 +1,87 @@
|
|
|
1
1
|
import * as ui from 'datagrok-api/ui';
|
|
2
2
|
import * as DG from 'datagrok-api/dg';
|
|
3
3
|
|
|
4
|
+
import BitArray from '@datagrok-libraries/utils/src/bit-array';
|
|
4
5
|
import {StringDictionary} from '@datagrok-libraries/utils/src/type-declarations';
|
|
6
|
+
|
|
5
7
|
import $ from 'cash-dom';
|
|
6
8
|
|
|
7
9
|
import * as C from '../utils/constants';
|
|
8
10
|
import {getAggregatedColumnValues, getStats, Stats} from '../utils/statistics';
|
|
9
11
|
import {PeptidesModel} from '../model';
|
|
10
|
-
import {
|
|
11
|
-
import BitArray from '@datagrok-libraries/utils/src/bit-array';
|
|
12
|
-
|
|
13
|
-
const allConst = 'All';
|
|
14
|
-
const otherConst = 'Other';
|
|
12
|
+
import {getDistributionPanel, getDistributionTable} from '../utils/misc';
|
|
15
13
|
|
|
16
14
|
export function getDistributionWidget(table: DG.DataFrame, model: PeptidesModel): DG.Widget {
|
|
17
15
|
if (!table.selection.anyTrue)
|
|
18
16
|
return new DG.Widget(ui.divText('No distribution'));
|
|
19
17
|
|
|
20
|
-
const activityCol = table.getCol(C.COLUMNS_NAMES.
|
|
21
|
-
const activityColData = activityCol.getRawData();
|
|
18
|
+
const activityCol = table.getCol(C.COLUMNS_NAMES.ACTIVITY);
|
|
22
19
|
const rowCount = activityCol.length;
|
|
23
|
-
const selectionObject = model.invariantMapSelection;
|
|
24
|
-
const clustersColName = model.settings.clustersColumnName;
|
|
25
|
-
let clustersProcessedObject: string[] = [];
|
|
26
|
-
if (clustersColName)
|
|
27
|
-
clustersProcessedObject = Object.values(model.clusterSelection).flat();
|
|
28
20
|
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
21
|
+
// const setDefaultProperties = (input: DG.InputBase): void => {
|
|
22
|
+
// input.enabled = !model.isMutationCliffsSelectionEmpty;
|
|
23
|
+
// $(input.root).find('.ui-input-editor').css('margin', '0px');
|
|
24
|
+
// $(input.root).find('.ui-input-description').css('padding', '0px').css('padding-left', '5px');
|
|
25
|
+
// $(input.captionLabel).addClass('ui-label-right');
|
|
26
|
+
// };
|
|
27
|
+
//
|
|
28
|
+
// let defaultValuePos = model.splitByPos;
|
|
29
|
+
// let defaultValueMonomer = model.splitByMonomer;
|
|
30
|
+
// if (!model.isClusterSelectionEmpty && model.isMutationCliffsSelectionEmpty) {
|
|
31
|
+
// defaultValuePos = false;
|
|
32
|
+
// defaultValueMonomer = false;
|
|
33
|
+
// }
|
|
34
|
+
|
|
35
|
+
const distributionHost = ui.div([], 'd4-flex-wrap');
|
|
32
36
|
|
|
33
37
|
const updateDistributionHost = (): void => {
|
|
34
|
-
model.splitByPos = splitByPosition.value!;
|
|
35
|
-
model.splitByMonomer = splitByMonomer.value!;
|
|
36
38
|
const res: HTMLDivElement[] = [];
|
|
37
|
-
if (
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
[activityCol, DG.Column.fromBitSet(C.COLUMNS_NAMES.SPLIT_COL, mask)]);
|
|
55
|
-
const hist = getActivityDistribution(prepareTableForHistogram(distributionTable));
|
|
56
|
-
|
|
57
|
-
const stats = model.monomerPositionStats[position]![monomer]!;
|
|
58
|
-
const tableMap = getStatsTableMap(stats);
|
|
59
|
-
|
|
60
|
-
const aggregatedColMap = getAggregatedColumnValues(model.df, model.settings.columns!, {filterDf: true, mask});
|
|
61
|
-
|
|
62
|
-
const resultMap = {...tableMap, ...aggregatedColMap};
|
|
63
|
-
const distributionRoot = getStatsSummary(labels, hist, resultMap);
|
|
64
|
-
$(distributionRoot).addClass('d4-flex-col');
|
|
65
|
-
|
|
66
|
-
res.push(distributionRoot);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
} else if (splitByPosition.value) {
|
|
70
|
-
otherStr = otherConst;
|
|
71
|
-
for (const position of positions) {
|
|
72
|
-
const monomerList = selectionObject[position];
|
|
73
|
-
if (monomerList.length === 0)
|
|
74
|
-
continue;
|
|
75
|
-
|
|
76
|
-
monomerStr = `${position}: {${monomerList.join(', ')}}`;
|
|
77
|
-
const labels = getDistributionLegend(monomerStr, otherStr);
|
|
78
|
-
|
|
79
|
-
const posCol = table.getCol(position);
|
|
80
|
-
const posColCategories = posCol.categories;
|
|
81
|
-
const posColData = posCol.getRawData();
|
|
82
|
-
const monomerIndexesList = monomerList.map((monomer) => posColCategories.indexOf(monomer));
|
|
83
|
-
const mask = DG.BitSet.create(rowCount, (i) => monomerIndexesList.includes(posColData[i]));
|
|
84
|
-
const splitCol = DG.Column.fromBitSet(C.COLUMNS_NAMES.SPLIT_COL, mask);
|
|
85
|
-
|
|
86
|
-
const aggregatedColMap = getAggregatedColumnValues(model.df, model.settings.columns!, {filterDf: true, mask});
|
|
87
|
-
|
|
88
|
-
const distributionTable = DG.DataFrame.fromColumns([activityCol, splitCol]);
|
|
89
|
-
const hist = getActivityDistribution(prepareTableForHistogram(distributionTable));
|
|
90
|
-
|
|
91
|
-
const bitArray = BitArray.fromUint32Array(rowCount, splitCol.getRawData() as Uint32Array);
|
|
92
|
-
const stats = getStats(activityColData, bitArray);
|
|
93
|
-
const tableMap = getStatsTableMap(stats);
|
|
94
|
-
|
|
95
|
-
const resultMap = {...tableMap, ...aggregatedColMap};
|
|
96
|
-
const distributionRoot = getStatsSummary(labels, hist, resultMap);
|
|
97
|
-
$(distributionRoot).addClass('d4-flex-col');
|
|
98
|
-
|
|
99
|
-
res.push(distributionRoot);
|
|
100
|
-
}
|
|
101
|
-
} else if (splitByMonomer.value) {
|
|
102
|
-
const reversedSelectionObject: {[monomer: string]: string[]} = {};
|
|
103
|
-
const monomers = [];
|
|
104
|
-
for (const position of positions) {
|
|
105
|
-
for (const monomer of selectionObject[position]) {
|
|
106
|
-
if (!reversedSelectionObject.hasOwnProperty(monomer)) {
|
|
107
|
-
reversedSelectionObject[monomer] = [position];
|
|
108
|
-
monomers.push(monomer);
|
|
109
|
-
continue;
|
|
110
|
-
}
|
|
111
|
-
if (!reversedSelectionObject[monomer].includes(position))
|
|
112
|
-
reversedSelectionObject[monomer].push(position);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
otherStr = otherConst;
|
|
117
|
-
for (const monomer of monomers) {
|
|
118
|
-
const posList = reversedSelectionObject[monomer];
|
|
119
|
-
const posColList = posList.map((pos) => table.getCol(pos));
|
|
120
|
-
const posColCategoriesList = posColList.map((posCol) => posCol.categories);
|
|
121
|
-
const posColDataList = posColList.map((posCol) => posCol.getRawData());
|
|
122
|
-
const monomerCategoryIndexList = posColCategoriesList.map((posColCategories) => posColCategories.indexOf(monomer));
|
|
123
|
-
|
|
124
|
-
monomerStr = `${monomer}: {${posList.join(', ')}}`;
|
|
125
|
-
const labels = getDistributionLegend(monomerStr, otherStr);
|
|
126
|
-
|
|
127
|
-
const mask = DG.BitSet.create(rowCount,
|
|
128
|
-
(i) => posColDataList.some((posColData, j) => posColData[i] === monomerCategoryIndexList[j]));
|
|
129
|
-
const aggregatedColMap = getAggregatedColumnValues(model.df, model.settings.columns!, {filterDf: true, mask});
|
|
130
|
-
|
|
131
|
-
const splitCol = DG.Column.fromBitSet(C.COLUMNS_NAMES.SPLIT_COL, mask);
|
|
132
|
-
const distributionTable = DG.DataFrame.fromColumns([activityCol, splitCol]);
|
|
133
|
-
const hist = getActivityDistribution(prepareTableForHistogram(distributionTable));
|
|
134
|
-
|
|
135
|
-
const bitArray = BitArray.fromUint32Array(rowCount, splitCol.getRawData() as Uint32Array);
|
|
136
|
-
const stats = getStats(activityColData, bitArray);
|
|
137
|
-
const tableMap = getStatsTableMap(stats);
|
|
138
|
-
|
|
139
|
-
const resultMap: {[key: string]: any} = {...tableMap, ...aggregatedColMap};
|
|
140
|
-
const distributionRoot = getStatsSummary(labels, hist, resultMap);
|
|
141
|
-
$(distributionRoot).addClass('d4-flex-col');
|
|
142
|
-
|
|
143
|
-
res.push(distributionRoot);
|
|
144
|
-
}
|
|
145
|
-
} else {
|
|
146
|
-
if (!table.selection.anyTrue)
|
|
147
|
-
res.push(ui.divText('No distribution'));
|
|
148
|
-
else {
|
|
149
|
-
otherStr = '';
|
|
150
|
-
if (Object.values(selectionObject).some((selectedAar) => selectedAar.length !== 0) ||
|
|
151
|
-
clustersProcessedObject.length !== 0) {
|
|
152
|
-
monomerStr = '';
|
|
153
|
-
for (const position of positions) {
|
|
154
|
-
const monomerList = selectionObject[position];
|
|
155
|
-
if (monomerList.length !== 0)
|
|
156
|
-
monomerStr += `${position}: {${monomerList.join(', ')}}; `;
|
|
157
|
-
}
|
|
158
|
-
if (clustersProcessedObject.length !== 0)
|
|
159
|
-
monomerStr += `Clusters: ${clustersProcessedObject.join(', ')}`;
|
|
160
|
-
otherStr = otherConst;
|
|
161
|
-
}
|
|
162
|
-
const labels = getDistributionLegend(monomerStr, otherStr);
|
|
163
|
-
|
|
164
|
-
const distributionTable = DG.DataFrame.fromColumns([activityCol, DG.Column.fromBitSet(C.COLUMNS_NAMES.SPLIT_COL, table.selection)]);
|
|
165
|
-
const hist = getActivityDistribution(prepareTableForHistogram(distributionTable));
|
|
166
|
-
const bitArray = BitArray.fromString(table.selection.toBinaryString());
|
|
167
|
-
const mask = DG.BitSet.create(rowCount,
|
|
168
|
-
bitArray.allFalse || bitArray.allTrue ? (_): boolean => true : (i): boolean => bitArray.getBit(i));
|
|
169
|
-
const aggregatedColMap = getAggregatedColumnValues(model.df, model.settings.columns!, {filterDf: true, mask});
|
|
170
|
-
const stats = bitArray.allFalse || bitArray.allTrue ?
|
|
171
|
-
{count: rowCount, pValue: null, meanDifference: 0, ratio: 1, mask: bitArray,
|
|
172
|
-
mean: activityCol.stats.avg} :
|
|
173
|
-
getStats(activityColData, bitArray);
|
|
174
|
-
const tableMap = getStatsTableMap(stats);
|
|
175
|
-
const resultMap: {[key: string]: any} = {...tableMap, ...aggregatedColMap};
|
|
176
|
-
const distributionRoot = getStatsSummary(labels, hist, resultMap);
|
|
177
|
-
$(distributionRoot).addClass('d4-flex-col');
|
|
178
|
-
|
|
179
|
-
res.push(distributionRoot);
|
|
180
|
-
}
|
|
39
|
+
if (!table.selection.anyTrue)
|
|
40
|
+
res.push(ui.divText('No distribution'));
|
|
41
|
+
else {
|
|
42
|
+
const hist = getActivityDistribution(getDistributionTable(activityCol, model.df.selection, model.getCombinedSelection()));
|
|
43
|
+
const bitArray = BitArray.fromString(table.selection.toBinaryString());
|
|
44
|
+
const mask = DG.BitSet.create(rowCount,
|
|
45
|
+
bitArray.allFalse || bitArray.allTrue ? (_): boolean => true : (i): boolean => bitArray.getBit(i));
|
|
46
|
+
const aggregatedColMap = getAggregatedColumnValues(model.df, model.settings.columns!, {filterDf: true, mask});
|
|
47
|
+
const stats = bitArray.allFalse || bitArray.allTrue ?
|
|
48
|
+
{count: rowCount, pValue: null, meanDifference: 0, ratio: 1, mask: bitArray, mean: activityCol.stats.avg} :
|
|
49
|
+
getStats(activityCol.getRawData(), bitArray);
|
|
50
|
+
const tableMap = getStatsTableMap(stats);
|
|
51
|
+
const resultMap: { [key: string]: any } = {...tableMap, ...aggregatedColMap};
|
|
52
|
+
const distributionRoot = getDistributionPanel(hist, resultMap);
|
|
53
|
+
$(distributionRoot).addClass('d4-flex-col');
|
|
54
|
+
|
|
55
|
+
res.push(distributionRoot);
|
|
181
56
|
}
|
|
182
|
-
$(distributionHost).empty().append(res);
|
|
183
|
-
};
|
|
184
57
|
|
|
185
|
-
|
|
186
|
-
input.enabled = !model.isMutationCliffsSelectionEmpty;
|
|
187
|
-
$(input.root).find('.ui-input-editor').css('margin', '0px');
|
|
188
|
-
$(input.root).find('.ui-input-description').css('padding', '0px').css('padding-left', '5px');
|
|
189
|
-
$(input.captionLabel).addClass('ui-label-right');
|
|
58
|
+
$(distributionHost).empty().append(res);
|
|
190
59
|
};
|
|
191
60
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
splitByMonomer.setTooltip('Constructs distribution for each monomer separately');
|
|
205
|
-
setDefaultProperties(splitByMonomer);
|
|
206
|
-
|
|
207
|
-
const controlsHost = ui.divH([splitByPosition.root, splitByMonomer.root]);
|
|
208
|
-
const distributionHost = ui.div([], 'd4-flex-wrap');
|
|
209
|
-
splitByMonomer.fireChanged();
|
|
210
|
-
|
|
211
|
-
return new DG.Widget(ui.divV([controlsHost, distributionHost]));
|
|
61
|
+
// const splitByPosition = ui.boolInput('Split by position', defaultValuePos, updateDistributionHost);
|
|
62
|
+
// splitByPosition.setTooltip('Constructs distribution for each position separately');
|
|
63
|
+
// setDefaultProperties(splitByPosition);
|
|
64
|
+
// $(splitByPosition.root).css('margin-right', '10px');
|
|
65
|
+
// const splitByMonomer = ui.boolInput('Split by monomer', defaultValueMonomer, updateDistributionHost);
|
|
66
|
+
// splitByMonomer.setTooltip('Constructs distribution for each monomer separately');
|
|
67
|
+
// setDefaultProperties(splitByMonomer);
|
|
68
|
+
|
|
69
|
+
// const controlsHost = ui.divH([splitByPosition.root, splitByMonomer.root]);
|
|
70
|
+
// splitByMonomer.fireChanged();
|
|
71
|
+
updateDistributionHost();
|
|
72
|
+
return new DG.Widget(ui.divV([/*controlsHost,*/ distributionHost]));
|
|
212
73
|
}
|
|
213
74
|
|
|
214
|
-
export function getActivityDistribution(table: DG.DataFrame, isTooltip: boolean = false
|
|
215
|
-
): DG.Viewer<DG.IHistogramLookSettings> {
|
|
75
|
+
export function getActivityDistribution(table: DG.DataFrame, isTooltip: boolean = false): DG.Viewer<DG.IHistogramLookSettings> {
|
|
216
76
|
const hist = table.plot.histogram({
|
|
217
77
|
filteringEnabled: false,
|
|
218
|
-
valueColumnName: C.COLUMNS_NAMES.
|
|
78
|
+
valueColumnName: C.COLUMNS_NAMES.ACTIVITY,
|
|
219
79
|
splitColumnName: C.COLUMNS_NAMES.SPLIT_COL,
|
|
220
80
|
legendVisibility: 'Never',
|
|
221
81
|
showXAxis: true,
|
|
222
82
|
showColumnSelector: false,
|
|
223
83
|
showRangeSlider: false,
|
|
224
|
-
showBinSelector:
|
|
84
|
+
showBinSelector: false,
|
|
225
85
|
backColor: isTooltip ? '#fdffe5' : '#fffff',
|
|
226
86
|
}) as DG.Viewer<DG.IHistogramLookSettings>;
|
|
227
87
|
hist.root.style.width = 'auto';
|
|
@@ -239,9 +99,3 @@ export function getStatsTableMap(stats: Stats, options: {fractionDigits?: number
|
|
|
239
99
|
tableMap['p-value'] = stats.pValue < 0.01 ? '<0.01' : stats.pValue.toFixed(options.fractionDigits);
|
|
240
100
|
return tableMap;
|
|
241
101
|
}
|
|
242
|
-
|
|
243
|
-
export function getDistributionLegend(thisLabel: string, otherLabel: string = ''): HTMLDivElement {
|
|
244
|
-
return ui.divV([
|
|
245
|
-
ui.label(thisLabel, {style: {color: DG.Color.toHtml(otherLabel.length === 0 ? DG.Color.blue : DG.Color.orange)}}),
|
|
246
|
-
ui.label(otherLabel, {style: {color: DG.Color.toHtml(DG.Color.blue)}})]);
|
|
247
|
-
}
|
|
@@ -23,7 +23,7 @@ export function mutationCliffsWidget(table: DG.DataFrame, model: PeptidesModel):
|
|
|
23
23
|
const alignedSeqCol = table.getCol(model.settings.sequenceColumnName!);
|
|
24
24
|
const alignedSeqColCategories = alignedSeqCol.categories;
|
|
25
25
|
const alignedSeqColData = alignedSeqCol.getRawData();
|
|
26
|
-
const activityScaledCol = table.getCol(C.COLUMNS_NAMES.
|
|
26
|
+
const activityScaledCol = table.getCol(C.COLUMNS_NAMES.ACTIVITY);
|
|
27
27
|
const activityScaledColData = activityScaledCol.getRawData();
|
|
28
28
|
const seenIndexes = new Map<number, number[]>();
|
|
29
29
|
const uniqueSequencesBitSet = DG.BitSet.create(table.rowCount);
|
|
@@ -85,11 +85,10 @@ export function mutationCliffsWidget(table: DG.DataFrame, model: PeptidesModel):
|
|
|
85
85
|
else
|
|
86
86
|
pairsTable.filter.setAll(true);
|
|
87
87
|
});
|
|
88
|
-
aminoToInput.setTooltip('
|
|
88
|
+
aminoToInput.setTooltip('Filter the rows by the monomer that the mutation was substituted to');
|
|
89
89
|
|
|
90
90
|
const pairsGrid = pairsTable.plot.grid();
|
|
91
91
|
setGridProps(pairsGrid);
|
|
92
|
-
pairsGrid.root.style.height = '150px';
|
|
93
92
|
substCol.semType = C.SEM_TYPES.MACROMOLECULE_DIFFERENCE;
|
|
94
93
|
substCol.tags[C.TAGS.SEPARATOR] = getSeparator(alignedSeqCol);
|
|
95
94
|
substCol.tags[DG.TAGS.UNITS] = alignedSeqCol.tags[DG.TAGS.UNITS];
|
|
@@ -164,7 +163,6 @@ export function mutationCliffsWidget(table: DG.DataFrame, model: PeptidesModel):
|
|
|
164
163
|
const uniqueSequencesGrid = uniqueSequencesTable.plot.grid();
|
|
165
164
|
setGridProps(uniqueSequencesGrid);
|
|
166
165
|
uniqueSequencesGrid.props.rowHeight = 20;
|
|
167
|
-
uniqueSequencesGrid.root.style.height = '250px';
|
|
168
166
|
uniqueSequencesTable.filter.onChanged.subscribe(() => {
|
|
169
167
|
const uniqueSelectedIndexes: number[] = [];
|
|
170
168
|
for (const idx of pairsSelectedIndexes) {
|
package/src/widgets/peptides.ts
CHANGED
|
@@ -78,7 +78,7 @@ export function analyzePeptidesUI(df: DG.DataFrame, col?: DG.Column<string>): {h
|
|
|
78
78
|
|
|
79
79
|
const hist = DG.DataFrame.fromColumns([scaledCol]).plot.histogram({
|
|
80
80
|
filteringEnabled: false,
|
|
81
|
-
valueColumnName: C.COLUMNS_NAMES.
|
|
81
|
+
valueColumnName: C.COLUMNS_NAMES.ACTIVITY,
|
|
82
82
|
legendVisibility: 'Never',
|
|
83
83
|
showXAxis: true,
|
|
84
84
|
showColumnSelector: false,
|
|
@@ -169,7 +169,7 @@ export async function startAnalysis(activityColumn: DG.Column<number>, peptidesC
|
|
|
169
169
|
newDfCols.add(scaledCol);
|
|
170
170
|
for (const col of currentDf.columns) {
|
|
171
171
|
if (col.getTag(C.TAGS.ANALYSIS_COL) !== `${true}`) {
|
|
172
|
-
if (col.name === scaledCol.name)
|
|
172
|
+
if (col.name.toLowerCase() === scaledCol.name.toLowerCase())
|
|
173
173
|
col.name = currentDf.columns.getUnusedName(col.name);
|
|
174
174
|
newDfCols.add(col);
|
|
175
175
|
}
|
|
@@ -196,7 +196,7 @@ export async function startAnalysis(activityColumn: DG.Column<number>, peptidesC
|
|
|
196
196
|
}
|
|
197
197
|
newDf.setTag(C.TAGS.SETTINGS, JSON.stringify(settings));
|
|
198
198
|
|
|
199
|
-
let monomerType
|
|
199
|
+
let monomerType: string;
|
|
200
200
|
if (peptidesCol.getTag(DG.TAGS.UNITS) === NOTATION.HELM) {
|
|
201
201
|
const sampleSeq = peptidesCol.get(0)!;
|
|
202
202
|
monomerType = sampleSeq.startsWith('PEPTIDE') ? 'HELM_AA' : 'HELM_BASE';
|
package/src/widgets/selection.ts
CHANGED
|
@@ -6,13 +6,13 @@ import {PeptidesModel} from '../model';
|
|
|
6
6
|
import wu from 'wu';
|
|
7
7
|
import {COLUMNS_NAMES} from '../utils/constants';
|
|
8
8
|
import {addExpandIcon} from '../utils/misc';
|
|
9
|
-
import {CellRendererOptions,
|
|
9
|
+
import {CellRendererOptions, setWebLogoRenderer, WebLogoBounds} from '../utils/cell-renderer';
|
|
10
10
|
import {CachedWebLogoTooltip, SelectionItem} from '../utils/types';
|
|
11
11
|
import {TooltipOptions} from '../utils/tooltips';
|
|
12
12
|
import {calculateMonomerPositionStatistics} from '../utils/algorithms';
|
|
13
13
|
|
|
14
14
|
export function getSelectionWidget(table: DG.DataFrame, model: PeptidesModel): HTMLElement {
|
|
15
|
-
const compBitset = model.
|
|
15
|
+
const compBitset = model.getVisibleSelection();
|
|
16
16
|
if (compBitset.trueCount === 0)
|
|
17
17
|
return ui.divText('No compounds selected');
|
|
18
18
|
const newTable = DG.DataFrame.create(table.rowCount);
|
|
@@ -29,7 +29,7 @@ export function getSelectionWidget(table: DG.DataFrame, model: PeptidesModel): H
|
|
|
29
29
|
const sourceColCategories = sourceCol.categories;
|
|
30
30
|
const getValue = numericalCols.some((col) => col.name === sourceCol.name) ? (i: number): number => sourceColRawData[i] :
|
|
31
31
|
(i: number): string => sourceColCategories[sourceColRawData[i]];
|
|
32
|
-
const col = sourceCol.name === COLUMNS_NAMES.
|
|
32
|
+
const col = sourceCol.name === COLUMNS_NAMES.ACTIVITY ?
|
|
33
33
|
newTable.columns.addNewFloat(gridCol.name).init((i) => getValue(i)) :
|
|
34
34
|
newTable.columns.addNewVirtual(gridCol.name, (i) => getValue(i), sourceCol.type as DG.TYPE);
|
|
35
35
|
for (const [tag, value] of sourceCol.tags)
|
package/src/widgets/settings.ts
CHANGED
|
@@ -62,7 +62,7 @@ export function getSettingsDialog(model: PeptidesModel): SettingsElements {
|
|
|
62
62
|
const activityCol = ui.columnInput(GENERAL_INPUTS.ACTIVITY, model.df,
|
|
63
63
|
model.df.getCol(model.settings.activityColumnName!), () => result.activityColumnName = activityCol.value!.name,
|
|
64
64
|
{filter: (col: DG.Column) => (col.type === DG.TYPE.FLOAT || col.type === DG.TYPE.INT) &&
|
|
65
|
-
col.name !== C.COLUMNS_NAMES.
|
|
65
|
+
col.name !== C.COLUMNS_NAMES.ACTIVITY && col.stats.missingValueCount === 0});
|
|
66
66
|
activityCol.setTooltip('Numeric activity column');
|
|
67
67
|
const activityScaling =
|
|
68
68
|
ui.choiceInput(GENERAL_INPUTS.ACTIVITY_SCALING, currentScaling, Object.values(C.SCALING_METHODS),
|
|
@@ -120,7 +120,7 @@ export function getSettingsDialog(model: PeptidesModel): SettingsElements {
|
|
|
120
120
|
const includedColumnsInputs: DG.InputBase[] = [];
|
|
121
121
|
for (const col of model.df.columns.numerical) {
|
|
122
122
|
const colName = col.name;
|
|
123
|
-
if (colName === settings.activityColumnName || colName === C.COLUMNS_NAMES.
|
|
123
|
+
if (colName === settings.activityColumnName || colName === C.COLUMNS_NAMES.ACTIVITY)
|
|
124
124
|
continue;
|
|
125
125
|
|
|
126
126
|
const isIncludedInput = ui.boolInput(COLUMNS_INPUTS.IS_INCLUDED, typeof (currentColumns)[colName] !== 'undefined',
|