@datagrok/peptides 1.17.20 → 1.17.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/dist/package-test.js +2 -2
- package/dist/package.js +2 -2
- package/package.json +1 -1
- package/src/package.ts +10 -0
- package/src/utils/cell-renderer.ts +188 -0
- package/src/utils/misc.ts +5 -3
- package/src/utils/statistics.ts +16 -0
- package/src/viewers/logo-summary.ts +49 -15
- package/src/viewers/sar-viewer.ts +4 -4
package/package.json
CHANGED
package/src/package.ts
CHANGED
|
@@ -14,6 +14,7 @@ import {PeptidesModel} from './model';
|
|
|
14
14
|
import {macromoleculeSarFastaDemoUI} from './demo/fasta';
|
|
15
15
|
import {u2} from '@datagrok-libraries/utils/src/u2';
|
|
16
16
|
import {ClusterMaxActivityViewer} from './viewers/cluster-max-activity-viewer';
|
|
17
|
+
import {LSTPieChartRenderer} from './utils/cell-renderer';
|
|
17
18
|
|
|
18
19
|
let monomerWorks: MonomerWorks | null = null;
|
|
19
20
|
let treeHelper: ITreeHelper;
|
|
@@ -169,3 +170,12 @@ export function manualAlignment(_monomer: string): DG.Widget {
|
|
|
169
170
|
export async function macromoleculeSarFastaDemo(): Promise<void> {
|
|
170
171
|
return macromoleculeSarFastaDemoUI();
|
|
171
172
|
}
|
|
173
|
+
|
|
174
|
+
//name: LST Pie Chart
|
|
175
|
+
//tags: cellRenderer
|
|
176
|
+
//meta.cellType: lst-pie-chart
|
|
177
|
+
//meta.gridChart: true
|
|
178
|
+
//output: grid_cell_renderer result
|
|
179
|
+
export function lstPiechartCellRenderer(): LSTPieChartRenderer {
|
|
180
|
+
return new LSTPieChartRenderer();
|
|
181
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable max-len */
|
|
1
2
|
import * as ui from 'datagrok-api/ui';
|
|
2
3
|
import * as DG from 'datagrok-api/dg';
|
|
3
4
|
|
|
@@ -439,3 +440,190 @@ function findWebLogoMonomerPosition(cell: DG.GridCell, ev: MouseEvent, webLogoBo
|
|
|
439
440
|
|
|
440
441
|
return null;
|
|
441
442
|
}
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Renderer for LST pie chart cell
|
|
447
|
+
*
|
|
448
|
+
*/
|
|
449
|
+
|
|
450
|
+
export class LSTPieChartRenderer extends DG.GridCellRenderer {
|
|
451
|
+
get name(): string {return 'LST Pie Chart';}
|
|
452
|
+
|
|
453
|
+
get cellType(): string {return 'lst-pie-chart';}
|
|
454
|
+
|
|
455
|
+
get defaultWidth(): number | null {return 80;}
|
|
456
|
+
|
|
457
|
+
get defaultHeight(): number | null {return 80;}
|
|
458
|
+
|
|
459
|
+
colorCacheKey = 'lst-pie-chart-color-cache'; // key for temp storage of category number cache
|
|
460
|
+
categoryNumberCache(col: DG.Column): {[_: string]: number} {
|
|
461
|
+
if (!col.temp[this.colorCacheKey])
|
|
462
|
+
col.temp[this.colorCacheKey] = {};
|
|
463
|
+
return col.temp[this.colorCacheKey] as {[_: string]: number};
|
|
464
|
+
};
|
|
465
|
+
|
|
466
|
+
HoverTempKey = 'lst-pie-chart-hovered-sector'; // key for temp storage of hovered sector
|
|
467
|
+
hoverSeparator = ',,,,,'; // separator for hovered sector
|
|
468
|
+
|
|
469
|
+
getPrevHoveredSector(col: DG.Column): string | null {
|
|
470
|
+
return col.temp[this.HoverTempKey] as string;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
onMouseMove(gridCell: DG.GridCell, e: MouseEvent): void {
|
|
474
|
+
const prev = this.getPrevHoveredSector(gridCell.cell.column);
|
|
475
|
+
const beforeReturn = (): void => {
|
|
476
|
+
gridCell.cell.column.temp[this.HoverTempKey] = null;
|
|
477
|
+
ui.tooltip.hide();
|
|
478
|
+
|
|
479
|
+
if (prev !== null)
|
|
480
|
+
gridCell.grid.invalidate();
|
|
481
|
+
};
|
|
482
|
+
|
|
483
|
+
const value = gridCell.cell.value;
|
|
484
|
+
if (!value) {
|
|
485
|
+
beforeReturn();
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
const vectorX = e.offsetX - gridCell.bounds.midX;
|
|
489
|
+
const vectorY = e.offsetY - gridCell.bounds.midY;
|
|
490
|
+
const distance = Math.sqrt(vectorX * vectorX + vectorY * vectorY);
|
|
491
|
+
const atan2 = Math.atan2(vectorY, vectorX);
|
|
492
|
+
const angle = atan2 < 0 ? atan2 + 2 * Math.PI : atan2;
|
|
493
|
+
if (distance > Math.min(gridCell.bounds.width, gridCell.bounds.height) / 2 - 2) {
|
|
494
|
+
beforeReturn();
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
let JSONData: {[_: string]: number};
|
|
499
|
+
try {
|
|
500
|
+
JSONData = JSON.parse(value);
|
|
501
|
+
} catch (e) {
|
|
502
|
+
beforeReturn();
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
const angles = new Float64Array(Object.keys(JSONData).length + 1);
|
|
507
|
+
const totalCount = Object.values(JSONData).reduce((a, b) => a + b, 0);
|
|
508
|
+
angles[Object.keys(JSONData).length] = Math.PI * 2;
|
|
509
|
+
let angleAccum = 0;
|
|
510
|
+
let i = 0;
|
|
511
|
+
for (const val of Object.values(JSONData)) {
|
|
512
|
+
angles[i++] = angleAccum;
|
|
513
|
+
const angleAdd = 2 * Math.PI * val / totalCount;
|
|
514
|
+
angleAccum += angleAdd;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
let hitCategory = -1;
|
|
518
|
+
for (let i = 0; i < angles.length - 1; i++) {
|
|
519
|
+
if (angle >= angles[i] && angle < angles[i + 1]) {
|
|
520
|
+
hitCategory = i;
|
|
521
|
+
break;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
if (hitCategory === -1) {
|
|
525
|
+
beforeReturn();
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
const hitCategoryName = Object.keys(JSONData)[hitCategory];
|
|
529
|
+
const hitCategoryValue = JSONData[hitCategoryName];
|
|
530
|
+
const percentage = (hitCategoryValue / totalCount * 100).toFixed(2);
|
|
531
|
+
ui.tooltip.show(ui.h1(`${hitCategoryName}: ${hitCategoryValue} (${percentage}%)`), e.x + 16, e.y +
|
|
532
|
+
16);
|
|
533
|
+
const hoverTemp = gridCell.cell.rowIndex.toString() + this.hoverSeparator + hitCategoryName;
|
|
534
|
+
gridCell.cell.column.temp[this.HoverTempKey] = hoverTemp;
|
|
535
|
+
if (prev !== hoverTemp)
|
|
536
|
+
gridCell.grid.invalidate();
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
render(
|
|
540
|
+
g: CanvasRenderingContext2D,
|
|
541
|
+
x: number, y: number, w: number, h: number,
|
|
542
|
+
gridCell: DG.GridCell, _cellStyle: DG.GridCellStyle,
|
|
543
|
+
): void {
|
|
544
|
+
const df = gridCell.cell.dataFrame;
|
|
545
|
+
const box = new DG.Rect(x, y, w, h).fitSquare().inflate(-2, -2);
|
|
546
|
+
if (w < 5 || h < 5 || !df) return;
|
|
547
|
+
const value = gridCell.cell.value;
|
|
548
|
+
g.clearRect(x, y, w, h);
|
|
549
|
+
if (!value) return;
|
|
550
|
+
|
|
551
|
+
let JSONData: {[_: string]: number};
|
|
552
|
+
try {
|
|
553
|
+
JSONData = JSON.parse(value);
|
|
554
|
+
} catch (e) {
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
const totalCount = Object.values(JSONData).reduce((a, b) => a + b, 0);
|
|
559
|
+
|
|
560
|
+
let angleAccum = 0;
|
|
561
|
+
|
|
562
|
+
const alphas = Object.fromEntries(Object.keys(JSONData).map((key) => [key, 255]));
|
|
563
|
+
|
|
564
|
+
const hoverTemp = gridCell.cell.column.temp[this.HoverTempKey] as string;
|
|
565
|
+
if (hoverTemp && hoverTemp.split(this.hoverSeparator).length === 2) {
|
|
566
|
+
const [rowIdx, category] = hoverTemp.split(this.hoverSeparator);
|
|
567
|
+
if (rowIdx === gridCell.cell.rowIndex.toString()) {
|
|
568
|
+
for (const [key, _] of Object.entries(JSONData))
|
|
569
|
+
alphas[key] = 100;
|
|
570
|
+
alphas[category] = 255;
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
const radius = Math.min(w, h) / 2.2;
|
|
575
|
+
|
|
576
|
+
for (const [key, val] of Object.entries(JSONData)) {
|
|
577
|
+
const angle = 2 * Math.PI * val / totalCount;
|
|
578
|
+
g.beginPath();
|
|
579
|
+
g.moveTo(box.midX, box.midY);
|
|
580
|
+
g.arc(box.midX, box.midY, radius, angleAccum, angleAccum + angle);
|
|
581
|
+
angleAccum += angle;
|
|
582
|
+
const colorCache = this.categoryNumberCache(gridCell.cell.column);
|
|
583
|
+
if (!colorCache[key]) {
|
|
584
|
+
colorCache[key] = Object.keys(colorCache).length; // cache category number keys, so that colors are consistent
|
|
585
|
+
gridCell.cell.column.temp[this.colorCacheKey] = colorCache;
|
|
586
|
+
}
|
|
587
|
+
g.fillStyle = DG.Color.toHtml(
|
|
588
|
+
DG.Color.setAlpha(DG.Color.getCategoricalColor(colorCache[key]), alphas[key]),
|
|
589
|
+
);
|
|
590
|
+
g.fill();
|
|
591
|
+
g.strokeStyle = DG.Color.toRgb(DG.Color.lightGray);
|
|
592
|
+
g.stroke();
|
|
593
|
+
|
|
594
|
+
|
|
595
|
+
// text rendering
|
|
596
|
+
const text = key;
|
|
597
|
+
// g.font = '10px Arial'; // Adjust font size and family as needed
|
|
598
|
+
g.fillStyle = DG.Color.toRgb(DG.Color.white);
|
|
599
|
+
g.font = '9px Arial';
|
|
600
|
+
const textWidth = g.measureText(text).width;
|
|
601
|
+
|
|
602
|
+
const middleAngle = angleAccum - (angle / 2);
|
|
603
|
+
|
|
604
|
+
// get the best position for the text
|
|
605
|
+
for (let textRadiusMult = 0.8; textRadiusMult >= 0.4; textRadiusMult -= 0.05) {
|
|
606
|
+
const textRadius = radius * textRadiusMult;
|
|
607
|
+
const textX = box.midX + Math.cos(middleAngle) * textRadius;
|
|
608
|
+
const textY = box.midY + Math.sin(middleAngle) * textRadius;
|
|
609
|
+
|
|
610
|
+
// perform pseudo hit test to check if text fits in the pie slice
|
|
611
|
+
const leftPart = textX - textWidth / 2 - 2;
|
|
612
|
+
const rightPart = textX + textWidth / 2 + 2;
|
|
613
|
+
|
|
614
|
+
const isTextInside = [[leftPart, textY], [rightPart, textY]]
|
|
615
|
+
.every((point) => {
|
|
616
|
+
const d = Math.sqrt((point[0] - box.midX) ** 2 + (point[1] - box.midY) ** 2);
|
|
617
|
+
const at = Math.atan2(point[1] - box.midY, point[0] - box.midX);
|
|
618
|
+
const a = at < 0 ? at + 2 * Math.PI : at;
|
|
619
|
+
return d < radius - 2 && a > angleAccum - angle && a < angleAccum;
|
|
620
|
+
});
|
|
621
|
+
|
|
622
|
+
if (isTextInside) {
|
|
623
|
+
g.fillText(text, textX, textY);
|
|
624
|
+
break;
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
}
|
package/src/utils/misc.ts
CHANGED
|
@@ -431,12 +431,14 @@ export function mutationCliffsToMaskInfo(mutationCliffs: type.MutationCliffs, ro
|
|
|
431
431
|
* @param aggColsModel - Object with aggregation columns from analysis settings.
|
|
432
432
|
* @return - Array of combined aggregation columns.
|
|
433
433
|
*/
|
|
434
|
-
export function getTotalAggColumns(viewerSelectedColNames: string[],
|
|
435
|
-
aggColsModel?: AggregationColumns): [string, DG.AggregationType][] {
|
|
434
|
+
export function getTotalAggColumns(df: DG.DataFrame, viewerSelectedColNames: string[],
|
|
435
|
+
aggColsViewer: AggregationColumns, aggColsModel?: AggregationColumns): [string, DG.AggregationType][] {
|
|
436
436
|
const aggColsEntries = Object.entries(aggColsViewer);
|
|
437
437
|
const aggColsEntriesFromSettings = !aggColsModel ? [] : Object.entries(aggColsModel)
|
|
438
438
|
.filter((it) => !viewerSelectedColNames.includes(it[0]) || aggColsViewer[it[0]] !== it[1]);
|
|
439
|
-
|
|
439
|
+
|
|
440
|
+
return aggColsEntries.concat(aggColsEntriesFromSettings)
|
|
441
|
+
.filter((it) => df.columns.contains(it[0]) && df.col(it[0])!.matches('numerical'));
|
|
440
442
|
}
|
|
441
443
|
|
|
442
444
|
/**
|
package/src/utils/statistics.ts
CHANGED
|
@@ -152,3 +152,19 @@ export function getAggregatedColumnValuesFromDf(df: DG.DataFrame, idx: number,
|
|
|
152
152
|
}
|
|
153
153
|
return colResults;
|
|
154
154
|
}
|
|
155
|
+
|
|
156
|
+
export function getStringColAggregatedJSON(df: DG.DataFrame, colName: string, mask?: DG.BitSet): string {
|
|
157
|
+
const col = df.col(colName.substring(5, colName.length - 1)); // remove 'dist(' and ')'
|
|
158
|
+
if (!col || !col.matches('categorical'))
|
|
159
|
+
return '{}';
|
|
160
|
+
mask ??= DG.BitSet.create(df.rowCount, () => true);
|
|
161
|
+
const values = col.getRawData();
|
|
162
|
+
const valueCounts = new Map<number, number>();
|
|
163
|
+
for (let i = -1; (i = mask.findNext(i, true)) !== -1;)
|
|
164
|
+
valueCounts.set(values[i], (valueCounts.get(values[i]) ?? 0) + 1);
|
|
165
|
+
|
|
166
|
+
const resJSON: {[_: string]: number} = {};
|
|
167
|
+
for (const [value, count] of valueCounts)
|
|
168
|
+
resJSON[col.categories[value]] = count;
|
|
169
|
+
return JSON.stringify(resJSON);
|
|
170
|
+
}
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
getAggregatedColumnValues,
|
|
15
15
|
getAggregatedValue,
|
|
16
16
|
getStats,
|
|
17
|
+
getStringColAggregatedJSON,
|
|
17
18
|
StatsItem,
|
|
18
19
|
} from '../utils/statistics';
|
|
19
20
|
import wu from 'wu';
|
|
@@ -276,7 +277,9 @@ export class LogoSummaryTable extends DG.JsViewer implements ILogoSummaryTable {
|
|
|
276
277
|
* @return - map of columns and aggregations.
|
|
277
278
|
*/
|
|
278
279
|
getAggregationColumns(): AggregationColumns {
|
|
279
|
-
return Object.fromEntries(this.columns.map((colName) => [colName, this.aggregation] as [string, DG.AGG])
|
|
280
|
+
return Object.fromEntries(this.columns.map((colName) => [colName, this.aggregation] as [string, DG.AGG])
|
|
281
|
+
.filter(([colName, _]) => this.model.df.columns.contains(colName) &&
|
|
282
|
+
this.model.df.col(colName)!.matches('numerical')));
|
|
280
283
|
}
|
|
281
284
|
|
|
282
285
|
/** Processes attached table and sets viewer properties. */
|
|
@@ -411,7 +414,12 @@ export class LogoSummaryTable extends DG.JsViewer implements ILogoSummaryTable {
|
|
|
411
414
|
*/
|
|
412
415
|
getTotalViewerAggColumns(): [string, DG.AggregationType][] {
|
|
413
416
|
const aggrCols = this.getAggregationColumns();
|
|
414
|
-
return getTotalAggColumns(this.columns, aggrCols, this.model?.settings?.columns);
|
|
417
|
+
return getTotalAggColumns(this.model.df, this.columns, aggrCols, this.model?.settings?.columns);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
getStringAggregatedColumns(): string[] {
|
|
421
|
+
return this.columns.filter((colName) => this.model.df.columns.contains(colName) &&
|
|
422
|
+
this.model.df.col(colName)!.matches('categorical')).map((cn) => `dist(${cn})`);
|
|
415
423
|
}
|
|
416
424
|
|
|
417
425
|
/**
|
|
@@ -449,16 +457,18 @@ export class LogoSummaryTable extends DG.JsViewer implements ILogoSummaryTable {
|
|
|
449
457
|
const customRatioColData = customLSTCols.addNewFloat(C.LST_COLUMN_NAMES.RATIO).getRawData();
|
|
450
458
|
|
|
451
459
|
let origLSTBuilder = filteredDf.groupBy([clustersColName]);
|
|
452
|
-
const
|
|
453
|
-
const
|
|
454
|
-
const
|
|
455
|
-
const
|
|
460
|
+
const aggNumericColsEntries = this.getTotalViewerAggColumns();
|
|
461
|
+
const aggStringColNames = this.getStringAggregatedColumns();
|
|
462
|
+
const aggStringCols = aggStringColNames.map((colName) => customLSTCols.addNewString(colName));
|
|
463
|
+
const aggNumericColNames = aggNumericColsEntries.map(([colName, aggFn]) => getAggregatedColName(aggFn, colName));
|
|
464
|
+
const customAggRawCols = new Array(aggNumericColNames.length + aggStringColNames.length);
|
|
465
|
+
const numericColAggEntries = aggNumericColsEntries.map(
|
|
456
466
|
([colName, aggFn]) => [filteredDf.getCol(colName), aggFn] as [DG.Column<number>, DG.AggregationType]);
|
|
457
467
|
|
|
458
|
-
for (let aggIdx = 0; aggIdx <
|
|
459
|
-
const [colName, aggFn] =
|
|
460
|
-
origLSTBuilder = origLSTBuilder.add(aggFn, colName,
|
|
461
|
-
const customLSTAggCol = customLSTCols.addNewFloat(
|
|
468
|
+
for (let aggIdx = 0; aggIdx < aggNumericColsEntries.length; ++aggIdx) {
|
|
469
|
+
const [colName, aggFn] = aggNumericColsEntries[aggIdx];
|
|
470
|
+
origLSTBuilder = origLSTBuilder.add(aggFn, colName, aggNumericColNames[aggIdx]);
|
|
471
|
+
const customLSTAggCol = customLSTCols.addNewFloat(aggNumericColNames[aggIdx]);
|
|
462
472
|
customAggRawCols[aggIdx] = customLSTAggCol.getRawData();
|
|
463
473
|
}
|
|
464
474
|
|
|
@@ -484,10 +494,15 @@ export class LogoSummaryTable extends DG.JsViewer implements ILogoSummaryTable {
|
|
|
484
494
|
customPValColData[rowIdx] = stats.pValue ?? DG.FLOAT_NULL;
|
|
485
495
|
customRatioColData[rowIdx] = stats.ratio;
|
|
486
496
|
|
|
487
|
-
for (let aggColIdx = 0; aggColIdx <
|
|
488
|
-
const [col, aggFn] =
|
|
497
|
+
for (let aggColIdx = 0; aggColIdx < aggNumericColNames.length; ++aggColIdx) {
|
|
498
|
+
const [col, aggFn] = numericColAggEntries[aggColIdx];
|
|
489
499
|
customAggRawCols[aggColIdx][rowIdx] = getAggregatedValue(col, aggFn, bsMask);
|
|
490
500
|
}
|
|
501
|
+
for (let aggColIdx = aggNumericColNames.length; aggColIdx < customAggRawCols.length; ++aggColIdx) {
|
|
502
|
+
const colName = aggStringColNames[aggColIdx - aggNumericColNames.length];
|
|
503
|
+
aggStringCols[aggColIdx - aggNumericColNames.length]
|
|
504
|
+
.set(rowIdx, getStringColAggregatedJSON(filteredDf, colName, bsMask));
|
|
505
|
+
}
|
|
491
506
|
}
|
|
492
507
|
customWebLogoCol.setTag(DG.TAGS.CELL_RENDERER, 'html');
|
|
493
508
|
customDistCol.setTag(DG.TAGS.CELL_RENDERER, 'html');
|
|
@@ -512,6 +527,7 @@ export class LogoSummaryTable extends DG.JsViewer implements ILogoSummaryTable {
|
|
|
512
527
|
const origMDColData = origLSTCols.addNewFloat(C.LST_COLUMN_NAMES.MEAN_DIFFERENCE).getRawData();
|
|
513
528
|
const origPValColData = origLSTCols.addNewFloat(C.LST_COLUMN_NAMES.P_VALUE).getRawData();
|
|
514
529
|
const origRatioColData = origLSTCols.addNewFloat(C.LST_COLUMN_NAMES.RATIO).getRawData();
|
|
530
|
+
const origAggStringCols = aggStringColNames.map((colName) => origLSTCols.addNewString(colName));
|
|
515
531
|
const origBitsets: DG.BitSet[] = new Array(origLSTLen);
|
|
516
532
|
const origClustMasks = Array.from({length: origLSTLen},
|
|
517
533
|
() => new BitArray(filteredDfRowCount, false));
|
|
@@ -527,10 +543,15 @@ export class LogoSummaryTable extends DG.JsViewer implements ILogoSummaryTable {
|
|
|
527
543
|
if (mask.allFalse)
|
|
528
544
|
continue;
|
|
529
545
|
|
|
546
|
+
|
|
530
547
|
const bsMask = DG.BitSet.fromBytes(mask.buffer.buffer, filteredDfRowCount);
|
|
531
548
|
const stats = isDfFiltered ? getStats(activityColData, mask) :
|
|
532
549
|
this.clusterStats[CLUSTER_TYPE.ORIGINAL][origLSTClustColCat[rowIdx]];
|
|
533
|
-
|
|
550
|
+
for (let aggColIdx = 0; aggColIdx < aggStringColNames.length; ++aggColIdx) {
|
|
551
|
+
const colName = aggStringColNames[aggColIdx];
|
|
552
|
+
origAggStringCols[aggColIdx]
|
|
553
|
+
.set(rowIdx, getStringColAggregatedJSON(filteredDf, colName, bsMask));
|
|
554
|
+
}
|
|
534
555
|
origMembersColData[rowIdx] = stats.count;
|
|
535
556
|
origBitsets[rowIdx] = bsMask;
|
|
536
557
|
origMDColData[rowIdx] = stats.meanDifference;
|
|
@@ -544,6 +565,9 @@ export class LogoSummaryTable extends DG.JsViewer implements ILogoSummaryTable {
|
|
|
544
565
|
// combine LSTs and create a grid
|
|
545
566
|
const summaryTable = origLST.append(customLST);
|
|
546
567
|
this.bitsets = origBitsets.concat(customBitsets);
|
|
568
|
+
|
|
569
|
+
aggStringColNames.forEach((sn) => summaryTable.col(sn)!.semType = 'lst-pie-chart');
|
|
570
|
+
|
|
547
571
|
return summaryTable;
|
|
548
572
|
}
|
|
549
573
|
|
|
@@ -563,7 +587,8 @@ export class LogoSummaryTable extends DG.JsViewer implements ILogoSummaryTable {
|
|
|
563
587
|
const gridClustersCol = grid.col(C.LST_COLUMN_NAMES.CLUSTER)!;
|
|
564
588
|
gridClustersCol.visible = true;
|
|
565
589
|
grid.columns.setOrder([C.LST_COLUMN_NAMES.CLUSTER, C.LST_COLUMN_NAMES.MEMBERS,
|
|
566
|
-
C.LST_COLUMN_NAMES.WEB_LOGO,
|
|
590
|
+
C.LST_COLUMN_NAMES.WEB_LOGO, ...this.getStringAggregatedColumns(),
|
|
591
|
+
C.LST_COLUMN_NAMES.DISTRIBUTION, C.LST_COLUMN_NAMES.MEAN_DIFFERENCE,
|
|
567
592
|
C.LST_COLUMN_NAMES.P_VALUE, C.LST_COLUMN_NAMES.RATIO, ...aggColNames]);
|
|
568
593
|
grid.columns.rowHeader!.visible = false;
|
|
569
594
|
grid.props.rowHeight = 55;
|
|
@@ -800,13 +825,21 @@ export class LogoSummaryTable extends DG.JsViewer implements ILogoSummaryTable {
|
|
|
800
825
|
const aggregatedValues: {
|
|
801
826
|
[colName: string]: number
|
|
802
827
|
} = {};
|
|
828
|
+
const stringAggregatedValues: {
|
|
829
|
+
[colName: string]: string
|
|
830
|
+
} = {};
|
|
803
831
|
const aggColsEntries = this.getTotalViewerAggColumns();
|
|
832
|
+
const aggStringColNames = this.getStringAggregatedColumns();
|
|
804
833
|
for (const [colName, aggFn] of aggColsEntries) {
|
|
805
834
|
const newColName = getAggregatedColName(aggFn, colName);
|
|
806
835
|
const col = this.dataFrame.getCol(colName);
|
|
807
836
|
aggregatedValues[newColName] = getAggregatedValue(col, aggFn, currentSelection);
|
|
808
837
|
}
|
|
809
838
|
|
|
839
|
+
for (const colName of aggStringColNames)
|
|
840
|
+
stringAggregatedValues[colName] = getStringColAggregatedJSON(this.dataFrame, colName, currentSelection);
|
|
841
|
+
|
|
842
|
+
|
|
810
843
|
for (let i = 0; i < viewerDfColsLength; ++i) {
|
|
811
844
|
const col = viewerDfCols.byIndex(i);
|
|
812
845
|
newClusterVals[i] = col.name === C.LST_COLUMN_NAMES.CLUSTER ? newClusterName :
|
|
@@ -817,7 +850,8 @@ export class LogoSummaryTable extends DG.JsViewer implements ILogoSummaryTable {
|
|
|
817
850
|
col.name === C.LST_COLUMN_NAMES.P_VALUE ? stats.pValue :
|
|
818
851
|
col.name === C.LST_COLUMN_NAMES.RATIO ? stats.ratio :
|
|
819
852
|
col.name in aggregatedValues ? aggregatedValues[col.name] :
|
|
820
|
-
|
|
853
|
+
col.name in stringAggregatedValues ? stringAggregatedValues[col.name] :
|
|
854
|
+
undefined;
|
|
821
855
|
if (typeof newClusterVals[i] === 'undefined')
|
|
822
856
|
_package.logger.warning(`PeptidesLSTWarn: value for column ${col.name} is undefined`);
|
|
823
857
|
}
|
|
@@ -122,7 +122,6 @@ export abstract class SARViewer extends DG.JsViewer implements ISARViewer {
|
|
|
122
122
|
{category: PROPERTY_CATEGORIES.MUTATION_CLIFFS, min: 0, max: 100});
|
|
123
123
|
this.maxMutations = this.int(SAR_PROPERTIES.MAX_MUTATIONS, 1,
|
|
124
124
|
{category: PROPERTY_CATEGORIES.MUTATION_CLIFFS, min: 1, max: 20});
|
|
125
|
-
|
|
126
125
|
this.columns = this.columnList(SAR_PROPERTIES.COLUMNS, [], {category: PROPERTY_CATEGORIES.AGGREGATION});
|
|
127
126
|
this.aggregation = this.string(SAR_PROPERTIES.AGGREGATION, DG.AGG.AVG,
|
|
128
127
|
{category: PROPERTY_CATEGORIES.AGGREGATION, choices: C.AGGREGATION_TYPES});
|
|
@@ -422,8 +421,9 @@ export abstract class SARViewer extends DG.JsViewer implements ISARViewer {
|
|
|
422
421
|
* @return - map of columns and aggregations.
|
|
423
422
|
*/
|
|
424
423
|
getAggregationColumns(): AggregationColumns {
|
|
425
|
-
return Object.fromEntries(
|
|
426
|
-
|
|
424
|
+
return Object.fromEntries(this.columns.map((colName) => [colName, this.aggregation] as [string, DG.AGG])
|
|
425
|
+
.filter(([colName, _]) => this.model.df.columns.contains(colName) &&
|
|
426
|
+
this.model.df.col(colName)!.matches('numerical')));
|
|
427
427
|
}
|
|
428
428
|
|
|
429
429
|
/**
|
|
@@ -432,7 +432,7 @@ export abstract class SARViewer extends DG.JsViewer implements ISARViewer {
|
|
|
432
432
|
*/
|
|
433
433
|
getTotalViewerAggColumns(): [string, DG.AggregationType][] {
|
|
434
434
|
const aggrCols = this.getAggregationColumns();
|
|
435
|
-
return getTotalAggColumns(this.columns, aggrCols, this.model?.settings?.columns);
|
|
435
|
+
return getTotalAggColumns(this.model.df, this.columns, aggrCols, this.model?.settings?.columns);
|
|
436
436
|
}
|
|
437
437
|
|
|
438
438
|
/** Creates viewer grid. */
|