@datagrok/peptides 0.8.10 → 0.8.12

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.
@@ -4,22 +4,29 @@ import * as ui from 'datagrok-api/ui';
4
4
  import {MonomerLibrary} from '../monomer-library';
5
5
  import {PeptidesController} from '../peptides';
6
6
 
7
+ import * as C from '../utils/constants';
8
+ import * as type from '../utils/types';
9
+
7
10
  export function addViewerToHeader(grid: DG.Grid, barchart: StackedBarChart) {
8
11
  if (grid.temp['containsBarchart'])
9
12
  return;
13
+
14
+ const compareBarParts = (bar1: type.BarChart.BarPart | null, bar2: type.BarChart.BarPart | null) =>
15
+ bar1 && bar2 && bar1.aaName === bar2.aaName && bar1.colName === bar2.colName;
10
16
 
11
- function eventAction(mouseMove: MouseEvent) {
17
+ const eventAction = (mouseMove: MouseEvent) => {
12
18
  const cell = grid.hitTest(mouseMove.offsetX, mouseMove.offsetY);
13
- if (cell !== null && cell?.isColHeader && cell.tableColumn?.semType == 'aminoAcids')
14
- barchart.highlight(cell, mouseMove.offsetX, mouseMove.offsetY, mouseMove);
15
- else
16
- return;
17
-
18
- if (cell?.isColHeader && cell.tableColumn?.semType == 'aminoAcids')
19
- barchart.beginSelection(mouseMove);
20
- else
21
- barchart.unhighlight();
22
- }
19
+ if (cell?.isColHeader && cell.tableColumn?.semType == C.SEM_TYPES.AMINO_ACIDS) {
20
+ const newBarPart = barchart.findAARandPosition(cell, mouseMove);
21
+ const previousClickedBarPart = barchart._previousClickedBarPart;
22
+ if (mouseMove.type === 'click' && compareBarParts(newBarPart, previousClickedBarPart))
23
+ barchart.isSameBarClicked = true;
24
+ else
25
+ barchart.currentBarPart = newBarPart;
26
+ barchart.requestAction(mouseMove);
27
+ barchart.computeData();
28
+ }
29
+ };
23
30
 
24
31
  // The following events makes the barchart interactive
25
32
  rxjs.fromEvent<MouseEvent>(grid.overlay, 'mousemove').subscribe((mouseMove: MouseEvent) => eventAction(mouseMove));
@@ -32,16 +39,17 @@ export function addViewerToHeader(grid: DG.Grid, barchart: StackedBarChart) {
32
39
  grid.setOptions({'colHeaderHeight': 130});
33
40
 
34
41
  grid.onCellTooltip((cell, x, y) => {
35
- if (cell.tableColumn && ['aminoAcids', 'alignedSequence'].includes(cell.tableColumn.semType) ) {
42
+ if (
43
+ cell.tableColumn &&
44
+ [C.SEM_TYPES.AMINO_ACIDS, C.SEM_TYPES.ALIGNED_SEQUENCE].includes(cell.tableColumn.semType as C.SEM_TYPES)
45
+ ) {
36
46
  if (!cell.isColHeader) {
37
47
  const monomerLib = cell.cell.dataFrame.temp[MonomerLibrary.id];
38
48
  PeptidesController.chemPalette.showTooltip(cell, x, y, monomerLib);
39
- } else {
40
- if (barchart.highlighted) {
41
- let elements: HTMLElement[] = [];
42
- elements = elements.concat([ui.divText(barchart.highlighted.aaName)]);
43
- ui.tooltip.show(ui.divV(elements), x, y);
44
- }
49
+ } else if (barchart.currentBarPart) {
50
+ let elements: HTMLElement[] = [];
51
+ elements = elements.concat([ui.divText(barchart.currentBarPart.aaName)]);
52
+ ui.tooltip.show(ui.divV(elements), x, y);
45
53
  }
46
54
  }
47
55
  return true;
@@ -72,36 +80,33 @@ export function addViewerToHeader(grid: DG.Grid, barchart: StackedBarChart) {
72
80
  barchart.unhighlight();
73
81
  }
74
82
 
75
- type stackedBarChartDatatype = {
76
- 'name': string,
77
- 'data': {'name': string, 'count': number, 'selectedCount': number, 'fixedSelectedCount': number}[],
78
- }[];
79
-
80
- type bartStatsType = {
81
- [Key: string]: {'name': string, 'count': number, 'selectedCount': number, 'fixedSelectedCount': number}[],
82
- };
83
-
84
83
  export class StackedBarChart extends DG.JsViewer {
85
- public dataEmptyAA: string;
86
- public highlighted: {'colName' : string, 'aaName' : string} | null = null;
87
- public tableCanvas: HTMLCanvasElement | undefined;
88
- public aminoColumnNames: string[] = [];
89
- private ord: { [Key: string]: number; } = {};
90
- private aminoColumnIndices: {[Key: string]: number} = {};
91
- private aggregatedTables: {[Key: string]: DG.DataFrame} = {};
92
- private aggregatedHighlightedTables: {[Key: string]: DG.DataFrame} = {};
93
- private max = 0;
94
- private barStats:
95
- {[Key: string]: {'name': string, 'count': number, 'highlightedCount': number, 'selectedCount': number}[]} = {};
96
- private selected: {'colName' : string, 'aaName' : string}[] = [];
97
- private highlightedMask: DG.BitSet | null = null;
98
- private aggregatedSelectedTables: {[Key: string]: DG.DataFrame} = {};
84
+ dataEmptyAA: string;
85
+ _currentBarPart: type.BarChart.BarPart | null = null;
86
+ tableCanvas: HTMLCanvasElement | undefined;
87
+ aminoColumnNames: string[] = [];
88
+ ord: { [Key: string]: number; } = {};
89
+ aminoColumnIndices: {[Key: string]: number} = {};
90
+ aggregatedFilterTables: type.DataFrameDict = {};
91
+ max = 0;
92
+ barStats: {[Key: string]: type.BarChart.BarStatsObject[]} = {};
93
+ selected: type.BarChart.BarPart[] = [];
94
+ aggregatedSelectedTables: type.DataFrameDict = {};
95
+ controller!: PeptidesController;
96
+ isSameBarClicked: boolean = false;
97
+ _previousClickedBarPart: type.BarChart.BarPart | null = null;
99
98
 
100
99
  constructor() {
101
100
  super();
102
101
  this.dataEmptyAA = this.string('dataEmptyAA', '-');
103
102
  }
104
103
 
104
+ get currentBarPart() { return this._currentBarPart; }
105
+ set currentBarPart(barPart: type.BarChart.BarPart | null) {
106
+ this._currentBarPart = barPart;
107
+ this.isSameBarClicked = false;
108
+ }
109
+
105
110
  init() {
106
111
  const groups: {[key: string]: string[]} = {
107
112
  'yellow': ['C', 'U'],
@@ -122,12 +127,14 @@ export class StackedBarChart extends DG.JsViewer {
122
127
  }
123
128
 
124
129
  // Stream subscriptions
125
- onTableAttached() {
130
+ async onTableAttached() {
126
131
  this.init();
132
+ this.controller = await PeptidesController.getInstance(this.dataFrame);
133
+ this.controller.init(this.dataFrame);
127
134
  if (this.dataFrame) {
128
135
  this.subs.push(DG.debounce(this.dataFrame.selection.onChanged, 50).subscribe((_) => this.computeData()));
129
136
  this.subs.push(DG.debounce(this.dataFrame.filter.onChanged, 50).subscribe((_) => this.computeData()));
130
- this.highlightedMask = DG.BitSet.create(this.dataFrame.rowCount);
137
+ this.subs.push(DG.debounce(this.dataFrame.onValuesChanged, 50).subscribe(() => this.computeData()));
131
138
  }
132
139
  }
133
140
 
@@ -141,7 +148,7 @@ export class StackedBarChart extends DG.JsViewer {
141
148
  this.aminoColumnIndices = {};
142
149
 
143
150
  this.dataFrame!.columns.names().forEach((name: string) => {
144
- if (this.dataFrame!.getCol(name).semType === 'aminoAcids' &&
151
+ if (this.dataFrame!.getCol(name).semType === C.SEM_TYPES.AMINO_ACIDS &&
145
152
  !this.dataFrame!.getCol(name).categories.includes('COOH') &&
146
153
  !this.dataFrame!.getCol(name).categories.includes('NH2')) {
147
154
  this.aminoColumnIndices[name] = this.aminoColumnNames.length + 1;
@@ -149,23 +156,16 @@ export class StackedBarChart extends DG.JsViewer {
149
156
  }
150
157
  });
151
158
 
152
- this.aggregatedTables = {};
153
- this.aggregatedHighlightedTables = {};
159
+ this.aggregatedFilterTables = {};
154
160
  this.aggregatedSelectedTables = {};
155
161
  //TODO: optimize it, why store so many tables?
156
162
  this.aminoColumnNames.forEach((name) => {
157
- this.aggregatedTables[name] = this.dataFrame!
163
+ this.aggregatedFilterTables[name] = this.dataFrame!
158
164
  .groupBy([name])
159
165
  .whereRowMask(this.dataFrame!.filter)
160
166
  .add('count', name, `${name}_count`)
161
167
  .aggregate();
162
168
 
163
- this.aggregatedHighlightedTables[name] = this.dataFrame!
164
- .groupBy([name])
165
- .whereRowMask(this.highlightedMask!)
166
- .add('count', name, `${name}_count`)
167
- .aggregate();
168
-
169
169
  this.aggregatedSelectedTables[name] = this.dataFrame!
170
170
  .groupBy([name])
171
171
  .whereRowMask(this.dataFrame!.selection)
@@ -175,43 +175,35 @@ export class StackedBarChart extends DG.JsViewer {
175
175
 
176
176
  this.barStats = {};
177
177
 
178
- for (const [name, df] of Object.entries(this.aggregatedTables)) {
179
- const colObj: {
180
- 'name': string,
181
- 'data': { 'name': string, 'count': number, 'highlightedCount': number, 'selectedCount': number}[],
182
- } = {'name': name, 'data': []};
178
+ for (const [name, df] of Object.entries(this.aggregatedFilterTables)) {
179
+ const colData: {'name': string, 'count': number, 'selectedCount': number}[] = [];
183
180
  const aminoCol = df.getCol(name);
184
181
  const aminoCountCol = df.getCol(`${name}_count`);
185
- this.barStats[colObj['name']] = colObj['data'];
182
+ this.barStats[name] = colData;
186
183
 
187
184
  for (let i = 0; i < df.rowCount; i++) {
188
185
  const amino = aminoCol.get(i);
189
186
  const aminoCount = aminoCountCol.get(i);
190
- const aminoObj = {'name': amino, 'count': aminoCount, 'highlightedCount': 0, 'selectedCount': 0};
191
- const aggHighlightedAminoCol = this.aggregatedHighlightedTables[name].getCol(`${name}`);
192
- const aggHighlightedCountCol = this.aggregatedHighlightedTables[name].getCol(`${name}_count`);
187
+ const aminoObj = {'name': amino, 'count': aminoCount, 'selectedCount': 0};
193
188
  const aggSelectedAminoCol = this.aggregatedSelectedTables[name].getCol(`${name}`);
194
189
  const aggSelectedCountCol = this.aggregatedSelectedTables[name].getCol(`${name}_count`);
195
190
 
196
191
  if (!amino || amino === this.dataEmptyAA)
197
192
  continue;
198
193
 
199
- colObj['data'].push(aminoObj);
200
-
201
- for (const col of [aggHighlightedCountCol, aggSelectedCountCol]) {
202
- for (let j = 0; j < col.length; j++) {
203
- const highlightedAmino = aggHighlightedAminoCol.get(j);
204
- const selectedAmino = aggSelectedAminoCol.get(j);
205
- const curAmino = (col == aggHighlightedCountCol ? highlightedAmino : selectedAmino);
206
- if (curAmino == amino) {
207
- aminoObj[col == aggHighlightedCountCol ? 'highlightedCount' : 'selectedCount'] = col.get(j);
208
- break;
209
- }
194
+ colData.push(aminoObj);
195
+
196
+ for (let j = 0; j < aggSelectedCountCol.length; j++) {
197
+ const selectedAmino = aggSelectedAminoCol.get(j);
198
+ const curAmino = (selectedAmino);
199
+ if (curAmino == amino) {
200
+ aminoObj['selectedCount'] = aggSelectedCountCol.get(j);
201
+ break;
210
202
  }
211
203
  }
212
204
  }
213
205
 
214
- colObj['data'].sort((o1, o2) => this.ord[o2['name']] - this.ord[o1['name']]);
206
+ colData.sort((o1, o2) => this.ord[o2['name']] - this.ord[o1['name']]);
215
207
  }
216
208
 
217
209
  this.max = this.dataFrame!.filter.trueCount;
@@ -291,24 +283,16 @@ export class StackedBarChart extends DG.JsViewer {
291
283
  );
292
284
  }
293
285
 
294
- if (obj['highlightedCount'] > eps && obj['highlightedCount'] > obj['selectedCount']) {
295
- g.fillStyle = 'rgb(209,242,251)';
296
- g.fillRect(
297
- x + xStart - w * selectLineRatio * 2,
298
- y + yStart + h * obj['selectedCount'] / this.max - gapSize,
299
- barWidth * selectLineRatio,
300
- h * (obj['highlightedCount'] - obj['selectedCount']) / this.max - gapSize,
301
- );
302
- }
303
-
304
286
  sum -= obj['count'];
305
287
  });
306
288
  }
307
289
 
308
- highlight(cell: DG.GridCell, offsetX:number, offsetY:number, mouseEvent: MouseEvent) {
290
+ findAARandPosition(cell: DG.GridCell, mouseEvent: MouseEvent) {
309
291
  if (!cell.tableColumn?.name || !this.aminoColumnNames.includes(cell.tableColumn.name))
310
- return;
292
+ return null;
311
293
 
294
+ const offsetX = mouseEvent.offsetX;
295
+ const offsetY = mouseEvent.offsetY;
312
296
  const colName = cell.tableColumn?.name;
313
297
  const innerMargin = 0.02;
314
298
  const margin = 0.2;
@@ -326,73 +310,53 @@ export class StackedBarChart extends DG.JsViewer {
326
310
  sum += obj['count'];
327
311
  });
328
312
 
329
- this.highlighted = null;
330
- barData.forEach((obj) => {
313
+ const xStart = x + (w - barWidth) / 2;
314
+ for (const obj of barData) {
331
315
  const sBarHeight = h * obj['count'] / this.max;
332
316
  const gapSize = sBarHeight * innerMargin;
333
317
  const verticalShift = (this.max - sum) / this.max;
334
318
  const subBartHeight = sBarHeight - gapSize;
335
- const yStart = h * verticalShift + gapSize / 2;
336
- const xStart = (w - barWidth) / 2;
319
+ const yStart = y + h * verticalShift + gapSize / 2;
337
320
 
338
- if (offsetX >= x + xStart &&
339
- offsetY >= y + yStart &&
340
- offsetX <= x + xStart + barWidth &&
341
- offsetY <= y + yStart + subBartHeight)
342
- this.highlighted = {'colName': colName, 'aaName': obj['name']};
321
+ const isIntersectingX = offsetX >= xStart && offsetX <= xStart + barWidth;
322
+ const isIntersectingY = offsetY >= yStart && offsetY <= yStart + subBartHeight;
343
323
 
324
+ if (isIntersectingX && isIntersectingY)
325
+ return {'colName': colName, 'aaName': obj['name']};
344
326
 
345
327
  sum -= obj['count'];
346
- });
347
-
348
- if (!this.highlighted)
349
- return;
350
-
351
- if (mouseEvent.type == 'click') {
352
- let idx = -1;
353
-
354
- for (let i = 0; i < this.selected.length; ++i) {
355
- if (JSON.stringify(this.selected[i]) == JSON.stringify(this.highlighted))
356
- idx = i;
357
- }
358
-
359
- if (mouseEvent.shiftKey && idx == -1)
360
- this.selected.push(this.highlighted);
361
-
362
- if (mouseEvent.shiftKey && (mouseEvent.ctrlKey || mouseEvent.metaKey) && idx != -1)
363
- this.selected.splice(idx, 1);
364
328
  }
329
+
330
+ return null;
365
331
  }
366
332
 
367
333
  unhighlight() {
368
- this.highlighted = null;
369
- this.highlightedMask!.setAll(false);
334
+ ui.tooltip.hide();
370
335
  this.computeData();
371
336
  }
372
337
 
373
- beginSelection(event: MouseEvent) {
374
- if (!this.dataFrame)
338
+ /**
339
+ * Requests highlight/select/filter action based on currentBarPart
340
+ * @param event
341
+ * @returns
342
+ */
343
+ requestAction(event: MouseEvent) {
344
+ if (!this._currentBarPart)
375
345
  return;
376
-
377
- this.highlightedMask!.setAll(false);
378
-
379
- this.dataFrame.selection.handleClick((i: number) => {
380
- for (const high of this.selected) {
381
- if (high['aaName'] === (this.dataFrame!.getCol(high['colName']).get(i)))
382
- return true;
346
+ let aar = this._currentBarPart!['aaName'];
347
+ let position = this._currentBarPart!['colName'];
348
+ if (event.type === 'click') {
349
+ if (this.isSameBarClicked) {
350
+ aar = position = C.CATEGORIES.ALL;
351
+ this.currentBarPart = null;
383
352
  }
384
- return false;
385
- }, event);
386
-
387
- if (this.highlighted) {
388
- this.dataFrame.rows.match({[this.highlighted['colName']]: this.highlighted['aaName']}).highlight();
389
- this.highlightedMask!.handleClick((i: number) => {
390
- if (this.highlighted!['aaName'] === (this.dataFrame!.getCol(this.highlighted!['colName']).get(i)))
391
- return true;
392
- return false;
393
- }, event);
353
+ this.controller.setSARGridCellAt(aar, position);
354
+ this._previousClickedBarPart = this._currentBarPart;
355
+ } else {
356
+ ui.tooltip.showRowGroup(this.dataFrame, (i) => {
357
+ const currentAAR = this.dataFrame.get(position, i);
358
+ return currentAAR === aar;
359
+ }, event.offsetX, event.offsetY);
394
360
  }
395
-
396
- this.computeData();
397
361
  }
398
362
  }
@@ -5,6 +5,8 @@ import {callMVA} from '../utils/multivariate-analysis';
5
5
  import {PeptidesController} from '../peptides';
6
6
  import '../styles.css';
7
7
  import {StringDictionary} from '@datagrok-libraries/utils/src/type-declarations';
8
+ import * as C from '../utils/constants';
9
+ import {FilteringStatistics} from '../utils/filtering-statistics';
8
10
 
9
11
  /**
10
12
  * Peptide analysis widget.
@@ -16,9 +18,7 @@ import {StringDictionary} from '@datagrok-libraries/utils/src/type-declarations'
16
18
  * @param {DG.DataFrame} currentDf Working table.
17
19
  * @return {Promise<DG.Widget>} Widget containing peptide analysis.
18
20
  */
19
- export async function analyzePeptidesWidget(
20
- col: DG.Column, view: DG.TableView, tableGrid: DG.Grid, currentDf: DG.DataFrame,
21
- ): Promise<DG.Widget> {
21
+ export async function analyzePeptidesWidget(currentDf: DG.DataFrame, col: DG.Column): Promise<DG.Widget> {
22
22
  let tempCol = null;
23
23
  let tempDf: DG.DataFrame;
24
24
  let newScaledColName: string;
@@ -33,13 +33,14 @@ export async function analyzePeptidesWidget(
33
33
  'Scaling', 'none', ['none', 'lg', '-lg'],
34
34
  async (currentMethod: string) => {
35
35
  const currentActivityCol = activityColumnChoice.value.name;
36
+
36
37
 
37
38
  [tempDf, newScaledColName] = await PeptidesController.scaleActivity(
38
- currentMethod, currentActivityCol, `${currentActivityCol}Scaled`, currentDf);
39
+ currentMethod, currentDf, currentActivityCol, true);
39
40
 
40
41
  const hist = tempDf.plot.histogram({
41
42
  filteringEnabled: false,
42
- valueColumnName: `${currentActivityCol}Scaled`,
43
+ valueColumnName: C.COLUMNS_NAMES.ACTIVITY_SCALED,
43
44
  legendVisibility: 'Never',
44
45
  showXAxis: true,
45
46
  showColumnSelector: false,
@@ -69,45 +70,47 @@ export async function analyzePeptidesWidget(
69
70
  const startBtn = ui.button('Launch SAR', async () => {
70
71
  const progress = DG.TaskBarProgressIndicator.create('Loading SAR...');
71
72
  if (activityColumnChoice.value.type === DG.TYPE.FLOAT) {
72
- const activityColumn = activityColumnChoice.value.name;
73
- const activityColumnScaled = `${activityColumn}Scaled`;
74
- const originalDfColumns = (currentDf.columns as DG.ColumnList).names();
73
+ const activityColumn: string = activityColumnChoice.value.name;
74
+ // const activityColumnScaled = `${activityColumn}Scaled`;
75
+ // const originalDfColumns = (currentDf.columns as DG.ColumnList).names();
75
76
  const options: StringDictionary = {
76
- 'activityColumnName': activityColumn,
77
77
  'scaling': activityScalingMethod.value,
78
78
  };
79
79
 
80
- const scaledCol = tempDf.getCol(activityColumnScaled);
81
- (currentDf.columns as DG.ColumnList).add(scaledCol);
82
- tableGrid.col(activityColumnScaled)!.name = newScaledColName;
83
- scaledCol.temp['gridName'] = newScaledColName;
84
- if (newScaledColName === activityColumn)
85
- tableGrid.col(activityColumn)!.name = `~${activityColumn}`;
86
- tableGrid.columns.setOrder([newScaledColName]);
87
-
88
- const peptides = await PeptidesController.getInstance(currentDf);
89
- await peptides.init(tableGrid, view, options, col, originalDfColumns);
80
+ //prepare new DF
81
+ const newDf = currentDf.clone(currentDf.filter, [col.name, activityColumn]);
82
+ newDf.getCol(activityColumn).name = C.COLUMNS_NAMES.ACTIVITY;
83
+ newDf.getCol(col.name).name = C.COLUMNS_NAMES.ALIGNED_SEQUENCE;
84
+ const activityScaledCol = tempDf.getCol(C.COLUMNS_NAMES.ACTIVITY_SCALED);
85
+ (newDf.columns as DG.ColumnList).add(activityScaledCol);
86
+ // newDf.temp[C.COLUMNS_NAMES.ACTIVITY] = activityColumn;
87
+ newDf.name = 'Peptides analysis';
88
+ newDf.temp[C.COLUMNS_NAMES.ACTIVITY_SCALED] = newScaledColName;
89
+ newDf.tags['isPeptidesAnalysis'] = 'true';
90
+
91
+ const peptides = await PeptidesController.getInstance(newDf);
92
+ await peptides.init(newDf);
90
93
  } else
91
94
  grok.shell.error('The activity column must be of floating point number type!');
92
95
  progress.close();
93
96
  });
94
97
  startBtn.style.alignSelf = 'center';
95
98
 
96
- const startMVABtn = ui.button('Launch MVA', async () => {
97
- if (activityColumnChoice.value.type === DG.TYPE.FLOAT) {
98
- const progress = DG.TaskBarProgressIndicator.create('Loading MVA...');
99
+ // const startMVABtn = ui.button('Launch MVA', async () => {
100
+ // if (activityColumnChoice.value.type === DG.TYPE.FLOAT) {
101
+ // const progress = DG.TaskBarProgressIndicator.create('Loading MVA...');
99
102
 
100
- const options: {[key: string]: string} = {
101
- 'activityColumnName': activityColumnChoice.value.name,
102
- 'scaling': activityScalingMethod.value,
103
- };
103
+ // const options: {[key: string]: string} = {
104
+ // 'activityColumnName': activityColumnChoice.value.name,
105
+ // 'scaling': activityScalingMethod.value,
106
+ // };
104
107
 
105
- await callMVA(tableGrid, view, currentDf, options, col);
108
+ // await callMVA(tableGrid, view, currentDf, options, col);
106
109
 
107
- progress.close();
108
- } else
109
- grok.shell.error('The activity column must be of floating point number type!');
110
- });
110
+ // progress.close();
111
+ // } else
112
+ // grok.shell.error('The activity column must be of floating point number type!');
113
+ // });
111
114
 
112
115
 
113
116
  const viewer = await currentDf.plot.fromType('peptide-logo-viewer');
@@ -0,0 +1,61 @@
1
+ import * as ui from 'datagrok-api/ui';
2
+ import * as DG from 'datagrok-api/dg';
3
+
4
+ import * as C from '../utils/constants';
5
+ import {StringDictionary} from '@datagrok-libraries/utils/src/type-declarations';
6
+ import {FilteringStatistics} from '../utils/filtering-statistics';
7
+
8
+ export function getDistributionPlot(df: DG.DataFrame, valueCol: string, splitCol: string) {
9
+ return df.plot.histogram({
10
+ // const hist = originalDf.plot.histogram({
11
+ filteringEnabled: false,
12
+ valueColumnName: valueCol,
13
+ splitColumnName: splitCol,
14
+ legendVisibility: 'Never',
15
+ showXAxis: true,
16
+ showColumnSelector: false,
17
+ showRangeSlider: false,
18
+ });
19
+ }
20
+
21
+ export function getDistributionWidget(table: DG.DataFrame): DG.Widget {
22
+ // const labelStr = this.multipleFilter.filterLabel;
23
+ const splitCol = table.col(C.COLUMNS_NAMES.SPLIT_COL);
24
+ if (!splitCol)
25
+ return new DG.Widget(ui.divText('No distribution'));
26
+ let [aarStr, otherStr] = splitCol.categories;
27
+ if (typeof otherStr === 'undefined')
28
+ [aarStr, otherStr] = [otherStr, aarStr];
29
+ // const currentColor = DG.Color.toHtml(DG.Color.orange);
30
+ // const otherColor = DG.Color.toHtml(DG.Color.blue);
31
+ const currentColor = DG.Color.toHtml(DG.Color.getCategoryColor(splitCol, aarStr));
32
+ const otherColor = DG.Color.toHtml(DG.Color.getCategoryColor(splitCol, otherStr));
33
+
34
+ const currentLabel = ui.label(aarStr, {style: {color: currentColor}});
35
+ const otherLabel = ui.label(otherStr, {style: {color: otherColor}});
36
+ const elements: (HTMLLabelElement | HTMLElement)[] = [currentLabel, otherLabel];
37
+
38
+ const getContent = () => {
39
+ // const processedDf =
40
+ // table.clone(null, [C.COLUMNS_NAMES.ACTIVITY_SCALED, C.COLUMNS_NAMES.SPLIT_COL]);
41
+ const hist = getDistributionPlot(table, C.COLUMNS_NAMES.ACTIVITY_SCALED, C.COLUMNS_NAMES.SPLIT_COL).root;
42
+
43
+ hist.style.width = 'auto';
44
+ elements.push(hist);
45
+
46
+ const stats = (table.temp[C.STATS] as FilteringStatistics).result;
47
+ if (stats) {
48
+ const tableMap: StringDictionary = {
49
+ 'Statistics:': '',
50
+ 'Count': stats.count.toString(),
51
+ 'p-value': stats.pValue < 0.01 ? '<0.01' : stats.pValue.toFixed(2),
52
+ 'Mean difference': stats.meanDifference.toFixed(2),
53
+ };
54
+
55
+ elements.push(ui.tableFromMap(tableMap));
56
+ }
57
+ return ui.divV(elements);
58
+ };
59
+
60
+ return new DG.Widget(getContent());
61
+ }
@@ -34,6 +34,7 @@ export function manualAlignmentWidget(alignedSequenceCol: DG.Column, currentDf:
34
34
  grok.shell.o = temp;
35
35
 
36
36
  const peptidesController = await PeptidesController.getInstance(currentDf);
37
+ peptidesController.init(currentDf);
37
38
  peptidesController.updateDefault();
38
39
  });
39
40
 
@@ -1,27 +1,27 @@
1
1
  import * as ui from 'datagrok-api/ui';
2
2
  import * as DG from 'datagrok-api/dg';
3
+ import { PeptidesController } from '../peptides';
3
4
 
4
- export function substTableWidget(table: DG.DataFrame): DG.Widget {
5
- if (!table?.temp['isReal'])
6
- return new DG.Widget(ui.label('No substitution'));
5
+ export async function substitutionsWidget(table: DG.DataFrame): Promise<DG.Widget> {
6
+ const controller = await PeptidesController.getInstance(table);
7
+ controller.init(table);
8
+ const substTable = controller.getSubstitutions();
7
9
 
8
- const dfRowCount = table.rowCount;
10
+ if (!substTable)
11
+ return new DG.Widget(ui.label('No substitution table generated'));
12
+
13
+ const dfRowCount = substTable.rowCount;
9
14
  const aminoInputFrom = ui.stringInput('from', '');
10
15
  const aminoInputTo = ui.stringInput('to', '');
11
16
  const fromToMap: {[key: string]: DG.BitSet} = {};
12
17
  let aminoFrom = '';
13
18
  let aminoTo = '';
14
- const initialCol: DG.Column = table.columns.byName('Initial');
15
- const substitutedCol: DG.Column = table.columns.byName('Substituted');
16
-
17
- for (let i = 0; i < initialCol.length; ++i) {
18
- const sequenceDifference = `${initialCol.get(i)}#${substitutedCol.get(i)}`;
19
- initialCol.set(i, sequenceDifference);
20
- }
19
+ const initialCol: DG.Column = substTable.getCol('Initial');
20
+ const substitutedCol: DG.Column = substTable.getCol('Substituted');
21
21
 
22
22
  initialCol.semType = 'alignedSequenceDifference';
23
23
  initialCol.name = 'Substitution';
24
- table.columns.remove('Substituted');
24
+ // substTable.columns.remove('Substituted');
25
25
  // const substCol = table.getCol('Substitution');
26
26
 
27
27
  for (let i = 0; i < dfRowCount; ++i) {
@@ -33,7 +33,7 @@ export function substTableWidget(table: DG.DataFrame): DG.Widget {
33
33
 
34
34
  for (let j = 0; j < aminosFrom.length; ++j) {
35
35
  if (aminosFrom[j] != aminosTo[j]) {
36
- const idx = (aminosFrom[j] === '' ? '-' : aminosFrom[j]) + '#' + (aminosTo[j] === '' ? '-' : aminosTo[j]);
36
+ const idx = `${getAmino(aminosFrom[j])}#${getAmino(aminosTo[j])}`;
37
37
 
38
38
  if (!(idx in fromToMap))
39
39
  fromToMap[idx] = DG.BitSet.create(dfRowCount);
@@ -42,22 +42,32 @@ export function substTableWidget(table: DG.DataFrame): DG.Widget {
42
42
  }
43
43
  }
44
44
 
45
+ for (let i = 0; i < initialCol.length; ++i) {
46
+ const sequenceDifference = `${initialCol.get(i)}#${substitutedCol.get(i)}`;
47
+ initialCol.set(i, sequenceDifference);
48
+ }
49
+
45
50
  aminoInputFrom.onInput(() => {
46
- aminoFrom = aminoInputFrom.value;
47
- const fromKey = aminoFrom + '#' + aminoTo;
51
+ aminoFrom = getAmino(aminoInputFrom.value);
52
+ const fromKey = `${aminoFrom}#${aminoTo}`;
48
53
  if (fromKey in fromToMap)
49
- table.selection.copyFrom(fromToMap[fromKey]);
54
+ substTable.selection.copyFrom(fromToMap[fromKey]);
50
55
  });
51
56
 
52
57
  aminoInputTo.onInput(() => {
53
- aminoTo = aminoInputTo.value;
54
- const toKey = aminoFrom + '#' + aminoTo;
58
+ aminoTo = getAmino(aminoInputTo.value);
59
+ const toKey = `${aminoFrom}#${aminoTo}`;
55
60
  if (toKey in fromToMap)
56
- table.selection.copyFrom(fromToMap[toKey]);
61
+ substTable.selection.copyFrom(fromToMap[toKey]);
57
62
  });
58
63
 
59
- const grid = table.plot.grid();
64
+ const grid = substTable.plot.grid();
60
65
  grid.props.allowEdit = false;
61
66
  grid.root.style.width = 'auto';
67
+ grid.root.style.height = '150px';
62
68
  return new DG.Widget(ui.divV([aminoInputFrom.root, aminoInputTo.root, grid.root]));
63
69
  }
70
+
71
+ function getAmino(amino: string): string {
72
+ return amino === '' ? '-' : amino;
73
+ }