@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datagrok/peptides",
3
- "version": "1.3.7",
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.6.0",
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
- monomerLib: bio.IMonomerLib | null = null; // To get monomers from lib(s)
60
- monomerWorks: bio.MonomerWorks | null = null; // To get processed monomers
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
- const proprtyChanged =
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
- const viewer = this.getViewer();
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) < viewer.minActivityDelta)
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 > viewer.maxSubstitutions;
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(activityScaling: string, splitSeqDf: DG.DataFrame): void {
434
- const scaledCol = scaleActivity(activityScaling, this.df.getCol(C.COLUMNS_NAMES.ACTIVITY));
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.getViewer().bidirectionalAnalysis) {
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.getViewer().bidirectionalAnalysis ?
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
- canvasContext, currentAAR, currentPosition, this.monomerPositionStatsDf, viewer.bidirectionalAnalysis,
751
- mdCol, bound, cellValue, this.mutationCliffsSelection, this.substitutionsInfo);
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
- const monomer: bio.Monomer | null = wu(['HELM_AA', 'HELM_CHEM'])
820
- .map((monomerType) => this.monomerWorks!.getCappedMonomer(monomerType, monomerName))
821
- .find((m) => m != null) ?? null;
790
+ let mw = getMoomerWorks();
791
+ let mol = mw?.getCappedRotatedMonomer('PEPTIDE', aar);
822
792
 
823
- if (monomer) {
824
- tooltipElements.push(ui.div(monomer.n));
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(monomer.m, undefined, undefined, options));
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
- this.mutationCliffsViewer = await this.df.plot.fromType('peptide-sar-viewer', options) as MutationCliffsViewer;
1082
+ const mutationCliffsViewer = await this.df.plot.fromType('peptide-sar-viewer', options) as MutationCliffsViewer;
1133
1083
 
1134
- this.mostPotentResiduesViewer =
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(this.mutationCliffsViewer, DG.DOCK_TYPE.DOWN, null, this.mutationCliffsViewer.name);
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 {analyzePeptidesWidget} from './widgets/peptides';
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
- return analyzePeptidesWidget(currentTable, alignedSequenceColumn);
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', simpleActivityCol);
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', complexActivityCol);
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', simpleActivityCol);
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, twoColorMode: boolean, mdCol: DG.Column<number>, bound: DG.Rect,
23
- cellValue: number, mutationCliffsSelection: types.PositionToAARList, substitutionsInfo: types.SubstitutionsInfo,
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(scaling: string, activityCol: DG.Column<number>): DG.Column<number> {
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) {
@@ -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.style.position = 'absolute';
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([ui.divH([switchHost, this._titleHost]), viewerRoot]));
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
- const propName = property.name;
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() || IS_PROPERTY_CHANGING)
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() || IS_PROPERTY_CHANGING)
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');