@datagrok/peptides 1.3.8 → 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 +357 -299
- package/dist/package.js +321 -261
- package/package.json +1 -1
- package/src/model.ts +132 -162
- package/src/package.ts +4 -4
- package/src/tests/algorithms.ts +51 -0
- package/src/tests/core.ts +10 -10
- package/src/utils/algorithms.ts +91 -0
- package/src/utils/cell-renderer.ts +35 -81
- package/src/utils/types.ts +24 -7
- package/src/widgets/manual-alignment.ts +2 -2
- package/src/widgets/peptides.ts +3 -2
- package/src/widgets/settings.ts +36 -6
- package/test-Peptides-62cc009524f3-0949dc07.html +276 -0
package/package.json
CHANGED
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,15 +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';
|
|
20
19
|
import {getSettingsDialog} from './widgets/settings';
|
|
21
|
-
import {
|
|
20
|
+
import {getMonomerWorks} from './package';
|
|
21
|
+
import * as bio from '@datagrok-libraries/bio';
|
|
22
|
+
import {findMutations} from './utils/algorithms';
|
|
22
23
|
|
|
23
24
|
export class PeptidesModel {
|
|
24
25
|
static modelName = 'peptidesModel';
|
|
@@ -51,15 +52,21 @@ export class PeptidesModel {
|
|
|
51
52
|
isChangingEdfBitset = false;
|
|
52
53
|
|
|
53
54
|
monomerMap: { [key: string]: { molfile: string, fullName: string } } = {};
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
cachedBarchartTooltip: { bar: string, tooltip: null | HTMLDivElement } = {bar: '', tooltip: null};
|
|
55
|
+
monomerLib: bio.IMonomerLib | null = null; // To get monomers from lib(s)
|
|
56
|
+
monomerWorks: bio.MonomerWorks | null = null; // To get processed monomers
|
|
57
57
|
|
|
58
58
|
_settings!: type.PeptidesSettings;
|
|
59
59
|
isRibbonSet = false;
|
|
60
60
|
|
|
61
|
+
cp: bio.SeqPalette;
|
|
62
|
+
xorBitset?: DG.BitSet;
|
|
63
|
+
initBitset: DG.BitSet;
|
|
64
|
+
isInvariantMapTrigger: boolean = false;;
|
|
65
|
+
|
|
61
66
|
private constructor(dataFrame: DG.DataFrame) {
|
|
62
67
|
this.df = dataFrame;
|
|
68
|
+
this.initBitset = this.df.filter.clone();
|
|
69
|
+
this.cp = bio.pickUpPalette(this.df.getCol(C.COLUMNS_NAMES.MACROMOLECULE));
|
|
63
70
|
}
|
|
64
71
|
|
|
65
72
|
static async getInstance(dataFrame: DG.DataFrame): Promise<PeptidesModel> {
|
|
@@ -100,7 +107,9 @@ export class PeptidesModel {
|
|
|
100
107
|
set invariantMapSelection(selection: type.PositionToAARList) {
|
|
101
108
|
this._invariantMapSelection = selection;
|
|
102
109
|
this.df.tags[C.TAGS.FILTER] = JSON.stringify(selection);
|
|
110
|
+
this.isInvariantMapTrigger = true;
|
|
103
111
|
this.df.filter.fireChanged();
|
|
112
|
+
this.isInvariantMapTrigger = false;
|
|
104
113
|
this.invalidateGrids();
|
|
105
114
|
}
|
|
106
115
|
|
|
@@ -180,7 +189,7 @@ export class PeptidesModel {
|
|
|
180
189
|
|
|
181
190
|
updateDefault(): void {
|
|
182
191
|
if ((this.sourceGrid && !this._isUpdating) || !this.isInitialized) {
|
|
183
|
-
this.isInitialized = true;
|
|
192
|
+
// this.isInitialized = true;
|
|
184
193
|
this._isUpdating = true;
|
|
185
194
|
this.initializeViewersComponents();
|
|
186
195
|
//FIXME: modify during the initializeViewersComponents stages
|
|
@@ -204,7 +213,7 @@ export class PeptidesModel {
|
|
|
204
213
|
const alphabet = col.tags['alphabet'];
|
|
205
214
|
const splitSeqDf = splitAlignedSequences(col);
|
|
206
215
|
|
|
207
|
-
this.barData = calculateBarsData(splitSeqDf.columns.toList(), this.df.selection);
|
|
216
|
+
// this.barData = calculateBarsData(splitSeqDf.columns.toList(), this.df.selection);
|
|
208
217
|
|
|
209
218
|
const positionColumns = splitSeqDf.columns.names();
|
|
210
219
|
|
|
@@ -239,7 +248,9 @@ export class PeptidesModel {
|
|
|
239
248
|
// SAR vertical table (naive, choose best Mean difference from pVals <= 0.01)
|
|
240
249
|
const sequenceDf = this.createVerticalTable();
|
|
241
250
|
|
|
242
|
-
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);
|
|
243
254
|
|
|
244
255
|
[this.mutationCliffsGrid, this.mostPotentResiduesGrid] =
|
|
245
256
|
this.createGrids(matrixDf, sequenceDf, positionColumns, alphabet);
|
|
@@ -254,7 +265,7 @@ export class PeptidesModel {
|
|
|
254
265
|
|
|
255
266
|
positionColumns.push(C.COLUMNS_NAMES.MEAN_DIFFERENCE);
|
|
256
267
|
|
|
257
|
-
this.setBarChartInteraction();
|
|
268
|
+
// this.setBarChartInteraction();
|
|
258
269
|
|
|
259
270
|
this.setCellRenderers(positionColumns);
|
|
260
271
|
|
|
@@ -268,91 +279,6 @@ export class PeptidesModel {
|
|
|
268
279
|
this.postProcessGrids();
|
|
269
280
|
}
|
|
270
281
|
|
|
271
|
-
//TODO: move out
|
|
272
|
-
calcSubstitutions(): void {
|
|
273
|
-
const activityValues: DG.Column<number> = this.df.columns.bySemType(C.SEM_TYPES.ACTIVITY_SCALED)!;
|
|
274
|
-
const columnList: DG.Column<string>[] = this.df.columns.bySemTypeAll(C.SEM_TYPES.MONOMER);
|
|
275
|
-
const nCols = columnList.length;
|
|
276
|
-
if (nCols == 0)
|
|
277
|
-
throw new Error(`Couldn't find any column of semType '${C.SEM_TYPES.MONOMER}'`);
|
|
278
|
-
|
|
279
|
-
this.substitutionsInfo = new Map();
|
|
280
|
-
const nRows = this.df.rowCount;
|
|
281
|
-
for (let seq1Idx = 0; seq1Idx < nRows - 1; seq1Idx++) {
|
|
282
|
-
for (let seq2Idx = seq1Idx + 1; seq2Idx < nRows; seq2Idx++) {
|
|
283
|
-
let substCounter = 0;
|
|
284
|
-
const activityValSeq1 = activityValues.get(seq1Idx)!;
|
|
285
|
-
const activityValSeq2 = activityValues.get(seq2Idx)!;
|
|
286
|
-
const delta = activityValSeq1 - activityValSeq2;
|
|
287
|
-
if (Math.abs(delta) < (this.settings.minActivityDelta ?? 0))
|
|
288
|
-
continue;
|
|
289
|
-
|
|
290
|
-
let substCounterFlag = false;
|
|
291
|
-
const tempData: { pos: string, seq1monomer: string, seq2monomer: string, seq1Idx: number, seq2Idx: number }[] =
|
|
292
|
-
[];
|
|
293
|
-
for (const currentPosCol of columnList) {
|
|
294
|
-
const seq1monomer = currentPosCol.get(seq1Idx)!;
|
|
295
|
-
const seq2monomer = currentPosCol.get(seq2Idx)!;
|
|
296
|
-
if (seq1monomer == seq2monomer)
|
|
297
|
-
continue;
|
|
298
|
-
|
|
299
|
-
substCounter++;
|
|
300
|
-
substCounterFlag = substCounter > (this.settings.maxMutations ?? 1);
|
|
301
|
-
if (substCounterFlag)
|
|
302
|
-
break;
|
|
303
|
-
|
|
304
|
-
tempData.push({
|
|
305
|
-
pos: currentPosCol.name,
|
|
306
|
-
seq1monomer: seq1monomer,
|
|
307
|
-
seq2monomer: seq2monomer,
|
|
308
|
-
seq1Idx: seq1Idx,
|
|
309
|
-
seq2Idx: seq2Idx,
|
|
310
|
-
});
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
if (substCounterFlag || substCounter == 0)
|
|
314
|
-
continue;
|
|
315
|
-
|
|
316
|
-
for (const tempDataElement of tempData) {
|
|
317
|
-
const position = tempDataElement.pos;
|
|
318
|
-
|
|
319
|
-
//Working with seq1monomer
|
|
320
|
-
const seq1monomer = tempDataElement.seq1monomer;
|
|
321
|
-
if (!this.substitutionsInfo.has(seq1monomer))
|
|
322
|
-
this.substitutionsInfo.set(seq1monomer, new Map());
|
|
323
|
-
|
|
324
|
-
let positionsMap = this.substitutionsInfo.get(seq1monomer)!;
|
|
325
|
-
if (!positionsMap.has(position))
|
|
326
|
-
positionsMap.set(position, new Map());
|
|
327
|
-
|
|
328
|
-
let indexes = positionsMap.get(position)!;
|
|
329
|
-
|
|
330
|
-
!indexes.has(seq1Idx) ? indexes.set(seq1Idx, [seq2Idx]) : (indexes.get(seq1Idx)! as number[]).push(seq2Idx);
|
|
331
|
-
|
|
332
|
-
//Working with seq2monomer
|
|
333
|
-
const seq2monomer = tempDataElement.seq2monomer;
|
|
334
|
-
if (!this.substitutionsInfo.has(seq2monomer))
|
|
335
|
-
this.substitutionsInfo.set(seq2monomer, new Map());
|
|
336
|
-
|
|
337
|
-
positionsMap = this.substitutionsInfo.get(seq2monomer)!;
|
|
338
|
-
if (!positionsMap.has(position))
|
|
339
|
-
positionsMap.set(position, new Map());
|
|
340
|
-
|
|
341
|
-
indexes = positionsMap.get(position)!;
|
|
342
|
-
!indexes.has(seq2Idx) ? indexes.set(seq2Idx, [seq1Idx]) : (indexes.get(seq2Idx)! as number[]).push(seq1Idx);
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
const TypedArray = getTypedArrayConstructor(nRows);
|
|
348
|
-
for (const positionMap of this.substitutionsInfo.values()) {
|
|
349
|
-
for (const indexMap of positionMap.values()) {
|
|
350
|
-
for (const [index, indexArray] of indexMap.entries())
|
|
351
|
-
indexMap.set(index, new TypedArray(indexArray));
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
|
|
356
282
|
initSelections(positionColumns: string[]): void {
|
|
357
283
|
const tempInvariantMapSelection: type.PositionToAARList = this.invariantMapSelection;
|
|
358
284
|
const mutationCliffsSelection: type.PositionToAARList = this.mutationCliffsSelection;
|
|
@@ -362,7 +288,7 @@ export class PeptidesModel {
|
|
|
362
288
|
}
|
|
363
289
|
this.invariantMapSelection = tempInvariantMapSelection;
|
|
364
290
|
this.mutationCliffsSelection = mutationCliffsSelection;
|
|
365
|
-
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);
|
|
366
292
|
}
|
|
367
293
|
|
|
368
294
|
joinDataFrames(positionColumns: string[], splitSeqDf: DG.DataFrame, alphabet: string): void {
|
|
@@ -563,6 +489,9 @@ export class PeptidesModel {
|
|
|
563
489
|
tempDfList[index] = dfSlice;
|
|
564
490
|
webLogoCol.set(index, index.toString());
|
|
565
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);
|
|
566
495
|
}
|
|
567
496
|
webLogoCol.setTag(DG.TAGS.CELL_RENDERER, 'html');
|
|
568
497
|
|
|
@@ -589,7 +518,7 @@ export class PeptidesModel {
|
|
|
589
518
|
this.modifyClusterSelection(cluster);
|
|
590
519
|
else
|
|
591
520
|
this.initClusterSelection(cluster);
|
|
592
|
-
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);
|
|
593
522
|
});
|
|
594
523
|
grid.onCellRender.subscribe((gridCellArgs) => {
|
|
595
524
|
const gc = gridCellArgs.cell;
|
|
@@ -632,51 +561,51 @@ export class PeptidesModel {
|
|
|
632
561
|
this.logoSummarySelection = [cluster];
|
|
633
562
|
}
|
|
634
563
|
|
|
635
|
-
setBarChartInteraction(): void {
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
findAARandPosition(cell: DG.GridCell, ev: MouseEvent): { monomer: string, position: string } | null {
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
requestBarchartAction(ev: MouseEvent, barPart: { position: string, monomer: string } | null): void {
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
}
|
|
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
|
+
// }
|
|
680
609
|
|
|
681
610
|
setCellRenderers(renderColNames: string[]): void {
|
|
682
611
|
const mdCol = this.monomerPositionStatsDf.getCol(C.COLUMNS_NAMES.MEAN_DIFFERENCE);
|
|
@@ -731,22 +660,40 @@ export class PeptidesModel {
|
|
|
731
660
|
|
|
732
661
|
this.sourceGrid.setOptions({'colHeaderHeight': 130});
|
|
733
662
|
this.sourceGrid.onCellRender.subscribe((gcArgs) => {
|
|
734
|
-
const
|
|
663
|
+
const ctx = gcArgs.g;
|
|
735
664
|
const bounds = gcArgs.bounds;
|
|
736
665
|
const col = gcArgs.cell.tableColumn;
|
|
737
666
|
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
667
|
+
ctx.save();
|
|
668
|
+
ctx.beginPath();
|
|
669
|
+
ctx.rect(bounds.x, bounds.y, bounds.width, bounds.height);
|
|
670
|
+
ctx.clip();
|
|
742
671
|
|
|
743
672
|
if (gcArgs.cell.isColHeader && col?.semType == C.SEM_TYPES.MONOMER) {
|
|
744
|
-
const
|
|
745
|
-
|
|
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);
|
|
746
693
|
gcArgs.preventDefault();
|
|
747
694
|
}
|
|
748
695
|
|
|
749
|
-
|
|
696
|
+
ctx.restore();
|
|
750
697
|
});
|
|
751
698
|
}
|
|
752
699
|
|
|
@@ -787,7 +734,7 @@ export class PeptidesModel {
|
|
|
787
734
|
const tooltipElements: HTMLDivElement[] = [];
|
|
788
735
|
const monomerName = aar.toLowerCase();
|
|
789
736
|
|
|
790
|
-
let mw =
|
|
737
|
+
let mw = getMonomerWorks();
|
|
791
738
|
let mol = mw?.getCappedRotatedMonomer('PEPTIDE', aar);
|
|
792
739
|
|
|
793
740
|
if (mol) {
|
|
@@ -856,7 +803,7 @@ export class PeptidesModel {
|
|
|
856
803
|
(aar: string, position: string, isShiftPressed: boolean, isInvariantMapSelection: boolean = true): void => {
|
|
857
804
|
isShiftPressed ? this.modifyMonomerPositionSelection(aar, position, isInvariantMapSelection) :
|
|
858
805
|
this.initMonomerPositionSelection(aar, position, isInvariantMapSelection);
|
|
859
|
-
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);
|
|
860
807
|
};
|
|
861
808
|
|
|
862
809
|
this.mutationCliffsGrid.root.addEventListener('click', (ev) => {
|
|
@@ -967,18 +914,26 @@ export class PeptidesModel {
|
|
|
967
914
|
};
|
|
968
915
|
|
|
969
916
|
selection.onChanged.subscribe(() => changeSelectionBitset(selection));
|
|
917
|
+
|
|
970
918
|
filter.onChanged.subscribe(() => {
|
|
971
919
|
const positionList = Object.keys(this.invariantMapSelection);
|
|
972
|
-
|
|
920
|
+
const invariantMapBitset = DG.BitSet.create(filter.length, (index) => {
|
|
973
921
|
let result = true;
|
|
974
922
|
for (const position of positionList) {
|
|
975
923
|
const aarList = this.invariantMapSelection[position];
|
|
976
924
|
result &&= aarList.length === 0 || aarList.includes(this.df.get(position, index));
|
|
977
925
|
if (!result)
|
|
978
|
-
|
|
926
|
+
return result;
|
|
979
927
|
}
|
|
980
|
-
|
|
981
|
-
}
|
|
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);
|
|
982
937
|
});
|
|
983
938
|
this.isBitsetChangedInitialized = true;
|
|
984
939
|
}
|
|
@@ -1021,6 +976,14 @@ export class PeptidesModel {
|
|
|
1021
976
|
setViewerGridProps(this.mostPotentResiduesGrid);
|
|
1022
977
|
if (this.df.getTag(C.TAGS.CLUSTERS))
|
|
1023
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
|
+
}
|
|
1024
987
|
}
|
|
1025
988
|
|
|
1026
989
|
getSplitColValueAt(index: number, aar: string, position: string, aarLabel: string): string {
|
|
@@ -1040,19 +1003,26 @@ export class PeptidesModel {
|
|
|
1040
1003
|
async init(): Promise<void> {
|
|
1041
1004
|
if (this.isInitialized)
|
|
1042
1005
|
return;
|
|
1006
|
+
this.isInitialized = true;
|
|
1007
|
+
|
|
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);
|
|
1043
1013
|
|
|
1044
|
-
this.
|
|
1045
|
-
grok.shell.addTableView(this.df);
|
|
1014
|
+
this.df.setTag('newAnalysis', '');
|
|
1046
1015
|
if (!this.isRibbonSet) {
|
|
1047
|
-
|
|
1016
|
+
const settingsButton = ui.bigButton('Settings', () => getSettingsDialog(this), 'Peptides analysis settings');
|
|
1017
|
+
this.currentView.setRibbonPanels([[settingsButton]], false);
|
|
1048
1018
|
this.isRibbonSet = true;
|
|
1049
1019
|
}
|
|
1050
1020
|
grok.shell.v = this.currentView;
|
|
1051
1021
|
this.sourceGrid = this.currentView.grid;
|
|
1052
|
-
if (this.df.tags[C.PEPTIDES_ANALYSIS] === '
|
|
1022
|
+
if (this.df.tags[C.PEPTIDES_ANALYSIS] === '1')
|
|
1053
1023
|
return;
|
|
1054
1024
|
|
|
1055
|
-
this.df.tags[C.PEPTIDES_ANALYSIS] = '
|
|
1025
|
+
this.df.tags[C.PEPTIDES_ANALYSIS] = '1';
|
|
1056
1026
|
const scaledGridCol = this.sourceGrid.col(C.COLUMNS_NAMES.ACTIVITY_SCALED)!;
|
|
1057
1027
|
scaledGridCol.name = scaledGridCol.column!.getTag('gridName');
|
|
1058
1028
|
scaledGridCol.format = '#.000';
|
package/src/package.ts
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
import * as grok from 'datagrok-api/grok';
|
|
3
3
|
import * as ui from 'datagrok-api/ui';
|
|
4
4
|
import * as DG from 'datagrok-api/dg';
|
|
5
|
-
import * as bio from '@datagrok-libraries/bio';
|
|
6
5
|
import * as C from './utils/constants';
|
|
7
6
|
|
|
8
7
|
import {analyzePeptidesUI} from './widgets/peptides';
|
|
@@ -12,14 +11,15 @@ import {MutationCliffsViewer, MostPotentResiduesViewer} from './viewers/sar-view
|
|
|
12
11
|
|
|
13
12
|
import {PeptideSpaceViewer} from './viewers/peptide-space-viewer';
|
|
14
13
|
import {LogoSummary} from './viewers/logo-summary';
|
|
14
|
+
import {MonomerWorks} from '@datagrok-libraries/bio';
|
|
15
15
|
|
|
16
|
-
export let monomerWorks:
|
|
16
|
+
export let monomerWorks: MonomerWorks | null;
|
|
17
17
|
|
|
18
18
|
export const _package = new DG.Package();
|
|
19
19
|
let currentTable: DG.DataFrame;
|
|
20
20
|
let alignedSequenceColumn: DG.Column;
|
|
21
21
|
|
|
22
|
-
export function
|
|
22
|
+
export function getMonomerWorks() {
|
|
23
23
|
return monomerWorks;
|
|
24
24
|
};
|
|
25
25
|
|
|
@@ -42,7 +42,7 @@ export async function Peptides(): Promise<void> {
|
|
|
42
42
|
const textLink = ui.inlineText(['For more details, see our ', wikiLink, '.']);
|
|
43
43
|
if (monomerWorks == null) {
|
|
44
44
|
let lib = await grok.functions.call('Bio:getBioLib');
|
|
45
|
-
monomerWorks = new
|
|
45
|
+
monomerWorks = new MonomerWorks(lib);
|
|
46
46
|
}
|
|
47
47
|
const appDescription = ui.info(
|
|
48
48
|
[
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import * as grok from 'datagrok-api/grok';
|
|
2
|
+
import * as DG from 'datagrok-api/dg';
|
|
3
|
+
|
|
4
|
+
import {category, test, expect, delay, before} from '@datagrok-libraries/utils/src/test';
|
|
5
|
+
|
|
6
|
+
import {_package} from '../package-test';
|
|
7
|
+
import {startAnalysis} from '../widgets/peptides';
|
|
8
|
+
import {PeptidesModel} from '../model';
|
|
9
|
+
import * as C from '../utils/constants';
|
|
10
|
+
import {scaleActivity} from '../utils/misc';
|
|
11
|
+
import {ALPHABET, TAGS, NOTATION, ALIGNMENT} from '@datagrok-libraries/bio';
|
|
12
|
+
import {findMutations} from '../utils/algorithms';
|
|
13
|
+
import * as type from '../utils/types';
|
|
14
|
+
|
|
15
|
+
category('Algorithms', () => {
|
|
16
|
+
let activityCol: DG.Column<number>;
|
|
17
|
+
let monomerColumns: DG.Column<string>[];
|
|
18
|
+
let settings: type.PeptidesSettings;
|
|
19
|
+
|
|
20
|
+
before(async () => {
|
|
21
|
+
activityCol = DG.Column.fromList('int', 'test', [1, 2, 5]);
|
|
22
|
+
monomerColumns = [
|
|
23
|
+
DG.Column.fromList('string', '1', 'ABC'.split('')),
|
|
24
|
+
DG.Column.fromList('string', '2', 'ACC'.split('')),
|
|
25
|
+
DG.Column.fromList('string', '3', 'ACD'.split('')),
|
|
26
|
+
];
|
|
27
|
+
settings = {maxMutations: 1, minActivityDelta: 2};
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test('MutationCliffs', async () => {
|
|
31
|
+
const substInfo: type.SubstitutionsInfo = findMutations(activityCol, monomerColumns, settings);
|
|
32
|
+
expect(substInfo.has('C'), true);
|
|
33
|
+
expect(substInfo.has('D'), true);
|
|
34
|
+
expect(substInfo.has('A'), false);
|
|
35
|
+
|
|
36
|
+
const c = substInfo.get('C')!;
|
|
37
|
+
const d = substInfo.get('D')!;
|
|
38
|
+
expect(c.has('3'), true);
|
|
39
|
+
expect(d.has('3'), true);
|
|
40
|
+
|
|
41
|
+
const c3 = c.get('3')!;
|
|
42
|
+
const d3 = d.get('3')!;
|
|
43
|
+
expect(c3.has(2), true);
|
|
44
|
+
expect(d3.has(3), true);
|
|
45
|
+
|
|
46
|
+
const c32 = c3.get(2)!;
|
|
47
|
+
const d33 = d3.get(3)!;
|
|
48
|
+
expect(c32[0], 3);
|
|
49
|
+
expect(d33[0], 2);
|
|
50
|
+
});
|
|
51
|
+
});
|
package/src/tests/core.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import * as grok from 'datagrok-api/grok';
|
|
2
2
|
import * as DG from 'datagrok-api/dg';
|
|
3
|
-
import * as bio from '@datagrok-libraries/bio';
|
|
4
3
|
|
|
5
4
|
import {category, test, expect, delay} from '@datagrok-libraries/utils/src/test';
|
|
6
5
|
|
|
@@ -9,6 +8,7 @@ import {startAnalysis} from '../widgets/peptides';
|
|
|
9
8
|
import {PeptidesModel} from '../model';
|
|
10
9
|
import * as C from '../utils/constants';
|
|
11
10
|
import {scaleActivity} from '../utils/misc';
|
|
11
|
+
import {ALPHABET, TAGS, NOTATION, ALIGNMENT} from '@datagrok-libraries/bio';
|
|
12
12
|
|
|
13
13
|
category('Core', () => {
|
|
14
14
|
let simpleTable: DG.DataFrame;
|
|
@@ -33,9 +33,9 @@ category('Core', () => {
|
|
|
33
33
|
simpleActivityCol = simpleTable.getCol(simpleActivityColName);
|
|
34
34
|
simpleAlignedSeqCol = simpleTable.getCol(alignedSequenceCol);
|
|
35
35
|
simpleAlignedSeqCol.semType = C.SEM_TYPES.MACROMOLECULE;
|
|
36
|
-
simpleAlignedSeqCol.setTag(C.TAGS.ALPHABET,
|
|
37
|
-
simpleAlignedSeqCol.setTag(DG.TAGS.UNITS,
|
|
38
|
-
simpleAlignedSeqCol.setTag(
|
|
36
|
+
simpleAlignedSeqCol.setTag(C.TAGS.ALPHABET, ALPHABET.PT);
|
|
37
|
+
simpleAlignedSeqCol.setTag(DG.TAGS.UNITS, NOTATION.FASTA);
|
|
38
|
+
simpleAlignedSeqCol.setTag(TAGS.aligned, ALIGNMENT.SEQ_MSA);
|
|
39
39
|
simpleScaledCol = scaleActivity(simpleActivityCol, '-lg');
|
|
40
40
|
|
|
41
41
|
model = await startAnalysis(simpleActivityCol, simpleAlignedSeqCol, null, simpleTable, simpleScaledCol, '-lg');
|
|
@@ -53,9 +53,9 @@ category('Core', () => {
|
|
|
53
53
|
complexActivityCol = complexTable.getCol(complexActivityColName);
|
|
54
54
|
complexAlignedSeqCol = complexTable.getCol('MSA');
|
|
55
55
|
complexAlignedSeqCol.semType = C.SEM_TYPES.MACROMOLECULE;
|
|
56
|
-
complexAlignedSeqCol.setTag(C.TAGS.ALPHABET,
|
|
57
|
-
complexAlignedSeqCol.setTag(DG.TAGS.UNITS,
|
|
58
|
-
complexAlignedSeqCol.setTag(
|
|
56
|
+
complexAlignedSeqCol.setTag(C.TAGS.ALPHABET, ALPHABET.UN);
|
|
57
|
+
complexAlignedSeqCol.setTag(DG.TAGS.UNITS, NOTATION.SEPARATOR);
|
|
58
|
+
complexAlignedSeqCol.setTag(TAGS.aligned, ALIGNMENT.SEQ_MSA);
|
|
59
59
|
complexAlignedSeqCol.tags[C.TAGS.SEPARATOR] = '/';
|
|
60
60
|
complexScaledCol = scaleActivity(complexActivityCol, '-lg');
|
|
61
61
|
|
|
@@ -75,9 +75,9 @@ category('Core', () => {
|
|
|
75
75
|
simpleActivityCol = simpleTable.getCol(simpleActivityColName);
|
|
76
76
|
simpleAlignedSeqCol = simpleTable.getCol(alignedSequenceCol);
|
|
77
77
|
simpleAlignedSeqCol.semType = C.SEM_TYPES.MACROMOLECULE;
|
|
78
|
-
simpleAlignedSeqCol.setTag(C.TAGS.ALPHABET,
|
|
79
|
-
simpleAlignedSeqCol.setTag(DG.TAGS.UNITS,
|
|
80
|
-
simpleAlignedSeqCol.setTag(
|
|
78
|
+
simpleAlignedSeqCol.setTag(C.TAGS.ALPHABET, ALPHABET.PT);
|
|
79
|
+
simpleAlignedSeqCol.setTag(DG.TAGS.UNITS, NOTATION.FASTA);
|
|
80
|
+
simpleAlignedSeqCol.setTag(TAGS.aligned, ALIGNMENT.SEQ_MSA);
|
|
81
81
|
simpleScaledCol = scaleActivity(simpleActivityCol, '-lg');
|
|
82
82
|
|
|
83
83
|
model = await startAnalysis(simpleActivityCol, simpleAlignedSeqCol, null, simpleTable, simpleScaledCol, '-lg');
|