@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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@datagrok/peptides",
3
3
  "friendlyName": "Peptides",
4
- "version": "1.17.20",
4
+ "version": "1.17.22",
5
5
  "author": {
6
6
  "name": "Davit Rizhinashvili",
7
7
  "email": "drizhinashvili@datagrok.ai"
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[], aggColsViewer: AggregationColumns,
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
- return aggColsEntries.concat(aggColsEntriesFromSettings);
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
  /**
@@ -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.onDataChanged.subscribe(() => {
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, {category: LST_CATEGORIES.GENERAL, nullable: false});
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 aggColsEntries = this.getTotalViewerAggColumns();
453
- const aggColNames = aggColsEntries.map(([colName, aggFn]) => getAggregatedColName(aggFn, colName));
454
- const customAggRawCols = new Array(aggColNames.length);
455
- const colAggEntries = aggColsEntries.map(
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 < aggColsEntries.length; ++aggIdx) {
459
- const [colName, aggFn] = aggColsEntries[aggIdx];
460
- origLSTBuilder = origLSTBuilder.add(aggFn, colName, aggColNames[aggIdx]);
461
- const customLSTAggCol = customLSTCols.addNewFloat(aggColNames[aggIdx]);
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 < aggColNames.length; ++aggColIdx) {
488
- const [col, aggFn] = colAggEntries[aggColIdx];
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, C.LST_COLUMN_NAMES.DISTRIBUTION, C.LST_COLUMN_NAMES.MEAN_DIFFERENCE,
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
- undefined;
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
- this.columns.map((colName) => [colName, this.aggregation] as [string, DG.AGG]));
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
- // "sourceMap": true, /* Generates corresponding '.map' file. */
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
@@ -34,7 +34,7 @@ module.exports = {
34
34
  resolve: {
35
35
  extensions: ['.mjs', '.ts', '.js', '.json', '.tsx'],
36
36
  },
37
- devtool: 'inline-source-map',
37
+ devtool: 'source-map',
38
38
  externals: {
39
39
  'datagrok-api/dg': 'DG',
40
40
  'datagrok-api/grok': 'grok',