@datagrok/peptides 1.3.7 → 1.3.9
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/dist/package-test.js +1450 -592
- package/dist/package.js +1011 -793
- package/package.json +2 -2
- package/src/model.ts +167 -250
- package/src/package.ts +23 -4
- package/src/tests/algorithms.ts +51 -0
- package/src/tests/core.ts +13 -13
- package/src/utils/algorithms.ts +91 -0
- package/src/utils/cell-renderer.ts +38 -84
- package/src/utils/misc.ts +1 -1
- package/src/utils/types.ts +25 -4
- package/src/viewers/sar-viewer.ts +7 -55
- package/src/widgets/distribution.ts +1 -1
- package/src/widgets/manual-alignment.ts +2 -2
- package/src/widgets/peptides.ts +52 -28
- package/src/widgets/settings.ts +67 -0
- package/test-Peptides-62cc009524f3-0949dc07.html +276 -0
package/src/model.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import * as ui from 'datagrok-api/ui';
|
|
2
2
|
import * as grok from 'datagrok-api/grok';
|
|
3
3
|
import * as DG from 'datagrok-api/dg';
|
|
4
|
-
import * as bio from '@datagrok-libraries/bio';
|
|
5
4
|
|
|
6
5
|
import {splitAlignedSequences} from '@datagrok-libraries/bio/src/utils/splitter';
|
|
7
6
|
|
|
@@ -10,13 +9,17 @@ import * as rxjs from 'rxjs';
|
|
|
10
9
|
|
|
11
10
|
import * as C from './utils/constants';
|
|
12
11
|
import * as type from './utils/types';
|
|
13
|
-
import {
|
|
14
|
-
import {MutationCliffsViewer,
|
|
12
|
+
import {isGridCellInvalid, scaleActivity} from './utils/misc';
|
|
13
|
+
import {MutationCliffsViewer, MostPotentResiduesViewer} from './viewers/sar-viewer';
|
|
15
14
|
import * as CR from './utils/cell-renderer';
|
|
16
15
|
import {mutationCliffsWidget} from './widgets/mutation-cliffs';
|
|
17
16
|
import {getDistributionAndStats, getDistributionWidget} from './widgets/distribution';
|
|
18
17
|
import {getStats, Stats} from './utils/statistics';
|
|
19
18
|
import {LogoSummary} from './viewers/logo-summary';
|
|
19
|
+
import {getSettingsDialog} from './widgets/settings';
|
|
20
|
+
import {getMonomerWorks} from './package';
|
|
21
|
+
import * as bio from '@datagrok-libraries/bio';
|
|
22
|
+
import {findMutations} from './utils/algorithms';
|
|
20
23
|
|
|
21
24
|
export class PeptidesModel {
|
|
22
25
|
static modelName = 'peptidesModel';
|
|
@@ -48,19 +51,22 @@ export class PeptidesModel {
|
|
|
48
51
|
isPeptideSpaceChangingBitset = false;
|
|
49
52
|
isChangingEdfBitset = false;
|
|
50
53
|
|
|
51
|
-
mutationCliffsViewer!: MutationCliffsViewer;
|
|
52
|
-
mostPotentResiduesViewer!: MostPotentResiduesViewer;
|
|
53
|
-
|
|
54
|
-
_usedProperties: { [propName: string]: string | number | boolean } = {};
|
|
55
54
|
monomerMap: { [key: string]: { molfile: string, fullName: string } } = {};
|
|
56
|
-
barData: type.MonomerDfStats = {};
|
|
57
|
-
barsBounds: { [position: string]: type.BarCoordinates } = {};
|
|
58
|
-
cachedBarchartTooltip: { bar: string, tooltip: null | HTMLDivElement } = {bar: '', tooltip: null};
|
|
59
55
|
monomerLib: bio.IMonomerLib | null = null; // To get monomers from lib(s)
|
|
60
56
|
monomerWorks: bio.MonomerWorks | null = null; // To get processed monomers
|
|
61
57
|
|
|
58
|
+
_settings!: type.PeptidesSettings;
|
|
59
|
+
isRibbonSet = false;
|
|
60
|
+
|
|
61
|
+
cp: bio.SeqPalette;
|
|
62
|
+
xorBitset?: DG.BitSet;
|
|
63
|
+
initBitset: DG.BitSet;
|
|
64
|
+
isInvariantMapTrigger: boolean = false;;
|
|
65
|
+
|
|
62
66
|
private constructor(dataFrame: DG.DataFrame) {
|
|
63
67
|
this.df = dataFrame;
|
|
68
|
+
this.initBitset = this.df.filter.clone();
|
|
69
|
+
this.cp = bio.pickUpPalette(this.df.getCol(C.COLUMNS_NAMES.MACROMOLECULE));
|
|
64
70
|
}
|
|
65
71
|
|
|
66
72
|
static async getInstance(dataFrame: DG.DataFrame): Promise<PeptidesModel> {
|
|
@@ -101,7 +107,9 @@ export class PeptidesModel {
|
|
|
101
107
|
set invariantMapSelection(selection: type.PositionToAARList) {
|
|
102
108
|
this._invariantMapSelection = selection;
|
|
103
109
|
this.df.tags[C.TAGS.FILTER] = JSON.stringify(selection);
|
|
110
|
+
this.isInvariantMapTrigger = true;
|
|
104
111
|
this.df.filter.fireChanged();
|
|
112
|
+
this.isInvariantMapTrigger = false;
|
|
105
113
|
this.invalidateGrids();
|
|
106
114
|
}
|
|
107
115
|
|
|
@@ -117,16 +125,6 @@ export class PeptidesModel {
|
|
|
117
125
|
this.invalidateGrids();
|
|
118
126
|
}
|
|
119
127
|
|
|
120
|
-
get usedProperties(): { [propName: string]: string | number | boolean } {
|
|
121
|
-
this._usedProperties = JSON.parse(this.df.tags['sarProperties'] ?? '{}');
|
|
122
|
-
return this._usedProperties;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
set usedProperties(properties: { [propName: string]: string | number | boolean }) {
|
|
126
|
-
this.df.tags['sarProperties'] = JSON.stringify(properties);
|
|
127
|
-
this._usedProperties = properties;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
128
|
get splitByPos(): boolean {
|
|
131
129
|
const splitByPosFlag = (this.df.tags['distributionSplit'] ?? '00')[0];
|
|
132
130
|
return splitByPosFlag == '1' ? true : false;
|
|
@@ -156,9 +154,10 @@ export class PeptidesModel {
|
|
|
156
154
|
}
|
|
157
155
|
|
|
158
156
|
get isMutationCliffSelectionEmpty(): boolean {
|
|
159
|
-
for (const aarList of Object.values(this.mutationCliffsSelection))
|
|
157
|
+
for (const aarList of Object.values(this.mutationCliffsSelection)) {
|
|
160
158
|
if (aarList.length !== 0)
|
|
161
159
|
return false;
|
|
160
|
+
}
|
|
162
161
|
return true;
|
|
163
162
|
}
|
|
164
163
|
|
|
@@ -166,6 +165,18 @@ export class PeptidesModel {
|
|
|
166
165
|
return this.logoSummarySelection.length === 0;
|
|
167
166
|
}
|
|
168
167
|
|
|
168
|
+
get settings(): type.PeptidesSettings {
|
|
169
|
+
this._settings ??= JSON.parse(this.df.getTag('settings') ?? '{}');
|
|
170
|
+
return this._settings;
|
|
171
|
+
}
|
|
172
|
+
set settings(s: type.PeptidesSettings) {
|
|
173
|
+
for (const [key, value] of Object.entries(s))
|
|
174
|
+
this._settings[key as keyof type.PeptidesSettings] = value as any;
|
|
175
|
+
this.df.setTag('settings', JSON.stringify(this._settings));
|
|
176
|
+
//TODO: update only needed components
|
|
177
|
+
this.updateDefault();
|
|
178
|
+
}
|
|
179
|
+
|
|
169
180
|
createAccordion(): DG.Accordion {
|
|
170
181
|
const acc = ui.accordion();
|
|
171
182
|
acc.root.style.width = '100%';
|
|
@@ -176,37 +187,9 @@ export class PeptidesModel {
|
|
|
176
187
|
return acc;
|
|
177
188
|
}
|
|
178
189
|
|
|
179
|
-
getViewer(): SARViewerBase {
|
|
180
|
-
const viewer = this.mutationCliffsViewer ?? this.mostPotentResiduesViewer;
|
|
181
|
-
if (!viewer)
|
|
182
|
-
throw new Error('ViewerError: none of the SAR viewers is initialized');
|
|
183
|
-
return viewer;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
isPropertyChanged(viewer: SARViewerBase): boolean {
|
|
187
|
-
let result = false;
|
|
188
|
-
if (typeof viewer == 'undefined')
|
|
189
|
-
return result;
|
|
190
|
-
|
|
191
|
-
const viewerProps = viewer.props.getProperties();
|
|
192
|
-
const tempProps = this.usedProperties;
|
|
193
|
-
for (const property of viewerProps) {
|
|
194
|
-
const propName = property.name;
|
|
195
|
-
const propVal = property.get(viewer);
|
|
196
|
-
if (tempProps[propName] != propVal) {
|
|
197
|
-
tempProps[propName] = propVal;
|
|
198
|
-
result = true;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
this.usedProperties = tempProps;
|
|
202
|
-
return result;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
190
|
updateDefault(): void {
|
|
206
|
-
|
|
207
|
-
this.
|
|
208
|
-
if ((this.sourceGrid && !this._isUpdating && proprtyChanged) || !this.isInitialized) {
|
|
209
|
-
this.isInitialized = true;
|
|
191
|
+
if ((this.sourceGrid && !this._isUpdating) || !this.isInitialized) {
|
|
192
|
+
// this.isInitialized = true;
|
|
210
193
|
this._isUpdating = true;
|
|
211
194
|
this.initializeViewersComponents();
|
|
212
195
|
//FIXME: modify during the initializeViewersComponents stages
|
|
@@ -230,7 +213,7 @@ export class PeptidesModel {
|
|
|
230
213
|
const alphabet = col.tags['alphabet'];
|
|
231
214
|
const splitSeqDf = splitAlignedSequences(col);
|
|
232
215
|
|
|
233
|
-
this.barData = calculateBarsData(splitSeqDf.columns.toList(), this.df.selection);
|
|
216
|
+
// this.barData = calculateBarsData(splitSeqDf.columns.toList(), this.df.selection);
|
|
234
217
|
|
|
235
218
|
const positionColumns = splitSeqDf.columns.names();
|
|
236
219
|
|
|
@@ -241,9 +224,7 @@ export class PeptidesModel {
|
|
|
241
224
|
|
|
242
225
|
this.sortSourceGrid();
|
|
243
226
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
this.createScaledCol(viewer.scaling, splitSeqDf);
|
|
227
|
+
this.createScaledCol(splitSeqDf);
|
|
247
228
|
|
|
248
229
|
//unpivot a table and handle duplicates
|
|
249
230
|
let matrixDf = splitSeqDf.groupBy(positionColumns).aggregate();
|
|
@@ -267,7 +248,9 @@ export class PeptidesModel {
|
|
|
267
248
|
// SAR vertical table (naive, choose best Mean difference from pVals <= 0.01)
|
|
268
249
|
const sequenceDf = this.createVerticalTable();
|
|
269
250
|
|
|
270
|
-
this.
|
|
251
|
+
const scaledActivityCol = this.df.getCol(C.COLUMNS_NAMES.ACTIVITY_SCALED);
|
|
252
|
+
const monomerColumns = this.df.columns.bySemTypeAll(C.SEM_TYPES.MONOMER);
|
|
253
|
+
this.substitutionsInfo = findMutations(scaledActivityCol, monomerColumns, this.settings);
|
|
271
254
|
|
|
272
255
|
[this.mutationCliffsGrid, this.mostPotentResiduesGrid] =
|
|
273
256
|
this.createGrids(matrixDf, sequenceDf, positionColumns, alphabet);
|
|
@@ -282,7 +265,7 @@ export class PeptidesModel {
|
|
|
282
265
|
|
|
283
266
|
positionColumns.push(C.COLUMNS_NAMES.MEAN_DIFFERENCE);
|
|
284
267
|
|
|
285
|
-
this.setBarChartInteraction();
|
|
268
|
+
// this.setBarChartInteraction();
|
|
286
269
|
|
|
287
270
|
this.setCellRenderers(positionColumns);
|
|
288
271
|
|
|
@@ -296,91 +279,6 @@ export class PeptidesModel {
|
|
|
296
279
|
this.postProcessGrids();
|
|
297
280
|
}
|
|
298
281
|
|
|
299
|
-
calcSubstitutions(): void {
|
|
300
|
-
const activityValues: DG.Column<number> = this.df.columns.bySemType(C.SEM_TYPES.ACTIVITY_SCALED)!;
|
|
301
|
-
const columnList: DG.Column<string>[] = this.df.columns.bySemTypeAll(C.SEM_TYPES.MONOMER);
|
|
302
|
-
const nCols = columnList.length;
|
|
303
|
-
if (nCols == 0)
|
|
304
|
-
throw new Error(`Couldn't find any column of semType '${C.SEM_TYPES.MONOMER}'`);
|
|
305
|
-
|
|
306
|
-
const viewer = this.getViewer();
|
|
307
|
-
this.substitutionsInfo = new Map();
|
|
308
|
-
const nRows = this.df.rowCount;
|
|
309
|
-
for (let seq1Idx = 0; seq1Idx < nRows - 1; seq1Idx++) {
|
|
310
|
-
for (let seq2Idx = seq1Idx + 1; seq2Idx < nRows; seq2Idx++) {
|
|
311
|
-
let substCounter = 0;
|
|
312
|
-
const activityValSeq1 = activityValues.get(seq1Idx)!;
|
|
313
|
-
const activityValSeq2 = activityValues.get(seq2Idx)!;
|
|
314
|
-
const delta = activityValSeq1 - activityValSeq2;
|
|
315
|
-
if (Math.abs(delta) < viewer.minActivityDelta)
|
|
316
|
-
continue;
|
|
317
|
-
|
|
318
|
-
let substCounterFlag = false;
|
|
319
|
-
const tempData: { pos: string, seq1monomer: string, seq2monomer: string, seq1Idx: number, seq2Idx: number }[] =
|
|
320
|
-
[];
|
|
321
|
-
for (const currentPosCol of columnList) {
|
|
322
|
-
const seq1monomer = currentPosCol.get(seq1Idx)!;
|
|
323
|
-
const seq2monomer = currentPosCol.get(seq2Idx)!;
|
|
324
|
-
if (seq1monomer == seq2monomer)
|
|
325
|
-
continue;
|
|
326
|
-
|
|
327
|
-
substCounter++;
|
|
328
|
-
substCounterFlag = substCounter > viewer.maxSubstitutions;
|
|
329
|
-
if (substCounterFlag)
|
|
330
|
-
break;
|
|
331
|
-
|
|
332
|
-
tempData.push({
|
|
333
|
-
pos: currentPosCol.name,
|
|
334
|
-
seq1monomer: seq1monomer,
|
|
335
|
-
seq2monomer: seq2monomer,
|
|
336
|
-
seq1Idx: seq1Idx,
|
|
337
|
-
seq2Idx: seq2Idx,
|
|
338
|
-
});
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
if (substCounterFlag || substCounter == 0)
|
|
342
|
-
continue;
|
|
343
|
-
|
|
344
|
-
for (const tempDataElement of tempData) {
|
|
345
|
-
const position = tempDataElement.pos;
|
|
346
|
-
|
|
347
|
-
//Working with seq1monomer
|
|
348
|
-
const seq1monomer = tempDataElement.seq1monomer;
|
|
349
|
-
if (!this.substitutionsInfo.has(seq1monomer))
|
|
350
|
-
this.substitutionsInfo.set(seq1monomer, new Map());
|
|
351
|
-
|
|
352
|
-
let positionsMap = this.substitutionsInfo.get(seq1monomer)!;
|
|
353
|
-
if (!positionsMap.has(position))
|
|
354
|
-
positionsMap.set(position, new Map());
|
|
355
|
-
|
|
356
|
-
let indexes = positionsMap.get(position)!;
|
|
357
|
-
|
|
358
|
-
!indexes.has(seq1Idx) ? indexes.set(seq1Idx, [seq2Idx]) : (indexes.get(seq1Idx)! as number[]).push(seq2Idx);
|
|
359
|
-
|
|
360
|
-
//Working with seq2monomer
|
|
361
|
-
const seq2monomer = tempDataElement.seq2monomer;
|
|
362
|
-
if (!this.substitutionsInfo.has(seq2monomer))
|
|
363
|
-
this.substitutionsInfo.set(seq2monomer, new Map());
|
|
364
|
-
|
|
365
|
-
positionsMap = this.substitutionsInfo.get(seq2monomer)!;
|
|
366
|
-
if (!positionsMap.has(position))
|
|
367
|
-
positionsMap.set(position, new Map());
|
|
368
|
-
|
|
369
|
-
indexes = positionsMap.get(position)!;
|
|
370
|
-
!indexes.has(seq2Idx) ? indexes.set(seq2Idx, [seq1Idx]) : (indexes.get(seq2Idx)! as number[]).push(seq1Idx);
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
const TypedArray = getTypedArrayConstructor(nRows);
|
|
376
|
-
for (const positionMap of this.substitutionsInfo.values()) {
|
|
377
|
-
for (const indexMap of positionMap.values()) {
|
|
378
|
-
for (const [index, indexArray] of indexMap.entries())
|
|
379
|
-
indexMap.set(index, new TypedArray(indexArray));
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
|
|
384
282
|
initSelections(positionColumns: string[]): void {
|
|
385
283
|
const tempInvariantMapSelection: type.PositionToAARList = this.invariantMapSelection;
|
|
386
284
|
const mutationCliffsSelection: type.PositionToAARList = this.mutationCliffsSelection;
|
|
@@ -390,7 +288,7 @@ export class PeptidesModel {
|
|
|
390
288
|
}
|
|
391
289
|
this.invariantMapSelection = tempInvariantMapSelection;
|
|
392
290
|
this.mutationCliffsSelection = mutationCliffsSelection;
|
|
393
|
-
this.barData = calculateBarsData(this.df.columns.bySemTypeAll(C.SEM_TYPES.MONOMER), this.df.selection);
|
|
291
|
+
// this.barData = calculateBarsData(this.df.columns.bySemTypeAll(C.SEM_TYPES.MONOMER), this.df.selection);
|
|
394
292
|
}
|
|
395
293
|
|
|
396
294
|
joinDataFrames(positionColumns: string[], splitSeqDf: DG.DataFrame, alphabet: string): void {
|
|
@@ -430,8 +328,8 @@ export class PeptidesModel {
|
|
|
430
328
|
this.sourceGrid.columns.setOrder(colNames.map((v) => v.name));
|
|
431
329
|
}
|
|
432
330
|
|
|
433
|
-
createScaledCol(
|
|
434
|
-
const scaledCol = scaleActivity(
|
|
331
|
+
createScaledCol(splitSeqDf: DG.DataFrame): void {
|
|
332
|
+
const scaledCol = scaleActivity(this.df.getCol(C.COLUMNS_NAMES.ACTIVITY), this.settings.scaling);
|
|
435
333
|
//TODO: make another func
|
|
436
334
|
splitSeqDf.columns.add(scaledCol);
|
|
437
335
|
this.df.columns.replace(C.COLUMNS_NAMES.ACTIVITY_SCALED, scaledCol);
|
|
@@ -499,7 +397,7 @@ export class PeptidesModel {
|
|
|
499
397
|
|
|
500
398
|
setCategoryOrder(matrixDf: DG.DataFrame): void {
|
|
501
399
|
let sortArgument: string = C.COLUMNS_NAMES.MEAN_DIFFERENCE;
|
|
502
|
-
if (this.
|
|
400
|
+
if (this.settings.isBidirectional) {
|
|
503
401
|
const mdCol = this.monomerPositionStatsDf.getCol(sortArgument);
|
|
504
402
|
sortArgument = 'Absolute Mean difference';
|
|
505
403
|
const absMDCol = this.monomerPositionStatsDf.columns.addNewFloat(sortArgument);
|
|
@@ -535,7 +433,7 @@ export class PeptidesModel {
|
|
|
535
433
|
const rowCount = sequenceDf.rowCount;
|
|
536
434
|
for (const pos of posColCategories) {
|
|
537
435
|
tempStats = DG.Stats.fromColumn(mdCol, DG.BitSet.create(rowCount, (i) => posCol.get(i) === pos));
|
|
538
|
-
maxAtPos[pos] = this.
|
|
436
|
+
maxAtPos[pos] = this.settings.isBidirectional ?
|
|
539
437
|
(tempStats.max > Math.abs(tempStats.min) ? tempStats.max : tempStats.min) :
|
|
540
438
|
tempStats.max;
|
|
541
439
|
}
|
|
@@ -591,6 +489,9 @@ export class PeptidesModel {
|
|
|
591
489
|
tempDfList[index] = dfSlice;
|
|
592
490
|
webLogoCol.set(index, index.toString());
|
|
593
491
|
membersCol.set(index, dfSlice.rowCount);
|
|
492
|
+
//TODO: user should be able to choose threshold
|
|
493
|
+
if (dfSlice.rowCount <= Math.ceil(this.clusterStatsDf.getCol(C.COLUMNS_NAMES.COUNT).stats.max * 0.70))
|
|
494
|
+
summaryTable.filter.set(index, false, false);
|
|
594
495
|
}
|
|
595
496
|
webLogoCol.setTag(DG.TAGS.CELL_RENDERER, 'html');
|
|
596
497
|
|
|
@@ -617,7 +518,7 @@ export class PeptidesModel {
|
|
|
617
518
|
this.modifyClusterSelection(cluster);
|
|
618
519
|
else
|
|
619
520
|
this.initClusterSelection(cluster);
|
|
620
|
-
this.barData = calculateBarsData(this.df.columns.bySemTypeAll(C.SEM_TYPES.MONOMER), this.df.selection);
|
|
521
|
+
// this.barData = calculateBarsData(this.df.columns.bySemTypeAll(C.SEM_TYPES.MONOMER), this.df.selection);
|
|
621
522
|
});
|
|
622
523
|
grid.onCellRender.subscribe((gridCellArgs) => {
|
|
623
524
|
const gc = gridCellArgs.cell;
|
|
@@ -660,51 +561,51 @@ export class PeptidesModel {
|
|
|
660
561
|
this.logoSummarySelection = [cluster];
|
|
661
562
|
}
|
|
662
563
|
|
|
663
|
-
setBarChartInteraction(): void {
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
findAARandPosition(cell: DG.GridCell, ev: MouseEvent): { monomer: string, position: string } | null {
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
requestBarchartAction(ev: MouseEvent, barPart: { position: string, monomer: string } | null): void {
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
}
|
|
564
|
+
// setBarChartInteraction(): void {
|
|
565
|
+
// const eventAction = (ev: MouseEvent): void => {
|
|
566
|
+
// const cell = this.sourceGrid.hitTest(ev.offsetX, ev.offsetY);
|
|
567
|
+
// if (cell?.isColHeader && cell.tableColumn?.semType == C.SEM_TYPES.MONOMER) {
|
|
568
|
+
// const newBarPart = this.findAARandPosition(cell, ev);
|
|
569
|
+
// this.requestBarchartAction(ev, newBarPart);
|
|
570
|
+
// }
|
|
571
|
+
// };
|
|
572
|
+
|
|
573
|
+
// // The following events makes the barchart interactive
|
|
574
|
+
// rxjs.fromEvent<MouseEvent>(this.sourceGrid.overlay, 'mousemove')
|
|
575
|
+
// .subscribe((mouseMove: MouseEvent) => eventAction(mouseMove));
|
|
576
|
+
// rxjs.fromEvent<MouseEvent>(this.sourceGrid.overlay, 'click')
|
|
577
|
+
// .subscribe((mouseMove: MouseEvent) => eventAction(mouseMove));
|
|
578
|
+
// }
|
|
579
|
+
|
|
580
|
+
// findAARandPosition(cell: DG.GridCell, ev: MouseEvent): { monomer: string, position: string } | null {
|
|
581
|
+
// const barCoords = this.barsBounds[cell.tableColumn!.name];
|
|
582
|
+
// for (const [monomer, coords] of Object.entries(barCoords)) {
|
|
583
|
+
// const isIntersectingX = ev.offsetX >= coords.x && ev.offsetX <= coords.x + coords.width;
|
|
584
|
+
// const isIntersectingY = ev.offsetY >= coords.y && ev.offsetY <= coords.y + coords.height;
|
|
585
|
+
// if (isIntersectingX && isIntersectingY)
|
|
586
|
+
// return {monomer: monomer, position: cell.tableColumn!.name};
|
|
587
|
+
// }
|
|
588
|
+
|
|
589
|
+
// return null;
|
|
590
|
+
// }
|
|
591
|
+
|
|
592
|
+
// requestBarchartAction(ev: MouseEvent, barPart: { position: string, monomer: string } | null): void {
|
|
593
|
+
// if (!barPart)
|
|
594
|
+
// return;
|
|
595
|
+
// const monomer = barPart.monomer;
|
|
596
|
+
// const position = barPart.position;
|
|
597
|
+
// if (ev.type === 'click') {
|
|
598
|
+
// ev.shiftKey ? this.modifyMonomerPositionSelection(monomer, position, true) :
|
|
599
|
+
// this.initMonomerPositionSelection(monomer, position, true);
|
|
600
|
+
// this.barData = calculateBarsData(this.df.columns.bySemTypeAll(C.SEM_TYPES.MONOMER), this.df.selection);
|
|
601
|
+
// } else {
|
|
602
|
+
// const bar = `${monomer}:${position}`;
|
|
603
|
+
// if (this.cachedBarchartTooltip.bar == bar)
|
|
604
|
+
// ui.tooltip.show(this.cachedBarchartTooltip.tooltip!, ev.clientX, ev.clientY);
|
|
605
|
+
// else
|
|
606
|
+
// this.cachedBarchartTooltip = {bar: bar, tooltip: this.showTooltipAt(monomer, position, ev.clientX, ev.clientY)};
|
|
607
|
+
// }
|
|
608
|
+
// }
|
|
708
609
|
|
|
709
610
|
setCellRenderers(renderColNames: string[]): void {
|
|
710
611
|
const mdCol = this.monomerPositionStatsDf.getCol(C.COLUMNS_NAMES.MEAN_DIFFERENCE);
|
|
@@ -737,7 +638,6 @@ export class PeptidesModel {
|
|
|
737
638
|
tableColName : gridTable.get(C.COLUMNS_NAMES.POSITION, tableRowIndex);
|
|
738
639
|
const currentAAR: string = gridTable.get(C.COLUMNS_NAMES.MONOMER, tableRowIndex);
|
|
739
640
|
|
|
740
|
-
const viewer = this.getViewer();
|
|
741
641
|
if (this.isInvariantMap) {
|
|
742
642
|
const value: number = this.monomerPositionStatsDf
|
|
743
643
|
.groupBy([C.COLUMNS_NAMES.POSITION, C.COLUMNS_NAMES.MONOMER, C.COLUMNS_NAMES.COUNT])
|
|
@@ -746,9 +646,9 @@ export class PeptidesModel {
|
|
|
746
646
|
CR.renderInvaraintMapCell(
|
|
747
647
|
canvasContext, currentAAR, currentPosition, this.invariantMapSelection, value, bound);
|
|
748
648
|
} else {
|
|
749
|
-
CR.renderMutationCliffCell(
|
|
750
|
-
|
|
751
|
-
|
|
649
|
+
CR.renderMutationCliffCell(canvasContext, currentAAR, currentPosition, this.monomerPositionStatsDf,
|
|
650
|
+
mdCol, bound, cellValue, this.mutationCliffsSelection, this.substitutionsInfo,
|
|
651
|
+
this.settings.isBidirectional);
|
|
752
652
|
}
|
|
753
653
|
}
|
|
754
654
|
args.preventDefault();
|
|
@@ -760,22 +660,40 @@ export class PeptidesModel {
|
|
|
760
660
|
|
|
761
661
|
this.sourceGrid.setOptions({'colHeaderHeight': 130});
|
|
762
662
|
this.sourceGrid.onCellRender.subscribe((gcArgs) => {
|
|
763
|
-
const
|
|
663
|
+
const ctx = gcArgs.g;
|
|
764
664
|
const bounds = gcArgs.bounds;
|
|
765
665
|
const col = gcArgs.cell.tableColumn;
|
|
766
666
|
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
667
|
+
ctx.save();
|
|
668
|
+
ctx.beginPath();
|
|
669
|
+
ctx.rect(bounds.x, bounds.y, bounds.width, bounds.height);
|
|
670
|
+
ctx.clip();
|
|
771
671
|
|
|
772
672
|
if (gcArgs.cell.isColHeader && col?.semType == C.SEM_TYPES.MONOMER) {
|
|
773
|
-
const
|
|
774
|
-
|
|
673
|
+
const countStatsCol: DG.Column<number> = this.monomerPositionStatsDf.getCol(C.COLUMNS_NAMES.COUNT);
|
|
674
|
+
const monomerStatsCol: DG.Column<string> = this.monomerPositionStatsDf.getCol(C.COLUMNS_NAMES.MONOMER);
|
|
675
|
+
const positionStatsCol: DG.Column<string> = this.monomerPositionStatsDf.getCol(C.COLUMNS_NAMES.POSITION);
|
|
676
|
+
const rowMask = DG.BitSet.create(this.monomerPositionStatsDf.rowCount, (i) => positionStatsCol.get(i) === col.name);
|
|
677
|
+
//TODO: precalc on stats creation
|
|
678
|
+
const sortedStatsOrder = this.monomerPositionStatsDf.getSortedOrder([C.COLUMNS_NAMES.COUNT], [false], rowMask)
|
|
679
|
+
.sort((a, b) => {
|
|
680
|
+
if (monomerStatsCol.get(a) === '-')
|
|
681
|
+
return -1;
|
|
682
|
+
else if (monomerStatsCol.get(b) === '-')
|
|
683
|
+
return +1;
|
|
684
|
+
return 0;
|
|
685
|
+
});
|
|
686
|
+
const statsInfo: type.StatsInfo = {
|
|
687
|
+
countCol: countStatsCol,
|
|
688
|
+
monomerCol: monomerStatsCol,
|
|
689
|
+
orderedIndexes: sortedStatsOrder,
|
|
690
|
+
};
|
|
691
|
+
|
|
692
|
+
CR.drawLogoInBounds(ctx, bounds, statsInfo, this.df.rowCount, this.cp);
|
|
775
693
|
gcArgs.preventDefault();
|
|
776
694
|
}
|
|
777
695
|
|
|
778
|
-
|
|
696
|
+
ctx.restore();
|
|
779
697
|
});
|
|
780
698
|
}
|
|
781
699
|
|
|
@@ -816,14 +734,13 @@ export class PeptidesModel {
|
|
|
816
734
|
const tooltipElements: HTMLDivElement[] = [];
|
|
817
735
|
const monomerName = aar.toLowerCase();
|
|
818
736
|
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
.find((m) => m != null) ?? null;
|
|
737
|
+
let mw = getMonomerWorks();
|
|
738
|
+
let mol = mw?.getCappedRotatedMonomer('PEPTIDE', aar);
|
|
822
739
|
|
|
823
|
-
if (
|
|
824
|
-
tooltipElements.push(ui.div(
|
|
740
|
+
if (mol) {
|
|
741
|
+
tooltipElements.push(ui.div(monomerName));
|
|
825
742
|
const options = {autoCrop: true, autoCropMargin: 0, suppressChiralText: true};
|
|
826
|
-
tooltipElements.push(grok.chem.svgMol(
|
|
743
|
+
tooltipElements.push(grok.chem.svgMol(mol, undefined, undefined, options));
|
|
827
744
|
} else
|
|
828
745
|
tooltipElements.push(ui.div(aar));
|
|
829
746
|
|
|
@@ -886,7 +803,7 @@ export class PeptidesModel {
|
|
|
886
803
|
(aar: string, position: string, isShiftPressed: boolean, isInvariantMapSelection: boolean = true): void => {
|
|
887
804
|
isShiftPressed ? this.modifyMonomerPositionSelection(aar, position, isInvariantMapSelection) :
|
|
888
805
|
this.initMonomerPositionSelection(aar, position, isInvariantMapSelection);
|
|
889
|
-
this.barData = calculateBarsData(this.df.columns.bySemTypeAll(C.SEM_TYPES.MONOMER), this.df.selection);
|
|
806
|
+
// this.barData = calculateBarsData(this.df.columns.bySemTypeAll(C.SEM_TYPES.MONOMER), this.df.selection);
|
|
890
807
|
};
|
|
891
808
|
|
|
892
809
|
this.mutationCliffsGrid.root.addEventListener('click', (ev) => {
|
|
@@ -997,18 +914,26 @@ export class PeptidesModel {
|
|
|
997
914
|
};
|
|
998
915
|
|
|
999
916
|
selection.onChanged.subscribe(() => changeSelectionBitset(selection));
|
|
917
|
+
|
|
1000
918
|
filter.onChanged.subscribe(() => {
|
|
1001
919
|
const positionList = Object.keys(this.invariantMapSelection);
|
|
1002
|
-
|
|
920
|
+
const invariantMapBitset = DG.BitSet.create(filter.length, (index) => {
|
|
1003
921
|
let result = true;
|
|
1004
922
|
for (const position of positionList) {
|
|
1005
923
|
const aarList = this.invariantMapSelection[position];
|
|
1006
924
|
result &&= aarList.length === 0 || aarList.includes(this.df.get(position, index));
|
|
1007
925
|
if (!result)
|
|
1008
|
-
|
|
926
|
+
return result;
|
|
1009
927
|
}
|
|
1010
|
-
|
|
1011
|
-
}
|
|
928
|
+
return result;
|
|
929
|
+
});
|
|
930
|
+
|
|
931
|
+
if (!this.isInvariantMapTrigger)
|
|
932
|
+
this.initBitset = filter.clone();
|
|
933
|
+
|
|
934
|
+
// filter.copyFrom(invariantMapBitset.and(this.initBitset), false);
|
|
935
|
+
const temp = invariantMapBitset.and(this.initBitset);
|
|
936
|
+
filter.init((i) => temp.get(i), false);
|
|
1012
937
|
});
|
|
1013
938
|
this.isBitsetChangedInitialized = true;
|
|
1014
939
|
}
|
|
@@ -1051,6 +976,14 @@ export class PeptidesModel {
|
|
|
1051
976
|
setViewerGridProps(this.mostPotentResiduesGrid);
|
|
1052
977
|
if (this.df.getTag(C.TAGS.CLUSTERS))
|
|
1053
978
|
setViewerGridProps(this.logoSummaryGrid);
|
|
979
|
+
|
|
980
|
+
for (let gcIndex = 0; gcIndex < this.sourceGrid.columns.length; ++gcIndex) {
|
|
981
|
+
const col = this.sourceGrid.columns.byIndex(gcIndex)!;
|
|
982
|
+
col.visible =
|
|
983
|
+
col.column?.semType === C.SEM_TYPES.MONOMER ||
|
|
984
|
+
col.column?.name === C.COLUMNS_NAMES.ACTIVITY_SCALED ||
|
|
985
|
+
Object.keys(this.settings.columns ?? {}).includes(col.column?.name ?? '');
|
|
986
|
+
}
|
|
1054
987
|
}
|
|
1055
988
|
|
|
1056
989
|
getSplitColValueAt(index: number, aar: string, position: string, aarLabel: string): string {
|
|
@@ -1066,43 +999,30 @@ export class PeptidesModel {
|
|
|
1066
999
|
this.splitCol.compact();
|
|
1067
1000
|
}
|
|
1068
1001
|
|
|
1069
|
-
syncProperties(isSourceSAR = true): void {
|
|
1070
|
-
if (this.mutationCliffsViewer && this.mostPotentResiduesViewer) {
|
|
1071
|
-
const [sourceViewer, targetViewer] = isSourceSAR ? [this.mutationCliffsViewer, this.mostPotentResiduesViewer] :
|
|
1072
|
-
[this.mostPotentResiduesViewer, this.mutationCliffsViewer];
|
|
1073
|
-
const properties = sourceViewer.props.getProperties();
|
|
1074
|
-
const newProps: { [propName: string]: string | number | boolean } = {};
|
|
1075
|
-
for (const property of properties) {
|
|
1076
|
-
const propName = property.name;
|
|
1077
|
-
const propVal = property.get(sourceViewer);
|
|
1078
|
-
targetViewer.props.set(propName, propVal);
|
|
1079
|
-
newProps[propName] = propVal;
|
|
1080
|
-
}
|
|
1081
|
-
this.usedProperties = newProps;
|
|
1082
|
-
} else
|
|
1083
|
-
console.warn('Warning: could not sync viewer properties, one of the viewers is not initialized');
|
|
1084
|
-
}
|
|
1085
|
-
|
|
1086
1002
|
/** Class initializer */
|
|
1087
1003
|
async init(): Promise<void> {
|
|
1088
1004
|
if (this.isInitialized)
|
|
1089
1005
|
return;
|
|
1006
|
+
this.isInitialized = true;
|
|
1090
1007
|
|
|
1091
|
-
//
|
|
1092
|
-
this.
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
this.monomerWorks = new bio.MonomerWorks(this.monomerLib);
|
|
1008
|
+
// Don't find the dataset if the analysis started from button
|
|
1009
|
+
if (this.df.getTag('newAnalysis') !== '1')
|
|
1010
|
+
this.currentView = wu(grok.shell.tableViews).find(({dataFrame}) => dataFrame.tags[C.PEPTIDES_ANALYSIS] === '1')!;
|
|
1011
|
+
|
|
1012
|
+
this.currentView ??= grok.shell.addTableView(this.df);
|
|
1097
1013
|
|
|
1098
|
-
this.
|
|
1099
|
-
|
|
1014
|
+
this.df.setTag('newAnalysis', '');
|
|
1015
|
+
if (!this.isRibbonSet) {
|
|
1016
|
+
const settingsButton = ui.bigButton('Settings', () => getSettingsDialog(this), 'Peptides analysis settings');
|
|
1017
|
+
this.currentView.setRibbonPanels([[settingsButton]], false);
|
|
1018
|
+
this.isRibbonSet = true;
|
|
1019
|
+
}
|
|
1100
1020
|
grok.shell.v = this.currentView;
|
|
1101
1021
|
this.sourceGrid = this.currentView.grid;
|
|
1102
|
-
if (this.df.tags[C.PEPTIDES_ANALYSIS] === '
|
|
1022
|
+
if (this.df.tags[C.PEPTIDES_ANALYSIS] === '1')
|
|
1103
1023
|
return;
|
|
1104
1024
|
|
|
1105
|
-
this.df.tags[C.PEPTIDES_ANALYSIS] = '
|
|
1025
|
+
this.df.tags[C.PEPTIDES_ANALYSIS] = '1';
|
|
1106
1026
|
const scaledGridCol = this.sourceGrid.col(C.COLUMNS_NAMES.ACTIVITY_SCALED)!;
|
|
1107
1027
|
scaledGridCol.name = scaledGridCol.column!.getTag('gridName');
|
|
1108
1028
|
scaledGridCol.format = '#.000';
|
|
@@ -1129,9 +1049,9 @@ export class PeptidesModel {
|
|
|
1129
1049
|
|
|
1130
1050
|
const dockManager = this.currentView.dockManager;
|
|
1131
1051
|
|
|
1132
|
-
|
|
1052
|
+
const mutationCliffsViewer = await this.df.plot.fromType('peptide-sar-viewer', options) as MutationCliffsViewer;
|
|
1133
1053
|
|
|
1134
|
-
|
|
1054
|
+
const mostPotentResiduesViewer =
|
|
1135
1055
|
await this.df.plot.fromType('peptide-sar-viewer-vertical', options) as MostPotentResiduesViewer;
|
|
1136
1056
|
|
|
1137
1057
|
if (this.df.getTag(C.TAGS.CLUSTERS)) {
|
|
@@ -1142,10 +1062,9 @@ export class PeptidesModel {
|
|
|
1142
1062
|
this.updateDefault();
|
|
1143
1063
|
|
|
1144
1064
|
const mcNode =
|
|
1145
|
-
dockManager.dock(
|
|
1065
|
+
dockManager.dock(mutationCliffsViewer, DG.DOCK_TYPE.DOWN, null, mutationCliffsViewer.name);
|
|
1146
1066
|
|
|
1147
|
-
dockManager.dock(
|
|
1148
|
-
this.mostPotentResiduesViewer, DG.DOCK_TYPE.RIGHT, mcNode, this.mostPotentResiduesViewer.name, 0.3);
|
|
1067
|
+
dockManager.dock(mostPotentResiduesViewer, DG.DOCK_TYPE.RIGHT, mcNode, mostPotentResiduesViewer.name, 0.3);
|
|
1149
1068
|
|
|
1150
1069
|
|
|
1151
1070
|
this.sourceGrid.props.allowEdit = false;
|
|
@@ -1153,6 +1072,4 @@ export class PeptidesModel {
|
|
|
1153
1072
|
|
|
1154
1073
|
this.invalidateGrids();
|
|
1155
1074
|
}
|
|
1156
|
-
|
|
1157
|
-
invalidateSourceGrid(): void {this.sourceGrid.invalidate();}
|
|
1158
1075
|
}
|