@datagrok/peptides 1.17.20 → 1.17.22
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 +8 -0
- package/dist/111.js +1 -1
- package/dist/111.js.map +1 -0
- package/dist/216.js +1 -1
- package/dist/216.js.map +1 -0
- package/dist/501.js +1 -1
- package/dist/501.js.map +1 -0
- package/dist/603.js +1 -1
- package/dist/603.js.map +1 -0
- package/dist/682.js +1 -1
- package/dist/682.js.map +1 -0
- package/dist/705.js +1 -1
- package/dist/705.js.map +1 -0
- package/dist/778.js +1 -1
- package/dist/778.js.map +1 -0
- package/dist/795.js +1 -1
- package/dist/795.js.map +1 -0
- package/dist/950.js +1 -1
- package/dist/950.js.map +1 -0
- package/dist/package-test.js +2 -2
- package/dist/package-test.js.map +1 -0
- package/dist/package.js +2 -2
- package/dist/package.js.map +1 -0
- 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/cluster-max-activity-viewer.ts +3 -1
- package/src/viewers/logo-summary.ts +53 -16
- package/src/viewers/sar-viewer.ts +4 -4
- package/src/widgets/mutation-cliffs.ts +3 -0
- package/tsconfig.json +3 -3
- package/webpack.config.js +1 -1
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
|
+
}
|
|
@@ -290,7 +290,7 @@ export class ClusterMaxActivityViewer extends DG.JsViewer implements IClusterMax
|
|
|
290
290
|
|
|
291
291
|
this.render();
|
|
292
292
|
|
|
293
|
-
this.dataFrame
|
|
293
|
+
this.dataFrame?.onDataChanged.subscribe(() => {
|
|
294
294
|
this.render();
|
|
295
295
|
});
|
|
296
296
|
}
|
|
@@ -299,6 +299,8 @@ export class ClusterMaxActivityViewer extends DG.JsViewer implements IClusterMax
|
|
|
299
299
|
if (this.renderTimeout)
|
|
300
300
|
clearTimeout(this.renderTimeout);
|
|
301
301
|
this.renderTimeout = setTimeout(() => {
|
|
302
|
+
if (!this.dataFrame)
|
|
303
|
+
return;
|
|
302
304
|
$(this.root).empty();
|
|
303
305
|
const scViewer = this.scViewer;
|
|
304
306
|
if (scViewer == null) {
|
|
@@ -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';
|
|
@@ -96,8 +97,11 @@ export class LogoSummaryTable extends DG.JsViewer implements ILogoSummaryTable {
|
|
|
96
97
|
{
|
|
97
98
|
category: LST_CATEGORIES.GENERAL,
|
|
98
99
|
nullable: false,
|
|
100
|
+
columnTypeFilter: DG.TYPE.CATEGORICAL,
|
|
99
101
|
});
|
|
100
|
-
this.activityColumnName = this.column(LST_PROPERTIES.ACTIVITY, {
|
|
102
|
+
this.activityColumnName = this.column(LST_PROPERTIES.ACTIVITY, {
|
|
103
|
+
category: LST_CATEGORIES.GENERAL, nullable: false, columnTypeFilter: DG.TYPE.NUMERICAL,
|
|
104
|
+
});
|
|
101
105
|
this.activityScaling = this.string(LST_PROPERTIES.ACTIVITY_SCALING, C.SCALING_METHODS.NONE,
|
|
102
106
|
{
|
|
103
107
|
category: LST_CATEGORIES.GENERAL,
|
|
@@ -276,7 +280,9 @@ export class LogoSummaryTable extends DG.JsViewer implements ILogoSummaryTable {
|
|
|
276
280
|
* @return - map of columns and aggregations.
|
|
277
281
|
*/
|
|
278
282
|
getAggregationColumns(): AggregationColumns {
|
|
279
|
-
return Object.fromEntries(this.columns.map((colName) => [colName, this.aggregation] as [string, DG.AGG])
|
|
283
|
+
return Object.fromEntries(this.columns.map((colName) => [colName, this.aggregation] as [string, DG.AGG])
|
|
284
|
+
.filter(([colName, _]) => this.model.df.columns.contains(colName) &&
|
|
285
|
+
this.model.df.col(colName)!.matches('numerical')));
|
|
280
286
|
}
|
|
281
287
|
|
|
282
288
|
/** Processes attached table and sets viewer properties. */
|
|
@@ -411,7 +417,12 @@ export class LogoSummaryTable extends DG.JsViewer implements ILogoSummaryTable {
|
|
|
411
417
|
*/
|
|
412
418
|
getTotalViewerAggColumns(): [string, DG.AggregationType][] {
|
|
413
419
|
const aggrCols = this.getAggregationColumns();
|
|
414
|
-
return getTotalAggColumns(this.columns, aggrCols, this.model?.settings?.columns);
|
|
420
|
+
return getTotalAggColumns(this.model.df, this.columns, aggrCols, this.model?.settings?.columns);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
getStringAggregatedColumns(): string[] {
|
|
424
|
+
return this.columns.filter((colName) => this.model.df.columns.contains(colName) &&
|
|
425
|
+
this.model.df.col(colName)!.matches('categorical')).map((cn) => `dist(${cn})`);
|
|
415
426
|
}
|
|
416
427
|
|
|
417
428
|
/**
|
|
@@ -449,16 +460,18 @@ export class LogoSummaryTable extends DG.JsViewer implements ILogoSummaryTable {
|
|
|
449
460
|
const customRatioColData = customLSTCols.addNewFloat(C.LST_COLUMN_NAMES.RATIO).getRawData();
|
|
450
461
|
|
|
451
462
|
let origLSTBuilder = filteredDf.groupBy([clustersColName]);
|
|
452
|
-
const
|
|
453
|
-
const
|
|
454
|
-
const
|
|
455
|
-
const
|
|
463
|
+
const aggNumericColsEntries = this.getTotalViewerAggColumns();
|
|
464
|
+
const aggStringColNames = this.getStringAggregatedColumns();
|
|
465
|
+
const aggStringCols = aggStringColNames.map((colName) => customLSTCols.addNewString(colName));
|
|
466
|
+
const aggNumericColNames = aggNumericColsEntries.map(([colName, aggFn]) => getAggregatedColName(aggFn, colName));
|
|
467
|
+
const customAggRawCols = new Array(aggNumericColNames.length + aggStringColNames.length);
|
|
468
|
+
const numericColAggEntries = aggNumericColsEntries.map(
|
|
456
469
|
([colName, aggFn]) => [filteredDf.getCol(colName), aggFn] as [DG.Column<number>, DG.AggregationType]);
|
|
457
470
|
|
|
458
|
-
for (let aggIdx = 0; aggIdx <
|
|
459
|
-
const [colName, aggFn] =
|
|
460
|
-
origLSTBuilder = origLSTBuilder.add(aggFn, colName,
|
|
461
|
-
const customLSTAggCol = customLSTCols.addNewFloat(
|
|
471
|
+
for (let aggIdx = 0; aggIdx < aggNumericColsEntries.length; ++aggIdx) {
|
|
472
|
+
const [colName, aggFn] = aggNumericColsEntries[aggIdx];
|
|
473
|
+
origLSTBuilder = origLSTBuilder.add(aggFn, colName, aggNumericColNames[aggIdx]);
|
|
474
|
+
const customLSTAggCol = customLSTCols.addNewFloat(aggNumericColNames[aggIdx]);
|
|
462
475
|
customAggRawCols[aggIdx] = customLSTAggCol.getRawData();
|
|
463
476
|
}
|
|
464
477
|
|
|
@@ -484,10 +497,15 @@ export class LogoSummaryTable extends DG.JsViewer implements ILogoSummaryTable {
|
|
|
484
497
|
customPValColData[rowIdx] = stats.pValue ?? DG.FLOAT_NULL;
|
|
485
498
|
customRatioColData[rowIdx] = stats.ratio;
|
|
486
499
|
|
|
487
|
-
for (let aggColIdx = 0; aggColIdx <
|
|
488
|
-
const [col, aggFn] =
|
|
500
|
+
for (let aggColIdx = 0; aggColIdx < aggNumericColNames.length; ++aggColIdx) {
|
|
501
|
+
const [col, aggFn] = numericColAggEntries[aggColIdx];
|
|
489
502
|
customAggRawCols[aggColIdx][rowIdx] = getAggregatedValue(col, aggFn, bsMask);
|
|
490
503
|
}
|
|
504
|
+
for (let aggColIdx = aggNumericColNames.length; aggColIdx < customAggRawCols.length; ++aggColIdx) {
|
|
505
|
+
const colName = aggStringColNames[aggColIdx - aggNumericColNames.length];
|
|
506
|
+
aggStringCols[aggColIdx - aggNumericColNames.length]
|
|
507
|
+
.set(rowIdx, getStringColAggregatedJSON(filteredDf, colName, bsMask));
|
|
508
|
+
}
|
|
491
509
|
}
|
|
492
510
|
customWebLogoCol.setTag(DG.TAGS.CELL_RENDERER, 'html');
|
|
493
511
|
customDistCol.setTag(DG.TAGS.CELL_RENDERER, 'html');
|
|
@@ -512,6 +530,7 @@ export class LogoSummaryTable extends DG.JsViewer implements ILogoSummaryTable {
|
|
|
512
530
|
const origMDColData = origLSTCols.addNewFloat(C.LST_COLUMN_NAMES.MEAN_DIFFERENCE).getRawData();
|
|
513
531
|
const origPValColData = origLSTCols.addNewFloat(C.LST_COLUMN_NAMES.P_VALUE).getRawData();
|
|
514
532
|
const origRatioColData = origLSTCols.addNewFloat(C.LST_COLUMN_NAMES.RATIO).getRawData();
|
|
533
|
+
const origAggStringCols = aggStringColNames.map((colName) => origLSTCols.addNewString(colName));
|
|
515
534
|
const origBitsets: DG.BitSet[] = new Array(origLSTLen);
|
|
516
535
|
const origClustMasks = Array.from({length: origLSTLen},
|
|
517
536
|
() => new BitArray(filteredDfRowCount, false));
|
|
@@ -527,10 +546,15 @@ export class LogoSummaryTable extends DG.JsViewer implements ILogoSummaryTable {
|
|
|
527
546
|
if (mask.allFalse)
|
|
528
547
|
continue;
|
|
529
548
|
|
|
549
|
+
|
|
530
550
|
const bsMask = DG.BitSet.fromBytes(mask.buffer.buffer, filteredDfRowCount);
|
|
531
551
|
const stats = isDfFiltered ? getStats(activityColData, mask) :
|
|
532
552
|
this.clusterStats[CLUSTER_TYPE.ORIGINAL][origLSTClustColCat[rowIdx]];
|
|
533
|
-
|
|
553
|
+
for (let aggColIdx = 0; aggColIdx < aggStringColNames.length; ++aggColIdx) {
|
|
554
|
+
const colName = aggStringColNames[aggColIdx];
|
|
555
|
+
origAggStringCols[aggColIdx]
|
|
556
|
+
.set(rowIdx, getStringColAggregatedJSON(filteredDf, colName, bsMask));
|
|
557
|
+
}
|
|
534
558
|
origMembersColData[rowIdx] = stats.count;
|
|
535
559
|
origBitsets[rowIdx] = bsMask;
|
|
536
560
|
origMDColData[rowIdx] = stats.meanDifference;
|
|
@@ -544,6 +568,9 @@ export class LogoSummaryTable extends DG.JsViewer implements ILogoSummaryTable {
|
|
|
544
568
|
// combine LSTs and create a grid
|
|
545
569
|
const summaryTable = origLST.append(customLST);
|
|
546
570
|
this.bitsets = origBitsets.concat(customBitsets);
|
|
571
|
+
|
|
572
|
+
aggStringColNames.forEach((sn) => summaryTable.col(sn)!.semType = 'lst-pie-chart');
|
|
573
|
+
|
|
547
574
|
return summaryTable;
|
|
548
575
|
}
|
|
549
576
|
|
|
@@ -563,7 +590,8 @@ export class LogoSummaryTable extends DG.JsViewer implements ILogoSummaryTable {
|
|
|
563
590
|
const gridClustersCol = grid.col(C.LST_COLUMN_NAMES.CLUSTER)!;
|
|
564
591
|
gridClustersCol.visible = true;
|
|
565
592
|
grid.columns.setOrder([C.LST_COLUMN_NAMES.CLUSTER, C.LST_COLUMN_NAMES.MEMBERS,
|
|
566
|
-
C.LST_COLUMN_NAMES.WEB_LOGO,
|
|
593
|
+
C.LST_COLUMN_NAMES.WEB_LOGO, ...this.getStringAggregatedColumns(),
|
|
594
|
+
C.LST_COLUMN_NAMES.DISTRIBUTION, C.LST_COLUMN_NAMES.MEAN_DIFFERENCE,
|
|
567
595
|
C.LST_COLUMN_NAMES.P_VALUE, C.LST_COLUMN_NAMES.RATIO, ...aggColNames]);
|
|
568
596
|
grid.columns.rowHeader!.visible = false;
|
|
569
597
|
grid.props.rowHeight = 55;
|
|
@@ -800,13 +828,21 @@ export class LogoSummaryTable extends DG.JsViewer implements ILogoSummaryTable {
|
|
|
800
828
|
const aggregatedValues: {
|
|
801
829
|
[colName: string]: number
|
|
802
830
|
} = {};
|
|
831
|
+
const stringAggregatedValues: {
|
|
832
|
+
[colName: string]: string
|
|
833
|
+
} = {};
|
|
803
834
|
const aggColsEntries = this.getTotalViewerAggColumns();
|
|
835
|
+
const aggStringColNames = this.getStringAggregatedColumns();
|
|
804
836
|
for (const [colName, aggFn] of aggColsEntries) {
|
|
805
837
|
const newColName = getAggregatedColName(aggFn, colName);
|
|
806
838
|
const col = this.dataFrame.getCol(colName);
|
|
807
839
|
aggregatedValues[newColName] = getAggregatedValue(col, aggFn, currentSelection);
|
|
808
840
|
}
|
|
809
841
|
|
|
842
|
+
for (const colName of aggStringColNames)
|
|
843
|
+
stringAggregatedValues[colName] = getStringColAggregatedJSON(this.dataFrame, colName, currentSelection);
|
|
844
|
+
|
|
845
|
+
|
|
810
846
|
for (let i = 0; i < viewerDfColsLength; ++i) {
|
|
811
847
|
const col = viewerDfCols.byIndex(i);
|
|
812
848
|
newClusterVals[i] = col.name === C.LST_COLUMN_NAMES.CLUSTER ? newClusterName :
|
|
@@ -817,7 +853,8 @@ export class LogoSummaryTable extends DG.JsViewer implements ILogoSummaryTable {
|
|
|
817
853
|
col.name === C.LST_COLUMN_NAMES.P_VALUE ? stats.pValue :
|
|
818
854
|
col.name === C.LST_COLUMN_NAMES.RATIO ? stats.ratio :
|
|
819
855
|
col.name in aggregatedValues ? aggregatedValues[col.name] :
|
|
820
|
-
|
|
856
|
+
col.name in stringAggregatedValues ? stringAggregatedValues[col.name] :
|
|
857
|
+
undefined;
|
|
821
858
|
if (typeof newClusterVals[i] === 'undefined')
|
|
822
859
|
_package.logger.warning(`PeptidesLSTWarn: value for column ${col.name} is undefined`);
|
|
823
860
|
}
|
|
@@ -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. */
|
|
@@ -243,6 +243,9 @@ function cliffsPairsWidgetParts(table: DG.DataFrame, options: MutationCliffsOpti
|
|
|
243
243
|
pairsGrid.root.style.setProperty('width', '100%');
|
|
244
244
|
uniqueSequencesGrid.root.style.removeProperty('width');
|
|
245
245
|
uniqueSequencesGrid.root.style.setProperty('width', '100%');
|
|
246
|
+
pairsGrid.root.style.height = 'unset';
|
|
247
|
+
uniqueSequencesGrid.root.style.height = 'unset';
|
|
246
248
|
}, 200);
|
|
249
|
+
|
|
247
250
|
return {pairsGrid, uniqueSequencesGrid, aminoToInput};
|
|
248
251
|
}
|
package/tsconfig.json
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */
|
|
13
13
|
// "declaration": true, /* Generates corresponding '.d.ts' file. */
|
|
14
14
|
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
|
15
|
-
|
|
15
|
+
"sourceMap": true, /* Generates corresponding '.map' file. */
|
|
16
16
|
// "outFile": "./", /* Concatenate and emit output to single file. */
|
|
17
17
|
// "outDir": "./", /* Redirect output structure to the directory. */
|
|
18
18
|
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
|
@@ -57,8 +57,8 @@
|
|
|
57
57
|
/* Source Map Options */
|
|
58
58
|
"sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
|
|
59
59
|
"mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
|
60
|
-
"inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
|
|
61
|
-
"inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
|
|
60
|
+
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
|
|
61
|
+
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
|
|
62
62
|
|
|
63
63
|
/* Experimental Options */
|
|
64
64
|
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
|
package/webpack.config.js
CHANGED