@datagrok/peptides 1.16.0 → 1.17.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.
@@ -21,11 +21,14 @@ export enum MONOMER_POSITION_PROPERTIES {
21
21
  COLOR_COLUMN_NAME = 'color',
22
22
  AGGREGATION = 'aggregation',
23
23
  TARGET = 'target',
24
- };
24
+ }
25
+
26
+ const MUTATION_CLIFFS_CELL_WIDTH = 40;
27
+ const AAR_CELL_WIDTH = 30;
25
28
 
26
29
  /** Structure-activity relationship viewer */
27
30
  export class MonomerPosition extends DG.JsViewer {
28
- _titleHost = ui.divText(SELECTION_MODE.MUTATION_CLIFFS, {id: 'pep-viewer-title'});
31
+ // _titleHost = ui.divText(SELECTION_MODE.MUTATION_CLIFFS, {id: 'pep-viewer-title'});
29
32
  _viewerGrid!: DG.Grid;
30
33
  _model!: PeptidesModel;
31
34
  color: string;
@@ -38,13 +41,11 @@ export class MonomerPosition extends DG.JsViewer {
38
41
  super();
39
42
  this.target = this.string(MONOMER_POSITION_PROPERTIES.TARGET, null,
40
43
  {category: SELECTION_MODE.MUTATION_CLIFFS, choices: []});
41
- this.color = this.string(MONOMER_POSITION_PROPERTIES.COLOR_COLUMN_NAME, C.COLUMNS_NAMES.ACTIVITY_SCALED,
42
- {category: SELECTION_MODE.INVARIANT_MAP,
43
- choices: wu(grok.shell.t.columns.numerical).toArray().map((col) => col.name)});
44
+ this.color = this.string(MONOMER_POSITION_PROPERTIES.COLOR_COLUMN_NAME, C.COLUMNS_NAMES.ACTIVITY,
45
+ {category: SELECTION_MODE.INVARIANT_MAP, choices: wu(grok.shell.t.columns.numerical).toArray().map((col) => col.name)});
44
46
  this.aggregation = this.string(MONOMER_POSITION_PROPERTIES.AGGREGATION, DG.AGG.AVG,
45
47
  {category: SELECTION_MODE.INVARIANT_MAP,
46
- choices: Object.values(DG.AGG)
47
- .filter((agg) => ![DG.AGG.KEY, DG.AGG.PIVOT, DG.AGG.SELECTED_ROWS_COUNT].includes(agg))});
48
+ choices: Object.values(DG.AGG).filter((agg) => ![DG.AGG.KEY, DG.AGG.PIVOT, DG.AGG.SELECTED_ROWS_COUNT].includes(agg))});
48
49
  }
49
50
 
50
51
  get name(): string {return VIEWER_TYPE.MONOMER_POSITION;}
@@ -84,6 +85,10 @@ export class MonomerPosition extends DG.JsViewer {
84
85
  super.onPropertyChanged(property);
85
86
  if (property.name === MONOMER_POSITION_PROPERTIES.TARGET)
86
87
  this.model.updateMutationCliffs().then(() => this.render(true));
88
+ // this will cause colors to recalculate
89
+ this.model.df.columns.toList().forEach((col) => {
90
+ col.temp[C.TAGS.INVARIANT_MAP_COLOR_CACHE] = null;
91
+ });
87
92
 
88
93
  this.render(true);
89
94
  }
@@ -113,7 +118,8 @@ export class MonomerPosition extends DG.JsViewer {
113
118
  const monomerPositionDf = this.createMonomerPositionDf();
114
119
  this.viewerGrid = monomerPositionDf.plot.grid();
115
120
  this.viewerGrid.sort([C.COLUMNS_NAMES.MONOMER]);
116
- this.viewerGrid.columns.setOrder([C.COLUMNS_NAMES.MONOMER, ...this.model.positionColumns.toArray().map((col) => col.name)]);
121
+ const positionColumns = this.model.positionColumns.toArray().map((col) => col.name);
122
+ this.viewerGrid.columns.setOrder([C.COLUMNS_NAMES.MONOMER, ...positionColumns]);
117
123
  const monomerCol = monomerPositionDf.getCol(C.COLUMNS_NAMES.MONOMER);
118
124
  CR.setMonomerRenderer(monomerCol, this.model.alphabet);
119
125
  this.viewerGrid.onCellRender.subscribe((args: DG.GridCellRenderArgs) => renderCell(args, this.model,
@@ -175,6 +181,8 @@ export class MonomerPosition extends DG.JsViewer {
175
181
  this.model.modifyMutationCliffsSelection(monomerPosition, {shiftPressed: true, ctrlPressed: false}, false);
176
182
  }
177
183
  }
184
+ } else {
185
+ return;
178
186
  }
179
187
  this.model.fireBitsetChanged();
180
188
  this.viewerGrid.invalidate();
@@ -197,7 +205,21 @@ export class MonomerPosition extends DG.JsViewer {
197
205
  this.showHelp();
198
206
  });
199
207
 
200
- setViewerGridProps(this.viewerGrid, false);
208
+ setViewerGridProps(this.viewerGrid);
209
+
210
+ // Monomer cell renderer overrides width settings. This way I ensure is "initially" set.
211
+ const afterDraw = this.viewerGrid.onAfterDrawContent.subscribe(() => {
212
+ const monomerGCol = this.viewerGrid.col(C.COLUMNS_NAMES.MONOMER)!;
213
+ if (monomerGCol.width === AAR_CELL_WIDTH) {
214
+ afterDraw.unsubscribe();
215
+ return;
216
+ }
217
+ monomerGCol.width = AAR_CELL_WIDTH;
218
+ for (const posCol of positionColumns) {
219
+ const gcCol = this.viewerGrid.col(posCol)!;
220
+ gcCol.width = MUTATION_CLIFFS_CELL_WIDTH;
221
+ }
222
+ });
201
223
  }
202
224
 
203
225
  showHelp(): void {
@@ -212,6 +234,14 @@ export class MonomerPosition extends DG.JsViewer {
212
234
  }
213
235
 
214
236
  render(refreshOnly = false): void {
237
+ // Backward compatability with 1.16.0
238
+ const columnProperty = this.getProperty(MONOMER_POSITION_PROPERTIES.COLOR_COLUMN_NAME);
239
+ if (columnProperty) {
240
+ columnProperty.choices = wu(grok.shell.t.columns.numerical).toArray().map((col) => col.name);
241
+ if (columnProperty.get(this) === C.COLUMNS_NAMES.ACTIVITY_SCALED)
242
+ columnProperty.set(this, C.COLUMNS_NAMES.ACTIVITY);
243
+ }
244
+
215
245
  if (!refreshOnly) {
216
246
  $(this.root).empty();
217
247
  let switchHost = ui.divText(VIEWER_TYPE.MOST_POTENT_RESIDUES, {id: 'pep-viewer-title'});
@@ -254,7 +284,7 @@ export class MonomerPosition extends DG.JsViewer {
254
284
 
255
285
  /** Vertical structure activity relationship viewer */
256
286
  export class MostPotentResidues extends DG.JsViewer {
257
- _titleHost = ui.divText(VIEWER_TYPE.MOST_POTENT_RESIDUES, {id: 'pep-viewer-title'});
287
+ // _titleHost = ui.divText(VIEWER_TYPE.MOST_POTENT_RESIDUES, {id: 'pep-viewer-title'});
258
288
  _viewerGrid!: DG.Grid;
259
289
  _model!: PeptidesModel;
260
290
  keyPressed: boolean = false;
@@ -350,6 +380,7 @@ export class MostPotentResidues extends DG.JsViewer {
350
380
  pValData.length = i;
351
381
  countData.length = i;
352
382
  ratioData.length = i;
383
+ meanData.length = i;
353
384
 
354
385
  const mprDf = DG.DataFrame.create(i); // Subtract 'general' entry from mp-stats
355
386
  const mprDfCols = mprDf.columns;
@@ -420,6 +451,8 @@ export class MostPotentResidues extends DG.JsViewer {
420
451
  const monomerPosition = this.getMonomerPosition(this.viewerGrid.cell('Diff', rowIdx));
421
452
  this.model.modifyMutationCliffsSelection(monomerPosition, {shiftPressed: true, ctrlPressed: false}, false);
422
453
  }
454
+ } else {
455
+ return;
423
456
  }
424
457
  this.model.fireBitsetChanged();
425
458
  this.viewerGrid.invalidate();
@@ -440,9 +473,19 @@ export class MostPotentResidues extends DG.JsViewer {
440
473
  grok.shell.windows.help.showHelp(ui.markdown(text));
441
474
  }).catch((e) => grok.log.error(e));
442
475
  });
476
+ setViewerGridProps(this.viewerGrid);
443
477
  const mdCol: DG.GridColumn = this.viewerGrid.col(C.COLUMNS_NAMES.MEAN_DIFFERENCE)!;
444
478
  mdCol.name = 'Diff';
445
- setViewerGridProps(this.viewerGrid, true);
479
+ // Monomer cell renderer overrides width settings. This way I ensure is "initially" set.
480
+ const afterDraw = this.viewerGrid.onAfterDrawContent.subscribe(() => {
481
+ const monomerGCol = this.viewerGrid.col(C.COLUMNS_NAMES.MONOMER)!;
482
+ if (monomerGCol.width === AAR_CELL_WIDTH) {
483
+ afterDraw.unsubscribe();
484
+ return;
485
+ }
486
+ monomerGCol.width = AAR_CELL_WIDTH;
487
+ mdCol.width = MUTATION_CLIFFS_CELL_WIDTH;
488
+ });
446
489
  }
447
490
 
448
491
  getMonomerPosition(gridCell: DG.GridCell): SelectionItem {
@@ -464,7 +507,7 @@ export class MostPotentResidues extends DG.JsViewer {
464
507
  }
465
508
 
466
509
  function renderCell(args: DG.GridCellRenderArgs, model: PeptidesModel, isInvariantMap?: boolean,
467
- colorCol?: DG.Column<number>, colorAgg?: DG.AGG, renderNums?: boolean): void {
510
+ colorCol?: DG.Column<number>, colorAgg?: DG.AGG): void {
468
511
  const renderColNames = [...model.positionColumns.toArray().map((col) => col.name), C.COLUMNS_NAMES.MEAN_DIFFERENCE];
469
512
  const canvasContext = args.g;
470
513
  const bound = args.bounds;
@@ -505,31 +548,38 @@ function renderCell(args: DG.GridCellRenderArgs, model: PeptidesModel, isInvaria
505
548
  if (isInvariantMap) {
506
549
  const value = currentPosStats![currentMonomer]!.count;
507
550
  const positionCol = model.df.getCol(currentPosition);
508
- const positionColData = positionCol.getRawData();
509
- const positionColCategories = positionCol.categories;
510
-
511
- const colorColData = colorCol!.getRawData();
512
- const colorValuesIndexes: number[] = [];
513
- for (let i = 0; i < positionCol.length; ++i) {
514
- if (positionColCategories[positionColData[i]] === currentMonomer)
515
- colorValuesIndexes.push(i);
516
- }
517
- const cellColorDataCol = DG.Column.float('color', colorValuesIndexes.length)
518
- .init((i) => colorColData[colorValuesIndexes[i]]);
519
- const colorColStats = colorCol!.stats;
551
+ const colorCache: {[_: string]: number} = positionCol.temp[C.TAGS.INVARIANT_MAP_COLOR_CACHE] ?? {};
552
+ let color: number | null = null;
553
+ if (colorCache[currentMonomer])
554
+ color = colorCache[currentMonomer];
555
+ else {
556
+ const positionColData = positionCol.getRawData();
557
+ const positionColCategories = positionCol.categories;
558
+
559
+ const colorColData = colorCol!.getRawData();
560
+ const colorValuesIndexes: number[] = [];
561
+ for (let i = 0; i < positionCol.length; ++i) {
562
+ if (positionColCategories[positionColData[i]] === currentMonomer)
563
+ colorValuesIndexes.push(i);
564
+ }
565
+ const cellColorDataCol = DG.Column.float('color', colorValuesIndexes.length)
566
+ .init((i) => colorColData[colorValuesIndexes[i]]);
567
+ const colorColStats = colorCol!.stats;
520
568
 
521
- const color = DG.Color.scaleColor(cellColorDataCol.aggregate(colorAgg!), colorColStats.min, colorColStats.max);
522
- CR.renderInvaraintMapCell(
523
- canvasContext, currentMonomer, currentPosition, model.invariantMapSelection, value, bound, color);
569
+ color = DG.Color.scaleColor(cellColorDataCol.aggregate(colorAgg!), colorColStats.min, colorColStats.max);
570
+ colorCache[currentMonomer] = color;
571
+ positionCol.temp[C.TAGS.INVARIANT_MAP_COLOR_CACHE] = colorCache;
572
+ }
573
+ CR.renderInvariantMapCell(canvasContext, currentMonomer, currentPosition, model.invariantMapSelection, value, bound, color);
524
574
  } else {
525
575
  CR.renderMutationCliffCell(canvasContext, currentMonomer, currentPosition, model.monomerPositionStats, bound,
526
- model.mutationCliffsSelection, model.mutationCliffs, renderNums);
576
+ model.mutationCliffsSelection, model.mutationCliffs);
527
577
  }
528
578
  args.preventDefault();
529
579
  canvasContext.restore();
530
580
  }
531
581
 
532
- function setViewerGridProps(grid: DG.Grid, isMostPotentResiduesGrid: boolean): void {
582
+ function setViewerGridProps(grid: DG.Grid): void {
533
583
  const gridProps = grid.props;
534
584
  gridProps.allowEdit = false;
535
585
  gridProps.allowRowSelection = false;
@@ -539,12 +589,5 @@ function setViewerGridProps(grid: DG.Grid, isMostPotentResiduesGrid: boolean): v
539
589
  gridProps.showCurrentRowIndicator = false;
540
590
 
541
591
  gridProps.rowHeight = 20;
542
- const girdCols = grid.columns;
543
- const colNum = girdCols.length;
544
- for (let i = 0; i < colNum; ++i) {
545
- const col = girdCols.byIndex(i)!;
546
- const colName = col.name;
547
- col.width = isMostPotentResiduesGrid && colName !== 'Diff' && colName !== C.COLUMNS_NAMES.MONOMER ? 50 :
548
- gridProps.rowHeight + 10;
549
- }
592
+
550
593
  }
@@ -1,227 +1,87 @@
1
1
  import * as ui from 'datagrok-api/ui';
2
2
  import * as DG from 'datagrok-api/dg';
3
3
 
4
+ import BitArray from '@datagrok-libraries/utils/src/bit-array';
4
5
  import {StringDictionary} from '@datagrok-libraries/utils/src/type-declarations';
6
+
5
7
  import $ from 'cash-dom';
6
8
 
7
9
  import * as C from '../utils/constants';
8
10
  import {getAggregatedColumnValues, getStats, Stats} from '../utils/statistics';
9
11
  import {PeptidesModel} from '../model';
10
- import {getStatsSummary, prepareTableForHistogram} from '../utils/misc';
11
- import BitArray from '@datagrok-libraries/utils/src/bit-array';
12
-
13
- const allConst = 'All';
14
- const otherConst = 'Other';
12
+ import {getDistributionPanel, getDistributionTable} from '../utils/misc';
15
13
 
16
14
  export function getDistributionWidget(table: DG.DataFrame, model: PeptidesModel): DG.Widget {
17
15
  if (!table.selection.anyTrue)
18
16
  return new DG.Widget(ui.divText('No distribution'));
19
17
 
20
- const activityCol = table.getCol(C.COLUMNS_NAMES.ACTIVITY_SCALED);
21
- const activityColData = activityCol.getRawData();
18
+ const activityCol = table.getCol(C.COLUMNS_NAMES.ACTIVITY);
22
19
  const rowCount = activityCol.length;
23
- const selectionObject = model.invariantMapSelection;
24
- const clustersColName = model.settings.clustersColumnName;
25
- let clustersProcessedObject: string[] = [];
26
- if (clustersColName)
27
- clustersProcessedObject = Object.values(model.clusterSelection).flat();
28
20
 
29
- const positions = Object.keys(selectionObject);
30
- let monomerStr = allConst;
31
- let otherStr = '';
21
+ // const setDefaultProperties = (input: DG.InputBase): void => {
22
+ // input.enabled = !model.isMutationCliffsSelectionEmpty;
23
+ // $(input.root).find('.ui-input-editor').css('margin', '0px');
24
+ // $(input.root).find('.ui-input-description').css('padding', '0px').css('padding-left', '5px');
25
+ // $(input.captionLabel).addClass('ui-label-right');
26
+ // };
27
+ //
28
+ // let defaultValuePos = model.splitByPos;
29
+ // let defaultValueMonomer = model.splitByMonomer;
30
+ // if (!model.isClusterSelectionEmpty && model.isMutationCliffsSelectionEmpty) {
31
+ // defaultValuePos = false;
32
+ // defaultValueMonomer = false;
33
+ // }
34
+
35
+ const distributionHost = ui.div([], 'd4-flex-wrap');
32
36
 
33
37
  const updateDistributionHost = (): void => {
34
- model.splitByPos = splitByPosition.value!;
35
- model.splitByMonomer = splitByMonomer.value!;
36
38
  const res: HTMLDivElement[] = [];
37
- if (splitByPosition.value && splitByMonomer.value) {
38
- otherStr = otherConst;
39
- for (const position of positions) {
40
- const monomerList = selectionObject[position];
41
- if (monomerList.length === 0)
42
- continue;
43
-
44
- const posCol = table.getCol(position);
45
- const posColCategories = posCol.categories;
46
- const posColData = posCol.getRawData();
47
-
48
- for (const monomer of monomerList) {
49
- const labels = getDistributionLegend(`${position} : ${monomer}`, otherStr);
50
-
51
- const monomerCategoryIndex = posColCategories.indexOf(monomer);
52
- const mask = DG.BitSet.create(rowCount, (i) => posColData[i] === monomerCategoryIndex);
53
- const distributionTable = DG.DataFrame.fromColumns(
54
- [activityCol, DG.Column.fromBitSet(C.COLUMNS_NAMES.SPLIT_COL, mask)]);
55
- const hist = getActivityDistribution(prepareTableForHistogram(distributionTable));
56
-
57
- const stats = model.monomerPositionStats[position]![monomer]!;
58
- const tableMap = getStatsTableMap(stats);
59
-
60
- const aggregatedColMap = getAggregatedColumnValues(model.df, model.settings.columns!, {filterDf: true, mask});
61
-
62
- const resultMap = {...tableMap, ...aggregatedColMap};
63
- const distributionRoot = getStatsSummary(labels, hist, resultMap);
64
- $(distributionRoot).addClass('d4-flex-col');
65
-
66
- res.push(distributionRoot);
67
- }
68
- }
69
- } else if (splitByPosition.value) {
70
- otherStr = otherConst;
71
- for (const position of positions) {
72
- const monomerList = selectionObject[position];
73
- if (monomerList.length === 0)
74
- continue;
75
-
76
- monomerStr = `${position}: {${monomerList.join(', ')}}`;
77
- const labels = getDistributionLegend(monomerStr, otherStr);
78
-
79
- const posCol = table.getCol(position);
80
- const posColCategories = posCol.categories;
81
- const posColData = posCol.getRawData();
82
- const monomerIndexesList = monomerList.map((monomer) => posColCategories.indexOf(monomer));
83
- const mask = DG.BitSet.create(rowCount, (i) => monomerIndexesList.includes(posColData[i]));
84
- const splitCol = DG.Column.fromBitSet(C.COLUMNS_NAMES.SPLIT_COL, mask);
85
-
86
- const aggregatedColMap = getAggregatedColumnValues(model.df, model.settings.columns!, {filterDf: true, mask});
87
-
88
- const distributionTable = DG.DataFrame.fromColumns([activityCol, splitCol]);
89
- const hist = getActivityDistribution(prepareTableForHistogram(distributionTable));
90
-
91
- const bitArray = BitArray.fromUint32Array(rowCount, splitCol.getRawData() as Uint32Array);
92
- const stats = getStats(activityColData, bitArray);
93
- const tableMap = getStatsTableMap(stats);
94
-
95
- const resultMap = {...tableMap, ...aggregatedColMap};
96
- const distributionRoot = getStatsSummary(labels, hist, resultMap);
97
- $(distributionRoot).addClass('d4-flex-col');
98
-
99
- res.push(distributionRoot);
100
- }
101
- } else if (splitByMonomer.value) {
102
- const reversedSelectionObject: {[monomer: string]: string[]} = {};
103
- const monomers = [];
104
- for (const position of positions) {
105
- for (const monomer of selectionObject[position]) {
106
- if (!reversedSelectionObject.hasOwnProperty(monomer)) {
107
- reversedSelectionObject[monomer] = [position];
108
- monomers.push(monomer);
109
- continue;
110
- }
111
- if (!reversedSelectionObject[monomer].includes(position))
112
- reversedSelectionObject[monomer].push(position);
113
- }
114
- }
115
-
116
- otherStr = otherConst;
117
- for (const monomer of monomers) {
118
- const posList = reversedSelectionObject[monomer];
119
- const posColList = posList.map((pos) => table.getCol(pos));
120
- const posColCategoriesList = posColList.map((posCol) => posCol.categories);
121
- const posColDataList = posColList.map((posCol) => posCol.getRawData());
122
- const monomerCategoryIndexList = posColCategoriesList.map((posColCategories) => posColCategories.indexOf(monomer));
123
-
124
- monomerStr = `${monomer}: {${posList.join(', ')}}`;
125
- const labels = getDistributionLegend(monomerStr, otherStr);
126
-
127
- const mask = DG.BitSet.create(rowCount,
128
- (i) => posColDataList.some((posColData, j) => posColData[i] === monomerCategoryIndexList[j]));
129
- const aggregatedColMap = getAggregatedColumnValues(model.df, model.settings.columns!, {filterDf: true, mask});
130
-
131
- const splitCol = DG.Column.fromBitSet(C.COLUMNS_NAMES.SPLIT_COL, mask);
132
- const distributionTable = DG.DataFrame.fromColumns([activityCol, splitCol]);
133
- const hist = getActivityDistribution(prepareTableForHistogram(distributionTable));
134
-
135
- const bitArray = BitArray.fromUint32Array(rowCount, splitCol.getRawData() as Uint32Array);
136
- const stats = getStats(activityColData, bitArray);
137
- const tableMap = getStatsTableMap(stats);
138
-
139
- const resultMap: {[key: string]: any} = {...tableMap, ...aggregatedColMap};
140
- const distributionRoot = getStatsSummary(labels, hist, resultMap);
141
- $(distributionRoot).addClass('d4-flex-col');
142
-
143
- res.push(distributionRoot);
144
- }
145
- } else {
146
- if (!table.selection.anyTrue)
147
- res.push(ui.divText('No distribution'));
148
- else {
149
- otherStr = '';
150
- if (Object.values(selectionObject).some((selectedAar) => selectedAar.length !== 0) ||
151
- clustersProcessedObject.length !== 0) {
152
- monomerStr = '';
153
- for (const position of positions) {
154
- const monomerList = selectionObject[position];
155
- if (monomerList.length !== 0)
156
- monomerStr += `${position}: {${monomerList.join(', ')}}; `;
157
- }
158
- if (clustersProcessedObject.length !== 0)
159
- monomerStr += `Clusters: ${clustersProcessedObject.join(', ')}`;
160
- otherStr = otherConst;
161
- }
162
- const labels = getDistributionLegend(monomerStr, otherStr);
163
-
164
- const distributionTable = DG.DataFrame.fromColumns([activityCol, DG.Column.fromBitSet(C.COLUMNS_NAMES.SPLIT_COL, table.selection)]);
165
- const hist = getActivityDistribution(prepareTableForHistogram(distributionTable));
166
- const bitArray = BitArray.fromString(table.selection.toBinaryString());
167
- const mask = DG.BitSet.create(rowCount,
168
- bitArray.allFalse || bitArray.allTrue ? (_): boolean => true : (i): boolean => bitArray.getBit(i));
169
- const aggregatedColMap = getAggregatedColumnValues(model.df, model.settings.columns!, {filterDf: true, mask});
170
- const stats = bitArray.allFalse || bitArray.allTrue ?
171
- {count: rowCount, pValue: null, meanDifference: 0, ratio: 1, mask: bitArray,
172
- mean: activityCol.stats.avg} :
173
- getStats(activityColData, bitArray);
174
- const tableMap = getStatsTableMap(stats);
175
- const resultMap: {[key: string]: any} = {...tableMap, ...aggregatedColMap};
176
- const distributionRoot = getStatsSummary(labels, hist, resultMap);
177
- $(distributionRoot).addClass('d4-flex-col');
178
-
179
- res.push(distributionRoot);
180
- }
39
+ if (!table.selection.anyTrue)
40
+ res.push(ui.divText('No distribution'));
41
+ else {
42
+ const hist = getActivityDistribution(getDistributionTable(activityCol, model.df.selection, model.getCombinedSelection()));
43
+ const bitArray = BitArray.fromString(table.selection.toBinaryString());
44
+ const mask = DG.BitSet.create(rowCount,
45
+ bitArray.allFalse || bitArray.allTrue ? (_): boolean => true : (i): boolean => bitArray.getBit(i));
46
+ const aggregatedColMap = getAggregatedColumnValues(model.df, model.settings.columns!, {filterDf: true, mask});
47
+ const stats = bitArray.allFalse || bitArray.allTrue ?
48
+ {count: rowCount, pValue: null, meanDifference: 0, ratio: 1, mask: bitArray, mean: activityCol.stats.avg} :
49
+ getStats(activityCol.getRawData(), bitArray);
50
+ const tableMap = getStatsTableMap(stats);
51
+ const resultMap: { [key: string]: any } = {...tableMap, ...aggregatedColMap};
52
+ const distributionRoot = getDistributionPanel(hist, resultMap);
53
+ $(distributionRoot).addClass('d4-flex-col');
54
+
55
+ res.push(distributionRoot);
181
56
  }
182
- $(distributionHost).empty().append(res);
183
- };
184
57
 
185
- const setDefaultProperties = (input: DG.InputBase): void => {
186
- input.enabled = !model.isMutationCliffsSelectionEmpty;
187
- $(input.root).find('.ui-input-editor').css('margin', '0px');
188
- $(input.root).find('.ui-input-description').css('padding', '0px').css('padding-left', '5px');
189
- $(input.captionLabel).addClass('ui-label-right');
58
+ $(distributionHost).empty().append(res);
190
59
  };
191
60
 
192
- let defaultValuePos = model.splitByPos;
193
- let defaultValueMonomer = model.splitByMonomer;
194
- if (!model.isClusterSelectionEmpty && model.isMutationCliffsSelectionEmpty) {
195
- defaultValuePos = false;
196
- defaultValueMonomer = false;
197
- }
198
-
199
- const splitByPosition = ui.boolInput('Split by position', defaultValuePos, updateDistributionHost);
200
- splitByPosition.setTooltip('Constructs distribution for each position separately');
201
- setDefaultProperties(splitByPosition);
202
- $(splitByPosition.root).css('margin-right', '10px');
203
- const splitByMonomer = ui.boolInput('Split by monomer', defaultValueMonomer, updateDistributionHost);
204
- splitByMonomer.setTooltip('Constructs distribution for each monomer separately');
205
- setDefaultProperties(splitByMonomer);
206
-
207
- const controlsHost = ui.divH([splitByPosition.root, splitByMonomer.root]);
208
- const distributionHost = ui.div([], 'd4-flex-wrap');
209
- splitByMonomer.fireChanged();
210
-
211
- return new DG.Widget(ui.divV([controlsHost, distributionHost]));
61
+ // const splitByPosition = ui.boolInput('Split by position', defaultValuePos, updateDistributionHost);
62
+ // splitByPosition.setTooltip('Constructs distribution for each position separately');
63
+ // setDefaultProperties(splitByPosition);
64
+ // $(splitByPosition.root).css('margin-right', '10px');
65
+ // const splitByMonomer = ui.boolInput('Split by monomer', defaultValueMonomer, updateDistributionHost);
66
+ // splitByMonomer.setTooltip('Constructs distribution for each monomer separately');
67
+ // setDefaultProperties(splitByMonomer);
68
+
69
+ // const controlsHost = ui.divH([splitByPosition.root, splitByMonomer.root]);
70
+ // splitByMonomer.fireChanged();
71
+ updateDistributionHost();
72
+ return new DG.Widget(ui.divV([/*controlsHost,*/ distributionHost]));
212
73
  }
213
74
 
214
- export function getActivityDistribution(table: DG.DataFrame, isTooltip: boolean = false,
215
- ): DG.Viewer<DG.IHistogramLookSettings> {
75
+ export function getActivityDistribution(table: DG.DataFrame, isTooltip: boolean = false): DG.Viewer<DG.IHistogramLookSettings> {
216
76
  const hist = table.plot.histogram({
217
77
  filteringEnabled: false,
218
- valueColumnName: C.COLUMNS_NAMES.ACTIVITY_SCALED,
78
+ valueColumnName: C.COLUMNS_NAMES.ACTIVITY,
219
79
  splitColumnName: C.COLUMNS_NAMES.SPLIT_COL,
220
80
  legendVisibility: 'Never',
221
81
  showXAxis: true,
222
82
  showColumnSelector: false,
223
83
  showRangeSlider: false,
224
- showBinSelector: !isTooltip,
84
+ showBinSelector: false,
225
85
  backColor: isTooltip ? '#fdffe5' : '#fffff',
226
86
  }) as DG.Viewer<DG.IHistogramLookSettings>;
227
87
  hist.root.style.width = 'auto';
@@ -239,9 +99,3 @@ export function getStatsTableMap(stats: Stats, options: {fractionDigits?: number
239
99
  tableMap['p-value'] = stats.pValue < 0.01 ? '<0.01' : stats.pValue.toFixed(options.fractionDigits);
240
100
  return tableMap;
241
101
  }
242
-
243
- export function getDistributionLegend(thisLabel: string, otherLabel: string = ''): HTMLDivElement {
244
- return ui.divV([
245
- ui.label(thisLabel, {style: {color: DG.Color.toHtml(otherLabel.length === 0 ? DG.Color.blue : DG.Color.orange)}}),
246
- ui.label(otherLabel, {style: {color: DG.Color.toHtml(DG.Color.blue)}})]);
247
- }
@@ -23,7 +23,7 @@ export function mutationCliffsWidget(table: DG.DataFrame, model: PeptidesModel):
23
23
  const alignedSeqCol = table.getCol(model.settings.sequenceColumnName!);
24
24
  const alignedSeqColCategories = alignedSeqCol.categories;
25
25
  const alignedSeqColData = alignedSeqCol.getRawData();
26
- const activityScaledCol = table.getCol(C.COLUMNS_NAMES.ACTIVITY_SCALED);
26
+ const activityScaledCol = table.getCol(C.COLUMNS_NAMES.ACTIVITY);
27
27
  const activityScaledColData = activityScaledCol.getRawData();
28
28
  const seenIndexes = new Map<number, number[]>();
29
29
  const uniqueSequencesBitSet = DG.BitSet.create(table.rowCount);
@@ -85,11 +85,10 @@ export function mutationCliffsWidget(table: DG.DataFrame, model: PeptidesModel):
85
85
  else
86
86
  pairsTable.filter.setAll(true);
87
87
  });
88
- aminoToInput.setTooltip('Monomer to which the mutation was made');
88
+ aminoToInput.setTooltip('Filter the rows by the monomer that the mutation was substituted to');
89
89
 
90
90
  const pairsGrid = pairsTable.plot.grid();
91
91
  setGridProps(pairsGrid);
92
- pairsGrid.root.style.height = '150px';
93
92
  substCol.semType = C.SEM_TYPES.MACROMOLECULE_DIFFERENCE;
94
93
  substCol.tags[C.TAGS.SEPARATOR] = getSeparator(alignedSeqCol);
95
94
  substCol.tags[DG.TAGS.UNITS] = alignedSeqCol.tags[DG.TAGS.UNITS];
@@ -164,7 +163,6 @@ export function mutationCliffsWidget(table: DG.DataFrame, model: PeptidesModel):
164
163
  const uniqueSequencesGrid = uniqueSequencesTable.plot.grid();
165
164
  setGridProps(uniqueSequencesGrid);
166
165
  uniqueSequencesGrid.props.rowHeight = 20;
167
- uniqueSequencesGrid.root.style.height = '250px';
168
166
  uniqueSequencesTable.filter.onChanged.subscribe(() => {
169
167
  const uniqueSelectedIndexes: number[] = [];
170
168
  for (const idx of pairsSelectedIndexes) {
@@ -78,7 +78,7 @@ export function analyzePeptidesUI(df: DG.DataFrame, col?: DG.Column<string>): {h
78
78
 
79
79
  const hist = DG.DataFrame.fromColumns([scaledCol]).plot.histogram({
80
80
  filteringEnabled: false,
81
- valueColumnName: C.COLUMNS_NAMES.ACTIVITY_SCALED,
81
+ valueColumnName: C.COLUMNS_NAMES.ACTIVITY,
82
82
  legendVisibility: 'Never',
83
83
  showXAxis: true,
84
84
  showColumnSelector: false,
@@ -169,7 +169,7 @@ export async function startAnalysis(activityColumn: DG.Column<number>, peptidesC
169
169
  newDfCols.add(scaledCol);
170
170
  for (const col of currentDf.columns) {
171
171
  if (col.getTag(C.TAGS.ANALYSIS_COL) !== `${true}`) {
172
- if (col.name === scaledCol.name)
172
+ if (col.name.toLowerCase() === scaledCol.name.toLowerCase())
173
173
  col.name = currentDf.columns.getUnusedName(col.name);
174
174
  newDfCols.add(col);
175
175
  }
@@ -196,7 +196,7 @@ export async function startAnalysis(activityColumn: DG.Column<number>, peptidesC
196
196
  }
197
197
  newDf.setTag(C.TAGS.SETTINGS, JSON.stringify(settings));
198
198
 
199
- let monomerType = 'HELM_AA';
199
+ let monomerType: string;
200
200
  if (peptidesCol.getTag(DG.TAGS.UNITS) === NOTATION.HELM) {
201
201
  const sampleSeq = peptidesCol.get(0)!;
202
202
  monomerType = sampleSeq.startsWith('PEPTIDE') ? 'HELM_AA' : 'HELM_BASE';
@@ -6,13 +6,13 @@ import {PeptidesModel} from '../model';
6
6
  import wu from 'wu';
7
7
  import {COLUMNS_NAMES} from '../utils/constants';
8
8
  import {addExpandIcon} from '../utils/misc';
9
- import {CellRendererOptions, WebLogoBounds, setWebLogoRenderer} from '../utils/cell-renderer';
9
+ import {CellRendererOptions, setWebLogoRenderer, WebLogoBounds} from '../utils/cell-renderer';
10
10
  import {CachedWebLogoTooltip, SelectionItem} from '../utils/types';
11
11
  import {TooltipOptions} from '../utils/tooltips';
12
12
  import {calculateMonomerPositionStatistics} from '../utils/algorithms';
13
13
 
14
14
  export function getSelectionWidget(table: DG.DataFrame, model: PeptidesModel): HTMLElement {
15
- const compBitset = model.getCompoundBitset();
15
+ const compBitset = model.getVisibleSelection();
16
16
  if (compBitset.trueCount === 0)
17
17
  return ui.divText('No compounds selected');
18
18
  const newTable = DG.DataFrame.create(table.rowCount);
@@ -29,7 +29,7 @@ export function getSelectionWidget(table: DG.DataFrame, model: PeptidesModel): H
29
29
  const sourceColCategories = sourceCol.categories;
30
30
  const getValue = numericalCols.some((col) => col.name === sourceCol.name) ? (i: number): number => sourceColRawData[i] :
31
31
  (i: number): string => sourceColCategories[sourceColRawData[i]];
32
- const col = sourceCol.name === COLUMNS_NAMES.ACTIVITY_SCALED ?
32
+ const col = sourceCol.name === COLUMNS_NAMES.ACTIVITY ?
33
33
  newTable.columns.addNewFloat(gridCol.name).init((i) => getValue(i)) :
34
34
  newTable.columns.addNewVirtual(gridCol.name, (i) => getValue(i), sourceCol.type as DG.TYPE);
35
35
  for (const [tag, value] of sourceCol.tags)
@@ -62,7 +62,7 @@ export function getSettingsDialog(model: PeptidesModel): SettingsElements {
62
62
  const activityCol = ui.columnInput(GENERAL_INPUTS.ACTIVITY, model.df,
63
63
  model.df.getCol(model.settings.activityColumnName!), () => result.activityColumnName = activityCol.value!.name,
64
64
  {filter: (col: DG.Column) => (col.type === DG.TYPE.FLOAT || col.type === DG.TYPE.INT) &&
65
- col.name !== C.COLUMNS_NAMES.ACTIVITY_SCALED && col.stats.missingValueCount === 0});
65
+ col.name !== C.COLUMNS_NAMES.ACTIVITY && col.stats.missingValueCount === 0});
66
66
  activityCol.setTooltip('Numeric activity column');
67
67
  const activityScaling =
68
68
  ui.choiceInput(GENERAL_INPUTS.ACTIVITY_SCALING, currentScaling, Object.values(C.SCALING_METHODS),
@@ -120,7 +120,7 @@ export function getSettingsDialog(model: PeptidesModel): SettingsElements {
120
120
  const includedColumnsInputs: DG.InputBase[] = [];
121
121
  for (const col of model.df.columns.numerical) {
122
122
  const colName = col.name;
123
- if (colName === settings.activityColumnName || colName === C.COLUMNS_NAMES.ACTIVITY_SCALED)
123
+ if (colName === settings.activityColumnName || colName === C.COLUMNS_NAMES.ACTIVITY)
124
124
  continue;
125
125
 
126
126
  const isIncludedInput = ui.boolInput(COLUMNS_INPUTS.IS_INCLUDED, typeof (currentColumns)[colName] !== 'undefined',