@datagrok/peptides 1.0.0 → 1.1.0

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.
Files changed (38) hide show
  1. package/dist/package-test.js +9821 -5237
  2. package/dist/package.js +9737 -4734
  3. package/dist/vendors-node_modules_datagrok-libraries_ml_src_workers_dimensionality-reducer_js.js +450 -360
  4. package/files/aligned.csv +648 -648
  5. package/files/aligned_2.csv +541 -10275
  6. package/files/aligned_3.csv +335 -0
  7. package/helm/JSDraw/Pistoia.HELM.js +27 -0
  8. package/package.json +24 -16
  9. package/src/__jest__/remote.test.ts +33 -15
  10. package/src/__jest__/test-node.ts +3 -2
  11. package/src/model.ts +416 -521
  12. package/src/package-test.ts +0 -2
  13. package/src/package.ts +7 -126
  14. package/src/tests/core.ts +60 -18
  15. package/src/tests/peptide-space-test.ts +7 -7
  16. package/src/tests/utils.ts +3 -19
  17. package/src/utils/cell-renderer.ts +140 -262
  18. package/src/utils/constants.ts +7 -4
  19. package/src/utils/filtering-statistics.ts +21 -53
  20. package/src/utils/misc.ts +80 -16
  21. package/src/utils/peptide-similarity-space.ts +1 -1
  22. package/src/utils/types.ts +7 -5
  23. package/src/viewers/peptide-space-viewer.ts +18 -20
  24. package/src/viewers/sar-viewer.ts +33 -22
  25. package/src/widgets/analyze-peptides.ts +34 -10
  26. package/src/widgets/distribution.ts +169 -60
  27. package/src/widgets/manual-alignment.ts +5 -4
  28. package/src/widgets/subst-table.ts +6 -2
  29. package/{test-Peptides-69a4761f6044-40ac3a0c.html → test-Peptides-eb4783c07294-f4162403.html} +43 -22
  30. package/detectors.js +0 -9
  31. package/src/monomer-library.ts +0 -193
  32. package/src/tests/msa-tests.ts +0 -27
  33. package/src/utils/chem-palette.ts +0 -280
  34. package/src/utils/multiple-sequence-alignment.ts +0 -106
  35. package/src/utils/multivariate-analysis.ts +0 -76
  36. package/src/viewers/stacked-barchart-viewer.ts +0 -339
  37. package/src/widgets/multiple-sequence-alignment.ts +0 -9
  38. package/src/widgets/peptide-molecule.ts +0 -82
package/src/model.ts CHANGED
@@ -2,25 +2,23 @@ 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
4
 
5
+ import {splitAlignedSequences} from '@datagrok-libraries/bio/src/utils/splitter';
6
+
5
7
  import {Subject, Observable} from 'rxjs';
6
- import {addViewerToHeader, StackedBarChart} from './viewers/stacked-barchart-viewer';
7
- import {tTest} from '@datagrok-libraries/statistics/src/tests';
8
- import {fdrcorrection} from '@datagrok-libraries/statistics/src/multiple-tests';
9
- import {ChemPalette} from './utils/chem-palette';
10
- import {MonomerLibrary} from './monomer-library';
11
8
  import * as C from './utils/constants';
12
9
  import * as type from './utils/types';
13
- import {FilteringStatistics} from './utils/filtering-statistics';
14
- import {getSeparator, getTypedArrayConstructor, stringToBool} from './utils/misc';
15
- import {_package} from './package';
16
- import {SARViewer, SARViewerVertical} from './viewers/sar-viewer';
10
+ import {calculateBarsData, getTypedArrayConstructor, scaleActivity} from './utils/misc';
11
+ import {SARViewer, SARViewerBase, SARViewerVertical} from './viewers/sar-viewer';
17
12
  import {PeptideSpaceViewer} from './viewers/peptide-space-viewer';
18
- import {setAARRenderer} from './utils/cell-renderer';
13
+ import {renderBarchart, renderSARCell, setAARRenderer} from './utils/cell-renderer';
19
14
  import {substitutionsWidget} from './widgets/subst-table';
20
- import {getDistributionWidget} from './widgets/distribution';
15
+ import {getDistributionAndStats, getDistributionWidget} from './widgets/distribution';
16
+ import {getStats, Stats} from './utils/filtering-statistics';
17
+ import * as rxjs from 'rxjs';
18
+
21
19
 
22
20
  export class PeptidesModel {
23
- static _modelName = 'peptidesModel';
21
+ static modelName = 'peptidesModel';
24
22
 
25
23
  _statsDataFrameSubject = new Subject<DG.DataFrame>();
26
24
  _sarGridSubject = new Subject<DG.Grid>();
@@ -32,49 +30,41 @@ export class PeptidesModel {
32
30
  isBitsetChangedInitialized = false;
33
31
  isCellChanging = false;
34
32
 
35
- //viewer properties
36
- _filterMode!: boolean;
37
- _twoColorMode!: boolean;
38
- _activityScaling!: string;
39
- _isSubstitutionOn!: boolean;
40
- _activityLimit!: number;
41
- _maxSubstitutions!: number;
42
-
43
33
  _sarGrid!: DG.Grid;
44
34
  _sarVGrid!: DG.Grid;
45
35
  _sourceGrid!: DG.Grid;
46
- _dataFrame: DG.DataFrame;
36
+ df: DG.DataFrame;
47
37
  splitCol!: DG.Column<boolean>;
48
- stackedBarchart!: StackedBarChart;
49
38
  edf: DG.DataFrame | null = null;
50
-
39
+ statsDf!: DG.DataFrame;
40
+ _currentSelection!: type.SelectionObject;
51
41
  substitutionsInfo: type.SubstitutionsInfo = new Map();
52
- isInitialized: boolean = false;
42
+ isInitialized = false;
53
43
  currentView!: DG.TableView;
54
44
 
55
- _currentSelection!: type.SelectionObject;
56
- isPeptideSpaceChangingBitset: boolean = false;
57
- isChangingEdfBitset: boolean = false;
45
+ isPeptideSpaceChangingBitset = false;
46
+ isChangingEdfBitset = false;
47
+
48
+ sarViewer!: SARViewer;
49
+ sarViewerVertical!: SARViewerVertical;
50
+
51
+ _usedProperties: {[propName: string]: string | number | boolean} = {};
52
+ monomerMap: {[key: string]: {molfile: string, fullName: string}} = {};
53
+ barData: type.MonomerDfStats = {};
54
+ barsBounds: {[position: string]: type.BarCoordinates} = {};
55
+ cachedBarchartTooltip: {bar: string, tooltip: null | HTMLDivElement} = {bar: '', tooltip: null};
56
+ monomerLib: any;
58
57
 
59
58
  private constructor(dataFrame: DG.DataFrame) {
60
- this._dataFrame = dataFrame;
61
- this.updateProperties();
59
+ this.df = dataFrame;
62
60
  }
63
61
 
64
- static async getInstance(dataFrame: DG.DataFrame, dgPackage?: DG.Package): Promise<PeptidesModel> {
65
- if (dataFrame.temp[MonomerLibrary.id] === null) {
66
- const sdf = await (dgPackage ?? _package).files.readAsText('HELMMonomers_June10.sdf');
67
- dataFrame.temp[MonomerLibrary.id] ??= new MonomerLibrary(sdf);
68
- }
62
+ static async getInstance(dataFrame: DG.DataFrame): Promise<PeptidesModel> {
69
63
  dataFrame.temp[PeptidesModel.modelName] ??= new PeptidesModel(dataFrame);
70
64
  await (dataFrame.temp[PeptidesModel.modelName] as PeptidesModel).init();
71
65
  return dataFrame.temp[PeptidesModel.modelName] as PeptidesModel;
72
66
  }
73
67
 
74
- static get modelName(): string {return PeptidesModel._modelName;}
75
-
76
- static get chemPalette(): typeof ChemPalette {return ChemPalette;}
77
-
78
68
  get onStatsDataFrameChanged(): Observable<DG.DataFrame> {return this._statsDataFrameSubject.asObservable();}
79
69
 
80
70
  get onSARGridChanged(): Observable<DG.Grid> {return this._sarGridSubject.asObservable();}
@@ -84,13 +74,41 @@ export class PeptidesModel {
84
74
  get onSubstTableChanged(): Observable<type.SubstitutionsInfo> {return this._substitutionTableSubject.asObservable();}
85
75
 
86
76
  get currentSelection(): type.SelectionObject {
87
- this._currentSelection ??= JSON.parse(this._dataFrame.tags[C.TAGS.SELECTION] || '{}');
77
+ this._currentSelection ??= JSON.parse(this.df.tags[C.TAGS.SELECTION] || '{}');
88
78
  return this._currentSelection;
89
79
  }
90
80
  set currentSelection(selection: type.SelectionObject) {
91
81
  this._currentSelection = selection;
92
- this._dataFrame.tags[C.TAGS.SELECTION] = JSON.stringify(selection);
82
+ this.df.tags[C.TAGS.SELECTION] = JSON.stringify(selection);
93
83
  this.invalidateSelection();
84
+ this.barData = calculateBarsData(this.df.columns.bySemTypeAll(C.SEM_TYPES.MONOMER), this.df.selection);
85
+ }
86
+
87
+ get usedProperties(): {[propName: string]: string | number | boolean} {
88
+ this._usedProperties = JSON.parse(this.df.tags['sarProperties'] ?? '{}');
89
+ return this._usedProperties;
90
+ }
91
+ set usedProperties(properties: {[propName: string]: string | number | boolean}) {
92
+ this.df.tags['sarProperties'] = JSON.stringify(properties);
93
+ this._usedProperties = properties;
94
+ }
95
+
96
+ get splitByPos(): boolean {
97
+ const splitByPosFlag = (this.df.tags['distributionSplit'] ?? '00')[0];
98
+ return splitByPosFlag == '1' ? true : false;
99
+ }
100
+ set splitByPos(flag: boolean) {
101
+ const splitByAARFlag = (this.df.tags['distributionSplit'] ?? '00')[1];
102
+ this.df.tags['distributionSplit'] = `${flag ? 1 : 0}${splitByAARFlag}`;
103
+ }
104
+
105
+ get splitByAAR(): boolean {
106
+ const splitByPosFlag = (this.df.tags['distributionSplit'] ?? '00')[1];
107
+ return splitByPosFlag == '1' ? true : false;
108
+ }
109
+ set splitByAAR(flag: boolean) {
110
+ const splitByAARFlag = (this.df.tags['distributionSplit'] ?? '00')[0];
111
+ this.df.tags['distributionSplit'] = `${splitByAARFlag}${flag ? 1 : 0}`;
94
112
  }
95
113
 
96
114
  invalidateSelection(): void {
@@ -98,200 +116,173 @@ export class PeptidesModel {
98
116
  this.invalidateGrids();
99
117
  }
100
118
 
101
- createAccordion() {
102
- const acc = ui.accordion('Selection info');
119
+ createAccordion(): DG.Accordion {
120
+ const acc = ui.accordion();
103
121
  acc.root.style.width = '100%';
104
- acc.addTitle(ui.h1('Selection info'));
105
- acc.addPane('Substitutions', () => substitutionsWidget(this._dataFrame, this).root, true);
106
- acc.addPane('Distribtution', () => getDistributionWidget(this._dataFrame).root, true);
122
+ acc.addTitle(ui.h1(`${this.df.selection.trueCount} selected rows`));
123
+ acc.addPane('Substitutions', () => substitutionsWidget(this.df, this).root, true);
124
+ acc.addPane('Distribtution', () => getDistributionWidget(this.df, this).root, true);
107
125
 
108
126
  return acc;
109
127
  }
110
128
 
111
- updateProperties(): void {
112
- this._activityScaling = this._dataFrame.tags['scaling'];
113
- this._filterMode = stringToBool(this._dataFrame.tags['filterMode']);
114
- this._twoColorMode = stringToBool(this._dataFrame.tags['bidirectionalAnalysis']);
115
- this._isSubstitutionOn = stringToBool(this._dataFrame.tags['showSubstitution']);
116
- this._maxSubstitutions = parseInt(this._dataFrame.tags['maxSubstitutions']);
117
- this._activityLimit = parseFloat(this._dataFrame.tags['activityLimit']);
129
+ getViewer(): SARViewerBase {
130
+ const viewer = this.sarViewer ?? this.sarViewerVertical;
131
+ if (!viewer)
132
+ throw new Error('ViewerError: none of the SAR viewers is initialized');
133
+ return viewer;
118
134
  }
119
135
 
120
- setProperties(
121
- activityScaling: string, filterMode: boolean, twoColorMode: boolean, isSubstitutionOn: boolean,
122
- maxSubstitutions: number, activityLimit: number, forceUpdate = false,
123
- ): void {
124
- const chooseAction =
125
- (value: string, defaultValue: string | boolean | number): string | boolean | number =>
126
- forceUpdate ? value : defaultValue ?? value;
127
- this._dataFrame.tags['scaling'] = chooseAction(`${activityScaling}`, this._dataFrame.tags['scaling']);
128
- this._dataFrame.tags['filterMode'] = chooseAction(`${filterMode}`, this._dataFrame.tags['filterMode']);
129
- this._dataFrame.tags['bidirectionalAnalysis'] =
130
- chooseAction(`${twoColorMode}`, this._dataFrame.tags['bidirectionalAnalysis']);
131
- this._dataFrame.tags['showSubstitution'] =
132
- chooseAction(`${isSubstitutionOn}`, this._dataFrame.tags['showSubstitution']);
133
- this._dataFrame.tags['maxSubstitutions'] =
134
- chooseAction(`${maxSubstitutions}`, this._dataFrame.tags['maxSubstitutions']);
135
- this._dataFrame.tags['activityLimit'] = chooseAction(`${activityLimit}`, this._dataFrame.tags['activityLimit']);
136
-
137
- this.updateProperties();
138
- }
136
+ isPropertyChanged(viewer: SARViewerBase): boolean {
137
+ let result = false;
138
+ if (typeof viewer == 'undefined')
139
+ return result;
139
140
 
140
- async updateData(
141
- activityScaling?: string, sourceGrid?: DG.Grid, twoColorMode?: boolean, activityLimit?: number,
142
- maxSubstitutions?: number, isSubstitutionOn?: boolean, filterMode?: boolean,
143
- ): Promise<void> {
144
- //FIXME: threre are too many assignments, some are duplicating
145
- this._activityScaling = activityScaling ?? this._activityScaling;
146
- this._sourceGrid = sourceGrid ?? this._sourceGrid;
147
- this._twoColorMode = twoColorMode ?? this._twoColorMode;
148
- this._activityLimit = activityLimit ?? this._activityLimit;
149
- this._maxSubstitutions = maxSubstitutions ?? this._maxSubstitutions;
150
- this._isSubstitutionOn = isSubstitutionOn ?? this._isSubstitutionOn;
151
- this._filterMode = filterMode ?? this._filterMode;
152
- this.setProperties(this._activityScaling, this._filterMode, this._twoColorMode, this._isSubstitutionOn,
153
- this._maxSubstitutions, this._activityLimit, true);
154
-
155
- await this.updateDefault();
141
+ const viewerProps = viewer.props.getProperties();
142
+ const tempProps = this.usedProperties;
143
+ for (const property of viewerProps) {
144
+ const propName = property.name;
145
+ const propVal = property.get(viewer);
146
+ if (tempProps[propName] != propVal) {
147
+ tempProps[propName] = propVal;
148
+ result = true;
149
+ }
150
+ }
151
+ this.usedProperties = tempProps;
152
+ return result;
156
153
  }
157
154
 
158
- async updateDefault(): Promise<void> {
159
- if (this._activityScaling && this._sourceGrid && this._twoColorMode !== null && !this._isUpdating) {
155
+ updateDefault(): void {
156
+ const viewer = this.getViewer();
157
+ const proprtyChanged = this.isPropertyChanged(this.sarViewer) || this.isPropertyChanged(this.sarViewerVertical);
158
+ if ((this._sourceGrid && !this._isUpdating && proprtyChanged) || !this.isInitialized) {
159
+ this.isInitialized = true;
160
160
  this._isUpdating = true;
161
- const [viewerGrid, viewerVGrid, statsDf] = await this.initializeViewersComponents();
161
+ const [viewerGrid, viewerVGrid, statsDf] = this.initializeViewersComponents();
162
162
  //FIXME: modify during the initializeViewersComponents stages
163
163
  this._statsDataFrameSubject.next(statsDf);
164
164
  this._sarGridSubject.next(viewerGrid);
165
165
  this._sarVGridSubject.next(viewerVGrid);
166
- if (this._isSubstitutionOn) {
166
+ if (viewer.showSubstitution) {
167
167
  this._substitutionTableSubject.next(this.substitutionsInfo);
168
168
  this._isSubstInitialized = true;
169
169
  }
170
- }
171
- await this.updateBarchart();
172
- this.invalidateSelection();
173
170
 
174
- this._isUpdating = false;
175
- }
171
+ this.invalidateSelection();
176
172
 
177
- async updateBarchart(): Promise<void> {
178
- this.stackedBarchart ??= await this._dataFrame?.plot.fromType('StackedBarChartAA') as StackedBarChart;
179
- if (this.stackedBarchart && this._sourceGrid)
180
- addViewerToHeader(this._sourceGrid, this.stackedBarchart);
173
+ this._isUpdating = false;
174
+ }
181
175
  }
182
176
 
183
- async initializeViewersComponents(): Promise<[DG.Grid, DG.Grid, DG.DataFrame]> {
177
+ initializeViewersComponents(): [DG.Grid, DG.Grid, DG.DataFrame] {
184
178
  if (this._sourceGrid === null)
185
179
  throw new Error(`Source grid is not initialized`);
186
180
 
187
181
  //Split the aligned sequence into separate AARs
188
- let splitSeqDf: DG.DataFrame | undefined;
189
- let invalidIndexes: number[];
190
- const col: DG.Column = this._dataFrame.columns.bySemType(C.SEM_TYPES.ALIGNED_SEQUENCE)!;
191
- [splitSeqDf, invalidIndexes] = PeptidesModel.splitAlignedPeptides(col);
182
+ const col: DG.Column<string> = this.df.columns.bySemType(C.SEM_TYPES.MACROMOLECULE)!;
183
+ // const alphabet = col.tags[DG.TAGS.UNITS].split(':')[2];
184
+ const alphabet = col.tags['alphabet'];
185
+ const splitSeqDf = splitAlignedSequences(col);
186
+
187
+ this.barData = calculateBarsData(splitSeqDf.columns.toList(), this.df.selection);
192
188
 
193
189
  const positionColumns = splitSeqDf.columns.names();
194
- const renderColNames: string[] = splitSeqDf.columns.names();
195
190
 
196
- const activityCol = this._dataFrame.columns.bySemType(C.SEM_TYPES.ACTIVITY)!;
191
+ const activityCol = this.df.columns.bySemType(C.SEM_TYPES.ACTIVITY)!;
197
192
  splitSeqDf.columns.add(activityCol);
198
193
 
199
194
  this.joinDataFrames(positionColumns, splitSeqDf);
200
195
 
201
- for (const dfCol of this._dataFrame.columns) {
196
+ for (const dfCol of this.df.columns) {
202
197
  if (positionColumns.includes(dfCol.name))
203
- setAARRenderer(dfCol, this._sourceGrid);
198
+ setAARRenderer(dfCol, alphabet, this._sourceGrid);
204
199
  }
205
200
 
206
- this.sortSourceGrid(this._sourceGrid);
201
+ this.sortSourceGrid();
207
202
 
208
- await this.createScaledCol(this._activityScaling, this._dataFrame, this._sourceGrid, splitSeqDf);
203
+ const viewer = this.getViewer();
209
204
 
210
- //unpivot a table and handle duplicates
211
- splitSeqDf = splitSeqDf.groupBy(positionColumns)
212
- .add('med', C.COLUMNS_NAMES.ACTIVITY_SCALED, C.COLUMNS_NAMES.ACTIVITY_SCALED)
213
- .aggregate();
205
+ this.createScaledCol(viewer.scaling, splitSeqDf);
214
206
 
215
- const peptidesCount = splitSeqDf.rowCount;
207
+ //unpivot a table and handle duplicates
208
+ let matrixDf = splitSeqDf.groupBy(positionColumns).aggregate();
216
209
 
217
- let matrixDf = splitSeqDf.unpivot(
218
- [C.COLUMNS_NAMES.ACTIVITY_SCALED], positionColumns, C.COLUMNS_NAMES.POSITION, C.COLUMNS_NAMES.AMINO_ACID_RESIDUE);
210
+ matrixDf = matrixDf.unpivot([], positionColumns, C.COLUMNS_NAMES.POSITION, C.COLUMNS_NAMES.AMINO_ACID_RESIDUE);
219
211
 
220
- //FIXME: for some reason Mean difference is not calculated for all the AARs
221
212
  //statistics for specific AAR at a specific position
222
- const statsDf = await this.calculateStatistics(matrixDf, peptidesCount, splitSeqDf);
213
+ this.statsDf = this.calculateStatistics(matrixDf);
223
214
 
224
215
  // SAR matrix table
225
216
  //pivot a table to make it matrix-like
226
- matrixDf = statsDf.groupBy([C.COLUMNS_NAMES.AMINO_ACID_RESIDUE])
217
+ matrixDf = this.statsDf.groupBy([C.COLUMNS_NAMES.AMINO_ACID_RESIDUE])
227
218
  .pivot(C.COLUMNS_NAMES.POSITION)
228
219
  .add('first', C.COLUMNS_NAMES.MEAN_DIFFERENCE, '')
229
220
  .aggregate();
230
221
  matrixDf.name = 'SAR';
231
222
 
232
223
  // Setting category order
233
- await this.setCategoryOrder(this._twoColorMode, statsDf, matrixDf);
224
+ this.setCategoryOrder(matrixDf);
234
225
 
235
226
  // SAR vertical table (naive, choose best Mean difference from pVals <= 0.01)
236
- const sequenceDf = this.createVerticalTable(statsDf, this._twoColorMode);
237
- renderColNames.push(C.COLUMNS_NAMES.MEAN_DIFFERENCE);
227
+ const sequenceDf = this.createVerticalTable();
238
228
 
239
-
240
- if (this._isSubstitutionOn || !this._isSubstInitialized)
229
+ if (viewer.showSubstitution || !this._isSubstInitialized)
241
230
  this.calcSubstitutions();
242
231
 
243
- //TODO: move everything below out to controller
244
- const [sarGrid, sarVGrid] = this.createGrids(matrixDf, positionColumns, sequenceDf);
232
+ const [sarGrid, sarVGrid] = this.createGrids(matrixDf, positionColumns, sequenceDf, alphabet);
245
233
 
246
234
  this._sarGrid = sarGrid;
247
235
  this._sarVGrid = sarVGrid;
248
236
 
249
- this.setCellRenderers(
250
- renderColNames, statsDf, this._twoColorMode, sarGrid, sarVGrid, this._isSubstitutionOn);
237
+ positionColumns.push(C.COLUMNS_NAMES.MEAN_DIFFERENCE);
238
+
239
+ this.setBarChartInteraction();
240
+
241
+ this.setCellRenderers(positionColumns, sarGrid, sarVGrid);
251
242
 
252
243
  // show all the statistics in a tooltip over cell
253
- this.setTooltips(renderColNames, statsDf, peptidesCount, sarGrid, sarVGrid, this._dataFrame);
244
+ this.setTooltips(positionColumns, sarGrid, sarVGrid);
254
245
 
255
246
  this.setInteractionCallback();
256
247
 
257
248
  this.setBitsetCallback();
258
249
 
259
- this.postProcessGrids(this._sourceGrid, invalidIndexes, sarGrid, sarVGrid);
250
+ this.postProcessGrids(sarGrid, sarVGrid);
260
251
 
261
252
  //TODO: return class instead
262
- return [sarGrid, sarVGrid, statsDf];
253
+ return [sarGrid, sarVGrid, this.statsDf];
263
254
  }
264
255
 
265
- //TODO: move to controller?
266
256
  calcSubstitutions(): void {
267
- const activityValues: DG.Column<number> = this._dataFrame.columns.bySemType(C.SEM_TYPES.ACTIVITY_SCALED)!;
268
- const columnList: DG.Column<string>[] = this._dataFrame.columns.bySemTypeAll(C.SEM_TYPES.AMINO_ACIDS);
257
+ const activityValues: DG.Column<number> = this.df.columns.bySemType(C.SEM_TYPES.ACTIVITY_SCALED)!;
258
+ const columnList: DG.Column<string>[] = this.df.columns.bySemTypeAll(C.SEM_TYPES.MONOMER);
269
259
  const nCols = columnList.length;
270
260
  if (nCols == 0)
271
- throw new Error(`Couldn't find any column of semType '${C.SEM_TYPES.AMINO_ACIDS}'`);
261
+ throw new Error(`Couldn't find any column of semType '${C.SEM_TYPES.MONOMER}'`);
272
262
 
263
+ const viewer = this.getViewer();
273
264
  this.substitutionsInfo = new Map();
274
- const nRows = this._dataFrame.rowCount;
265
+ const nRows = this.df.rowCount;
275
266
  for (let seq1Idx = 0; seq1Idx < nRows - 1; seq1Idx++) {
276
267
  for (let seq2Idx = seq1Idx + 1; seq2Idx < nRows; seq2Idx++) {
277
268
  let substCounter = 0;
278
- const activityValSeq1 = activityValues.get(seq1Idx);
279
- const activityValSeq2 = activityValues.get(seq2Idx);
269
+ const activityValSeq1 = activityValues.get(seq1Idx)!;
270
+ const activityValSeq2 = activityValues.get(seq2Idx)!;
280
271
  const delta = activityValSeq1 - activityValSeq2;
281
- if (Math.abs(delta) < this._activityLimit)
272
+ if (Math.abs(delta) < viewer.minActivityDelta)
282
273
  continue;
283
274
 
284
275
  let substCounterFlag = false;
285
276
  const tempData: {pos: string, seq1monomer: string, seq2monomer: string, seq1Idx: number, seq2Idx: number}[] =
286
277
  [];
287
278
  for (const currentPosCol of columnList) {
288
- const seq1monomer = currentPosCol.get(seq1Idx);
289
- const seq2monomer = currentPosCol.get(seq2Idx);
279
+ const seq1monomer = currentPosCol.get(seq1Idx)!;
280
+ const seq2monomer = currentPosCol.get(seq2Idx)!;
290
281
  if (seq1monomer == seq2monomer)
291
282
  continue;
292
283
 
293
284
  substCounter++;
294
- substCounterFlag = substCounter > this._maxSubstitutions;
285
+ substCounterFlag = substCounter > viewer.maxSubstitutions;
295
286
  if (substCounterFlag)
296
287
  break;
297
288
 
@@ -349,116 +340,96 @@ export class PeptidesModel {
349
340
 
350
341
  joinDataFrames(positionColumns: string[], splitSeqDf: DG.DataFrame): void {
351
342
  // append splitSeqDf columns to source table and make sure columns are not added more than once
352
- const name = this._dataFrame.name;
353
- const dfColsSet = new Set(this._dataFrame.columns.names());
343
+ const name = this.df.name;
344
+ const dfColsSet = new Set(this.df.columns.names());
354
345
  if (!positionColumns.every((col: string) => dfColsSet.has(col))) {
355
- this._dataFrame.join(splitSeqDf, [C.COLUMNS_NAMES.ACTIVITY], [C.COLUMNS_NAMES.ACTIVITY],
356
- this._dataFrame.columns.names(), positionColumns, 'inner', true);
346
+ this.df.join(splitSeqDf, [C.COLUMNS_NAMES.ACTIVITY], [C.COLUMNS_NAMES.ACTIVITY],
347
+ this.df.columns.names(), positionColumns, 'inner', true);
357
348
  }
358
- this._dataFrame.name = name;
349
+ this.df.name = name;
359
350
  this.currentView.name = name;
360
351
  }
361
352
 
362
- sortSourceGrid(sourceGrid: DG.Grid): void {
363
- if (sourceGrid) {
364
- const colNames: DG.GridColumn[] = [];
365
- for (let i = 1; i < sourceGrid.columns.length; i++)
366
- colNames.push(sourceGrid.columns.byIndex(i)!);
367
-
368
- colNames.sort((a, b)=>{
369
- if (a.column!.semType == C.SEM_TYPES.AMINO_ACIDS) {
370
- if (b.column!.semType == C.SEM_TYPES.AMINO_ACIDS)
371
- return 0;
372
- return -1;
373
- }
374
- if (b.column!.semType == C.SEM_TYPES.AMINO_ACIDS)
375
- return 1;
376
- return 0;
377
- });
378
- sourceGrid.columns.setOrder(colNames.map((v) => v.name));
379
- }
353
+ sortSourceGrid(): void {
354
+ const colNames: DG.GridColumn[] = [];
355
+ for (let i = 1; i < this._sourceGrid.columns.length; i++)
356
+ colNames.push(this._sourceGrid.columns.byIndex(i)!);
357
+
358
+ colNames.sort((a, b)=>{
359
+ if (a.column!.semType == C.SEM_TYPES.MONOMER) {
360
+ if (b.column!.semType == C.SEM_TYPES.MONOMER)
361
+ return 0;
362
+ return -1;
363
+ }
364
+ if (b.column!.semType == C.SEM_TYPES.MONOMER)
365
+ return 1;
366
+ return 0;
367
+ });
368
+ this._sourceGrid.columns.setOrder(colNames.map((v) => v.name));
380
369
  }
381
370
 
382
- //TODO: move out, merge with controller's scaleActivity
383
- async createScaledCol(
384
- activityScaling: string, df: DG.DataFrame, sourceGrid: DG.Grid, splitSeqDf: DG.DataFrame,
385
- ): Promise<void> {
386
- const [scaledDf, newColName] = await PeptidesModel.scaleActivity(
387
- activityScaling, df, df.tags[C.COLUMNS_NAMES.ACTIVITY]);
371
+ createScaledCol(activityScaling: string, splitSeqDf: DG.DataFrame): void {
372
+ const [scaledDf, newColName] =
373
+ scaleActivity(activityScaling, this.df, this.df.tags[C.COLUMNS_NAMES.ACTIVITY]);
388
374
  //TODO: make another func
389
375
  const scaledCol = scaledDf.getCol(C.COLUMNS_NAMES.ACTIVITY_SCALED);
390
376
  scaledCol.semType = C.SEM_TYPES.ACTIVITY_SCALED;
391
377
  splitSeqDf.columns.add(scaledCol);
392
- const oldScaledCol = df.getCol(C.COLUMNS_NAMES.ACTIVITY_SCALED);
393
- df.columns.replace(oldScaledCol, scaledCol);
394
- const gridCol = sourceGrid.col(C.COLUMNS_NAMES.ACTIVITY_SCALED);
378
+ const oldScaledCol = this.df.getCol(C.COLUMNS_NAMES.ACTIVITY_SCALED);
379
+ this.df.columns.replace(oldScaledCol, scaledCol);
380
+ const gridCol = this._sourceGrid.col(C.COLUMNS_NAMES.ACTIVITY_SCALED);
395
381
  if (gridCol !== null) {
396
382
  gridCol.name = newColName;
397
- df.tags[C.COLUMNS_NAMES.ACTIVITY_SCALED] = newColName;
383
+ this.df.tags[C.COLUMNS_NAMES.ACTIVITY_SCALED] = newColName;
398
384
  }
399
385
 
400
- sourceGrid.columns.setOrder([newColName]);
386
+ this._sourceGrid.columns.setOrder([newColName]);
401
387
  }
402
388
 
403
- //TODO: move out
404
- async calculateStatistics(
405
- matrixDf: DG.DataFrame, peptidesCount: number, splitSeqDf: DG.DataFrame): Promise<DG.DataFrame> {
406
- matrixDf = matrixDf.groupBy([C.COLUMNS_NAMES.POSITION, C.COLUMNS_NAMES.AMINO_ACID_RESIDUE])
407
- .add('count', C.COLUMNS_NAMES.ACTIVITY_SCALED, 'Count')
408
- .aggregate();
409
-
410
- const countThreshold = 4;
411
- matrixDf.rows.filter((row) => row.Count >= countThreshold && row.Count <= peptidesCount - countThreshold);
412
- matrixDf = matrixDf.clone(matrixDf.filter);
413
-
414
- // calculate additional stats
415
- await matrixDf.columns.addNewCalculated('Ratio', '${count}/'.concat(`${peptidesCount}`));
389
+ calculateStatistics(matrixDf: DG.DataFrame): DG.DataFrame {
390
+ matrixDf = matrixDf.groupBy([C.COLUMNS_NAMES.POSITION, C.COLUMNS_NAMES.AMINO_ACID_RESIDUE]).aggregate();
416
391
 
417
392
  //calculate p-values based on t-test
418
- let pvalues: Float32Array = new Float32Array(matrixDf.rowCount).fill(1);
419
- const mdCol: DG.Column = matrixDf.columns.addNewFloat(C.COLUMNS_NAMES.MEAN_DIFFERENCE);
420
- const pValCol: DG.Column = matrixDf.columns.addNewFloat(C.COLUMNS_NAMES.P_VALUE);
393
+ const matrixCols = matrixDf.columns;
394
+ const mdCol= matrixCols.addNewFloat(C.COLUMNS_NAMES.MEAN_DIFFERENCE);
395
+ const pValCol = matrixCols.addNewFloat(C.COLUMNS_NAMES.P_VALUE);
396
+ const countCol = matrixCols.addNewInt(C.COLUMNS_NAMES.COUNT);
397
+ const ratioCol = matrixCols.addNewFloat(C.COLUMNS_NAMES.RATIO);
421
398
  const aarCol = matrixDf.getCol(C.COLUMNS_NAMES.AMINO_ACID_RESIDUE);
422
399
  const posCol = matrixDf.getCol(C.COLUMNS_NAMES.POSITION);
400
+ const activityCol: number[] = this.df.getCol(C.COLUMNS_NAMES.ACTIVITY_SCALED).toList();
401
+ const sourceDfLen = activityCol.length;
402
+
423
403
  for (let i = 0; i < matrixDf.rowCount; i++) {
424
- const position = posCol.get(i);
425
- const aar = aarCol.get(i);
426
-
427
- splitSeqDf.rows.select((row) => row[position] === aar);
428
- const currentActivity: number[] = splitSeqDf
429
- .clone(splitSeqDf.selection, [C.COLUMNS_NAMES.ACTIVITY_SCALED])
430
- .getCol(C.COLUMNS_NAMES.ACTIVITY_SCALED)
431
- .toList();
432
-
433
- splitSeqDf.rows.select((row) => row[position] !== aar);
434
- const otherActivity: number[] = splitSeqDf
435
- .clone(splitSeqDf.selection, [C.COLUMNS_NAMES.ACTIVITY_SCALED])
436
- .getCol(C.COLUMNS_NAMES.ACTIVITY_SCALED)
437
- .toList();
438
-
439
- const testResult = tTest(currentActivity, otherActivity);
440
- const currentMeanDiff = testResult[C.COLUMNS_NAMES.MEAN_DIFFERENCE]!;
441
- const pvalue = testResult[currentMeanDiff >= 0 ? 'p-value more' : 'p-value less'];
442
-
443
- mdCol.set(i, currentMeanDiff);
444
- pvalues[i] = pvalue;
404
+ const position: string = posCol.get(i);
405
+ const aar: string = aarCol.get(i);
406
+ const mask = DG.BitSet.create(sourceDfLen, (j) => this.df.get(position, j) == aar);
407
+ const stats = getStats(activityCol, mask);
408
+
409
+ mdCol.set(i, stats.meanDifference);
410
+ pValCol.set(i, stats.pValue);
411
+ countCol.set(i, stats.count);
412
+ ratioCol.set(i, stats.ratio);
445
413
  }
446
414
 
447
- pvalues = fdrcorrection(pvalues)[1];
448
-
449
- for (let i = 0; i < pvalues.length; ++i)
450
- pValCol.set(i, pvalues[i]);
415
+ const countThreshold = 4;
416
+ matrixDf = matrixDf.rows.match(`${C.COLUMNS_NAMES.COUNT} >= ${countThreshold}`).toDataFrame();
417
+ matrixDf = matrixDf.rows.match(`${C.COLUMNS_NAMES.COUNT} <= ${sourceDfLen - countThreshold}`).toDataFrame();
451
418
 
452
- return matrixDf.clone();
419
+ return matrixDf as DG.DataFrame;
453
420
  }
454
421
 
455
- async setCategoryOrder(twoColorMode: boolean, statsDf: DG.DataFrame, matrixDf: DG.DataFrame): Promise<void> {
456
- const absMD = 'Absolute Mean difference';
457
- const sortArgument = twoColorMode ? absMD : C.COLUMNS_NAMES.MEAN_DIFFERENCE;
458
- if (twoColorMode)
459
- await statsDf.columns.addNewCalculated(absMD, 'Abs(${Mean difference})');
422
+ setCategoryOrder(matrixDf: DG.DataFrame): void {
423
+ let sortArgument: string = C.COLUMNS_NAMES.MEAN_DIFFERENCE;
424
+ if (this.getViewer().bidirectionalAnalysis) {
425
+ const mdCol = this.statsDf.getCol(sortArgument);
426
+ sortArgument = 'Absolute Mean difference';
427
+ const absMDCol = this.statsDf.columns.addNewFloat(sortArgument);
428
+ absMDCol.init((i) => Math.abs(mdCol.get(i)));
429
+ }
460
430
 
461
- const aarWeightsDf = statsDf.groupBy([C.COLUMNS_NAMES.AMINO_ACID_RESIDUE]).sum(sortArgument, 'weight').aggregate();
431
+ const aarWeightsDf = this.statsDf.groupBy([C.COLUMNS_NAMES.AMINO_ACID_RESIDUE]).sum(sortArgument, 'weight')
432
+ .aggregate();
462
433
  const aarList = aarWeightsDf.getCol(C.COLUMNS_NAMES.AMINO_ACID_RESIDUE).toList();
463
434
  const getWeight = (aar: string): number => aarWeightsDf
464
435
  .groupBy(['weight'])
@@ -470,11 +441,11 @@ export class PeptidesModel {
470
441
  matrixDf.getCol(C.COLUMNS_NAMES.AMINO_ACID_RESIDUE).setCategoryOrder(aarList);
471
442
  }
472
443
 
473
- createVerticalTable(statsDf: DG.DataFrame, twoColorMode: boolean): DG.DataFrame {
444
+ createVerticalTable(): DG.DataFrame {
474
445
  // TODO: aquire ALL of the positions
475
446
  const columns = [C.COLUMNS_NAMES.MEAN_DIFFERENCE, C.COLUMNS_NAMES.AMINO_ACID_RESIDUE, C.COLUMNS_NAMES.POSITION,
476
447
  'Count', 'Ratio', C.COLUMNS_NAMES.P_VALUE];
477
- let sequenceDf = statsDf.groupBy(columns)
448
+ let sequenceDf = this.statsDf.groupBy(columns)
478
449
  .where('pValue <= 0.1')
479
450
  .aggregate();
480
451
 
@@ -486,7 +457,7 @@ export class PeptidesModel {
486
457
  const rowCount = sequenceDf.rowCount;
487
458
  for (const pos of posColCategories) {
488
459
  tempStats = DG.Stats.fromColumn(mdCol, DG.BitSet.create(rowCount, (i) => posCol.get(i) === pos));
489
- maxAtPos[pos] = twoColorMode ?
460
+ maxAtPos[pos] = this.getViewer().bidirectionalAnalysis ?
490
461
  (tempStats.max > Math.abs(tempStats.min) ? tempStats.max : tempStats.min) :
491
462
  tempStats.max;
492
463
  }
@@ -495,7 +466,8 @@ export class PeptidesModel {
495
466
  return sequenceDf;
496
467
  }
497
468
 
498
- createGrids(matrixDf: DG.DataFrame, positionColumns: string[], sequenceDf: DG.DataFrame): DG.Grid[] {
469
+ createGrids(
470
+ matrixDf: DG.DataFrame, positionColumns: string[], sequenceDf: DG.DataFrame, alphabet: string): DG.Grid[] {
499
471
  const sarGrid = matrixDf.plot.grid();
500
472
  sarGrid.sort([C.COLUMNS_NAMES.AMINO_ACID_RESIDUE]);
501
473
  sarGrid.columns.setOrder([C.COLUMNS_NAMES.AMINO_ACID_RESIDUE].concat(positionColumns as C.COLUMNS_NAMES[]));
@@ -508,166 +480,203 @@ export class PeptidesModel {
508
480
 
509
481
  let tempCol = matrixDf.getCol(C.COLUMNS_NAMES.AMINO_ACID_RESIDUE);
510
482
  if (tempCol)
511
- setAARRenderer(tempCol, sarGrid);
483
+ setAARRenderer(tempCol, alphabet, sarGrid);
512
484
 
513
485
  tempCol = sequenceDf.getCol(C.COLUMNS_NAMES.AMINO_ACID_RESIDUE);
514
486
  if (tempCol)
515
- setAARRenderer(tempCol, sarGrid);
487
+ setAARRenderer(tempCol, alphabet, sarGrid);
516
488
 
517
489
  return [sarGrid, sarVGrid];
518
490
  }
519
491
 
520
- //TODO: move out
521
- setCellRenderers(
522
- renderColNames: string[], statsDf: DG.DataFrame, twoColorMode: boolean, sarGrid: DG.Grid, sarVGrid: DG.Grid,
523
- isSubstitutionOn: boolean,
524
- ): void {
525
- const mdCol = statsDf.getCol(C.COLUMNS_NAMES.MEAN_DIFFERENCE);
492
+ setBarChartInteraction(): void {
493
+ const eventAction = (ev: MouseEvent): void => {
494
+ const cell = this._sourceGrid.hitTest(ev.offsetX, ev.offsetY);
495
+ if (cell?.isColHeader && cell.tableColumn?.semType == C.SEM_TYPES.MONOMER) {
496
+ const newBarPart = this.findAARandPosition(cell, ev);
497
+ this.requestBarchartAction(ev, newBarPart);
498
+ }
499
+ };
500
+
501
+ // The following events makes the barchart interactive
502
+ rxjs.fromEvent<MouseEvent>(this._sourceGrid.overlay, 'mousemove')
503
+ .subscribe((mouseMove: MouseEvent) => eventAction(mouseMove));
504
+ rxjs.fromEvent<MouseEvent>(this._sourceGrid.overlay, 'click')
505
+ .subscribe((mouseMove: MouseEvent) => eventAction(mouseMove));
506
+ }
507
+
508
+ findAARandPosition(cell: DG.GridCell, ev: MouseEvent): {monomer: string, position: string} | null {
509
+ const barCoords = this.barsBounds[cell.tableColumn!.name];
510
+ for (const [monomer, coords] of Object.entries(barCoords)) {
511
+ const isIntersectingX = ev.offsetX >= coords.x && ev.offsetX <= coords.x + coords.width;
512
+ const isIntersectingY = ev.offsetY >= coords.y && ev.offsetY <= coords.y + coords.height;
513
+ if (isIntersectingX && isIntersectingY)
514
+ return {monomer: monomer, position: cell.tableColumn!.name};
515
+ }
516
+
517
+ return null;
518
+ }
519
+
520
+ requestBarchartAction(ev: MouseEvent, barPart: {position: string, monomer: string} | null): void {
521
+ if (!barPart)
522
+ return;
523
+ const monomer = barPart.monomer;
524
+ const position = barPart.position;
525
+ if (ev.type === 'click') {
526
+ ev.shiftKey ? this.modifyCurrentSelection(monomer, position) :
527
+ this.initCurrentSelection(monomer, position);
528
+ } else {
529
+ const bar = `${monomer}:${position}`;
530
+ if (this.cachedBarchartTooltip.bar == bar)
531
+ ui.tooltip.show(this.cachedBarchartTooltip.tooltip!, ev.clientX, ev.clientY);
532
+ else
533
+ this.cachedBarchartTooltip = {bar: bar, tooltip: this.showTooltipAt(monomer, position, ev.clientX, ev.clientY)};
534
+ }
535
+ }
536
+
537
+ setCellRenderers(renderColNames: string[], sarGrid: DG.Grid, sarVGrid: DG.Grid): void {
538
+ const mdCol = this.statsDf.getCol(C.COLUMNS_NAMES.MEAN_DIFFERENCE);
526
539
  //decompose into two different renering funcs
527
- const cellRendererAction = (args: DG.GridCellRenderArgs): void => {
540
+ const renderCell = (args: DG.GridCellRenderArgs): void => {
528
541
  const canvasContext = args.g;
529
542
  const bound = args.bounds;
530
- const cell = args.cell;
531
- const tableColName = cell.tableColumn?.name;
532
- const tableRowIndex = cell.tableRowIndex!;
533
- const cellValue = cell.cell.value;
534
- const midX = bound.x + bound.width / 2;
535
- const midY = bound.y + bound.height / 2;
536
543
 
537
544
  canvasContext.save();
538
545
  canvasContext.beginPath();
539
546
  canvasContext.rect(bound.x, bound.y, bound.width, bound.height);
540
547
  canvasContext.clip();
541
548
 
549
+ // Hide row column
550
+ const cell = args.cell;
542
551
  if (cell.isRowHeader && cell.gridColumn.visible) {
543
552
  cell.gridColumn.visible = false;
544
553
  args.preventDefault();
545
554
  return;
546
555
  }
547
556
 
557
+ const tableColName = cell.tableColumn?.name;
558
+ const tableRowIndex = cell.tableRowIndex!;
548
559
  if (cell.isTableCell && tableColName && tableRowIndex !== null && renderColNames.indexOf(tableColName) !== -1) {
549
- const gridTable = cell.grid.table;
550
- const currentPosition: string = tableColName !== C.COLUMNS_NAMES.MEAN_DIFFERENCE ?
551
- tableColName : gridTable.get(C.COLUMNS_NAMES.POSITION, tableRowIndex);
552
- const currentAAR: string = gridTable.get(C.COLUMNS_NAMES.AMINO_ACID_RESIDUE, tableRowIndex);
553
-
554
- const queryAAR = `${C.COLUMNS_NAMES.AMINO_ACID_RESIDUE} = ${currentAAR}`;
555
- if (cellValue) {
556
- const query = `${queryAAR} and ${C.COLUMNS_NAMES.POSITION} = ${currentPosition}`;
557
- const pVal: number = statsDf
558
- .groupBy([C.COLUMNS_NAMES.P_VALUE])
559
- .where(query)
560
- .aggregate()
561
- .get(C.COLUMNS_NAMES.P_VALUE, 0);
562
-
563
- let coef: string;
564
- const variant = cellValue < 0;
565
- if (pVal < 0.01)
566
- coef = variant && twoColorMode ? '#FF7900' : '#299617';
567
- else if (pVal < 0.05)
568
- coef = variant && twoColorMode ? '#FFA500' : '#32CD32';
569
- else if (pVal < 0.1)
570
- coef = variant && twoColorMode ? '#FBCEB1' : '#98FF98';
571
- else
572
- coef = DG.Color.toHtml(DG.Color.lightLightGray);
573
-
574
-
575
- const chooseMin = (): number => twoColorMode ? 0 : mdCol.min;
576
- const chooseMax = (): number => twoColorMode ? Math.max(Math.abs(mdCol.min), mdCol.max) : mdCol.max;
577
- const chooseCurrent = (): any => twoColorMode ? Math.abs(cellValue) : cellValue;
578
-
579
- const rCoef = (chooseCurrent() - chooseMin()) / (chooseMax() - chooseMin());
580
-
581
- const maxRadius = 0.9 * (bound.width > bound.height ? bound.height : bound.width) / 2;
582
- const radius = Math.floor(maxRadius * rCoef);
583
-
584
- canvasContext.beginPath();
585
- canvasContext.fillStyle = coef;
586
- canvasContext.arc(midX, midY, radius < 3 ? 3 : radius, 0, Math.PI * 2, true);
587
- canvasContext.closePath();
588
-
589
- canvasContext.fill();
590
- if (isSubstitutionOn) {
591
- canvasContext.textBaseline = 'middle';
592
- canvasContext.textAlign = 'center';
593
- canvasContext.fillStyle = DG.Color.toHtml(DG.Color.getContrastColor(DG.Color.fromHtml(coef)));
594
- canvasContext.font = '13px Roboto, Roboto Local, sans-serif';
595
- let substValue = 0;
596
- this.substitutionsInfo.get(currentAAR)?.get(currentPosition)?.forEach((idxs) => substValue += idxs.length);
597
- if (substValue && substValue != 0)
598
- canvasContext.fillText(substValue.toString(), midX, midY);
599
- }
600
-
601
- //TODO: frame based on currentSelection
602
- const aarSelection = this.currentSelection[currentPosition];
603
- if (aarSelection && aarSelection.includes(currentAAR)) {
604
- canvasContext.strokeStyle = '#000';
605
- canvasContext.lineWidth = 1;
606
- canvasContext.strokeRect(bound.x + 1, bound.y + 1, bound.width - 1, bound.height - 1);
607
- }
560
+ const cellValue: number | null = cell.cell.value;
561
+
562
+ if (cellValue && cellValue !== DG.INT_NULL && cellValue !== DG.FLOAT_NULL) {
563
+ const gridTable = cell.grid.table;
564
+ const currentPosition: string = tableColName !== C.COLUMNS_NAMES.MEAN_DIFFERENCE ?
565
+ tableColName : gridTable.get(C.COLUMNS_NAMES.POSITION, tableRowIndex);
566
+ const currentAAR: string = gridTable.get(C.COLUMNS_NAMES.AMINO_ACID_RESIDUE, tableRowIndex);
567
+
568
+ const viewer = this.getViewer();
569
+ renderSARCell(canvasContext, currentAAR, currentPosition, this.statsDf, viewer.bidirectionalAnalysis, mdCol,
570
+ bound, cellValue, this.currentSelection, viewer.showSubstitution ? this.substitutionsInfo : null);
608
571
  }
609
572
  args.preventDefault();
610
573
  }
611
574
  canvasContext.restore();
612
575
  };
613
- sarGrid.onCellRender.subscribe(cellRendererAction);
614
- sarVGrid.onCellRender.subscribe(cellRendererAction);
576
+ sarGrid.onCellRender.subscribe(renderCell);
577
+ sarVGrid.onCellRender.subscribe(renderCell);
578
+
579
+ this._sourceGrid.setOptions({'colHeaderHeight': 130});
580
+ this._sourceGrid.onCellRender.subscribe((gcArgs) => {
581
+ const context = gcArgs.g;
582
+ const bounds = gcArgs.bounds;
583
+ const col = gcArgs.cell.tableColumn;
584
+
585
+ context.save();
586
+ context.beginPath();
587
+ context.rect(bounds.x, bounds.y, bounds.width, bounds.height);
588
+ context.clip();
589
+
590
+ if (gcArgs.cell.isColHeader && col?.semType == C.SEM_TYPES.MONOMER) {
591
+ const barBounds = renderBarchart(context, col, this.barData[col.name], bounds, this.df.filter.trueCount);
592
+ this.barsBounds[col.name] = barBounds;
593
+ gcArgs.preventDefault();
594
+ }
595
+
596
+ context.restore();
597
+ });
615
598
  }
616
599
 
617
- //FIXME: doesn't work at all
618
- setTooltips(
619
- renderColNames: string[], statsDf: DG.DataFrame, peptidesCount: number, sarGrid: DG.Grid, sarVGrid: DG.Grid,
620
- sourceDf: DG.DataFrame,
621
- ): void {
622
- const onCellTooltipAction = async (cell: DG.GridCell, x: number, y: number): Promise<boolean> => {
623
- if (
624
- !cell.isRowHeader && !cell.isColHeader && cell.tableColumn !== null && cell.cell.value !== null &&
625
- cell.tableRowIndex !== null && renderColNames.indexOf(cell.tableColumn.name) !== -1) {
626
- const tooltipMap: { [index: string]: string } = {};
627
-
628
- for (const col of statsDf.columns.names()) {
629
- if (col !== C.COLUMNS_NAMES.AMINO_ACID_RESIDUE && col !== C.COLUMNS_NAMES.POSITION) {
630
- const currentPosition = cell.tableColumn.name !== C.COLUMNS_NAMES.MEAN_DIFFERENCE ?
631
- cell.tableColumn.name : cell.grid.table.get(C.COLUMNS_NAMES.POSITION, cell.tableRowIndex);
632
- const query =
633
- `${C.COLUMNS_NAMES.AMINO_ACID_RESIDUE} = ` +
634
- `${cell.grid.table.get(C.COLUMNS_NAMES.AMINO_ACID_RESIDUE, cell.tableRowIndex)} ` +
635
- `and ${C.COLUMNS_NAMES.POSITION} = ${currentPosition}`;
636
- const textNum = statsDf.groupBy([col]).where(query).aggregate().get(col, 0);
637
- let text = `${col === 'Count' ? textNum : textNum.toFixed(5)}`;
638
-
639
- if (col === 'Count')
640
- text += ` / ${peptidesCount}`;
641
- else if (col === C.COLUMNS_NAMES.P_VALUE)
642
- text = parseFloat(text) !== 0 ? text : '<0.01';
643
-
644
-
645
- tooltipMap[col === C.COLUMNS_NAMES.P_VALUE ? 'p-value' : col] = text;
646
- }
647
- }
600
+ setTooltips(renderColNames: string[], sarGrid: DG.Grid, sarVGrid: DG.Grid): void {
601
+ const showTooltip = (cell: DG.GridCell, x: number, y: number): boolean => {
602
+ const tableCol = cell.tableColumn;
603
+ const tableColName = tableCol?.name;
604
+ const tableRowIndex = cell.tableRowIndex;
648
605
 
649
- ui.tooltip.show(ui.tableFromMap(tooltipMap), x, y);
650
- }
651
- if (!cell.isColHeader && cell.tableColumn?.name == C.COLUMNS_NAMES.AMINO_ACID_RESIDUE) {
652
- const monomerLib = sourceDf.temp[MonomerLibrary.id];
653
- ChemPalette.showTooltip(cell, x, y, monomerLib);
606
+ if (!cell.isRowHeader && !cell.isColHeader && tableCol && tableRowIndex != null) {
607
+ const table = cell.grid.table;
608
+ const currentAAR = table.get(C.COLUMNS_NAMES.AMINO_ACID_RESIDUE, tableRowIndex);
609
+
610
+ if (tableCol.semType == C.SEM_TYPES.MONOMER)
611
+ this.showMonomerTooltip(currentAAR, x, y);
612
+ else if (cell.cell.value && renderColNames.includes(tableColName!)) {
613
+ const currentPosition = tableColName !== C.COLUMNS_NAMES.MEAN_DIFFERENCE ? tableColName :
614
+ table.get(C.COLUMNS_NAMES.POSITION, tableRowIndex);
615
+
616
+ this.showTooltipAt(currentAAR, currentPosition, x, y);
617
+ }
654
618
  }
655
619
  return true;
656
620
  };
657
- sarGrid.onCellTooltip(onCellTooltipAction);
658
- sarVGrid.onCellTooltip(onCellTooltipAction);
621
+
622
+ sarGrid.onCellTooltip(showTooltip);
623
+ sarVGrid.onCellTooltip(showTooltip);
624
+ this._sourceGrid.onCellTooltip((cell, x, y) => {
625
+ const col = cell.tableColumn;
626
+ const cellValue = cell.cell.value;
627
+ if (cellValue && col && col.semType === C.SEM_TYPES.MONOMER)
628
+ this.showMonomerTooltip(cellValue, x, y);
629
+ return true;
630
+ });
631
+ }
632
+
633
+ showMonomerTooltip(aar: string, x: number, y: number): void {
634
+ const tooltipElements: HTMLDivElement[] = [];
635
+ //@ts-ignore: no types for org
636
+ // const monomer: type.HELMMonomer = org.helm.webeditor.monomers.getMonomer('HELM_AA', aar);
637
+ const monomer: type.HELMMonomer = this.monomerLib[aar.toLowerCase()];
638
+
639
+ if (monomer) {
640
+ tooltipElements.push(ui.div(monomer.n));
641
+ const options = {autoCrop: true, autoCropMargin: 0, suppressChiralText: true};
642
+ tooltipElements.push(grok.chem.svgMol(monomer.m, undefined, undefined, options));
643
+ } else
644
+ tooltipElements.push(ui.div(aar));
645
+
646
+ ui.tooltip.show(ui.divV(tooltipElements), x, y);
647
+ }
648
+
649
+ showTooltipAt(aar: string, position: string, x: number, y: number): HTMLDivElement | null {
650
+ const currentStatsDf = this.statsDf.rows.match({Pos: position, AAR: aar}).toDataFrame();
651
+ const activityCol = this.df.columns.bySemType(C.SEM_TYPES.ACTIVITY_SCALED)!;
652
+ const splitCol = DG.Column.bool(C.COLUMNS_NAMES.SPLIT_COL, activityCol.length);
653
+ const currentPosCol = this.df.getCol(position);
654
+ splitCol.init((i) => currentPosCol.get(i) == aar);
655
+ const distributionTable = DG.DataFrame.fromColumns([activityCol, splitCol]);
656
+ const stats: Stats = {
657
+ count: currentStatsDf.get(C.COLUMNS_NAMES.COUNT, 0),
658
+ ratio: currentStatsDf.get(C.COLUMNS_NAMES.RATIO, 0),
659
+ pValue: currentStatsDf.get(C.COLUMNS_NAMES.P_VALUE, 0),
660
+ meanDifference: currentStatsDf.get(C.COLUMNS_NAMES.MEAN_DIFFERENCE, 0),
661
+ };
662
+ if (!stats.count)
663
+ return null;
664
+
665
+ const tooltip = getDistributionAndStats(distributionTable, stats, `${position} : ${aar}`, 'Other', true);
666
+
667
+ ui.tooltip.show(tooltip, x, y);
668
+
669
+ return tooltip;
659
670
  }
660
671
 
661
- //TODO: think about it, move out?
662
672
  setInteractionCallback(): void {
663
673
  const sarDf = this._sarGrid.dataFrame;
664
674
  const sarVDf = this._sarVGrid.dataFrame;
665
675
 
666
- const chooseAction = (aar: string, position: string, isShiftPressed: boolean) => {
676
+ const chooseAction = (aar: string, position: string, isShiftPressed: boolean): void =>
667
677
  isShiftPressed ? this.modifyCurrentSelection(aar, position) : this.initCurrentSelection(aar, position);
668
- };
669
678
 
670
- const gridCellValidation = (gc: DG.GridCell | null) => !gc || !gc.cell.value || !gc.tableColumn ||
679
+ const gridCellValidation = (gc: DG.GridCell | null): boolean => !gc || !gc.cell.value || !gc.tableColumn ||
671
680
  gc.tableRowIndex == null || gc.tableRowIndex == -1;
672
681
  this._sarGrid.root.addEventListener('click', (ev) => {
673
682
  const gridCell = this._sarGrid.hitTest(ev.offsetX, ev.offsetY);
@@ -690,7 +699,7 @@ export class PeptidesModel {
690
699
  chooseAction(aar, position, ev.shiftKey);
691
700
  });
692
701
 
693
- const cellChanged = (table: DG.DataFrame) => {
702
+ const cellChanged = (table: DG.DataFrame): void => {
694
703
  if (this.isCellChanging)
695
704
  return;
696
705
  this.isCellChanging = true;
@@ -723,7 +732,7 @@ export class PeptidesModel {
723
732
  }
724
733
 
725
734
  invalidateGrids(): void {
726
- this.stackedBarchart?.computeData();
735
+ // this.stackedBarchart?.computeData();
727
736
  this._sarGrid.invalidate();
728
737
  this._sarVGrid.invalidate();
729
738
  this._sourceGrid?.invalidate();
@@ -733,12 +742,9 @@ export class PeptidesModel {
733
742
  setBitsetCallback(): void {
734
743
  if (this.isBitsetChangedInitialized)
735
744
  return;
736
- const filter = this._dataFrame.filter;
737
- const selection = this._dataFrame.selection;
738
-
739
- const changeBitset = (currentBitset: DG.BitSet, previousBitset: DG.BitSet): void => {
740
- previousBitset.setAll(!this._filterMode, false);
745
+ const selection = this.df.selection;
741
746
 
747
+ const changeBitset = (currentBitset: DG.BitSet): void => {
742
748
  const edfSelection = this.edf?.selection;
743
749
  if (this.isPeptideSpaceChangingBitset) {
744
750
  if (edfSelection == null)
@@ -748,7 +754,7 @@ export class PeptidesModel {
748
754
  return;
749
755
  }
750
756
 
751
- const updateEdfSelection = () => {
757
+ const updateEdfSelection = (): void => {
752
758
  this.isChangingEdfBitset = true;
753
759
  edfSelection?.copyFrom(currentBitset);
754
760
  this.isChangingEdfBitset = false;
@@ -762,10 +768,10 @@ export class PeptidesModel {
762
768
  }
763
769
 
764
770
  //TODO: move out
765
- const getBitAt = (i: number) => {
771
+ const getBitAt = (i: number): boolean => {
766
772
  for (const position of positionList) {
767
- const positionCol: DG.Column<string> = this._dataFrame.getCol(position);
768
- if (this._currentSelection[position].includes(positionCol.get(i)))
773
+ const positionCol: DG.Column<string> = this.df.getCol(position);
774
+ if (this._currentSelection[position].includes(positionCol.get(i)!))
769
775
  return true;
770
776
  }
771
777
  return false;
@@ -775,38 +781,19 @@ export class PeptidesModel {
775
781
  updateEdfSelection();
776
782
  };
777
783
 
778
- const recalculateStatistics =
779
- (bitset: DG.BitSet): void => (this._dataFrame.temp[C.STATS] as FilteringStatistics).setMask(bitset);
780
-
781
- filter.onChanged.subscribe(() => {
782
- changeBitset(filter, selection);
783
- recalculateStatistics(filter);
784
- });
785
- selection.onChanged.subscribe(() => {
786
- changeBitset(selection, filter);
787
- recalculateStatistics(selection);
788
- });
784
+ selection.onChanged.subscribe(() => changeBitset(selection));
789
785
  this.isBitsetChangedInitialized = true;
790
786
  }
791
787
 
792
788
  fireBitsetChanged(isPeptideSpaceSource: boolean = false): void {
793
789
  this.isPeptideSpaceChangingBitset = isPeptideSpaceSource;
794
- this.getBiteset().fireChanged();
795
- this.isPeptideSpaceChangingBitset = false;
790
+ this.df.selection.fireChanged();
796
791
  this.modifyOrCreateSplitCol();
797
792
  grok.shell.o = this.createAccordion().root;
793
+ this.isPeptideSpaceChangingBitset = false;
798
794
  }
799
795
 
800
- getBiteset(): DG.BitSet {return this._filterMode ? this._dataFrame.filter : this._dataFrame.selection;}
801
-
802
- //TODO: move out
803
- postProcessGrids(sourceGrid: DG.Grid, invalidIndexes: number[], sarGrid: DG.Grid, sarVGrid: DG.Grid): void {
804
- sourceGrid.onCellPrepare((cell: DG.GridCell) => {
805
- const currentRowIndex = cell.tableRowIndex;
806
- if (currentRowIndex && invalidIndexes.includes(currentRowIndex) && !cell.isRowHeader)
807
- cell.style.backColor = DG.Color.lightLightGray;
808
- });
809
-
796
+ postProcessGrids(sarGrid: DG.Grid, sarVGrid: DG.Grid): void {
810
797
  const mdCol: DG.GridColumn = sarVGrid.col(C.COLUMNS_NAMES.MEAN_DIFFERENCE)!;
811
798
  mdCol.name = 'Diff';
812
799
 
@@ -825,7 +812,7 @@ export class PeptidesModel {
825
812
  }
826
813
  }
827
814
 
828
- const setViewerGridProps = (grid: DG.Grid) => {
815
+ const setViewerGridProps = (grid: DG.Grid): void => {
829
816
  grid.props.allowEdit = false;
830
817
  grid.props.allowRowSelection = false;
831
818
  grid.props.allowBlockSelection = false;
@@ -836,148 +823,55 @@ export class PeptidesModel {
836
823
  }
837
824
 
838
825
  getSplitColValueAt(index: number, aar: string, position: string, aarLabel: string): string {
839
- const currentAAR = this._dataFrame.get(position, index) as string;
826
+ const currentAAR = this.df.get(position, index) as string;
840
827
  return currentAAR === aar ? aarLabel : C.CATEGORIES.OTHER;
841
828
  }
842
829
 
843
830
  modifyOrCreateSplitCol(): void {
844
- const bs = this.getBiteset();
845
- this.splitCol = this._dataFrame.col(C.COLUMNS_NAMES.SPLIT_COL) ??
846
- this._dataFrame.columns.addNewBool(C.COLUMNS_NAMES.SPLIT_COL);
831
+ const bs = this.df.selection;
832
+ this.splitCol = this.df.col(C.COLUMNS_NAMES.SPLIT_COL) ??
833
+ this.df.columns.addNewBool(C.COLUMNS_NAMES.SPLIT_COL);
847
834
  this.splitCol.init((i) => bs.get(i));
848
835
  this.splitCol.compact();
849
836
  }
850
837
 
851
- static async scaleActivity(
852
- activityScaling: string, df: DG.DataFrame, originalActivityName?: string, cloneBitset = false,
853
- ): Promise<[DG.DataFrame, string]> {
854
- let currentActivityColName = originalActivityName ?? C.COLUMNS_NAMES.ACTIVITY;
855
- const flag = df.columns.names().includes(currentActivityColName) &&
856
- currentActivityColName === originalActivityName;
857
- currentActivityColName = flag ? currentActivityColName : C.COLUMNS_NAMES.ACTIVITY;
858
- const tempDf = df.clone(cloneBitset ? df.filter : null, [currentActivityColName]);
859
-
860
- let formula = '${' + currentActivityColName + '}';
861
- let newColName = 'activity';
862
- switch (activityScaling) {
863
- case 'none':
864
- break;
865
- case 'lg':
866
- formula = `Log10(${formula})`;
867
- newColName = `Log10(${newColName})`;
868
- break;
869
- case '-lg':
870
- formula = `-1*Log10(${formula})`;
871
- newColName = `-Log10(${newColName})`;
872
- break;
873
- default:
874
- throw new Error(`ScalingError: method \`${activityScaling}\` is not available.`);
875
- }
876
-
877
- await tempDf.columns.addNewCalculated(C.COLUMNS_NAMES.ACTIVITY_SCALED, formula);
878
- df.tags['scaling'] = activityScaling;
879
-
880
- return [tempDf, newColName];
881
- }
882
-
883
- static splitAlignedPeptides(peptideColumn: DG.Column<string>, filter: boolean = true): [DG.DataFrame, number[]] {
884
- const separator = peptideColumn.tags[C.TAGS.SEPARATOR] ?? getSeparator(peptideColumn);
885
- const splitPeptidesArray: string[][] = [];
886
- let currentSplitPeptide: string[];
887
- let modeMonomerCount = 0;
888
- let currentLength;
889
- const colLength = peptideColumn.length;
890
-
891
- // splitting data
892
- const monomerLengths: {[index: string]: number} = {};
893
- for (let i = 0; i < colLength; i++) {
894
- currentSplitPeptide = peptideColumn.get(i).split(separator).map((value: string) => value ? value : '-');
895
- splitPeptidesArray.push(currentSplitPeptide);
896
- currentLength = currentSplitPeptide.length;
897
- monomerLengths[currentLength + ''] =
898
- monomerLengths[currentLength + ''] ? monomerLengths[currentLength + ''] + 1 : 1;
899
- }
900
- modeMonomerCount =
901
- parseInt(Object.keys(monomerLengths).reduce((a, b) => monomerLengths[a] > monomerLengths[b] ? a : b));
902
-
903
- // making sure all of the sequences are of the same size
904
- // and marking invalid sequences
905
- let nTerminal: string;
906
- const invalidIndexes: number[] = [];
907
- let splitColumns: string[][] = Array.from({length: modeMonomerCount}, (_) => []);
908
- modeMonomerCount--; // minus N-terminal
909
- for (let i = 0; i < colLength; i++) {
910
- currentSplitPeptide = splitPeptidesArray[i];
911
- nTerminal = currentSplitPeptide.pop()!; // it is guaranteed that there will be at least one element
912
- currentLength = currentSplitPeptide.length;
913
- if (currentLength !== modeMonomerCount)
914
- invalidIndexes.push(i);
915
-
916
- for (let j = 0; j < modeMonomerCount; j++)
917
- splitColumns[j].push(j < currentLength ? currentSplitPeptide[j] : '-');
918
-
919
- splitColumns[modeMonomerCount].push(nTerminal);
920
- }
921
- modeMonomerCount--; // minus C-terminal
922
-
923
- //create column names list
924
- const columnNames = Array.from({length: modeMonomerCount}, (_, index) => `${index + 1 < 10 ? 0 : ''}${index + 1 }`);
925
- columnNames.splice(0, 0, 'N');
926
- columnNames.push('C');
927
-
928
- // filter out the columns with the same values
929
- if (filter) {
930
- splitColumns = splitColumns.filter((positionArray, index) => {
931
- const isRetained = new Set(positionArray).size > 1;
932
- if (!isRetained)
933
- columnNames.splice(index, 1);
934
-
935
- return isRetained;
936
- });
937
- }
938
-
939
- return [
940
- DG.DataFrame.fromColumns(splitColumns.map((positionArray, index) => {
941
- return DG.Column.fromList('string', columnNames[index], positionArray);
942
- })),
943
- invalidIndexes,
944
- ];
945
- }
946
-
947
838
  syncProperties(isSourceSAR = true): void {
948
- const sarViewer: SARViewer = this._dataFrame.temp['sarViewer'];
949
- const sarViewerVertical: SARViewerVertical = this._dataFrame.temp['sarViewerVertical'];
950
- const sourceViewer = isSourceSAR ? sarViewer : sarViewerVertical;
951
- const targetViewer = isSourceSAR ? sarViewerVertical : sarViewer;
952
- const properties = sourceViewer.props.getProperties();
953
- for (const property of properties)
954
- targetViewer.props.set(property.name, property.get(sourceViewer));
839
+ if (this.sarViewer && this.sarViewerVertical) {
840
+ const [sourceViewer, targetViewer] = isSourceSAR ? [this.sarViewer, this.sarViewerVertical] :
841
+ [this.sarViewerVertical, this.sarViewer];
842
+ const properties = sourceViewer.props.getProperties();
843
+ const newProps: {[propName: string]: string | number | boolean} = {};
844
+ for (const property of properties) {
845
+ const propName = property.name;
846
+ const propVal = property.get(sourceViewer);
847
+ targetViewer.props.set(propName, propVal);
848
+ newProps[propName] = propVal;
849
+ }
850
+ this.usedProperties = newProps;
851
+ } else
852
+ console.warn('Warning: could not sync viewer properties, one of the viewers is not initialized');
955
853
  }
956
854
 
957
855
  /** Class initializer */
958
856
  async init(): Promise<void> {
959
857
  if (this.isInitialized)
960
858
  return;
961
- this.isInitialized = true;
962
- //calculate initial stats
963
- const stats = new FilteringStatistics();
964
- const activityScaledCol = this._dataFrame.columns.bySemType(C.SEM_TYPES.ACTIVITY_SCALED)!;
965
- stats.setData(activityScaledCol.getRawData() as Float32Array);
966
- stats.setMask(this._dataFrame.selection);
967
- this._dataFrame.temp[C.STATS] = stats;
968
-
969
- this.currentView = this._dataFrame.tags[C.PEPTIDES_ANALYSIS] == 'true' ? grok.shell.v as DG.TableView :
970
- grok.shell.addTableView(this._dataFrame);
971
- const sourceGrid = this.currentView.grid;
972
- if (this._dataFrame.tags[C.PEPTIDES_ANALYSIS] == 'true')
973
- return;
974
859
 
975
- this._dataFrame.tags[C.PEPTIDES_ANALYSIS] = 'true';
976
- sourceGrid.col(C.COLUMNS_NAMES.ACTIVITY_SCALED)!.name = this._dataFrame.tags[C.COLUMNS_NAMES.ACTIVITY_SCALED];
977
- sourceGrid.columns.setOrder([this._dataFrame.tags[C.COLUMNS_NAMES.ACTIVITY_SCALED]]);
860
+ this.monomerLib =
861
+ JSON.parse(await grok.functions.call('Helm:getMonomerLib', {type: this.df.getTag('monomerType')}) as string);
978
862
 
863
+ this.currentView = this.df.tags[C.PEPTIDES_ANALYSIS] == 'true' ? grok.shell.v as DG.TableView :
864
+ grok.shell.addTableView(this.df);
865
+ this._sourceGrid = this.currentView.grid;
866
+ if (this.df.tags[C.PEPTIDES_ANALYSIS] == 'true')
867
+ return;
868
+
869
+ this.df.tags[C.PEPTIDES_ANALYSIS] = 'true';
870
+ this._sourceGrid.col(C.COLUMNS_NAMES.ACTIVITY_SCALED)!.name = this.df.tags[C.COLUMNS_NAMES.ACTIVITY_SCALED];
871
+ this._sourceGrid.columns.setOrder([this.df.tags[C.COLUMNS_NAMES.ACTIVITY_SCALED]]);
872
+ this._sourceGrid.props.allowColSelection = false;
979
873
 
980
- this._dataFrame.temp[C.EMBEDDING_STATUS] = false;
874
+ this.df.temp[C.EMBEDDING_STATUS] = false;
981
875
  const adjustCellSize = (grid: DG.Grid): void => {
982
876
  const colNum = grid.columns.length;
983
877
  for (let i = 0; i < colNum; ++i) {
@@ -987,36 +881,37 @@ export class PeptidesModel {
987
881
  grid.props.rowHeight = 20;
988
882
  };
989
883
 
990
- for (let i = 0; i < sourceGrid.columns.length; i++) {
991
- const aarCol = sourceGrid.columns.byIndex(i);
992
- if (aarCol && aarCol.name && aarCol.column?.semType !== C.SEM_TYPES.AMINO_ACIDS &&
993
- aarCol.name !== this._dataFrame.tags[C.COLUMNS_NAMES.ACTIVITY_SCALED])
884
+ for (let i = 0; i < this._sourceGrid.columns.length; i++) {
885
+ const aarCol = this._sourceGrid.columns.byIndex(i);
886
+ if (aarCol && aarCol.name && aarCol.column?.semType !== C.SEM_TYPES.MONOMER &&
887
+ aarCol.name !== this.df.tags[C.COLUMNS_NAMES.ACTIVITY_SCALED])
994
888
  aarCol.visible = false;
995
889
  }
996
890
 
997
- const options = {scaling: this._dataFrame.tags['scaling']};
998
- await this.updateData(this._dataFrame.tags['scaling'], sourceGrid, false, 1, 2, false, false);
891
+ const options = {scaling: this.df.tags['scaling']};
999
892
 
1000
893
  const dockManager = this.currentView.dockManager;
1001
894
 
1002
- const sarViewer = await this._dataFrame.plot.fromType('peptide-sar-viewer', options) as SARViewer;
895
+ this.sarViewer = await this.df.plot.fromType('peptide-sar-viewer', options) as SARViewer;
1003
896
 
1004
- const sarViewerVertical =
1005
- await this._dataFrame.plot.fromType('peptide-sar-viewer-vertical', options) as SARViewerVertical;
897
+ this.sarViewerVertical =
898
+ await this.df.plot.fromType('peptide-sar-viewer-vertical', options) as SARViewerVertical;
1006
899
 
1007
- const sarViewersGroup: viewerTypes[] = [sarViewer, sarViewerVertical];
900
+ const sarViewersGroup: viewerTypes[] = [this.sarViewer, this.sarViewerVertical];
1008
901
 
1009
- if (this._dataFrame.rowCount <= 10000) {
902
+ if (this.df.rowCount <= 10000) {
1010
903
  const peptideSpaceViewerOptions = {method: 'UMAP', measure: 'Levenshtein', cyclesCount: 100};
1011
904
  const peptideSpaceViewer =
1012
- await this._dataFrame.plot.fromType('peptide-space-viewer', peptideSpaceViewerOptions) as PeptideSpaceViewer;
905
+ await this.df.plot.fromType('peptide-space-viewer', peptideSpaceViewerOptions) as PeptideSpaceViewer;
1013
906
  dockManager.dock(peptideSpaceViewer, DG.DOCK_TYPE.RIGHT, null, 'Peptide Space Viewer');
1014
907
  }
1015
908
 
909
+ this.updateDefault();
910
+
1016
911
  dockViewers(sarViewersGroup, DG.DOCK_TYPE.RIGHT, dockManager, DG.DOCK_TYPE.DOWN);
1017
912
 
1018
- sourceGrid.props.allowEdit = false;
1019
- adjustCellSize(sourceGrid);
913
+ this._sourceGrid.props.allowEdit = false;
914
+ adjustCellSize(this._sourceGrid);
1020
915
 
1021
916
  this.invalidateGrids();
1022
917
  }