Skip to content

Commit ee7d1c1

Browse files
authored
feat: data bar render from API (#1415)
No specific ticket to close. Just alters the front-end to allow the new data from JSON API to be parsed and turned into a data bar Works in tandem with this deephaven/deephaven-core#4181 from deephaven-core ### Demo Code: ``` from deephaven import new_table from deephaven.column import int_col, double_col, string_col students = new_table([ string_col("Name", ["Andy", "Claire", "Jane", "Steven"]), int_col("StudentID", [1, 2, 3, 4]), int_col("Threshold", [3, 3, 3, 3]), double_col("GPA", [-3.0, 4.0, 3.7, 2.8]), double_col("DirectionalAxis", [-3.0, 4.0, 3.7, 2.8]), double_col("MiddleAxis", [-3.0, 4.0, 3.7, 2.8]), double_col("OverlapPlacement", [-3.0, 4.0, 3.7, 2.8]), double_col("HidePlacement", [-3.0, 4.0, 3.7, 2.8]), double_col("RTLDirection", [-3.0, 4.0, 3.7, 2.8]), double_col("Markers", [-3.0, 4.0, 3.7, 2.8]), double_col("Markers2", [-3.0, 4.0, 3.7, 2.8]), double_col("Gradient", [-3.0, 4.0, 3.7, 2.8]), ]) data_bars = students.format_data_bar(column= "GPA", value_column= "GPA").format_data_bar(column="DirectionalAxis", value_column="DirectionalAxis", axis="directional").format_data_bar(column="MiddleAxis", value_column="MiddleAxis", axis="middle").format_data_bar(column="OverlapPlacement", value_column="OverlapPlacement", value_placement="overlap").format_data_bar(column="HidePlacement", value_column="HidePlacement", value_placement="hide").format_data_bar(column="RTLDirection", value_column="RTLDirection", direction="RTL").format_data_bar(column="Markers", value_column="Markers", marker_column="Threshold").format_data_bar(column="Markers2", value_column="Markers2", marker_column="StudentID", marker_color="#0000FF").format_data_bar(column="Gradient", value_column="Gradient", negative_color=["#FF0000", "#FFFF00"], positive_color=["#FFFF00", "#00FF00"]) ``` ### Expected Output: <img width="1728" alt="image" src="https://github.com/deephaven/deephaven-core/assets/55671206/004372e1-dee1-4632-97f9-73d2e0bb9a98">
1 parent ce51229 commit ee7d1c1

11 files changed

Lines changed: 125 additions & 27 deletions

File tree

packages/code-studio/src/styleguide/grid-examples/DataBarExample.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ function DataBarExample(): JSX.Element {
5454
[
5555
12,
5656
[
57-
{ column: 13, color: 'white' },
58-
{ column: 14, color: 'gray' },
57+
{ value: 13, color: 'white' },
58+
{ value: 14, color: 'gray' },
5959
],
6060
],
6161
]);

packages/grid/src/DataBarCellRenderer.ts

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ class DataBarCellRenderer extends CellRenderer {
8585
markers,
8686
direction,
8787
value,
88-
} = model.dataBarOptionsForCell(modelColumn, modelRow);
88+
} = model.dataBarOptionsForCell(modelColumn, modelRow, theme);
8989

9090
const hasGradient = Array.isArray(dataBarColor);
9191
if (columnMin == null || columnMax == null) {
@@ -343,7 +343,7 @@ class DataBarCellRenderer extends CellRenderer {
343343
markers,
344344
direction,
345345
value,
346-
} = model.dataBarOptionsForCell(modelColumn, modelRow);
346+
} = model.dataBarOptionsForCell(modelColumn, modelRow, theme);
347347
const longestValueWidth = this.getCachedWidestValueForColumn(
348348
context,
349349
visibleRows,
@@ -398,11 +398,9 @@ class DataBarCellRenderer extends CellRenderer {
398398
? zeroPosition
399399
: zeroPosition - (Math.abs(value) / totalValueRange) * maxWidth;
400400
let markerXs = markers.map(marker => {
401-
const { column: markerColumn } = marker;
402-
const markerValue = Number(model.textForCell(markerColumn, modelRow));
403-
return markerValue >= 0
404-
? zeroPosition + (Math.abs(markerValue) / totalValueRange) * maxWidth
405-
: zeroPosition - (Math.abs(markerValue) / totalValueRange) * maxWidth;
401+
const { value: markerValue } = marker;
402+
const offset = (Math.abs(markerValue) / totalValueRange) * maxWidth;
403+
return markerValue >= 0 ? zeroPosition + offset : zeroPosition - offset;
406404
});
407405
let leftmostPosition =
408406
valuePlacement === 'beside' && textAlign === 'left'
@@ -424,8 +422,7 @@ class DataBarCellRenderer extends CellRenderer {
424422
? zeroPosition - (value / totalValueRange) * maxWidth
425423
: zeroPosition;
426424
markerXs = markers.map(marker => {
427-
const { column: markerColumn } = marker;
428-
const markerValue = Number(model.textForCell(markerColumn, modelRow));
425+
const { value: markerValue } = marker;
429426
return markerValue >= 0
430427
? zeroPosition - (Math.abs(markerValue) / totalValueRange) * maxWidth
431428
: zeroPosition + (Math.abs(markerValue) / totalValueRange) * maxWidth;
@@ -441,8 +438,8 @@ class DataBarCellRenderer extends CellRenderer {
441438
? zeroPosition
442439
: zeroPosition - (Math.abs(value) / columnLongest) * (maxWidth / 2);
443440
markerXs = markers.map(marker => {
444-
const { column: markerColumn } = marker;
445-
const markerValue = Number(model.textForCell(markerColumn, modelRow));
441+
const { value: markerValue } = marker;
442+
446443
return markerValue >= 0
447444
? zeroPosition +
448445
(Math.abs(markerValue) / columnLongest) * (maxWidth / 2)
@@ -456,8 +453,8 @@ class DataBarCellRenderer extends CellRenderer {
456453
? zeroPosition
457454
: zeroPosition - (Math.abs(value) / columnLongest) * (maxWidth / 2);
458455
markerXs = markers.map(marker => {
459-
const { column: markerColumn } = marker;
460-
const markerValue = Number(model.textForCell(markerColumn, modelRow));
456+
const { value: markerValue } = marker;
457+
461458
return markerValue <= 0
462459
? zeroPosition +
463460
(Math.abs(markerValue) / columnLongest) * (maxWidth / 2)
@@ -471,8 +468,8 @@ class DataBarCellRenderer extends CellRenderer {
471468
zeroPosition = 0;
472469
dataBarX = zeroPosition;
473470
markerXs = markers.map(marker => {
474-
const { column: markerColumn } = marker;
475-
const markerValue = Number(model.textForCell(markerColumn, modelRow));
471+
const { value: markerValue } = marker;
472+
476473
return (
477474
zeroPosition + (Math.abs(markerValue) / columnLongest) * maxWidth
478475
);
@@ -482,8 +479,8 @@ class DataBarCellRenderer extends CellRenderer {
482479
zeroPosition = columnWidth;
483480
dataBarX = zeroPosition - (Math.abs(value) / columnLongest) * maxWidth;
484481
markerXs = markers.map(marker => {
485-
const { column: markerColumn } = marker;
486-
const markerValue = Number(model.textForCell(markerColumn, modelRow));
482+
const { value: markerValue } = marker;
483+
487484
return (
488485
zeroPosition - (Math.abs(markerValue) / columnLongest) * maxWidth
489486
);

packages/grid/src/DataBarGridModel.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1+
import { GridThemeType } from '.';
12
import { ModelIndex } from './GridMetrics';
23
import GridModel from './GridModel';
34
import { GridColor } from './GridTheme';
45

5-
export type Marker = { column: ModelIndex; color: string };
6+
export type Marker = { value: number; color: string };
67
export type AxisOption = 'proportional' | 'middle' | 'directional';
78
export type ValuePlacementOption = 'beside' | 'overlap' | 'hide';
89
export type DirectionOption = 'LTR' | 'RTL';
@@ -49,5 +50,9 @@ export function isDataBarGridModel(
4950
}
5051

5152
export interface DataBarGridModel extends GridModel {
52-
dataBarOptionsForCell(column: ModelIndex, row: ModelIndex): DataBarOptions;
53+
dataBarOptionsForCell(
54+
column: ModelIndex,
55+
row: ModelIndex,
56+
theme: GridThemeType
57+
): DataBarOptions;
5358
}

packages/grid/src/GridTheme.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ export type GridTheme = {
136136
zeroLineColor: GridColor;
137137
positiveBarColor: GridColor;
138138
negativeBarColor: GridColor;
139+
markerBarColor: GridColor;
139140

140141
dataBarHorizontalPadding: number;
141142
};
@@ -232,6 +233,7 @@ const defaultTheme: GridTheme = Object.freeze({
232233
zeroLineColor: '#888888',
233234
positiveBarColor: '#00ff00',
234235
negativeBarColor: '#ff0000',
236+
markerBarColor: '#ffffff',
235237

236238
dataBarHorizontalPadding: 90,
237239
});

packages/grid/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,4 @@ export { default as TextCellRenderer } from './TextCellRenderer';
3131
export { default as DataBarCellRenderer } from './DataBarCellRenderer';
3232
export * from './TokenBoxCellRenderer';
3333
export * from './GridRendererTypes';
34+
export * from './DataBarGridModel';

packages/iris-grid/src/IrisGridModel.ts

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
/* eslint-disable class-methods-use-this */
22
import type { Event, EventTarget } from 'event-target-shim';
33
import {
4+
DataBarGridModel,
5+
DataBarOptions,
46
GridModel,
57
GridRange,
68
ModelIndex,
@@ -29,6 +31,7 @@ import {
2931
PendingDataErrorMap,
3032
} from './CommonTypes';
3133
import ColumnHeaderGroup from './ColumnHeaderGroup';
34+
import { IrisGridThemeType } from './IrisGridTheme';
3235

3336
type IrisGridModelEventNames =
3437
(typeof IrisGridModel.EVENT)[keyof typeof IrisGridModel.EVENT];
@@ -47,12 +50,15 @@ const EMPTY_ARRAY: never[] = [];
4750
* those out as well, so there's no dependency on IrisAPI at all, but it's a lot of work for no real gain at this time.
4851
*/
4952
abstract class IrisGridModel<
50-
TEventMap extends Record<string, Event<string>> = Record<
51-
string,
52-
Event<string>
53-
>,
54-
TMode extends 'standard' | 'strict' = 'standard',
55-
> extends GridModel<TEventMap & IrisGridModelEventMap, TMode> {
53+
TEventMap extends Record<string, Event<string>> = Record<
54+
string,
55+
Event<string>
56+
>,
57+
TMode extends 'standard' | 'strict' = 'standard',
58+
>
59+
extends GridModel<TEventMap & IrisGridModelEventMap, TMode>
60+
implements DataBarGridModel
61+
{
5662
static EVENT = Object.freeze({
5763
UPDATED: 'UPDATED',
5864
FORMATTER_UPDATED: 'FORMATTER_UPDATED',
@@ -532,6 +538,14 @@ abstract class IrisGridModel<
532538
modelIndex: ModelIndex,
533539
depth: number
534540
): ColumnHeaderGroup | undefined;
541+
542+
dataBarOptionsForCell(
543+
column: number,
544+
row: number,
545+
theme: IrisGridThemeType
546+
): DataBarOptions {
547+
throw new Error('Method not implemented.');
548+
}
535549
}
536550

537551
export default IrisGridModel;

packages/iris-grid/src/IrisGridProxyModel.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,12 @@ class IrisGridProxyModel extends IrisGridModel {
462462
valueForCell: IrisGridModel['valueForCell'] = (...args) =>
463463
this.model.valueForCell(...args);
464464

465+
renderTypeForCell: IrisGridModel['renderTypeForCell'] = (...args) =>
466+
this.model.renderTypeForCell(...args);
467+
468+
dataBarOptionsForCell: IrisGridModel['dataBarOptionsForCell'] = (...args) =>
469+
this.model.dataBarOptionsForCell(...args);
470+
465471
get filter(): readonly FilterCondition[] {
466472
return this.model.filter;
467473
}

packages/iris-grid/src/IrisGridTableModelTemplate.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import memoize from 'memoize-one';
44
import throttle from 'lodash.throttle';
55
import {
6+
CellRenderType,
67
EditOperation,
78
GridRange,
89
GridUtils,
@@ -38,6 +39,13 @@ import {
3839
assertNotNull,
3940
} from '@deephaven/utils';
4041
import { TableUtils, Formatter, FormatterUtils } from '@deephaven/jsapi-utils';
42+
import {
43+
AxisOption,
44+
DataBarOptions,
45+
DirectionOption,
46+
Marker,
47+
ValuePlacementOption,
48+
} from 'packages/grid/src/DataBarGridModel';
4149
import IrisGridModel from './IrisGridModel';
4250
import AggregationOperation from './sidebar/aggregations/AggregationOperation';
4351
import IrisGridUtils from './IrisGridUtils';
@@ -635,6 +643,54 @@ class IrisGridTableModelTemplate<
635643
return 'left';
636644
}
637645

646+
dataBarOptionsForCell(
647+
column: ModelIndex,
648+
row: ModelIndex,
649+
theme: IrisGridThemeType
650+
): DataBarOptions {
651+
const format = this.formatForCell(column, row);
652+
assertNotNull(format);
653+
const { axis, direction, max, min, valuePlacement, value, marker } =
654+
format.formatDataBar;
655+
let { positiveColor, negativeColor, markerColor, opacity } =
656+
format.formatDataBar;
657+
658+
positiveColor = positiveColor ?? theme.positiveBarColor;
659+
negativeColor = negativeColor ?? theme.negativeBarColor;
660+
let databarColor: string | string[] =
661+
format.color ?? (value >= 0 ? positiveColor : negativeColor);
662+
if (databarColor.includes(',')) {
663+
databarColor = databarColor.split(',');
664+
}
665+
markerColor = markerColor ?? theme.markerBarColor;
666+
667+
opacity = valuePlacement.toLowerCase() === 'overlap' ? 0.5 : opacity;
668+
669+
const databarOptions = {
670+
axis: axis.toLowerCase() as AxisOption,
671+
direction: direction.toUpperCase() as DirectionOption,
672+
columnMax: max,
673+
columnMin: min,
674+
opacity,
675+
color: databarColor,
676+
valuePlacement: valuePlacement.toLowerCase() as ValuePlacementOption,
677+
value,
678+
markers: [
679+
{
680+
value: marker,
681+
color: markerColor,
682+
},
683+
] as Marker[],
684+
};
685+
686+
return databarOptions;
687+
}
688+
689+
renderTypeForCell(column: ModelIndex, row: ModelIndex): CellRenderType {
690+
const format = this.formatForCell(column, row);
691+
return format?.formatDataBar != null ? 'dataBar' : 'text';
692+
}
693+
638694
textForColumnHeader(x: ModelIndex, depth = 0): string | undefined {
639695
const header = this.columnAtDepth(x, depth);
640696
if (isColumnHeaderGroup(header)) {

packages/iris-grid/src/IrisGridTheme.module.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,4 +99,5 @@ $header-height: 30px;
9999
zero-line-color: $gray-500;
100100
positive-bar-color: $green;
101101
negative-bar-color: $red;
102+
marker-bar-color: $white;
102103
}

packages/iris-grid/src/IrisGridTheme.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ const theme: Partial<IrisGridThemeType> = Object.freeze({
139139
zeroLineColor: IrisGridTheme['zero-line-color'],
140140
positiveBarColor: IrisGridTheme['positive-bar-color'],
141141
negativeBarColor: IrisGridTheme['negative-bar-color'],
142+
markerBarColor: IrisGridTheme['marker-bar-color'],
142143
});
143144

144145
export default theme;

0 commit comments

Comments
 (0)