@datagrok/peptides 1.21.3 → 1.21.5
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 +11 -0
- package/dist/package-test.js +1 -1
- package/dist/package-test.js.map +1 -1
- package/dist/package.js +1 -1
- package/dist/package.js.map +1 -1
- package/package.json +1 -1
- package/src/model.ts +1 -1
- package/src/package.ts +1 -0
- package/src/peptideUtils.ts +13 -0
- package/src/utils/cell-renderer.ts +8 -3
- package/src/viewers/sar-viewer.ts +5 -4
- package/src/widgets/mutation-cliffs.ts +20 -6
- package/test-console-output-1.log +5971 -73
- package/test-record-1.mp4 +0 -0
package/package.json
CHANGED
package/src/model.ts
CHANGED
|
@@ -150,7 +150,7 @@ export class PeptidesModel {
|
|
|
150
150
|
this._analysisView = grok.shell.addTableView(this.df);
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
-
if (this.df.getTag(C.TAGS.MULTIPLE_VIEWS) !== '1' && !this._layoutEventInitialized
|
|
153
|
+
if (this.df.getTag(C.TAGS.MULTIPLE_VIEWS) !== '1' && !this._layoutEventInitialized)
|
|
154
154
|
grok.shell.v = this._analysisView;
|
|
155
155
|
|
|
156
156
|
|
package/src/package.ts
CHANGED
|
@@ -37,6 +37,7 @@ export async function initPeptides(): Promise<void> {
|
|
|
37
37
|
monomerWorks ??= new MonomerWorks(await grok.functions.call('Bio:getBioLib'));
|
|
38
38
|
treeHelper ??= await getTreeHelper();
|
|
39
39
|
await PeptideUtils.loadSeqHelper();
|
|
40
|
+
await PeptideUtils.loadMonomerLib();
|
|
40
41
|
} catch (e) {
|
|
41
42
|
grok.log.error(e as string);
|
|
42
43
|
}
|
package/src/peptideUtils.ts
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
|
+
import {getMonomerLibHelper, IMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
|
|
2
|
+
import {IMonomerLib} from '@datagrok-libraries/bio/src/types';
|
|
1
3
|
import {getSeqHelper, ISeqHelper} from '@datagrok-libraries/bio/src/utils/seq-helper';
|
|
2
4
|
|
|
3
5
|
export class PeptideUtils {
|
|
4
6
|
private static _secHelper: ISeqHelper;
|
|
7
|
+
private static _monomerLibHelper: IMonomerLibHelper;
|
|
8
|
+
public static getMonomerLib(): IMonomerLib {
|
|
9
|
+
if (!this._monomerLibHelper)
|
|
10
|
+
throw new Error('MonomerLib is not initialized');
|
|
11
|
+
return this._monomerLibHelper.getMonomerLib();
|
|
12
|
+
}
|
|
5
13
|
public static getSeqHelper(): ISeqHelper {
|
|
6
14
|
if (!this._secHelper)
|
|
7
15
|
throw new Error('SeqHelper is not initialized');
|
|
@@ -11,4 +19,9 @@ export class PeptideUtils {
|
|
|
11
19
|
public static async loadSeqHelper(): Promise<void> {
|
|
12
20
|
this._secHelper ??= await getSeqHelper();
|
|
13
21
|
}
|
|
22
|
+
|
|
23
|
+
public static async loadMonomerLib(): Promise<void> {
|
|
24
|
+
this._monomerLibHelper ??= await getMonomerLibHelper();
|
|
25
|
+
await this._monomerLibHelper.awaitLoaded();
|
|
26
|
+
}
|
|
14
27
|
}
|
|
@@ -13,6 +13,9 @@ import {MonomerPositionStats, MonomerPositionStatsCache, PositionStats} from './
|
|
|
13
13
|
import {CLUSTER_TYPE} from '../viewers/logo-summary';
|
|
14
14
|
import {MonomerPosition, MostPotentResidues, SARViewer} from '../viewers/sar-viewer';
|
|
15
15
|
import {MONOMER_RENDERER_TAGS} from '@datagrok-libraries/bio/src/utils/cell-renderer';
|
|
16
|
+
import { getMonomerLibHelper } from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
|
|
17
|
+
import { PeptideUtils } from '../peptideUtils';
|
|
18
|
+
import { HelmTypes } from '@datagrok-libraries/bio/src/helm/consts';
|
|
16
19
|
|
|
17
20
|
/**
|
|
18
21
|
* Renders cell selection border.
|
|
@@ -51,7 +54,7 @@ export function renderMutationCliffCell(canvasContext: CanvasRenderingContext2D,
|
|
|
51
54
|
const halfWidth = bounds.width / 2;
|
|
52
55
|
const midX = Math.ceil(bounds.x + 1 + halfWidth);
|
|
53
56
|
const midY = Math.ceil(bounds.y + 1 + bounds.height / 2);
|
|
54
|
-
const maxRadius = 0.9 * halfWidth / 2; // Fill at most 90% of the half of the cell width
|
|
57
|
+
const maxRadius = Math.min(0.9 * halfWidth / 2, 0.9 * bounds.height / 2); // Fill at most 90% of the half of the cell width
|
|
55
58
|
// render most potent residues cells according to the p-value (color) and mean difference (size)
|
|
56
59
|
if (viewer instanceof MostPotentResidues) {
|
|
57
60
|
const positionStats = viewer.monomerPositionStats[currentPosition];
|
|
@@ -230,6 +233,7 @@ export function drawLogoInBounds(ctx: CanvasRenderingContext2D, bounds: DG.Rect,
|
|
|
230
233
|
const barWidth = (bounds.width - (leftShift + drawOptions.marginHorizontal)) * pr;
|
|
231
234
|
const xStart = (bounds.x + leftShift) * pr;
|
|
232
235
|
|
|
236
|
+
const monomerLib = PeptideUtils.getMonomerLib();
|
|
233
237
|
const monomerBounds: { [monomer: string]: DG.Rect } = {};
|
|
234
238
|
for (const monomer of sortedOrder) {
|
|
235
239
|
const monomerHeight = barHeight * (stats[monomer]!.count / rowCount);
|
|
@@ -246,8 +250,8 @@ export function drawLogoInBounds(ctx: CanvasRenderingContext2D, bounds: DG.Rect,
|
|
|
246
250
|
ctx.lineWidth = selectionWidth;
|
|
247
251
|
ctx.line(xSelection, currentY, xSelection, currentY + selectionHeight, DG.Color.rowSelection);
|
|
248
252
|
}
|
|
249
|
-
|
|
250
|
-
ctx.fillStyle =
|
|
253
|
+
const monomerColor = monomerLib.getMonomerTextColor(HelmTypes.AA, monomer);
|
|
254
|
+
ctx.fillStyle = monomerColor;
|
|
251
255
|
ctx.textAlign = 'left';
|
|
252
256
|
ctx.textBaseline = 'top';
|
|
253
257
|
ctx.font = drawOptions.symbolStyle;
|
|
@@ -318,6 +322,7 @@ export function setWebLogoRenderer(grid: DG.Grid, monomerPositionStats: MonomerP
|
|
|
318
322
|
ctx.save();
|
|
319
323
|
try {
|
|
320
324
|
ctx.beginPath();
|
|
325
|
+
ctx.clearRect(bounds.x, bounds.y, bounds.width, bounds.height);
|
|
321
326
|
ctx.rect(bounds.x, bounds.y, bounds.width, bounds.height);
|
|
322
327
|
ctx.clip();
|
|
323
328
|
|
|
@@ -427,7 +427,7 @@ export abstract class SARViewer extends DG.JsViewer implements ISARViewer {
|
|
|
427
427
|
|
|
428
428
|
private resetTargetCategoryValue(): void {
|
|
429
429
|
const colName = this.targetColumnName;
|
|
430
|
-
const col = this.dataFrame.col(colName);
|
|
430
|
+
const col = colName ? this.dataFrame.col(colName) : null;
|
|
431
431
|
this.targetCategoryInput.items = col?.categories ?? [];
|
|
432
432
|
this.targetCategoryInput.value = null;
|
|
433
433
|
if (!colName)
|
|
@@ -676,11 +676,11 @@ export class MonomerPosition extends SARViewer {
|
|
|
676
676
|
if (isApplicableDataframe(this.dataFrame)) {
|
|
677
677
|
this.getProperty(`${MONOMER_POSITION_PROPERTIES.COLOR}${COLUMN_NAME}`)
|
|
678
678
|
?.set(this, this.activityColumnName);
|
|
679
|
-
this.targetColumnInput = ui.input.column('Target', {value: undefined, nullable: true, table: this.dataFrame,
|
|
679
|
+
this.targetColumnInput = ui.input.column('Target', {value: undefined, nullable: true, table: this.dataFrame, filter: (col: DG.Column) => col.isCategorical,
|
|
680
680
|
onValueChanged: (value) => {
|
|
681
681
|
const prop = this.getProperty(`${SAR_PROPERTIES.TARGET}${COLUMN_NAME}`);
|
|
682
|
-
if (prop && prop.get(this)
|
|
683
|
-
prop?.set(this, value
|
|
682
|
+
if (prop && prop.get(this) != (value?.name ?? null))
|
|
683
|
+
prop?.set(this, value?.name ?? null);
|
|
684
684
|
},
|
|
685
685
|
});
|
|
686
686
|
} else {
|
|
@@ -1338,6 +1338,7 @@ export class MostPotentResidues extends SARViewer {
|
|
|
1338
1338
|
const afterDraw = grid.onAfterDrawContent.subscribe(() => {
|
|
1339
1339
|
const monomerGCol = grid.col(C.COLUMNS_NAMES.MONOMER)!;
|
|
1340
1340
|
if (monomerGCol.width === AAR_CELL_WIDTH) {
|
|
1341
|
+
mdCol.width = MUTATION_CLIFFS_CELL_WIDTH;
|
|
1341
1342
|
afterDraw.unsubscribe();
|
|
1342
1343
|
return;
|
|
1343
1344
|
}
|
|
@@ -34,20 +34,25 @@ export function mutationCliffsWidget(
|
|
|
34
34
|
addExpandIconGen('Mutation Cliffs pairs', aminoToInput.root, widgetRoot,
|
|
35
35
|
() => {
|
|
36
36
|
const parts = cliffsPairsWidgetParts(table, options);
|
|
37
|
-
const div = ui.
|
|
38
|
-
{style: {
|
|
37
|
+
const div = ui.splitH(
|
|
38
|
+
[ui.divV([parts!.aminoToInput.root, parts!.pairsGrid.root], {style: {marginRight: '10px'}}),
|
|
39
|
+
ui.divV([parts!.uniqueSequencesGrid.root], {style: {marginLeft: '10px'}})],
|
|
40
|
+
{style: {width: '100%', height: '100%'}}, true);
|
|
39
41
|
|
|
40
42
|
setTimeout(() => {
|
|
41
43
|
if (document.contains(div)) {
|
|
42
44
|
const dW = div.offsetWidth;
|
|
43
45
|
const pairsGridParent = parts!.pairsGrid.canvas?.parentElement;
|
|
46
|
+
parts!.pairsGrid.props.showRowHeader = true;
|
|
47
|
+
parts!.uniqueSequencesGrid.props.showRowHeader = true;
|
|
44
48
|
const uniqueSequencesGridParent = parts!.uniqueSequencesGrid.canvas?.parentElement;
|
|
45
49
|
if (pairsGridParent && uniqueSequencesGridParent) {
|
|
46
50
|
pairsGridParent.style.height = '100%';
|
|
47
51
|
uniqueSequencesGridParent.style.height = '100%';
|
|
48
52
|
uniqueSequencesGridParent.style.marginTop = '20px';
|
|
49
|
-
if (dW >
|
|
50
|
-
const macroMolWidth = Math.max(dW * 0.
|
|
53
|
+
if (dW > 400) {
|
|
54
|
+
const macroMolWidth = Math.max(dW * 0.33, 200);
|
|
55
|
+
|
|
51
56
|
const mutationGridCol = parts!.pairsGrid.columns.byName('Mutation');
|
|
52
57
|
if (mutationGridCol)
|
|
53
58
|
mutationGridCol.width = macroMolWidth;
|
|
@@ -79,6 +84,7 @@ function cliffsPairsWidgetParts(table: DG.DataFrame, options: MutationCliffsOpti
|
|
|
79
84
|
const substitutionsArray: string[] = [];
|
|
80
85
|
const deltaArray: number[] = [];
|
|
81
86
|
const substitutedToArray: string[] = [];
|
|
87
|
+
const mutationsGroupsArray: string[] = [];
|
|
82
88
|
const fromIdxArray: number[] = [];
|
|
83
89
|
const toIdxArray: number[] = [];
|
|
84
90
|
const alignedSeqCol = table.getCol(options.sequenceColumnName!);
|
|
@@ -89,6 +95,9 @@ function cliffsPairsWidgetParts(table: DG.DataFrame, options: MutationCliffsOpti
|
|
|
89
95
|
const seenIndexes = new Map<number, number[]>();
|
|
90
96
|
const uniqueSequencesBitSet = DG.BitSet.create(table.rowCount);
|
|
91
97
|
|
|
98
|
+
// one mutation position and monomer can contain multiple groups of substitutions
|
|
99
|
+
const mutationsGroupMap: Record<number, number> = {};
|
|
100
|
+
|
|
92
101
|
const positionColumns: { [colName: string]: DG.Column<string> } =
|
|
93
102
|
Object.fromEntries(options.positionColumns.map((col) => [col.name, col]));
|
|
94
103
|
for (const pos of positions) {
|
|
@@ -106,7 +115,9 @@ function cliffsPairsWidgetParts(table: DG.DataFrame, options: MutationCliffsOpti
|
|
|
106
115
|
for (const [referenceIdx, indexArray] of substitutionsMap.entries()) {
|
|
107
116
|
if (!filteredIndexes.includes(referenceIdx))
|
|
108
117
|
continue;
|
|
109
|
-
|
|
118
|
+
if (!mutationsGroupMap[referenceIdx])
|
|
119
|
+
mutationsGroupMap[referenceIdx] = Object.keys(mutationsGroupMap).length + 1;
|
|
120
|
+
const group = mutationsGroupMap[referenceIdx];
|
|
110
121
|
|
|
111
122
|
const forbiddentIndexes = seenIndexes.get(referenceIdx) ?? [];
|
|
112
123
|
const baseSequence = alignedSeqColCategories[alignedSeqColData[referenceIdx]];
|
|
@@ -125,6 +136,7 @@ function cliffsPairsWidgetParts(table: DG.DataFrame, options: MutationCliffsOpti
|
|
|
125
136
|
|
|
126
137
|
seenIndexes.get(subIdx)!.push(referenceIdx);
|
|
127
138
|
substitutionsArray.push(`${baseSequence}#${subSeq}`);
|
|
139
|
+
mutationsGroupsArray.push(`${group}`);
|
|
128
140
|
deltaArray.push(baseActivity - activityScaledColData[subIdx]);
|
|
129
141
|
substitutedToArray.push(posColCategories[posColData[subIdx]]);
|
|
130
142
|
fromIdxArray.push(referenceIdx);
|
|
@@ -142,10 +154,12 @@ function cliffsPairsWidgetParts(table: DG.DataFrame, options: MutationCliffsOpti
|
|
|
142
154
|
|
|
143
155
|
const substCol = DG.Column.fromStrings('Mutation', substitutionsArray);
|
|
144
156
|
const activityDeltaCol = DG.Column.fromList('double', 'Delta', deltaArray);
|
|
157
|
+
const mutationGroupCol = DG.Column.fromStrings('Group', mutationsGroupsArray);
|
|
145
158
|
const hiddenSubstToAarCol = DG.Column.fromStrings('~to', substitutedToArray);
|
|
146
159
|
const toIdxCol = DG.Column.fromList(DG.COLUMN_TYPE.INT, '~toIdx', toIdxArray);
|
|
147
160
|
const fromIdxCol = DG.Column.fromList(DG.COLUMN_TYPE.INT, '~fromIdx', fromIdxArray);
|
|
148
|
-
const pairsTable =
|
|
161
|
+
const pairsTable =
|
|
162
|
+
DG.DataFrame.fromColumns([substCol, activityDeltaCol, mutationGroupCol, hiddenSubstToAarCol, toIdxCol, fromIdxCol]);
|
|
149
163
|
pairsTable.name = 'Mutation Cliff pairs';
|
|
150
164
|
|
|
151
165
|
const aminoToInput = ui.input.string('Mutated to:', {value: '', onValueChanged: (value) => {
|