@datagrok/peptides 1.3.7 → 1.3.8
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 +1162 -362
- package/dist/package.js +745 -587
- package/package.json +2 -2
- package/src/model.ts +44 -97
- package/src/package.ts +23 -4
- package/src/tests/core.ts +3 -3
- package/src/utils/cell-renderer.ts +3 -3
- package/src/utils/misc.ts +1 -1
- package/src/utils/types.ts +4 -0
- package/src/viewers/sar-viewer.ts +7 -55
- package/src/widgets/distribution.ts +1 -1
- package/src/widgets/peptides.ts +49 -26
- package/src/widgets/settings.ts +37 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datagrok/peptides",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.8",
|
|
4
4
|
"author": {
|
|
5
5
|
"name": "Volodymyr Dyma",
|
|
6
6
|
"email": "vdyma@datagrok.ai"
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"directory": "packages/Peptides"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@datagrok-libraries/bio": "^5.
|
|
15
|
+
"@datagrok-libraries/bio": "^5.9.12",
|
|
16
16
|
"@datagrok-libraries/ml": "^2.0.1",
|
|
17
17
|
"@datagrok-libraries/statistics": "^0.1.6",
|
|
18
18
|
"@datagrok-libraries/utils": "^1.11.1",
|
package/src/model.ts
CHANGED
|
@@ -17,6 +17,8 @@ import {mutationCliffsWidget} from './widgets/mutation-cliffs';
|
|
|
17
17
|
import {getDistributionAndStats, getDistributionWidget} from './widgets/distribution';
|
|
18
18
|
import {getStats, Stats} from './utils/statistics';
|
|
19
19
|
import {LogoSummary} from './viewers/logo-summary';
|
|
20
|
+
import {getSettingsDialog} from './widgets/settings';
|
|
21
|
+
import {getMoomerWorks} from './package';
|
|
20
22
|
|
|
21
23
|
export class PeptidesModel {
|
|
22
24
|
static modelName = 'peptidesModel';
|
|
@@ -48,16 +50,13 @@ export class PeptidesModel {
|
|
|
48
50
|
isPeptideSpaceChangingBitset = false;
|
|
49
51
|
isChangingEdfBitset = false;
|
|
50
52
|
|
|
51
|
-
mutationCliffsViewer!: MutationCliffsViewer;
|
|
52
|
-
mostPotentResiduesViewer!: MostPotentResiduesViewer;
|
|
53
|
-
|
|
54
|
-
_usedProperties: { [propName: string]: string | number | boolean } = {};
|
|
55
53
|
monomerMap: { [key: string]: { molfile: string, fullName: string } } = {};
|
|
56
54
|
barData: type.MonomerDfStats = {};
|
|
57
55
|
barsBounds: { [position: string]: type.BarCoordinates } = {};
|
|
58
56
|
cachedBarchartTooltip: { bar: string, tooltip: null | HTMLDivElement } = {bar: '', tooltip: null};
|
|
59
|
-
|
|
60
|
-
|
|
57
|
+
|
|
58
|
+
_settings!: type.PeptidesSettings;
|
|
59
|
+
isRibbonSet = false;
|
|
61
60
|
|
|
62
61
|
private constructor(dataFrame: DG.DataFrame) {
|
|
63
62
|
this.df = dataFrame;
|
|
@@ -117,16 +116,6 @@ export class PeptidesModel {
|
|
|
117
116
|
this.invalidateGrids();
|
|
118
117
|
}
|
|
119
118
|
|
|
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
119
|
get splitByPos(): boolean {
|
|
131
120
|
const splitByPosFlag = (this.df.tags['distributionSplit'] ?? '00')[0];
|
|
132
121
|
return splitByPosFlag == '1' ? true : false;
|
|
@@ -156,9 +145,10 @@ export class PeptidesModel {
|
|
|
156
145
|
}
|
|
157
146
|
|
|
158
147
|
get isMutationCliffSelectionEmpty(): boolean {
|
|
159
|
-
for (const aarList of Object.values(this.mutationCliffsSelection))
|
|
148
|
+
for (const aarList of Object.values(this.mutationCliffsSelection)) {
|
|
160
149
|
if (aarList.length !== 0)
|
|
161
150
|
return false;
|
|
151
|
+
}
|
|
162
152
|
return true;
|
|
163
153
|
}
|
|
164
154
|
|
|
@@ -166,6 +156,18 @@ export class PeptidesModel {
|
|
|
166
156
|
return this.logoSummarySelection.length === 0;
|
|
167
157
|
}
|
|
168
158
|
|
|
159
|
+
get settings(): type.PeptidesSettings {
|
|
160
|
+
this._settings ??= JSON.parse(this.df.getTag('settings') ?? '{}');
|
|
161
|
+
return this._settings;
|
|
162
|
+
}
|
|
163
|
+
set settings(s: type.PeptidesSettings) {
|
|
164
|
+
for (const [key, value] of Object.entries(s))
|
|
165
|
+
this._settings[key as keyof type.PeptidesSettings] = value as any;
|
|
166
|
+
this.df.setTag('settings', JSON.stringify(this._settings));
|
|
167
|
+
//TODO: update only needed components
|
|
168
|
+
this.updateDefault();
|
|
169
|
+
}
|
|
170
|
+
|
|
169
171
|
createAccordion(): DG.Accordion {
|
|
170
172
|
const acc = ui.accordion();
|
|
171
173
|
acc.root.style.width = '100%';
|
|
@@ -176,36 +178,8 @@ export class PeptidesModel {
|
|
|
176
178
|
return acc;
|
|
177
179
|
}
|
|
178
180
|
|
|
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
181
|
updateDefault(): void {
|
|
206
|
-
|
|
207
|
-
this.isPropertyChanged(this.mutationCliffsViewer) || this.isPropertyChanged(this.mostPotentResiduesViewer);
|
|
208
|
-
if ((this.sourceGrid && !this._isUpdating && proprtyChanged) || !this.isInitialized) {
|
|
182
|
+
if ((this.sourceGrid && !this._isUpdating) || !this.isInitialized) {
|
|
209
183
|
this.isInitialized = true;
|
|
210
184
|
this._isUpdating = true;
|
|
211
185
|
this.initializeViewersComponents();
|
|
@@ -241,9 +215,7 @@ export class PeptidesModel {
|
|
|
241
215
|
|
|
242
216
|
this.sortSourceGrid();
|
|
243
217
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
this.createScaledCol(viewer.scaling, splitSeqDf);
|
|
218
|
+
this.createScaledCol(splitSeqDf);
|
|
247
219
|
|
|
248
220
|
//unpivot a table and handle duplicates
|
|
249
221
|
let matrixDf = splitSeqDf.groupBy(positionColumns).aggregate();
|
|
@@ -296,6 +268,7 @@ export class PeptidesModel {
|
|
|
296
268
|
this.postProcessGrids();
|
|
297
269
|
}
|
|
298
270
|
|
|
271
|
+
//TODO: move out
|
|
299
272
|
calcSubstitutions(): void {
|
|
300
273
|
const activityValues: DG.Column<number> = this.df.columns.bySemType(C.SEM_TYPES.ACTIVITY_SCALED)!;
|
|
301
274
|
const columnList: DG.Column<string>[] = this.df.columns.bySemTypeAll(C.SEM_TYPES.MONOMER);
|
|
@@ -303,7 +276,6 @@ export class PeptidesModel {
|
|
|
303
276
|
if (nCols == 0)
|
|
304
277
|
throw new Error(`Couldn't find any column of semType '${C.SEM_TYPES.MONOMER}'`);
|
|
305
278
|
|
|
306
|
-
const viewer = this.getViewer();
|
|
307
279
|
this.substitutionsInfo = new Map();
|
|
308
280
|
const nRows = this.df.rowCount;
|
|
309
281
|
for (let seq1Idx = 0; seq1Idx < nRows - 1; seq1Idx++) {
|
|
@@ -312,7 +284,7 @@ export class PeptidesModel {
|
|
|
312
284
|
const activityValSeq1 = activityValues.get(seq1Idx)!;
|
|
313
285
|
const activityValSeq2 = activityValues.get(seq2Idx)!;
|
|
314
286
|
const delta = activityValSeq1 - activityValSeq2;
|
|
315
|
-
if (Math.abs(delta) <
|
|
287
|
+
if (Math.abs(delta) < (this.settings.minActivityDelta ?? 0))
|
|
316
288
|
continue;
|
|
317
289
|
|
|
318
290
|
let substCounterFlag = false;
|
|
@@ -325,7 +297,7 @@ export class PeptidesModel {
|
|
|
325
297
|
continue;
|
|
326
298
|
|
|
327
299
|
substCounter++;
|
|
328
|
-
substCounterFlag = substCounter >
|
|
300
|
+
substCounterFlag = substCounter > (this.settings.maxMutations ?? 1);
|
|
329
301
|
if (substCounterFlag)
|
|
330
302
|
break;
|
|
331
303
|
|
|
@@ -430,8 +402,8 @@ export class PeptidesModel {
|
|
|
430
402
|
this.sourceGrid.columns.setOrder(colNames.map((v) => v.name));
|
|
431
403
|
}
|
|
432
404
|
|
|
433
|
-
createScaledCol(
|
|
434
|
-
const scaledCol = scaleActivity(
|
|
405
|
+
createScaledCol(splitSeqDf: DG.DataFrame): void {
|
|
406
|
+
const scaledCol = scaleActivity(this.df.getCol(C.COLUMNS_NAMES.ACTIVITY), this.settings.scaling);
|
|
435
407
|
//TODO: make another func
|
|
436
408
|
splitSeqDf.columns.add(scaledCol);
|
|
437
409
|
this.df.columns.replace(C.COLUMNS_NAMES.ACTIVITY_SCALED, scaledCol);
|
|
@@ -499,7 +471,7 @@ export class PeptidesModel {
|
|
|
499
471
|
|
|
500
472
|
setCategoryOrder(matrixDf: DG.DataFrame): void {
|
|
501
473
|
let sortArgument: string = C.COLUMNS_NAMES.MEAN_DIFFERENCE;
|
|
502
|
-
if (this.
|
|
474
|
+
if (this.settings.isBidirectional) {
|
|
503
475
|
const mdCol = this.monomerPositionStatsDf.getCol(sortArgument);
|
|
504
476
|
sortArgument = 'Absolute Mean difference';
|
|
505
477
|
const absMDCol = this.monomerPositionStatsDf.columns.addNewFloat(sortArgument);
|
|
@@ -535,7 +507,7 @@ export class PeptidesModel {
|
|
|
535
507
|
const rowCount = sequenceDf.rowCount;
|
|
536
508
|
for (const pos of posColCategories) {
|
|
537
509
|
tempStats = DG.Stats.fromColumn(mdCol, DG.BitSet.create(rowCount, (i) => posCol.get(i) === pos));
|
|
538
|
-
maxAtPos[pos] = this.
|
|
510
|
+
maxAtPos[pos] = this.settings.isBidirectional ?
|
|
539
511
|
(tempStats.max > Math.abs(tempStats.min) ? tempStats.max : tempStats.min) :
|
|
540
512
|
tempStats.max;
|
|
541
513
|
}
|
|
@@ -737,7 +709,6 @@ export class PeptidesModel {
|
|
|
737
709
|
tableColName : gridTable.get(C.COLUMNS_NAMES.POSITION, tableRowIndex);
|
|
738
710
|
const currentAAR: string = gridTable.get(C.COLUMNS_NAMES.MONOMER, tableRowIndex);
|
|
739
711
|
|
|
740
|
-
const viewer = this.getViewer();
|
|
741
712
|
if (this.isInvariantMap) {
|
|
742
713
|
const value: number = this.monomerPositionStatsDf
|
|
743
714
|
.groupBy([C.COLUMNS_NAMES.POSITION, C.COLUMNS_NAMES.MONOMER, C.COLUMNS_NAMES.COUNT])
|
|
@@ -746,9 +717,9 @@ export class PeptidesModel {
|
|
|
746
717
|
CR.renderInvaraintMapCell(
|
|
747
718
|
canvasContext, currentAAR, currentPosition, this.invariantMapSelection, value, bound);
|
|
748
719
|
} else {
|
|
749
|
-
CR.renderMutationCliffCell(
|
|
750
|
-
|
|
751
|
-
|
|
720
|
+
CR.renderMutationCliffCell(canvasContext, currentAAR, currentPosition, this.monomerPositionStatsDf,
|
|
721
|
+
mdCol, bound, cellValue, this.mutationCliffsSelection, this.substitutionsInfo,
|
|
722
|
+
this.settings.isBidirectional);
|
|
752
723
|
}
|
|
753
724
|
}
|
|
754
725
|
args.preventDefault();
|
|
@@ -816,14 +787,13 @@ export class PeptidesModel {
|
|
|
816
787
|
const tooltipElements: HTMLDivElement[] = [];
|
|
817
788
|
const monomerName = aar.toLowerCase();
|
|
818
789
|
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
.find((m) => m != null) ?? null;
|
|
790
|
+
let mw = getMoomerWorks();
|
|
791
|
+
let mol = mw?.getCappedRotatedMonomer('PEPTIDE', aar);
|
|
822
792
|
|
|
823
|
-
if (
|
|
824
|
-
tooltipElements.push(ui.div(
|
|
793
|
+
if (mol) {
|
|
794
|
+
tooltipElements.push(ui.div(monomerName));
|
|
825
795
|
const options = {autoCrop: true, autoCropMargin: 0, suppressChiralText: true};
|
|
826
|
-
tooltipElements.push(grok.chem.svgMol(
|
|
796
|
+
tooltipElements.push(grok.chem.svgMol(mol, undefined, undefined, options));
|
|
827
797
|
} else
|
|
828
798
|
tooltipElements.push(ui.div(aar));
|
|
829
799
|
|
|
@@ -1066,37 +1036,17 @@ export class PeptidesModel {
|
|
|
1066
1036
|
this.splitCol.compact();
|
|
1067
1037
|
}
|
|
1068
1038
|
|
|
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
1039
|
/** Class initializer */
|
|
1087
1040
|
async init(): Promise<void> {
|
|
1088
1041
|
if (this.isInitialized)
|
|
1089
1042
|
return;
|
|
1090
1043
|
|
|
1091
|
-
// Get monomer library through bio library
|
|
1092
|
-
this.monomerLib = await bio.getMonomerLib();
|
|
1093
|
-
this.monomerLib.onChanged.subscribe(() => {
|
|
1094
|
-
this.sourceGrid.invalidate();
|
|
1095
|
-
});
|
|
1096
|
-
this.monomerWorks = new bio.MonomerWorks(this.monomerLib);
|
|
1097
|
-
|
|
1098
1044
|
this.currentView = wu(grok.shell.tableViews).find(({dataFrame}) => dataFrame.tags[C.PEPTIDES_ANALYSIS] === 'true') ??
|
|
1099
1045
|
grok.shell.addTableView(this.df);
|
|
1046
|
+
if (!this.isRibbonSet) {
|
|
1047
|
+
this.currentView.setRibbonPanels([[ui.icons.settings(() => getSettingsDialog(this))]], false);
|
|
1048
|
+
this.isRibbonSet = true;
|
|
1049
|
+
}
|
|
1100
1050
|
grok.shell.v = this.currentView;
|
|
1101
1051
|
this.sourceGrid = this.currentView.grid;
|
|
1102
1052
|
if (this.df.tags[C.PEPTIDES_ANALYSIS] === 'true')
|
|
@@ -1129,9 +1079,9 @@ export class PeptidesModel {
|
|
|
1129
1079
|
|
|
1130
1080
|
const dockManager = this.currentView.dockManager;
|
|
1131
1081
|
|
|
1132
|
-
|
|
1082
|
+
const mutationCliffsViewer = await this.df.plot.fromType('peptide-sar-viewer', options) as MutationCliffsViewer;
|
|
1133
1083
|
|
|
1134
|
-
|
|
1084
|
+
const mostPotentResiduesViewer =
|
|
1135
1085
|
await this.df.plot.fromType('peptide-sar-viewer-vertical', options) as MostPotentResiduesViewer;
|
|
1136
1086
|
|
|
1137
1087
|
if (this.df.getTag(C.TAGS.CLUSTERS)) {
|
|
@@ -1142,10 +1092,9 @@ export class PeptidesModel {
|
|
|
1142
1092
|
this.updateDefault();
|
|
1143
1093
|
|
|
1144
1094
|
const mcNode =
|
|
1145
|
-
dockManager.dock(
|
|
1095
|
+
dockManager.dock(mutationCliffsViewer, DG.DOCK_TYPE.DOWN, null, mutationCliffsViewer.name);
|
|
1146
1096
|
|
|
1147
|
-
dockManager.dock(
|
|
1148
|
-
this.mostPotentResiduesViewer, DG.DOCK_TYPE.RIGHT, mcNode, this.mostPotentResiduesViewer.name, 0.3);
|
|
1097
|
+
dockManager.dock(mostPotentResiduesViewer, DG.DOCK_TYPE.RIGHT, mcNode, mostPotentResiduesViewer.name, 0.3);
|
|
1149
1098
|
|
|
1150
1099
|
|
|
1151
1100
|
this.sourceGrid.props.allowEdit = false;
|
|
@@ -1153,6 +1102,4 @@ export class PeptidesModel {
|
|
|
1153
1102
|
|
|
1154
1103
|
this.invalidateGrids();
|
|
1155
1104
|
}
|
|
1156
|
-
|
|
1157
|
-
invalidateSourceGrid(): void {this.sourceGrid.invalidate();}
|
|
1158
1105
|
}
|
package/src/package.ts
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
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
|
-
|
|
5
|
+
import * as bio from '@datagrok-libraries/bio';
|
|
6
6
|
import * as C from './utils/constants';
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import {analyzePeptidesUI} from './widgets/peptides';
|
|
9
9
|
import {PeptideSimilaritySpaceWidget} from './utils/peptide-similarity-space';
|
|
10
10
|
import {manualAlignmentWidget} from './widgets/manual-alignment';
|
|
11
11
|
import {MutationCliffsViewer, MostPotentResiduesViewer} from './viewers/sar-viewer';
|
|
@@ -13,10 +13,16 @@ import {MutationCliffsViewer, MostPotentResiduesViewer} from './viewers/sar-view
|
|
|
13
13
|
import {PeptideSpaceViewer} from './viewers/peptide-space-viewer';
|
|
14
14
|
import {LogoSummary} from './viewers/logo-summary';
|
|
15
15
|
|
|
16
|
+
export let monomerWorks: bio.MonomerWorks | null;
|
|
17
|
+
|
|
16
18
|
export const _package = new DG.Package();
|
|
17
19
|
let currentTable: DG.DataFrame;
|
|
18
20
|
let alignedSequenceColumn: DG.Column;
|
|
19
21
|
|
|
22
|
+
export function getMoomerWorks() {
|
|
23
|
+
return monomerWorks;
|
|
24
|
+
};
|
|
25
|
+
|
|
20
26
|
async function main(chosenFile: string): Promise<void> {
|
|
21
27
|
const pi = DG.TaskBarProgressIndicator.create('Loading Peptides');
|
|
22
28
|
const path = _package.webRoot + 'files/' + chosenFile;
|
|
@@ -34,7 +40,10 @@ async function main(chosenFile: string): Promise<void> {
|
|
|
34
40
|
export async function Peptides(): Promise<void> {
|
|
35
41
|
const wikiLink = ui.link('wiki', 'https://github.com/datagrok-ai/public/blob/master/help/domains/bio/peptides.md');
|
|
36
42
|
const textLink = ui.inlineText(['For more details, see our ', wikiLink, '.']);
|
|
37
|
-
|
|
43
|
+
if (monomerWorks == null) {
|
|
44
|
+
let lib = await grok.functions.call('Bio:getBioLib');
|
|
45
|
+
monomerWorks = new bio.MonomerWorks(lib);
|
|
46
|
+
}
|
|
38
47
|
const appDescription = ui.info(
|
|
39
48
|
[
|
|
40
49
|
ui.list([
|
|
@@ -71,13 +80,23 @@ export async function Peptides(): Promise<void> {
|
|
|
71
80
|
]);
|
|
72
81
|
}
|
|
73
82
|
|
|
83
|
+
//top-menu: Bio | Peptides...
|
|
84
|
+
//name: Bio Peptides
|
|
85
|
+
export async function peptidesDialog(): Promise<DG.Dialog> {
|
|
86
|
+
const analyzeObject = await analyzePeptidesUI(grok.shell.t);
|
|
87
|
+
const dialog = ui.dialog('Analyze Peptides').add(analyzeObject.host).onOK(analyzeObject.callback);
|
|
88
|
+
dialog.show();
|
|
89
|
+
return dialog.show();
|
|
90
|
+
}
|
|
91
|
+
|
|
74
92
|
//name: Peptides
|
|
75
93
|
//tags: panel, widgets
|
|
76
94
|
//input: column col {semType: Macromolecule}
|
|
77
95
|
//output: widget result
|
|
78
96
|
export async function peptidesPanel(col: DG.Column): Promise<DG.Widget> {
|
|
79
97
|
[currentTable, alignedSequenceColumn] = getOrDefine(col.dataFrame, col);
|
|
80
|
-
|
|
98
|
+
const analyzeObject = await analyzePeptidesUI(currentTable, alignedSequenceColumn);
|
|
99
|
+
return new DG.Widget(analyzeObject.host);
|
|
81
100
|
}
|
|
82
101
|
|
|
83
102
|
//name: peptide-sar-viewer
|
package/src/tests/core.ts
CHANGED
|
@@ -36,7 +36,7 @@ category('Core', () => {
|
|
|
36
36
|
simpleAlignedSeqCol.setTag(C.TAGS.ALPHABET, bio.ALPHABET.PT);
|
|
37
37
|
simpleAlignedSeqCol.setTag(DG.TAGS.UNITS, bio.NOTATION.FASTA);
|
|
38
38
|
simpleAlignedSeqCol.setTag(bio.TAGS.aligned, bio.ALIGNMENT.SEQ_MSA);
|
|
39
|
-
simpleScaledCol = scaleActivity('-lg'
|
|
39
|
+
simpleScaledCol = scaleActivity(simpleActivityCol, '-lg');
|
|
40
40
|
|
|
41
41
|
model = await startAnalysis(simpleActivityCol, simpleAlignedSeqCol, null, simpleTable, simpleScaledCol, '-lg');
|
|
42
42
|
expect(model instanceof PeptidesModel, true);
|
|
@@ -57,7 +57,7 @@ category('Core', () => {
|
|
|
57
57
|
complexAlignedSeqCol.setTag(DG.TAGS.UNITS, bio.NOTATION.SEPARATOR);
|
|
58
58
|
complexAlignedSeqCol.setTag(bio.TAGS.aligned, bio.ALIGNMENT.SEQ_MSA);
|
|
59
59
|
complexAlignedSeqCol.tags[C.TAGS.SEPARATOR] = '/';
|
|
60
|
-
complexScaledCol = scaleActivity('-lg'
|
|
60
|
+
complexScaledCol = scaleActivity(complexActivityCol, '-lg');
|
|
61
61
|
|
|
62
62
|
model = await startAnalysis(
|
|
63
63
|
complexActivityCol, complexAlignedSeqCol, null, complexTable, complexScaledCol, '-lg');
|
|
@@ -78,7 +78,7 @@ category('Core', () => {
|
|
|
78
78
|
simpleAlignedSeqCol.setTag(C.TAGS.ALPHABET, bio.ALPHABET.PT);
|
|
79
79
|
simpleAlignedSeqCol.setTag(DG.TAGS.UNITS, bio.NOTATION.FASTA);
|
|
80
80
|
simpleAlignedSeqCol.setTag(bio.TAGS.aligned, bio.ALIGNMENT.SEQ_MSA);
|
|
81
|
-
simpleScaledCol = scaleActivity('-lg'
|
|
81
|
+
simpleScaledCol = scaleActivity(simpleActivityCol, '-lg');
|
|
82
82
|
|
|
83
83
|
model = await startAnalysis(simpleActivityCol, simpleAlignedSeqCol, null, simpleTable, simpleScaledCol, '-lg');
|
|
84
84
|
let v = grok.shell.getTableView('Peptides analysis');
|
|
@@ -19,9 +19,9 @@ export function setAARRenderer(col: DG.Column, alphabet: string, grid: DG.Grid,
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
export function renderMutationCliffCell(canvasContext: CanvasRenderingContext2D, currentAAR: string,
|
|
22
|
-
currentPosition: string, statsDf: DG.DataFrame,
|
|
23
|
-
|
|
24
|
-
): void {
|
|
22
|
+
currentPosition: string, statsDf: DG.DataFrame, mdCol: DG.Column<number>, bound: DG.Rect, cellValue: number,
|
|
23
|
+
mutationCliffsSelection: types.PositionToAARList, substitutionsInfo: types.SubstitutionsInfo,
|
|
24
|
+
twoColorMode: boolean = false): void {
|
|
25
25
|
const queryAAR = `${C.COLUMNS_NAMES.MONOMER} = ${currentAAR}`;
|
|
26
26
|
const query = `${queryAAR} and ${C.COLUMNS_NAMES.POSITION} = ${currentPosition}`;
|
|
27
27
|
const pVal: number = statsDf
|
package/src/utils/misc.ts
CHANGED
|
@@ -18,7 +18,7 @@ export function getSeparator(col: DG.Column<string>): string {
|
|
|
18
18
|
return col.getTag(C.TAGS.SEPARATOR) ?? '';
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
export function scaleActivity(
|
|
21
|
+
export function scaleActivity(activityCol: DG.Column<number>, scaling: string = 'none'): DG.Column<number> {
|
|
22
22
|
let formula = (x: number): number => x;
|
|
23
23
|
let newColName = 'activity';
|
|
24
24
|
switch (scaling) {
|
package/src/utils/types.ts
CHANGED
|
@@ -14,3 +14,7 @@ export type MonomerColStats = {[monomer: string]: {count: number, selected: numb
|
|
|
14
14
|
export type MonomerDfStats = {[position: string]: MonomerColStats};
|
|
15
15
|
|
|
16
16
|
export type BarCoordinates = {[monomer: string]: DG.Rect};
|
|
17
|
+
|
|
18
|
+
export type ScalingMethods = 'none' | 'lg' | '-lg';
|
|
19
|
+
export type PeptidesSettings =
|
|
20
|
+
{scaling?: ScalingMethods, isBidirectional?: boolean, maxMutations?: number, minActivityDelta?: number};
|
|
@@ -6,18 +6,11 @@ import $ from 'cash-dom';
|
|
|
6
6
|
import * as C from '../utils/constants';
|
|
7
7
|
import {PeptidesModel} from '../model';
|
|
8
8
|
|
|
9
|
-
let IS_PROPERTY_CHANGING = false;
|
|
10
|
-
|
|
11
9
|
export class SARViewerBase extends DG.JsViewer {
|
|
12
10
|
tempName!: string;
|
|
13
11
|
viewerGrid!: DG.Grid;
|
|
14
12
|
sourceGrid!: DG.Grid;
|
|
15
13
|
model!: PeptidesModel;
|
|
16
|
-
scaling: string;
|
|
17
|
-
bidirectionalAnalysis: boolean;
|
|
18
|
-
maxSubstitutions: number;
|
|
19
|
-
minActivityDelta: number;
|
|
20
|
-
_titleHost = ui.divText('SAR Viewer', {id: 'pep-viewer-title'});
|
|
21
14
|
initialized = false;
|
|
22
15
|
isPropertyChanging: boolean = false;
|
|
23
16
|
_isVertical = false;
|
|
@@ -25,11 +18,6 @@ export class SARViewerBase extends DG.JsViewer {
|
|
|
25
18
|
|
|
26
19
|
constructor() {
|
|
27
20
|
super();
|
|
28
|
-
|
|
29
|
-
this.scaling = this.string('scaling', 'none', {choices: ['none', 'lg', '-lg']});
|
|
30
|
-
this.bidirectionalAnalysis = this.bool('bidirectionalAnalysis', false);
|
|
31
|
-
this.maxSubstitutions = this.int('maxSubstitutions', 1);
|
|
32
|
-
this.minActivityDelta = this.float('minActivityDelta', 0);
|
|
33
21
|
}
|
|
34
22
|
|
|
35
23
|
get name(): string {return '';}
|
|
@@ -39,16 +27,6 @@ export class SARViewerBase extends DG.JsViewer {
|
|
|
39
27
|
this.sourceGrid = this.view?.grid ?? (grok.shell.v as DG.TableView).grid;
|
|
40
28
|
this.model = await PeptidesModel.getInstance(this.dataFrame);
|
|
41
29
|
this.helpUrl = '/help/domains/bio/peptides.md';
|
|
42
|
-
|
|
43
|
-
this.initProperties();
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
initProperties(): void {
|
|
47
|
-
const props = this.model.usedProperties;
|
|
48
|
-
IS_PROPERTY_CHANGING = true;
|
|
49
|
-
for (const [propName, propVal] of Object.entries(props))
|
|
50
|
-
this.props.set(propName, propVal as any as object);
|
|
51
|
-
IS_PROPERTY_CHANGING = false;
|
|
52
30
|
}
|
|
53
31
|
|
|
54
32
|
detach(): void {this.subs.forEach((sub) => sub.unsubscribe());}
|
|
@@ -74,7 +52,6 @@ export class SARViewerBase extends DG.JsViewer {
|
|
|
74
52
|
invariantMapMode.value = !invariantMapMode.value;
|
|
75
53
|
this.isMutationCliffsMode = '1';
|
|
76
54
|
this.isModeChanging = false;
|
|
77
|
-
this._titleHost.innerText = 'Mutation Cliffs';
|
|
78
55
|
this.model.isInvariantMap = false;
|
|
79
56
|
this.viewerGrid.invalidate();
|
|
80
57
|
});
|
|
@@ -86,7 +63,6 @@ export class SARViewerBase extends DG.JsViewer {
|
|
|
86
63
|
mutationCliffsMode.value = !mutationCliffsMode.value;
|
|
87
64
|
this.isMutationCliffsMode = '0';
|
|
88
65
|
this.isModeChanging = false;
|
|
89
|
-
this._titleHost.innerText = 'Invariant Map';
|
|
90
66
|
this.model.isInvariantMap = true;
|
|
91
67
|
this.viewerGrid.invalidate();
|
|
92
68
|
});
|
|
@@ -99,34 +75,21 @@ export class SARViewerBase extends DG.JsViewer {
|
|
|
99
75
|
setDefaultProperties(invariantMapMode);
|
|
100
76
|
$(mutationCliffsMode.root).css('padding-right', '10px').css('padding-left', '5px');
|
|
101
77
|
|
|
102
|
-
switchHost = ui.divH([mutationCliffsMode.root, invariantMapMode.root]);
|
|
103
|
-
switchHost.
|
|
78
|
+
switchHost = ui.divH([mutationCliffsMode.root, invariantMapMode.root], {id: 'pep-viewer-title'});
|
|
79
|
+
$(switchHost).css('width', 'auto').css('align-self', 'center');
|
|
104
80
|
}
|
|
105
81
|
const viewerRoot = this.viewerGrid.root;
|
|
106
82
|
viewerRoot.style.width = 'auto';
|
|
107
|
-
this.root.appendChild(ui.divV([
|
|
83
|
+
this.root.appendChild(ui.divV([switchHost, viewerRoot]));
|
|
108
84
|
}
|
|
109
85
|
this.viewerGrid?.invalidate();
|
|
110
86
|
}
|
|
111
87
|
|
|
112
88
|
onPropertyChanged(property: DG.Property): void {
|
|
113
89
|
super.onPropertyChanged(property);
|
|
114
|
-
this.dataFrame.tags[property.name] = `${property.get(this)}`;
|
|
115
|
-
if (!this.initialized || IS_PROPERTY_CHANGING)
|
|
116
|
-
return;
|
|
117
90
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
if (propName === 'scaling' && typeof this.dataFrame !== 'undefined') {
|
|
121
|
-
const activityCol = this.dataFrame.columns.bySemType(C.SEM_TYPES.ACTIVITY)!;
|
|
122
|
-
const minActivity = activityCol.stats.min;
|
|
123
|
-
if (minActivity && minActivity <= 0 && this.scaling !== 'none') {
|
|
124
|
-
grok.shell.warning(`Could not apply ${this.scaling}: ` +
|
|
125
|
-
`activity column ${activityCol.name} contains zero or negative values, falling back to 'none'.`);
|
|
126
|
-
property.set(this, 'none');
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
91
|
+
if (!this.initialized)
|
|
92
|
+
return;
|
|
130
93
|
|
|
131
94
|
this.model.updateDefault();
|
|
132
95
|
this.render(true);
|
|
@@ -147,7 +110,6 @@ export class MutationCliffsViewer extends SARViewerBase {
|
|
|
147
110
|
|
|
148
111
|
async onTableAttached(): Promise<void> {
|
|
149
112
|
await super.onTableAttached();
|
|
150
|
-
this.model.mutationCliffsViewer ??= this;
|
|
151
113
|
|
|
152
114
|
this.subs.push(this.model.onMutationCliffsGridChanged.subscribe((data) => {
|
|
153
115
|
this.viewerGrid = data;
|
|
@@ -164,16 +126,10 @@ export class MutationCliffsViewer extends SARViewerBase {
|
|
|
164
126
|
|
|
165
127
|
//1. debouncing in rxjs; 2. flags?
|
|
166
128
|
onPropertyChanged(property: DG.Property): void {
|
|
167
|
-
if (!this.isInitialized()
|
|
129
|
+
if (!this.isInitialized())
|
|
168
130
|
return;
|
|
169
131
|
|
|
170
|
-
if (property.name == 'invariantMap')
|
|
171
|
-
this._titleHost = ui.divText(property.get(this) ? 'Invariant Map' : 'Mutation Cliffs', {id: 'pep-viewer-title'});
|
|
172
|
-
|
|
173
132
|
super.onPropertyChanged(property);
|
|
174
|
-
IS_PROPERTY_CHANGING = true;
|
|
175
|
-
this.model.syncProperties(true);
|
|
176
|
-
IS_PROPERTY_CHANGING = false;
|
|
177
133
|
}
|
|
178
134
|
}
|
|
179
135
|
|
|
@@ -191,7 +147,6 @@ export class MostPotentResiduesViewer extends SARViewerBase {
|
|
|
191
147
|
|
|
192
148
|
async onTableAttached(): Promise<void> {
|
|
193
149
|
await super.onTableAttached();
|
|
194
|
-
this.model.mostPotentResiduesViewer ??= this;
|
|
195
150
|
|
|
196
151
|
this.subs.push(this.model.onMostPotentResiduesGridChanged.subscribe((data) => {
|
|
197
152
|
this.viewerGrid = data;
|
|
@@ -208,12 +163,9 @@ export class MostPotentResiduesViewer extends SARViewerBase {
|
|
|
208
163
|
isInitialized(): DG.Grid {return this.model?.mostPotentResiduesGrid;}
|
|
209
164
|
|
|
210
165
|
onPropertyChanged(property: DG.Property): void {
|
|
211
|
-
if (!this.isInitialized()
|
|
166
|
+
if (!this.isInitialized())
|
|
212
167
|
return;
|
|
213
168
|
|
|
214
169
|
super.onPropertyChanged(property);
|
|
215
|
-
IS_PROPERTY_CHANGING = true;
|
|
216
|
-
this.model.syncProperties(false);
|
|
217
|
-
IS_PROPERTY_CHANGING = false;
|
|
218
170
|
}
|
|
219
171
|
}
|
|
@@ -152,7 +152,7 @@ export function getDistributionWidget(table: DG.DataFrame, model: PeptidesModel)
|
|
|
152
152
|
if (!model.isLogoSummarySelectionEmpty && model.isMutationCliffSelectionEmpty) {
|
|
153
153
|
defaultValuePos = false;
|
|
154
154
|
defaultValueAAR = false;
|
|
155
|
-
}
|
|
155
|
+
}
|
|
156
156
|
|
|
157
157
|
const splitByPosition = ui.boolInput('', defaultValuePos, updateDistributionHost);
|
|
158
158
|
splitByPosition.addPostfix('Split by position');
|