@datagrok/peptides 1.12.0 → 1.13.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 +16 -0
- package/dist/535.js +2 -2
- package/dist/package-test.js +2 -2
- package/dist/package.js +2 -2
- package/package.json +7 -7
- package/src/demo/fasta.ts +6 -25
- package/src/model.ts +275 -296
- package/src/package.ts +1 -1
- package/src/tests/core.ts +2 -10
- package/src/tests/table-view.ts +48 -48
- package/src/tests/viewers.ts +15 -13
- package/src/tests/widgets.ts +3 -4
- package/src/utils/cell-renderer.ts +33 -39
- package/src/utils/constants.ts +1 -0
- package/src/utils/misc.ts +2 -5
- package/src/utils/statistics.ts +22 -3
- package/src/utils/types.ts +6 -5
- package/src/viewers/logo-summary.ts +55 -42
- package/src/viewers/sar-viewer.ts +161 -107
- package/src/widgets/distribution.ts +60 -59
- package/src/widgets/mutation-cliffs.ts +2 -2
- package/src/widgets/peptides.ts +18 -11
package/src/model.ts
CHANGED
|
@@ -3,9 +3,7 @@ import * as grok from 'datagrok-api/grok';
|
|
|
3
3
|
import * as DG from 'datagrok-api/dg';
|
|
4
4
|
|
|
5
5
|
import {splitAlignedSequences} from '@datagrok-libraries/bio/src/utils/splitter';
|
|
6
|
-
import {IMonomerLib} from '@datagrok-libraries/bio/src/types';
|
|
7
6
|
import {SeqPalette} from '@datagrok-libraries/bio/src/seq-palettes';
|
|
8
|
-
import {MonomerWorks} from '@datagrok-libraries/bio/src/monomer-works/monomer-works';
|
|
9
7
|
import {pickUpPalette, TAGS as bioTAGS} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
10
8
|
import {calculateScores, SCORE} from '@datagrok-libraries/bio/src/utils/macromolecule/scoring';
|
|
11
9
|
import {StringDictionary} from '@datagrok-libraries/utils/src/type-declarations';
|
|
@@ -23,7 +21,7 @@ import $ from 'cash-dom';
|
|
|
23
21
|
import * as C from './utils/constants';
|
|
24
22
|
import * as type from './utils/types';
|
|
25
23
|
import {calculateSelected, extractColInfo, scaleActivity, getStatsSummary, prepareTableForHistogram} from './utils/misc';
|
|
26
|
-
import {MONOMER_POSITION_PROPERTIES, MonomerPosition, MostPotentResidues} from './viewers/sar-viewer';
|
|
24
|
+
import {MONOMER_POSITION_PROPERTIES, MonomerPosition, MostPotentResidues, SELECTION_MODE} from './viewers/sar-viewer';
|
|
27
25
|
import * as CR from './utils/cell-renderer';
|
|
28
26
|
import {mutationCliffsWidget} from './widgets/mutation-cliffs';
|
|
29
27
|
import {getActivityDistribution, getDistributionLegend, getDistributionWidget, getStatsTableMap} from './widgets/distribution';
|
|
@@ -41,8 +39,8 @@ export type SummaryStats = {
|
|
|
41
39
|
minPValue: number, maxPValue: number,
|
|
42
40
|
minRatio: number, maxRatio: number,
|
|
43
41
|
};
|
|
44
|
-
export type PositionStats = {[monomer: string]: Stats} & {general: SummaryStats};
|
|
45
|
-
export type MonomerPositionStats = {[position: string]: PositionStats} & {general: SummaryStats};
|
|
42
|
+
export type PositionStats = {[monomer: string]: Stats | undefined} & {general: SummaryStats};
|
|
43
|
+
export type MonomerPositionStats = {[position: string]: PositionStats | undefined} & {general: SummaryStats};
|
|
46
44
|
export type ClusterStats = {[cluster: string]: Stats};
|
|
47
45
|
export enum CLUSTER_TYPE {
|
|
48
46
|
ORIGINAL = 'original',
|
|
@@ -62,43 +60,34 @@ export const getAggregatedColName = (aggF: string, colName: string): string => `
|
|
|
62
60
|
export class PeptidesModel {
|
|
63
61
|
static modelName = 'peptidesModel';
|
|
64
62
|
|
|
65
|
-
_isUpdating: boolean = false;
|
|
66
63
|
isBitsetChangedInitialized = false;
|
|
67
|
-
isCellChanging = false;
|
|
68
64
|
isUserChangedSelection = true;
|
|
69
65
|
|
|
70
66
|
df: DG.DataFrame;
|
|
71
|
-
splitCol!: DG.Column<boolean>;
|
|
72
67
|
_monomerPositionStats?: MonomerPositionStats;
|
|
73
68
|
_clusterStats?: ClusterTypeStats;
|
|
74
|
-
_mutationCliffsSelection!: type.
|
|
75
|
-
_invariantMapSelection!: type.
|
|
76
|
-
_clusterSelection!:
|
|
69
|
+
_mutationCliffsSelection!: type.Selection;
|
|
70
|
+
_invariantMapSelection!: type.Selection;
|
|
71
|
+
_clusterSelection!: type.Selection;
|
|
77
72
|
_mutationCliffs: type.MutationCliffs | null = null;
|
|
78
73
|
isInitialized = false;
|
|
79
74
|
_analysisView?: DG.TableView;
|
|
80
75
|
|
|
81
|
-
monomerMap: {[key: string]: {molfile: string, fullName: string}} = {};
|
|
82
|
-
monomerLib: IMonomerLib | null = null; // To get monomers from lib(s)
|
|
83
|
-
monomerWorks: MonomerWorks | null = null; // To get processed monomers
|
|
84
|
-
|
|
85
76
|
_settings!: type.PeptidesSettings;
|
|
86
77
|
isRibbonSet = false;
|
|
87
78
|
|
|
88
79
|
_cp?: SeqPalette;
|
|
89
|
-
headerSelectedMonomers: type.
|
|
80
|
+
headerSelectedMonomers: type.SelectionStats = {};
|
|
90
81
|
webLogoBounds: {[positon: string]: {[monomer: string]: DG.Rect}} = {};
|
|
91
82
|
cachedWebLogoTooltip: {bar: string, tooltip: HTMLDivElement | null} = {bar: '', tooltip: null};
|
|
92
|
-
_monomerPositionDf?: DG.DataFrame;
|
|
93
83
|
_alphabet?: string;
|
|
94
|
-
_mostPotentResiduesDf?: DG.DataFrame;
|
|
95
|
-
_matrixDf?: DG.DataFrame;
|
|
96
84
|
_splitSeqDf?: DG.DataFrame;
|
|
97
|
-
_distanceMatrix!: DistanceMatrix;
|
|
98
85
|
_dm!: DistanceMatrix;
|
|
99
86
|
_layoutEventInitialized = false;
|
|
100
87
|
|
|
101
88
|
subs: rxjs.Subscription[] = [];
|
|
89
|
+
isHighlighting: boolean = false;
|
|
90
|
+
latestSelectionItem: (type.SelectionItem & {kind: SELECTION_MODE | 'Cluster'}) | null = null;
|
|
102
91
|
|
|
103
92
|
private constructor(dataFrame: DG.DataFrame) {
|
|
104
93
|
this.df = dataFrame;
|
|
@@ -118,15 +107,6 @@ export class PeptidesModel {
|
|
|
118
107
|
return id;
|
|
119
108
|
}
|
|
120
109
|
|
|
121
|
-
get monomerPositionDf(): DG.DataFrame {
|
|
122
|
-
this._monomerPositionDf ??= this.createMonomerPositionDf();
|
|
123
|
-
return this._monomerPositionDf;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
set monomerPositionDf(df: DG.DataFrame) {
|
|
127
|
-
this._monomerPositionDf = df;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
110
|
get monomerPositionStats(): MonomerPositionStats {
|
|
131
111
|
this._monomerPositionStats ??= this.calculateMonomerPositionStatistics();
|
|
132
112
|
return this._monomerPositionStats;
|
|
@@ -145,15 +125,6 @@ export class PeptidesModel {
|
|
|
145
125
|
this._splitSeqDf = df;
|
|
146
126
|
}
|
|
147
127
|
|
|
148
|
-
get mostPotentResiduesDf(): DG.DataFrame {
|
|
149
|
-
this._mostPotentResiduesDf ??= this.createMostPotentResiduesDf();
|
|
150
|
-
return this._mostPotentResiduesDf;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
set mostPotentResiduesDf(df: DG.DataFrame) {
|
|
154
|
-
this._mostPotentResiduesDf = df;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
128
|
get alphabet(): string {
|
|
158
129
|
const col = this.df.getCol(this.settings.sequenceColumnName!);
|
|
159
130
|
return col.getTag(bioTAGS.alphabet);
|
|
@@ -207,14 +178,19 @@ export class PeptidesModel {
|
|
|
207
178
|
return this._analysisView;
|
|
208
179
|
}
|
|
209
180
|
|
|
210
|
-
get mutationCliffsSelection(): type.
|
|
211
|
-
this.
|
|
181
|
+
get mutationCliffsSelection(): type.Selection {
|
|
182
|
+
const tagSelection = this.df.getTag(C.TAGS.MUTATION_CLIFFS_SELECTION) ?? this.df.getTag(C.TAGS.SELECTION);
|
|
183
|
+
if (tagSelection === null)
|
|
184
|
+
this.initMutationCliffsSelection({notify: false});
|
|
185
|
+
this._mutationCliffsSelection ??= JSON.parse(tagSelection ?? this.df.getTag(C.TAGS.MUTATION_CLIFFS_SELECTION) ?? this.df.getTag(C.TAGS.SELECTION)!);
|
|
212
186
|
return this._mutationCliffsSelection;
|
|
213
187
|
}
|
|
214
188
|
|
|
215
|
-
set mutationCliffsSelection(selection: type.
|
|
189
|
+
set mutationCliffsSelection(selection: type.Selection) {
|
|
216
190
|
this._mutationCliffsSelection = selection;
|
|
217
|
-
|
|
191
|
+
// TODO: Remove in 1.14.0
|
|
192
|
+
this.df.setTag(C.TAGS.SELECTION, JSON.stringify(selection));
|
|
193
|
+
this.df.setTag(C.TAGS.MUTATION_CLIFFS_SELECTION, JSON.stringify(selection));
|
|
218
194
|
this.fireBitsetChanged();
|
|
219
195
|
|
|
220
196
|
const mpViewer = this.findViewer(VIEWER_TYPE.MONOMER_POSITION) as MonomerPosition | null;
|
|
@@ -225,25 +201,45 @@ export class PeptidesModel {
|
|
|
225
201
|
this.analysisView.grid.invalidate();
|
|
226
202
|
}
|
|
227
203
|
|
|
228
|
-
get invariantMapSelection(): type.
|
|
229
|
-
this.
|
|
230
|
-
|
|
204
|
+
get invariantMapSelection(): type.Selection {
|
|
205
|
+
const tagSelection = this.df.getTag(C.TAGS.INVARIANT_MAP_SELECTION) ?? this.df.getTag(C.TAGS.FILTER);
|
|
206
|
+
if (tagSelection === null)
|
|
207
|
+
this.initInvariantMapSelection({notify: false});
|
|
208
|
+
this._invariantMapSelection ??= JSON.parse(tagSelection ?? this.df.getTag(C.TAGS.INVARIANT_MAP_SELECTION) ?? this.df.getTag(C.TAGS.FILTER)!);
|
|
231
209
|
return this._invariantMapSelection;
|
|
232
210
|
}
|
|
233
211
|
|
|
234
|
-
set invariantMapSelection(selection: type.
|
|
212
|
+
set invariantMapSelection(selection: type.Selection) {
|
|
235
213
|
this._invariantMapSelection = selection;
|
|
236
|
-
this.df.
|
|
214
|
+
this.df.setTag(C.TAGS.INVARIANT_MAP_SELECTION, JSON.stringify(selection));
|
|
215
|
+
// TODO: Remove in 1.14.0
|
|
216
|
+
this.df.setTag(C.TAGS.FILTER, JSON.stringify(selection));
|
|
237
217
|
this.fireBitsetChanged();
|
|
238
218
|
this.analysisView.grid.invalidate();
|
|
239
219
|
}
|
|
240
220
|
|
|
241
|
-
get clusterSelection():
|
|
242
|
-
|
|
221
|
+
get clusterSelection(): type.Selection {
|
|
222
|
+
const tagSelection = this.df.getTag(C.TAGS.CLUSTER_SELECTION);
|
|
223
|
+
if (tagSelection === null)
|
|
224
|
+
this.initClusterSelection({notify: false});
|
|
225
|
+
this._clusterSelection ??= JSON.parse(tagSelection ?? this.df.getTag(C.TAGS.CLUSTER_SELECTION)!);
|
|
226
|
+
// TODO: Remove in 1.14.0
|
|
227
|
+
if (Array.isArray(this._clusterSelection)) {
|
|
228
|
+
const newSelection: type.Selection = {};
|
|
229
|
+
newSelection[CLUSTER_TYPE.ORIGINAL] = [];
|
|
230
|
+
newSelection[CLUSTER_TYPE.CUSTOM] = [];
|
|
231
|
+
for (const cluster of this._clusterSelection) {
|
|
232
|
+
if (wu(this.customClusters).some((col) => col.name === cluster))
|
|
233
|
+
newSelection[CLUSTER_TYPE.CUSTOM].push(cluster);
|
|
234
|
+
else
|
|
235
|
+
newSelection[CLUSTER_TYPE.ORIGINAL].push(cluster);
|
|
236
|
+
}
|
|
237
|
+
this._clusterSelection = newSelection;
|
|
238
|
+
}
|
|
243
239
|
return this._clusterSelection;
|
|
244
240
|
}
|
|
245
241
|
|
|
246
|
-
set clusterSelection(selection:
|
|
242
|
+
set clusterSelection(selection: type.Selection) {
|
|
247
243
|
this._clusterSelection = selection;
|
|
248
244
|
this.df.tags[C.TAGS.CLUSTER_SELECTION] = JSON.stringify(selection);
|
|
249
245
|
this.fireBitsetChanged();
|
|
@@ -256,30 +252,30 @@ export class PeptidesModel {
|
|
|
256
252
|
}
|
|
257
253
|
|
|
258
254
|
set splitByPos(flag: boolean) {
|
|
259
|
-
const
|
|
260
|
-
this.df.tags['distributionSplit'] = `${flag ? 1 : 0}${
|
|
255
|
+
const splitByMonomerFlag = (this.df.tags['distributionSplit'] || '00')[1];
|
|
256
|
+
this.df.tags['distributionSplit'] = `${flag ? 1 : 0}${splitByMonomerFlag}`;
|
|
261
257
|
}
|
|
262
258
|
|
|
263
|
-
get
|
|
259
|
+
get splitByMonomer(): boolean {
|
|
264
260
|
const splitByPosFlag = (this.df.tags['distributionSplit'] || '00')[1];
|
|
265
261
|
return splitByPosFlag === '1' ? true : false;
|
|
266
262
|
}
|
|
267
263
|
|
|
268
|
-
set
|
|
269
|
-
const
|
|
270
|
-
this.df.tags['distributionSplit'] = `${
|
|
264
|
+
set splitByMonomer(flag: boolean) {
|
|
265
|
+
const splitByMonomerFlag = (this.df.tags['distributionSplit'] || '00')[0];
|
|
266
|
+
this.df.tags['distributionSplit'] = `${splitByMonomerFlag}${flag ? 1 : 0}`;
|
|
271
267
|
}
|
|
272
268
|
|
|
273
269
|
get isMonomerPositionSelectionEmpty(): boolean {
|
|
274
|
-
for (const
|
|
275
|
-
if (
|
|
270
|
+
for (const monomerList of Object.values(this.mutationCliffsSelection)) {
|
|
271
|
+
if (monomerList.length !== 0)
|
|
276
272
|
return false;
|
|
277
273
|
}
|
|
278
274
|
return true;
|
|
279
275
|
}
|
|
280
276
|
|
|
281
277
|
get isClusterSelectionEmpty(): boolean {
|
|
282
|
-
return this.clusterSelection.length === 0;
|
|
278
|
+
return (this.clusterSelection[CLUSTER_TYPE.ORIGINAL].length + this.clusterSelection[CLUSTER_TYPE.CUSTOM].length) === 0;
|
|
283
279
|
}
|
|
284
280
|
|
|
285
281
|
get customClusters(): Iterable<DG.Column<boolean>> {
|
|
@@ -337,8 +333,13 @@ export class PeptidesModel {
|
|
|
337
333
|
break;
|
|
338
334
|
case 'stats':
|
|
339
335
|
this.monomerPositionStats = this.calculateMonomerPositionStatistics();
|
|
340
|
-
this.mostPotentResiduesDf = this.createMostPotentResiduesDf();
|
|
341
336
|
this.clusterStats = this.calculateClusterStatistics();
|
|
337
|
+
const mpViewer = this.findViewer(VIEWER_TYPE.MONOMER_POSITION) as MonomerPosition;
|
|
338
|
+
mpViewer.createMonomerPositionGrid();
|
|
339
|
+
mpViewer.render();
|
|
340
|
+
const mprViewer = this.findViewer(VIEWER_TYPE.MOST_POTENT_RESIDUES) as MostPotentResidues;
|
|
341
|
+
mprViewer.createMostPotentResiduesGrid();
|
|
342
|
+
mprViewer.render();
|
|
342
343
|
break;
|
|
343
344
|
case 'grid':
|
|
344
345
|
this.setGridProperties();
|
|
@@ -397,26 +398,6 @@ export class PeptidesModel {
|
|
|
397
398
|
this._mutationCliffs = mutationCliffs;
|
|
398
399
|
}
|
|
399
400
|
|
|
400
|
-
createMonomerPositionDf(): DG.DataFrame {
|
|
401
|
-
const uniqueMonomers = new Set<string>();
|
|
402
|
-
const splitSeqCols = this.splitSeqDf.columns;
|
|
403
|
-
for (const col of splitSeqCols) {
|
|
404
|
-
const colCat = col.categories;
|
|
405
|
-
for (const cat of colCat) {
|
|
406
|
-
if (cat !== '')
|
|
407
|
-
uniqueMonomers.add(cat);
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
const monomerCol = DG.Column.fromStrings(C.COLUMNS_NAMES.MONOMER, Array.from(uniqueMonomers));
|
|
412
|
-
const monomerPositionDf = DG.DataFrame.fromColumns([monomerCol]);
|
|
413
|
-
monomerPositionDf.name = 'SAR';
|
|
414
|
-
for (const col of splitSeqCols)
|
|
415
|
-
monomerPositionDf.columns.addNewBool(col.name);
|
|
416
|
-
|
|
417
|
-
return monomerPositionDf;
|
|
418
|
-
}
|
|
419
|
-
|
|
420
401
|
buildSplitSeqDf(): DG.DataFrame {
|
|
421
402
|
const sequenceCol = this.df.getCol(this.settings.sequenceColumnName!);
|
|
422
403
|
const splitSeqDf = splitAlignedSequences(sequenceCol);
|
|
@@ -465,8 +446,7 @@ export class PeptidesModel {
|
|
|
465
446
|
};
|
|
466
447
|
removeCluster.onmouseover =
|
|
467
448
|
(ev): void => ui.tooltip.show('Removes currently selected custom cluster', ev.clientX + 5, ev.clientY + 5);
|
|
468
|
-
removeCluster.style.visibility = trueModel.clusterSelection.length === 0
|
|
469
|
-
!wu(this.customClusters).some((c) => trueModel.clusterSelection.includes(c.name)) ? 'hidden' : 'visible';
|
|
449
|
+
removeCluster.style.visibility = trueModel.clusterSelection[CLUSTER_TYPE.CUSTOM].length === 0 ? 'hidden' : 'visible';
|
|
470
450
|
return ui.divV([newView, newCluster, removeCluster]);
|
|
471
451
|
});
|
|
472
452
|
}
|
|
@@ -485,6 +465,7 @@ export class PeptidesModel {
|
|
|
485
465
|
|
|
486
466
|
this.initInvariantMapSelection({notify: false});
|
|
487
467
|
this.initMutationCliffsSelection({notify: false});
|
|
468
|
+
this.initClusterSelection({notify: false});
|
|
488
469
|
|
|
489
470
|
this.setWebLogoInteraction();
|
|
490
471
|
this.webLogoBounds = {};
|
|
@@ -498,33 +479,27 @@ export class PeptidesModel {
|
|
|
498
479
|
this.setGridProperties();
|
|
499
480
|
}
|
|
500
481
|
|
|
501
|
-
initInvariantMapSelection(options: {
|
|
502
|
-
options.cleanInit ??= false;
|
|
482
|
+
initInvariantMapSelection(options: {notify?: boolean} = {}): void {
|
|
503
483
|
options.notify ??= true;
|
|
504
484
|
|
|
505
|
-
const
|
|
485
|
+
const tempSelection: type.Selection = {};
|
|
506
486
|
const positionColumns = this.splitSeqDf.columns.names();
|
|
507
|
-
for (const pos of positionColumns)
|
|
508
|
-
|
|
509
|
-
tempFilter[pos] = [];
|
|
510
|
-
}
|
|
487
|
+
for (const pos of positionColumns)
|
|
488
|
+
tempSelection[pos] = [];
|
|
511
489
|
|
|
512
490
|
if (options.notify)
|
|
513
|
-
this.invariantMapSelection =
|
|
491
|
+
this.invariantMapSelection = tempSelection;
|
|
514
492
|
else
|
|
515
|
-
this._invariantMapSelection =
|
|
493
|
+
this._invariantMapSelection = tempSelection;
|
|
516
494
|
}
|
|
517
495
|
|
|
518
|
-
initMutationCliffsSelection(options: {
|
|
519
|
-
options.cleanInit ??= false;
|
|
496
|
+
initMutationCliffsSelection(options: {notify?: boolean} = {}): void {
|
|
520
497
|
options.notify ??= true;
|
|
521
498
|
|
|
522
|
-
const tempSelection: type.
|
|
499
|
+
const tempSelection: type.Selection = {};
|
|
523
500
|
const positionColumns = this.splitSeqDf.columns.names();
|
|
524
|
-
for (const pos of positionColumns)
|
|
525
|
-
|
|
526
|
-
tempSelection[pos] = [];
|
|
527
|
-
}
|
|
501
|
+
for (const pos of positionColumns)
|
|
502
|
+
tempSelection[pos] = [];
|
|
528
503
|
|
|
529
504
|
if (options.notify)
|
|
530
505
|
this.mutationCliffsSelection = tempSelection;
|
|
@@ -546,7 +521,7 @@ export class PeptidesModel {
|
|
|
546
521
|
const newColCat = newCol.categories;
|
|
547
522
|
const newColData = newCol.getRawData();
|
|
548
523
|
col = cols.addNew(newCol.name, newCol.type).init((i) => newColCat[newColData[i]]);
|
|
549
|
-
CR.
|
|
524
|
+
CR.setMonomerRenderer(col, this.alphabet);
|
|
550
525
|
}
|
|
551
526
|
this.df.name = name;
|
|
552
527
|
}
|
|
@@ -569,7 +544,7 @@ export class PeptidesModel {
|
|
|
569
544
|
for (const posCol of positionColumns) {
|
|
570
545
|
const posColData = posCol.getRawData();
|
|
571
546
|
const posColCateogries = posCol.categories;
|
|
572
|
-
const currentPositionObject = {general: {}} as PositionStats & {
|
|
547
|
+
const currentPositionObject = {general: {}} as PositionStats & {general: SummaryStats};
|
|
573
548
|
|
|
574
549
|
for (let categoryIndex = 0; categoryIndex < posColCateogries.length; ++categoryIndex) {
|
|
575
550
|
const monomer = posColCateogries[categoryIndex];
|
|
@@ -582,7 +557,9 @@ export class PeptidesModel {
|
|
|
582
557
|
boolArray[i] = true;
|
|
583
558
|
}
|
|
584
559
|
const bitArray = BitArray.fromValues(boolArray);
|
|
585
|
-
const stats =
|
|
560
|
+
const stats = bitArray.allFalse || bitArray.allTrue ?
|
|
561
|
+
{count: sourceDfLen, meanDifference: 0, ratio: 1.0, pValue: null, mask: bitArray} :
|
|
562
|
+
getStats(activityColData, bitArray);
|
|
586
563
|
currentPositionObject[monomer] = stats;
|
|
587
564
|
this.getSummaryStats(currentPositionObject.general, stats);
|
|
588
565
|
}
|
|
@@ -616,15 +593,17 @@ export class PeptidesModel {
|
|
|
616
593
|
if (genObj.minMeanDifference > possibleMinMeanDifference)
|
|
617
594
|
genObj.minMeanDifference = possibleMinMeanDifference;
|
|
618
595
|
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
genObj.maxPValue
|
|
596
|
+
if (!isNaN(stats?.pValue ?? NaN)) {
|
|
597
|
+
const possibleMaxPValue = stats?.pValue ?? summaryStats!.maxPValue;
|
|
598
|
+
genObj.maxPValue ??= possibleMaxPValue;
|
|
599
|
+
if (genObj.maxPValue < possibleMaxPValue)
|
|
600
|
+
genObj.maxPValue = possibleMaxPValue;
|
|
623
601
|
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
602
|
+
const possibleMinPValue = stats?.pValue ?? summaryStats!.minPValue;
|
|
603
|
+
genObj.minPValue ??= possibleMinPValue;
|
|
604
|
+
if (genObj.minPValue > possibleMinPValue)
|
|
605
|
+
genObj.minPValue = possibleMinPValue;
|
|
606
|
+
}
|
|
628
607
|
|
|
629
608
|
const possibleMaxRatio = stats?.ratio ?? summaryStats!.maxRatio;
|
|
630
609
|
genObj.maxRatio ??= possibleMaxRatio;
|
|
@@ -658,13 +637,14 @@ export class PeptidesModel {
|
|
|
658
637
|
const origClustStats: ClusterStats = {};
|
|
659
638
|
const customClustStats: ClusterStats = {};
|
|
660
639
|
|
|
661
|
-
for (
|
|
662
|
-
const masks = clustType ===
|
|
663
|
-
const clustNames = clustType ===
|
|
664
|
-
const resultStats = clustType ===
|
|
640
|
+
for (const clustType of Object.values(CLUSTER_TYPE)) {
|
|
641
|
+
const masks = clustType === CLUSTER_TYPE.ORIGINAL ? origClustMasks : customClustMasks;
|
|
642
|
+
const clustNames = clustType === CLUSTER_TYPE.ORIGINAL ? origClustColCat : customClustColNamesList;
|
|
643
|
+
const resultStats = clustType === CLUSTER_TYPE.ORIGINAL ? origClustStats : customClustStats;
|
|
665
644
|
for (let maskIdx = 0; maskIdx < masks.length; ++maskIdx) {
|
|
666
645
|
const mask = masks[maskIdx];
|
|
667
|
-
const stats =
|
|
646
|
+
const stats = mask.allTrue || mask.allFalse ? {count: mask.length, meanDifference: 0, ratio: 1.0, pValue: null, mask: mask} :
|
|
647
|
+
getStats(activityColData, mask);
|
|
668
648
|
resultStats[clustNames[maskIdx]] = stats;
|
|
669
649
|
}
|
|
670
650
|
}
|
|
@@ -675,66 +655,16 @@ export class PeptidesModel {
|
|
|
675
655
|
return resultStats;
|
|
676
656
|
}
|
|
677
657
|
|
|
678
|
-
createMostPotentResiduesDf(): DG.DataFrame {
|
|
679
|
-
const monomerPositionStatsEntries = Object.entries(this.monomerPositionStats) as [string, PositionStats][];
|
|
680
|
-
const mprDf = DG.DataFrame.create(monomerPositionStatsEntries.length - 1); // Subtract 'general' entry from mp-stats
|
|
681
|
-
const mprDfCols = mprDf.columns;
|
|
682
|
-
const posCol = mprDfCols.addNewInt(C.COLUMNS_NAMES.POSITION);
|
|
683
|
-
const monomerCol = mprDfCols.addNewString(C.COLUMNS_NAMES.MONOMER);
|
|
684
|
-
const mdCol = mprDfCols.addNewFloat(C.COLUMNS_NAMES.MEAN_DIFFERENCE);
|
|
685
|
-
const pValCol = mprDfCols.addNewFloat(C.COLUMNS_NAMES.P_VALUE);
|
|
686
|
-
const countCol = mprDfCols.addNewInt(C.COLUMNS_NAMES.COUNT);
|
|
687
|
-
const ratioCol = mprDfCols.addNewFloat(C.COLUMNS_NAMES.RATIO);
|
|
688
|
-
|
|
689
|
-
let i = 0;
|
|
690
|
-
for (const [position, positionStats] of monomerPositionStatsEntries) {
|
|
691
|
-
const generalPositionStats = positionStats.general;
|
|
692
|
-
if (!generalPositionStats)
|
|
693
|
-
continue;
|
|
694
|
-
|
|
695
|
-
const filteredMonomerStats = Object.entries(positionStats).filter((v) => {
|
|
696
|
-
const key = v[0];
|
|
697
|
-
if (key === 'general')
|
|
698
|
-
return false;
|
|
699
|
-
|
|
700
|
-
return (v[1] as Stats).pValue === generalPositionStats.minPValue;
|
|
701
|
-
}) as [string, Stats][];
|
|
702
|
-
|
|
703
|
-
let maxEntry: [string, Stats];
|
|
704
|
-
for (const [monomer, monomerStats] of filteredMonomerStats) {
|
|
705
|
-
if (typeof maxEntry! === 'undefined' || maxEntry[1].meanDifference < monomerStats.meanDifference)
|
|
706
|
-
maxEntry = [monomer, monomerStats];
|
|
707
|
-
}
|
|
708
|
-
|
|
709
|
-
posCol.set(i, parseInt(position));
|
|
710
|
-
monomerCol.set(i, maxEntry![0]);
|
|
711
|
-
mdCol.set(i, maxEntry![1].meanDifference);
|
|
712
|
-
pValCol.set(i, maxEntry![1].pValue);
|
|
713
|
-
countCol.set(i, maxEntry![1].count);
|
|
714
|
-
ratioCol.set(i, maxEntry![1].ratio);
|
|
715
|
-
++i;
|
|
716
|
-
}
|
|
717
|
-
return mprDf;
|
|
718
|
-
}
|
|
719
|
-
|
|
720
|
-
modifyClusterSelection(cluster: string): void {
|
|
721
|
-
const tempSelection = this.clusterSelection;
|
|
722
|
-
const idx = tempSelection.indexOf(cluster);
|
|
723
|
-
if (idx !== -1)
|
|
724
|
-
tempSelection.splice(idx, 1);
|
|
725
|
-
else
|
|
726
|
-
tempSelection.push(cluster);
|
|
727
|
-
|
|
728
|
-
this.clusterSelection = tempSelection;
|
|
729
|
-
}
|
|
730
|
-
|
|
731
658
|
initClusterSelection(options: {notify?: boolean} = {}): void {
|
|
732
659
|
options.notify ??= true;
|
|
733
660
|
|
|
661
|
+
const newClusterSelection = {} as type.Selection;
|
|
662
|
+
newClusterSelection[CLUSTER_TYPE.ORIGINAL] = [];
|
|
663
|
+
newClusterSelection[CLUSTER_TYPE.CUSTOM] = [];
|
|
734
664
|
if (options.notify)
|
|
735
|
-
this.clusterSelection =
|
|
665
|
+
this.clusterSelection = newClusterSelection;
|
|
736
666
|
else
|
|
737
|
-
this._clusterSelection =
|
|
667
|
+
this._clusterSelection = newClusterSelection;
|
|
738
668
|
}
|
|
739
669
|
|
|
740
670
|
setWebLogoInteraction(): void {
|
|
@@ -742,8 +672,13 @@ export class PeptidesModel {
|
|
|
742
672
|
const eventAction = (ev: MouseEvent): void => {
|
|
743
673
|
const cell = sourceView.hitTest(ev.offsetX, ev.offsetY);
|
|
744
674
|
if (cell?.isColHeader && cell.tableColumn?.semType === C.SEM_TYPES.MONOMER) {
|
|
745
|
-
const
|
|
746
|
-
|
|
675
|
+
const monomerPosition = this.findWebLogoMonomerPosition(cell, ev);
|
|
676
|
+
if (monomerPosition === null) {
|
|
677
|
+
this.unhighlight();
|
|
678
|
+
return;
|
|
679
|
+
}
|
|
680
|
+
this.requestBarchartAction(ev, monomerPosition);
|
|
681
|
+
this.highlightMonomerPosition(monomerPosition);
|
|
747
682
|
}
|
|
748
683
|
};
|
|
749
684
|
|
|
@@ -754,37 +689,61 @@ export class PeptidesModel {
|
|
|
754
689
|
.subscribe((mouseMove: MouseEvent) => eventAction(mouseMove));
|
|
755
690
|
}
|
|
756
691
|
|
|
757
|
-
|
|
692
|
+
highlightMonomerPosition(monomerPosition: type.SelectionItem): void {
|
|
693
|
+
const bitArray = new BitArray(this.df.rowCount);
|
|
694
|
+
if (monomerPosition.positionOrClusterType === C.COLUMNS_NAMES.MONOMER) {
|
|
695
|
+
const positionStats = Object.values(this.monomerPositionStats);
|
|
696
|
+
for (const posStat of positionStats) {
|
|
697
|
+
const monomerPositionStats = (posStat as PositionStats)[monomerPosition.monomerOrCluster];
|
|
698
|
+
if (monomerPositionStats ?? false)
|
|
699
|
+
bitArray.or(monomerPositionStats!.mask);
|
|
700
|
+
}
|
|
701
|
+
} else {
|
|
702
|
+
const monomerPositionStats = this.monomerPositionStats[monomerPosition.positionOrClusterType]![monomerPosition.monomerOrCluster];
|
|
703
|
+
if (monomerPositionStats ?? false)
|
|
704
|
+
bitArray.or(monomerPositionStats!.mask);
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
this.df.rows.highlight((i) => bitArray.getBit(i));
|
|
708
|
+
this.isHighlighting = true;
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
highlightCluster(cluster: type.SelectionItem): void {
|
|
712
|
+
const bitArray = this.clusterStats[cluster.positionOrClusterType as ClusterType][cluster.monomerOrCluster].mask;
|
|
713
|
+
this.df.rows.highlight((i) => bitArray.getBit(i));
|
|
714
|
+
this.isHighlighting = true;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
unhighlight(): void {
|
|
718
|
+
if (!this.isHighlighting)
|
|
719
|
+
return;
|
|
720
|
+
this.df.rows.highlight(null);
|
|
721
|
+
this.isHighlighting = false;
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
findWebLogoMonomerPosition(cell: DG.GridCell, ev: MouseEvent): type.SelectionItem | null {
|
|
758
725
|
const barCoords = this.webLogoBounds[cell.tableColumn!.name];
|
|
759
726
|
for (const [monomer, coords] of Object.entries(barCoords)) {
|
|
760
727
|
const isIntersectingX = ev.offsetX >= coords.x && ev.offsetX <= coords.x + coords.width;
|
|
761
728
|
const isIntersectingY = ev.offsetY >= coords.y && ev.offsetY <= coords.y + coords.height;
|
|
762
729
|
if (isIntersectingX && isIntersectingY)
|
|
763
|
-
return {
|
|
730
|
+
return {monomerOrCluster: monomer, positionOrClusterType: cell.tableColumn!.name};
|
|
764
731
|
}
|
|
765
732
|
|
|
766
733
|
return null;
|
|
767
734
|
}
|
|
768
735
|
|
|
769
|
-
requestBarchartAction(ev: MouseEvent,
|
|
770
|
-
if (
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
if (ev.type === 'click') {
|
|
775
|
-
if (!ev.shiftKey)
|
|
776
|
-
this.initInvariantMapSelection({cleanInit: true, notify: false});
|
|
777
|
-
|
|
778
|
-
this.modifyMonomerPositionSelection(monomer, position, true);
|
|
779
|
-
} else {
|
|
780
|
-
const bar = `${position} = ${monomer}`;
|
|
736
|
+
requestBarchartAction(ev: MouseEvent, monomerPosition: type.SelectionItem): void {
|
|
737
|
+
if (ev.type === 'click')
|
|
738
|
+
this.modifyInvariantMapSelection(monomerPosition, {shiftPressed: ev.shiftKey, ctrlPressed: ev.ctrlKey});
|
|
739
|
+
else {
|
|
740
|
+
const bar = `${monomerPosition.positionOrClusterType} = ${monomerPosition.monomerOrCluster}`;
|
|
781
741
|
if (this.cachedWebLogoTooltip.bar === bar)
|
|
782
742
|
ui.tooltip.show(this.cachedWebLogoTooltip.tooltip!, ev.clientX, ev.clientY);
|
|
783
|
-
else
|
|
784
|
-
this.cachedWebLogoTooltip = {bar: bar,
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
// this.df.rows.match(bar).highlight();
|
|
743
|
+
else {
|
|
744
|
+
this.cachedWebLogoTooltip = {bar: bar,
|
|
745
|
+
tooltip: this.showTooltipAt(monomerPosition, ev.clientX, ev.clientY)};
|
|
746
|
+
}
|
|
788
747
|
}
|
|
789
748
|
}
|
|
790
749
|
|
|
@@ -805,6 +764,8 @@ export class PeptidesModel {
|
|
|
805
764
|
//TODO: optimize
|
|
806
765
|
if (gcArgs.cell.isColHeader && col?.semType === C.SEM_TYPES.MONOMER) {
|
|
807
766
|
const stats = this.monomerPositionStats[col.name];
|
|
767
|
+
if (!stats)
|
|
768
|
+
return;
|
|
808
769
|
//TODO: precalc on stats creation
|
|
809
770
|
const sortedStatsOrder = Object.keys(stats).sort((a, b) => {
|
|
810
771
|
if (a === '' || a === '-')
|
|
@@ -830,10 +791,8 @@ export class PeptidesModel {
|
|
|
830
791
|
|
|
831
792
|
if (!this._layoutEventInitialized) {
|
|
832
793
|
grok.events.onViewLayoutApplied.subscribe((layout) => {
|
|
833
|
-
if (layout.view.id === this.analysisView.id)
|
|
834
|
-
// this.analysisView.grid.onCellRender.subscribe((gcArgs) => headerRenderer(gcArgs));
|
|
794
|
+
if (layout.view.id === this.analysisView.id)
|
|
835
795
|
this.updateGrid();
|
|
836
|
-
}
|
|
837
796
|
});
|
|
838
797
|
this._layoutEventInitialized = true;
|
|
839
798
|
}
|
|
@@ -851,19 +810,19 @@ export class PeptidesModel {
|
|
|
851
810
|
});
|
|
852
811
|
}
|
|
853
812
|
|
|
854
|
-
showMonomerTooltip(
|
|
813
|
+
showMonomerTooltip(monomer: string, x: number, y: number): boolean {
|
|
855
814
|
const tooltipElements: HTMLDivElement[] = [];
|
|
856
|
-
const monomerName =
|
|
815
|
+
const monomerName = monomer.toLowerCase();
|
|
857
816
|
|
|
858
817
|
const mw = getMonomerWorksInstance();
|
|
859
|
-
const mol = mw?.getCappedRotatedMonomer('PEPTIDE',
|
|
818
|
+
const mol = mw?.getCappedRotatedMonomer('PEPTIDE', monomer);
|
|
860
819
|
|
|
861
820
|
if (mol) {
|
|
862
821
|
tooltipElements.push(ui.div(monomerName));
|
|
863
822
|
const options = {autoCrop: true, autoCropMargin: 0, suppressChiralText: true};
|
|
864
823
|
tooltipElements.push(grok.chem.svgMol(mol, undefined, undefined, options));
|
|
865
|
-
} else if (
|
|
866
|
-
tooltipElements.push(ui.div(
|
|
824
|
+
} else if (monomer !== '')
|
|
825
|
+
tooltipElements.push(ui.div(monomer));
|
|
867
826
|
else
|
|
868
827
|
return true;
|
|
869
828
|
|
|
@@ -873,27 +832,35 @@ export class PeptidesModel {
|
|
|
873
832
|
return true;
|
|
874
833
|
}
|
|
875
834
|
|
|
835
|
+
showTooltip(monomerPosition: type.SelectionItem, x: number, y: number, fromViewer: boolean = false): boolean {
|
|
836
|
+
if (monomerPosition.positionOrClusterType === C.COLUMNS_NAMES.MONOMER)
|
|
837
|
+
this.showMonomerTooltip(monomerPosition.monomerOrCluster, x, y);
|
|
838
|
+
else
|
|
839
|
+
this.showTooltipAt(monomerPosition, x, y, fromViewer);
|
|
840
|
+
return true;
|
|
841
|
+
}
|
|
876
842
|
//TODO: move out to viewer code
|
|
877
|
-
showTooltipAt(
|
|
878
|
-
const stats = this.monomerPositionStats[
|
|
843
|
+
showTooltipAt(monomerPosition: type.SelectionItem, x: number, y: number, fromViewer: boolean = false): HTMLDivElement | null {
|
|
844
|
+
const stats = this.monomerPositionStats[monomerPosition.positionOrClusterType]![monomerPosition.monomerOrCluster];
|
|
879
845
|
if (!stats?.count)
|
|
880
846
|
return null;
|
|
881
847
|
|
|
882
848
|
const activityCol = this.df.getCol(C.COLUMNS_NAMES.ACTIVITY_SCALED);
|
|
883
|
-
const
|
|
884
|
-
const posColCategories = posCol.categories;
|
|
885
|
-
const aarCategoryIndex = posColCategories.indexOf(aar);
|
|
886
|
-
const posColData = posCol.getRawData();
|
|
887
|
-
const mask = DG.BitSet.create(activityCol.length, (i) => posColData[i] === aarCategoryIndex);
|
|
888
|
-
|
|
849
|
+
const mask = DG.BitSet.fromBytes(stats.mask.buffer.buffer, activityCol.length);
|
|
889
850
|
const distributionTable = DG.DataFrame.fromColumns(
|
|
890
851
|
[activityCol, DG.Column.fromBitSet(C.COLUMNS_NAMES.SPLIT_COL, mask)]);
|
|
891
|
-
const labels = getDistributionLegend(`${position} : ${aar}`, 'Other');
|
|
892
852
|
const hist = getActivityDistribution(prepareTableForHistogram(distributionTable), true);
|
|
853
|
+
|
|
893
854
|
const tableMap = getStatsTableMap(stats);
|
|
855
|
+
if (fromViewer) {
|
|
856
|
+
tableMap['Mean difference'] = `${tableMap['Mean difference']} (size)`;
|
|
857
|
+
if (tableMap['p-value'])
|
|
858
|
+
tableMap['p-value'] = `${tableMap['p-value']} (color)`;
|
|
859
|
+
}
|
|
894
860
|
const aggregatedColMap = this.getAggregatedColumnValues({mask: mask});
|
|
895
|
-
|
|
896
861
|
const resultMap = {...tableMap, ...aggregatedColMap};
|
|
862
|
+
|
|
863
|
+
const labels = getDistributionLegend(`${monomerPosition.positionOrClusterType} : ${monomerPosition.monomerOrCluster}`, 'Other');
|
|
897
864
|
const distroStatsElem = getStatsSummary(labels, hist, resultMap);
|
|
898
865
|
|
|
899
866
|
ui.tooltip.show(distroStatsElem, x, y);
|
|
@@ -917,99 +884,84 @@ export class PeptidesModel {
|
|
|
917
884
|
return colResults;
|
|
918
885
|
}
|
|
919
886
|
|
|
920
|
-
modifyMonomerPositionSelection(aar: string, position: string, isInvariantMap: boolean): void {
|
|
921
|
-
if (this.df.getCol(position).categories.indexOf(aar) === -1)
|
|
922
|
-
return;
|
|
923
|
-
|
|
924
|
-
const tempSelection = isInvariantMap ? this.invariantMapSelection : this.mutationCliffsSelection;
|
|
925
|
-
const tempSelectionAt = tempSelection[position];
|
|
926
|
-
const aarIndex = tempSelectionAt.indexOf(aar);
|
|
927
|
-
if (aarIndex === -1)
|
|
928
|
-
tempSelectionAt.push(aar);
|
|
929
|
-
else
|
|
930
|
-
tempSelectionAt.splice(aarIndex, 1);
|
|
931
|
-
|
|
932
|
-
if (isInvariantMap)
|
|
933
|
-
this.invariantMapSelection = tempSelection;
|
|
934
|
-
else
|
|
935
|
-
this.mutationCliffsSelection = tempSelection;
|
|
936
|
-
}
|
|
937
|
-
|
|
938
887
|
setBitsetCallback(): void {
|
|
939
888
|
if (this.isBitsetChangedInitialized)
|
|
940
889
|
return;
|
|
941
890
|
const selection = this.df.selection;
|
|
942
891
|
const filter = this.df.filter;
|
|
943
|
-
const clusterCol = this.df.col(this.settings.clustersColumnName!);
|
|
944
892
|
|
|
945
|
-
const
|
|
946
|
-
|
|
947
|
-
|
|
893
|
+
const getCombinedSelection = (): DG.BitSet => {
|
|
894
|
+
const combinedSelection = new BitArray(this.df.rowCount, false);
|
|
895
|
+
// Invariant map selection
|
|
896
|
+
for (const [position, monomerList] of Object.entries(this.invariantMapSelection)) {
|
|
897
|
+
for (const monomer of monomerList) {
|
|
898
|
+
const monomerPositionStats = this.monomerPositionStats[position]![monomer]!;
|
|
899
|
+
combinedSelection.or(monomerPositionStats.mask);
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
// Mutation cliffs selection
|
|
948
904
|
for (const [position, monomerList] of Object.entries(this.mutationCliffsSelection)) {
|
|
949
905
|
for (const monomer of monomerList) {
|
|
950
906
|
const substitutions = this.mutationCliffs?.get(monomer)?.get(position) ?? null;
|
|
951
907
|
if (substitutions === null)
|
|
952
908
|
continue;
|
|
953
909
|
for (const [key, value] of substitutions.entries()) {
|
|
954
|
-
|
|
910
|
+
combinedSelection.setTrue(key);
|
|
955
911
|
for (const v of value)
|
|
956
|
-
|
|
912
|
+
combinedSelection.setTrue(v);
|
|
957
913
|
}
|
|
958
914
|
}
|
|
959
915
|
}
|
|
960
916
|
|
|
961
|
-
|
|
962
|
-
const
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
const positionColCat = positionCol.categories;
|
|
967
|
-
const aarList = this.invariantMapSelection[position];
|
|
968
|
-
for (const aar of aarList) {
|
|
969
|
-
const aarIndex = positionColCat.indexOf(aar);
|
|
970
|
-
if (aarIndex === -1)
|
|
971
|
-
continue;
|
|
972
|
-
for (let i = 0; i < rowCount; ++i) {
|
|
973
|
-
if (positionColData[i] === aarIndex)
|
|
974
|
-
indexes.add(i);
|
|
975
|
-
}
|
|
917
|
+
// Cluster selection
|
|
918
|
+
for (const clustType of Object.keys(this.clusterSelection)) {
|
|
919
|
+
for (const clust of this.clusterSelection[clustType]) {
|
|
920
|
+
const clusterStats = this.clusterStats[clustType as CLUSTER_TYPE][clust]!;
|
|
921
|
+
combinedSelection.or(clusterStats.mask);
|
|
976
922
|
}
|
|
977
923
|
}
|
|
978
924
|
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
return true;
|
|
982
|
-
|
|
983
|
-
//TODO: preprocess
|
|
984
|
-
const currentOrigClust = clustColCat[clustColData[i]];
|
|
985
|
-
if (typeof currentOrigClust === undefined)
|
|
986
|
-
return false;
|
|
987
|
-
|
|
988
|
-
for (const clust of this.clusterSelection) {
|
|
989
|
-
if (clust === currentOrigClust)
|
|
990
|
-
return true;
|
|
925
|
+
return DG.BitSet.fromBytes(combinedSelection.buffer.buffer, combinedSelection.length);
|
|
926
|
+
};
|
|
991
927
|
|
|
992
|
-
|
|
993
|
-
|
|
928
|
+
const getLatestSelection = (): DG.BitSet => {
|
|
929
|
+
if (this.latestSelectionItem === null)
|
|
930
|
+
return getCombinedSelection();
|
|
931
|
+
if (this.latestSelectionItem.kind === SELECTION_MODE.INVARIANT_MAP) {
|
|
932
|
+
const monomerPositionStats = this.monomerPositionStats[this.latestSelectionItem.positionOrClusterType]![this.latestSelectionItem.monomerOrCluster]!;
|
|
933
|
+
return DG.BitSet.fromBytes(monomerPositionStats.mask.buffer.buffer, monomerPositionStats.mask.length);
|
|
934
|
+
} else if (this.latestSelectionItem.kind === SELECTION_MODE.MUTATION_CLIFFS) {
|
|
935
|
+
const substitutions = this.mutationCliffs?.get(this.latestSelectionItem.monomerOrCluster)?.get(this.latestSelectionItem.positionOrClusterType) ?? null;
|
|
936
|
+
if (substitutions === null)
|
|
937
|
+
throw new Error(`Couldn't find substitutions for ${this.latestSelectionItem.monomerOrCluster} at ${this.latestSelectionItem.positionOrClusterType}`);
|
|
938
|
+
const latestSelection = new BitArray(this.df.rowCount, false);
|
|
939
|
+
for (const [key, value] of substitutions.entries()) {
|
|
940
|
+
latestSelection.setTrue(key);
|
|
941
|
+
for (const v of value)
|
|
942
|
+
latestSelection.setTrue(v);
|
|
994
943
|
}
|
|
944
|
+
return DG.BitSet.fromBytes(latestSelection.buffer.buffer, latestSelection.length);
|
|
945
|
+
} else if (this.latestSelectionItem.kind === 'Cluster') {
|
|
946
|
+
const clusterStats = this.clusterStats[this.latestSelectionItem.positionOrClusterType as CLUSTER_TYPE][this.latestSelectionItem.monomerOrCluster]!;
|
|
947
|
+
return DG.BitSet.fromBytes(clusterStats.mask.buffer.buffer, clusterStats.mask.length);
|
|
948
|
+
}
|
|
949
|
+
throw new Error(`Unknown selection kind: ${this.latestSelectionItem.kind}`);
|
|
950
|
+
};
|
|
995
951
|
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
952
|
+
const showAccordion = (): void => {
|
|
953
|
+
const acc = this.createAccordion();
|
|
954
|
+
if (acc !== null) {
|
|
955
|
+
grok.shell.o = acc.root;
|
|
956
|
+
for (const pane of acc.panes)
|
|
957
|
+
pane.expanded = true;
|
|
958
|
+
}
|
|
999
959
|
};
|
|
1000
960
|
|
|
1001
961
|
selection.onChanged.subscribe(() => {
|
|
1002
|
-
if (this.isUserChangedSelection)
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
const clustColCat = clusterCol?.categories ?? [];
|
|
1006
|
-
const clustColData = clusterCol?.getRawData() ?? new Int32Array(0);
|
|
1007
|
-
const customClust: {[key: string]: BitArray} = {};
|
|
1008
|
-
const rowCount = this.df.rowCount;
|
|
1009
|
-
for (const clust of this.customClusters)
|
|
1010
|
-
customClust[clust.name] = BitArray.fromUint32Array(rowCount, clust.getRawData() as Uint32Array);
|
|
1011
|
-
|
|
1012
|
-
changeSelectionBitset(selection, clustColCat, clustColData, customClust);
|
|
962
|
+
if (!this.isUserChangedSelection)
|
|
963
|
+
selection.copyFrom(getLatestSelection(), false);
|
|
964
|
+
showAccordion();
|
|
1013
965
|
});
|
|
1014
966
|
|
|
1015
967
|
filter.onChanged.subscribe(() => {
|
|
@@ -1018,6 +970,7 @@ export class PeptidesModel {
|
|
|
1018
970
|
lstViewer.createLogoSummaryTableGrid();
|
|
1019
971
|
lstViewer.render();
|
|
1020
972
|
}
|
|
973
|
+
showAccordion();
|
|
1021
974
|
});
|
|
1022
975
|
this.isBitsetChangedInitialized = true;
|
|
1023
976
|
}
|
|
@@ -1027,15 +980,7 @@ export class PeptidesModel {
|
|
|
1027
980
|
this.df.selection.fireChanged();
|
|
1028
981
|
if (fireFilterChanged)
|
|
1029
982
|
this.df.filter.fireChanged();
|
|
1030
|
-
this.modifyOrCreateSplitCol();
|
|
1031
983
|
this.headerSelectedMonomers = calculateSelected(this.df);
|
|
1032
|
-
|
|
1033
|
-
const acc = this.createAccordion();
|
|
1034
|
-
if (acc !== null) {
|
|
1035
|
-
grok.shell.o = acc.root;
|
|
1036
|
-
for (const pane of acc.panes)
|
|
1037
|
-
pane.expanded = true;
|
|
1038
|
-
}
|
|
1039
984
|
this.isUserChangedSelection = true;
|
|
1040
985
|
}
|
|
1041
986
|
|
|
@@ -1084,19 +1029,6 @@ export class PeptidesModel {
|
|
|
1084
1029
|
}
|
|
1085
1030
|
}
|
|
1086
1031
|
|
|
1087
|
-
getSplitColValueAt(index: number, aar: string, position: string, aarLabel: string): string {
|
|
1088
|
-
const currentAAR = this.df.get(position, index) as string;
|
|
1089
|
-
return currentAAR === aar ? aarLabel : C.CATEGORIES.OTHER;
|
|
1090
|
-
}
|
|
1091
|
-
|
|
1092
|
-
modifyOrCreateSplitCol(): void {
|
|
1093
|
-
const bs = this.df.selection;
|
|
1094
|
-
this.splitCol = this.df.col(C.COLUMNS_NAMES.SPLIT_COL) ??
|
|
1095
|
-
this.df.columns.addNewBool(C.COLUMNS_NAMES.SPLIT_COL);
|
|
1096
|
-
this.splitCol.init((i) => bs.get(i));
|
|
1097
|
-
this.splitCol.compact();
|
|
1098
|
-
}
|
|
1099
|
-
|
|
1100
1032
|
/** Class initializer */
|
|
1101
1033
|
init(): void {
|
|
1102
1034
|
if (this.isInitialized)
|
|
@@ -1224,4 +1156,51 @@ export class PeptidesModel {
|
|
|
1224
1156
|
|
|
1225
1157
|
return newDfId;
|
|
1226
1158
|
}
|
|
1159
|
+
|
|
1160
|
+
modifyInvariantMapSelection(monomerPosition: type.SelectionItem, options: type.SelectionOptions = {shiftPressed: false, ctrlPressed: false}, notify: boolean = true): void {
|
|
1161
|
+
if (notify)
|
|
1162
|
+
this.invariantMapSelection = this.modifySelection(this.invariantMapSelection, monomerPosition, options);
|
|
1163
|
+
else
|
|
1164
|
+
this._invariantMapSelection = this.modifySelection(this._invariantMapSelection, monomerPosition, options);
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
modifyMutationCliffsSelection(monomerPosition: type.SelectionItem, options: type.SelectionOptions = {shiftPressed: false, ctrlPressed: false}, notify: boolean = true): void {
|
|
1168
|
+
if (notify)
|
|
1169
|
+
this.mutationCliffsSelection = this.modifySelection(this.mutationCliffsSelection, monomerPosition, options);
|
|
1170
|
+
else
|
|
1171
|
+
this._mutationCliffsSelection = this.modifySelection(this._mutationCliffsSelection, monomerPosition, options);
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
modifyClusterSelection(cluster: type.SelectionItem, options: type.SelectionOptions = {shiftPressed: false, ctrlPressed: false}, notify: boolean = true): void {
|
|
1175
|
+
if (notify)
|
|
1176
|
+
this.clusterSelection = this.modifySelection(this.clusterSelection, cluster, options);
|
|
1177
|
+
else
|
|
1178
|
+
this._clusterSelection = this.modifySelection(this._clusterSelection, cluster, options);
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
modifySelection(selection: type.Selection, clusterOrMonomerPosition: type.SelectionItem, options: type.SelectionOptions): type.Selection {
|
|
1182
|
+
const monomerList = selection[clusterOrMonomerPosition.positionOrClusterType];
|
|
1183
|
+
const monomerIndex = monomerList.indexOf(clusterOrMonomerPosition.monomerOrCluster);
|
|
1184
|
+
if (options.shiftPressed && options.ctrlPressed) {
|
|
1185
|
+
if (monomerIndex !== -1)
|
|
1186
|
+
monomerList.splice(monomerIndex, 1);
|
|
1187
|
+
} else if (options.ctrlPressed) {
|
|
1188
|
+
if (monomerIndex === -1)
|
|
1189
|
+
monomerList.push(clusterOrMonomerPosition.monomerOrCluster);
|
|
1190
|
+
else
|
|
1191
|
+
monomerList.splice(monomerIndex, 1);
|
|
1192
|
+
} else if (options.shiftPressed) {
|
|
1193
|
+
if (monomerIndex === -1)
|
|
1194
|
+
monomerList.push(clusterOrMonomerPosition.monomerOrCluster);
|
|
1195
|
+
} else {
|
|
1196
|
+
const selectionKeys = Object.keys(selection);
|
|
1197
|
+
selection = {};
|
|
1198
|
+
for (const posOrClustType of selectionKeys) {
|
|
1199
|
+
selection[posOrClustType] = [];
|
|
1200
|
+
if (posOrClustType === clusterOrMonomerPosition.positionOrClusterType)
|
|
1201
|
+
selection[posOrClustType].push(clusterOrMonomerPosition.monomerOrCluster);
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
return selection;
|
|
1205
|
+
}
|
|
1227
1206
|
}
|