Skip to content

Commit

Permalink
#6674 add heatmap highlighter support (#6779)
Browse files Browse the repository at this point in the history
* #6674 add cell highlighters - heatmap highlighter

* #6674 add heatmap highlighter tests
  • Loading branch information
Mariusz Jurowicz authored and scottdraves committed Feb 5, 2018
1 parent eb2cf2f commit e33cf89
Show file tree
Hide file tree
Showing 26 changed files with 748 additions and 46 deletions.
74 changes: 36 additions & 38 deletions js/notebook/src/shared/bkGlobals.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,42 +14,40 @@
* limitations under the License.
*/

define(function() {
return {
DEFAULT_EVALUATOR: 'JavaScript',
REQUIREJS_TIMEOUT: 30,
RECONNECT_TIMEOUT: 30 * 1000, // 30 seconds
CELL_INSTANTIATION_DISTANCE: 500, // in pixels - if the cell is closer than from the viewport it gets instantiated
EVENTS: {
RECONNECT_FAILED: 'reconnect-failed',
LANGUAGE_MANAGER_SHOW_SPINNER: 'language-manager-show-spinner',
LANGUAGE_MANAGER_HIDE_SPINNER: 'language-manager-hide-spinner',
DISCARD_LANGUAGE_SETTINGS: 'discard-language-settings',
HIGHLIGHT_EDITED_LANGUAGE_SETTINGS: 'highlight-edited-language-settings',
SET_LANGUAGE_SETTINGS_EDITED: 'set-language-settings-edited',
LANGUAGE_ADDED: 'languageAdded',
CELL_OUTPUT_EXPANDED: 'cell-output-expanded',
CELL_OUTPUT_LM_SHOWED: 'cell-output-lm-showed',
ADVANCED_MODE_TOGGLED: 'advanced-mode-toggled',
FILE_DROPPED: 'file-dropped'
module.exports = {
DEFAULT_EVALUATOR: 'JavaScript',
REQUIREJS_TIMEOUT: 30,
RECONNECT_TIMEOUT: 30 * 1000, // 30 seconds
CELL_INSTANTIATION_DISTANCE: 500, // in pixels - if the cell is closer than from the viewport it gets instantiated
EVENTS: {
RECONNECT_FAILED: 'reconnect-failed',
LANGUAGE_MANAGER_SHOW_SPINNER: 'language-manager-show-spinner',
LANGUAGE_MANAGER_HIDE_SPINNER: 'language-manager-hide-spinner',
DISCARD_LANGUAGE_SETTINGS: 'discard-language-settings',
HIGHLIGHT_EDITED_LANGUAGE_SETTINGS: 'highlight-edited-language-settings',
SET_LANGUAGE_SETTINGS_EDITED: 'set-language-settings-edited',
LANGUAGE_ADDED: 'languageAdded',
CELL_OUTPUT_EXPANDED: 'cell-output-expanded',
CELL_OUTPUT_LM_SHOWED: 'cell-output-lm-showed',
ADVANCED_MODE_TOGGLED: 'advanced-mode-toggled',
FILE_DROPPED: 'file-dropped'
},
FILE_LOCATION: {
FILESYS: "file",
HTTP: "http",
AJAX: "ajax"
},
EVALUATOR_SPEC: {
PROPERTIES: {
STRING: "settableString",
BOOLEAN: "settableBoolean",
ENUM: "settableEnum",
SELECT: "settableSelect"
},
FILE_LOCATION: {
FILESYS: "file",
HTTP: "http",
AJAX: "ajax"
},
EVALUATOR_SPEC: {
PROPERTIES: {
STRING: "settableString",
BOOLEAN: "settableBoolean",
ENUM: "settableEnum",
SELECT: "settableSelect"
},
ACTION: "action"
},
THEMES: {
DEFAULT: 'default',
AMBIANCE: 'ambiance'
}
};
});
ACTION: "action"
},
THEMES: {
DEFAULT: 'default',
AMBIANCE: 'ambiance'
}
};
33 changes: 31 additions & 2 deletions js/notebook/src/tableDisplay/dataGrid/BeakerxDataGrid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* limitations under the License.
*/

import { chain, find } from '@phosphor/algorithm'
import { DataGrid, DataModel } from "@phosphor/datagrid";
import { ITriggerOptions } from "./headerMenu/HeaderMenu";
import { BeakerxDataGridModel } from "./model/BeakerxDataGridModel";
Expand All @@ -23,6 +24,9 @@ import { ICellData } from "./interface/ICell";
import { CellRendererFactory } from "./cell/CellRendererFactory";
import DataGridColumn, { COLUMN_TYPES } from "./column/DataGridColumn";
import IDataModelState from "./interface/IDataGridModelState";
import HighlighterManager from "./highlighter/HighlighterManager";
import IHihglighterState from "./interface/IHighlighterState";
import { DEFAULT_PAGE_LENGTH } from "../consts";

export class BeakerxDataGrid extends DataGrid {
columnSections: any;
Expand All @@ -31,11 +35,12 @@ export class BeakerxDataGrid extends DataGrid {
rowHeaderSections: any;
rowSections: any;
viewport: Widget;
highlighterManager: HighlighterManager;

columns = {};
headerCellHovered = new Signal<this, ICellData|null>(this);

constructor(options: DataGrid.IOptions, modelOptions: IDataModelState) {
constructor(options: DataGrid.IOptions, modelState: IDataModelState) {
super(options);

//@todo this is hack to use private properties
Expand All @@ -45,9 +50,12 @@ export class BeakerxDataGrid extends DataGrid {
this.rowSections = this['_rowSections'];
this.columnSections = this['_columnSections'];

this.addModel(modelOptions);

this.addModel(modelState);
this.addColumns();
this.addHighlighterManager(modelState);
this.addCellRenderers();
this.setWidgetHeight();
this.repaint();
}

Expand Down Expand Up @@ -75,10 +83,25 @@ export class BeakerxDataGrid extends DataGrid {
return this.columns[columnType][index];
}

getColumnByName(columnName: string): DataGridColumn|undefined {
return find(
chain(this.columns[COLUMN_TYPES.body], this.columns[COLUMN_TYPES.index]),
(column: DataGridColumn) => column.name === columnName
);
}

private addModel(modelState: IDataModelState) {
this.model = new BeakerxDataGridModel(modelState);
}

private addHighlighterManager(modelState: IDataModelState) {
let cellHighlighters: IHihglighterState[] = modelState && modelState.cellHighlighters
? modelState.cellHighlighters
: [];

this.highlighterManager = new HighlighterManager(this, cellHighlighters);
}

private addColumns() {
let bodyColumns: DataGridColumn[] = [];
let indexColumns: DataGridColumn[] = [];
Expand Down Expand Up @@ -135,6 +158,12 @@ export class BeakerxDataGrid extends DataGrid {
this.cellRenderers.set('row-header', {}, defaultRenderer);
}

private setWidgetHeight() {
let bodyRowCount = this.model.rowCount('body');
let rowCount = DEFAULT_PAGE_LENGTH < bodyRowCount ? DEFAULT_PAGE_LENGTH : bodyRowCount;
this.node.style.minHeight = `${ rowCount * this.baseRowSize + this.baseColumnHeaderSize }px`;
}

private destroyAllColumns() {
this.columns[COLUMN_TYPES.index].forEach((column: DataGridColumn) => column.destroy());
this.columns[COLUMN_TYPES.body].forEach((column: DataGridColumn) => column.destroy());
Expand Down
3 changes: 1 addition & 2 deletions js/notebook/src/tableDisplay/dataGrid/DataFormatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,7 @@ export class DataFormatter {
moment(value.timestamp).format(DEFAULT_TIME_FORMAT) :
JSON.stringify(value);
} else if (_.isString(value)) {
const escapedText = DataGridHelpers.escapeHTML(value);
const limitedText = DataGridHelpers.truncateString(escapedText);
const limitedText = DataGridHelpers.truncateString(value);

formattedValue = limitedText;
}
Expand Down
3 changes: 2 additions & 1 deletion js/notebook/src/tableDisplay/dataGrid/DataGridScope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { Widget } from '@phosphor/widgets';
import { BeakerxDataGrid } from './BeakerxDataGrid';
import { silverStripeStyle } from './style/dataGridStyle';
import IDataGridScopeOptions from "./interface/IDataGridScopeOptions";
import consts from "../consts";

export class DataGridScope {
private dataGrid: BeakerxDataGrid;
Expand All @@ -31,7 +32,7 @@ export class DataGridScope {
this.tableDisplayView = options.widgetView;
this.dataGrid = new BeakerxDataGrid(
{
style: silverStripeStyle
style: silverStripeStyle,
},
options.data
);
Expand Down
10 changes: 10 additions & 0 deletions js/notebook/src/tableDisplay/dataGrid/cell/CellRendererFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
import { DEFAULT_ALIGNMENT } from "../column/columnAlignment";
import { CellRenderer, TextRenderer } from "@phosphor/datagrid";
import { BeakerxDataGrid } from "../BeakerxDataGrid";
import DataGridCell from "./DataGridCell";

export const DEFAULT_CELL_BACKGROUND = '';

export class CellRendererFactory {
private dataGrid: BeakerxDataGrid;
Expand All @@ -29,6 +32,13 @@ export class CellRendererFactory {
let self = this;

return new TextRenderer({
backgroundColor: (config: CellRenderer.ICellConfig) => {
if (DataGridCell.isHeaderCell(config)) {
return DEFAULT_CELL_BACKGROUND;
}

return self.dataGrid.highlighterManager.getCellBackground(config);
},
horizontalAlignment: (config: CellRenderer.ICellConfig) => {
let column = self.dataGrid.getColumn(config.column, config.region);

Expand Down
23 changes: 23 additions & 0 deletions js/notebook/src/tableDisplay/dataGrid/cell/DataGridCell.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright 2017 TWO SIGMA OPEN SOURCE, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { CellRenderer } from "@phosphor/datagrid";

export default class DataGridCell {
static isHeaderCell(config: CellRenderer.ICellConfig) {
return config.region === 'column-header' || config.region === 'corner-header';
}
}
12 changes: 12 additions & 0 deletions js/notebook/src/tableDisplay/dataGrid/column/DataGridColumn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { ICellData } from "../interface/ICell";
import { getAlignmentByChar, getAlignmentByType} from "./columnAlignment";
import { DataModel, TextRenderer } from "@phosphor/datagrid";
import { ALL_TYPES, getTypeByName } from "../dataTypes";
import { minmax, MapIterator } from '@phosphor/algorithm';

export enum COLUMN_TYPES {
'index',
Expand All @@ -40,6 +41,9 @@ export default class DataGridColumn {
dataType: ALL_TYPES;
menu: ColumnMenu|IndexMenu;
dataGrid: BeakerxDataGrid;
valuesIterator: MapIterator<number, any>;
minValue: any;
maxValue: any;

private state: IColumnState;

Expand All @@ -49,6 +53,7 @@ export default class DataGridColumn {
this.type = options.type;
this.dataGrid = dataGrid;
this.dataType = this.getDataType();
this.valuesIterator = this.dataGrid.model.getColumnValuesIterator(this);
this.state = {
triggerShown: false,
horizontalAlignment: this.getInitialAlignment()
Expand All @@ -57,6 +62,7 @@ export default class DataGridColumn {
this.handleHeaderCellHovered = this.handleHeaderCellHovered.bind(this);
this.createMenu(options.menuOptions);
this.connectToHeaderCellHovered();
this.addMinMaxValues();
}

static getColumnTypeByRegion(region: DataModel.CellRegion) {
Expand Down Expand Up @@ -142,4 +148,10 @@ export default class DataGridColumn {
this.setState({ horizontalAlignment });
}

private addMinMaxValues() {
let minMax = minmax(this.valuesIterator.clone(), (a:number, b:number) => a - b);

this.minValue = minMax ? minMax[0] : null;
this.maxValue = minMax ? minMax[1] : null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright 2017 TWO SIGMA OPEN SOURCE, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import * as d3scale from 'd3-scale';
import { formatColor, getDefaultColor } from "../style/dataGridStyle";
import Highlighter from "./Highlighter";
import IHihglighterState, { HIGHLIGHTER_STYLE } from "../interface/IHighlighterState";
import DataGridColumn from "../column/DataGridColumn";
import {CellRenderer} from "@phosphor/datagrid";
import { find } from "@phosphor/algorithm";

export default class HeatmapHighlighter extends Highlighter {
colorScale: Function;

constructor(column: DataGridColumn, state: IHihglighterState) {
super(column, state);

this.state.minVal = this.state.minVal || this.column.minValue;
this.state.maxVal = this.state.maxVal || this.column.maxValue;
this.state.minColor = formatColor(state.minColor || getDefaultColor('blue'));
this.state.maxColor = formatColor(state.maxColor || getDefaultColor('red'));

this.colorScale = d3scale.scaleLinear()
.domain([this.state.minVal, this.state.maxVal])
.range([this.state.minColor, this.state.maxColor]);
}

getBackgroundColor(config: CellRenderer.ICellConfig) {
let value = config.value;

if (this.state.style === HIGHLIGHTER_STYLE.FULL_ROW) {
value = find(this.column.valuesIterator.clone(), (value, index) => {
return index === config.row;
});
}

return this.colorScale(value);
}
}
35 changes: 35 additions & 0 deletions js/notebook/src/tableDisplay/dataGrid/highlighter/Highlighter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright 2017 TWO SIGMA OPEN SOURCE, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import IHihglighterState, { HIGHLIGHTER_STYLE } from "../interface/IHighlighterState";
import { DEFAULT_CELL_BACKGROUND } from "../cell/CellRendererFactory";
import { CellRenderer } from "@phosphor/datagrid";
import DataGridColumn from "../column/DataGridColumn";

export default class Highlighter {
column: DataGridColumn;
state: IHihglighterState;

constructor(column: DataGridColumn, state: IHihglighterState) {
this.column = column;
this.state = state;
this.state.style = state.style || HIGHLIGHTER_STYLE.SINGLE_COLUMN;
}

getBackgroundColor(config: CellRenderer.ICellConfig) {
return DEFAULT_CELL_BACKGROUND;
}
}
Loading

0 comments on commit e33cf89

Please sign in to comment.