Skip to content

Commit

Permalink
fix merge
Browse files Browse the repository at this point in the history
  • Loading branch information
dgodinez-dh committed Sep 3, 2024
1 parent 60667e2 commit de1e40d
Show file tree
Hide file tree
Showing 11 changed files with 1,323 additions and 1,992 deletions.
2,594 changes: 644 additions & 1,950 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions plugins/ui/docs/Plotting.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Plotting and dh.ui
# Plotting and deephaven.ui

Creating dynamic plots that respond to user input is a common task in data analysis. The `dh.ui` module provides a simple interface for creating interactive plots using the `deephaven-express` library. This guide will show you how to create plots that updates based on user input.
Creating dynamic plots that respond to user input is a common task in data analysis. The `deephaven.ui` module provides a simple interface for creating interactive plots using the `deephaven-express` library. This guide will show you how to create plots that updates based on user input.

## Plotting a filtered table

This example demonstrates how to create a simple line plot that updates based on user input. The plot will display the price of a stock filtered based on the stock symbol entered by the user. Here we have used a `ui.text_field` to get the value, but it could be driven by any dh.ui input, including double clicking on a value from a `ui.table`. We've previously referred to this sort of behaviour as a "one-click" component in enterprise, as the plot updates as soon as the user enters a filter.
This example demonstrates how to create a simple line plot that updates based on user input. The plot will display the price of a stock filtered based on the stock symbol entered by the user. Here we have used a `ui.text_field` to get the value, but it could be driven by any deephaven.ui input, including double clicking on a value from a `ui.table`. We've previously referred to this sort of behaviour as a "one-click" component in enterprise, as the plot updates as soon as the user enters a filter.

```python
import deephaven.plot.express as dx
Expand Down
2 changes: 1 addition & 1 deletion plugins/ui/docs/components/view.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ view = ui.view(

Recommendations for creating views:

1. Views are analogous to HTML <div>'s, and can be used in a similar regard to ensure consistency in styling across components.
1. Views are analogous to HTML `<div>`'s, and can be used in a similar regard to ensure consistency in styling across components.
2. Views lose their value when overused. Use them sparingly to avoid creating unnecessary complexity.
3. A view's height is flexible; it should accommodate the amount of content inside.
4. Views should be used when a flexible layout container is needed that can handle various combinations of components (ie., `text_field`s, `text_area`s, or buttons).
Expand Down
48 changes: 48 additions & 0 deletions plugins/ui/docs/sidebar.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,57 @@
{
"label": "Components",
"items": [
{
"label": "Action Button",
"path": "components/action_button.md"
},
{
"label": "Button",
"path": "components/button.md"
},
{
"label": "Checkbox",
"path": "components/checkbox.md"
},
{
"label": "Combo Box",
"path": "components/combo_box.md"
},
{
"label": "Date Picker",
"path": "components/date_picker.md"
},
{
"label": "Illustrated Message",
"path": "components/illustrated_message.md"
},
{
"label": "Image",
"path": "components/image.md"
},
{
"label": "Picker",
"path": "components/picker.md"
},
{
"label": "Radio Group",
"path": "components/radio_group.md"
},
{
"label": "Range Slider",
"path": "components/range_slider.md"
},
{
"label": "Slider",
"path": "components/slider.md"
},
{
"label": "Text Area",
"path": "components/text_area.md"
},
{
"label": "View",
"path": "components/view.md"
}
]
},
Expand Down
2 changes: 2 additions & 0 deletions plugins/ui/src/deephaven/ui/components/table.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
ColumnGroup,
ColumnName,
ColumnPressCallback,
DatabarConfig,
QuickFilterExpression,
RowPressCallback,
ResolvableContextMenuItem,
Expand Down Expand Up @@ -39,6 +40,7 @@ def table(
context_header_menu: (
ResolvableContextMenuItem | list[ResolvableContextMenuItem] | None
) = None,
databars: list[DatabarConfig] | None = None,
) -> UITable:
"""
Customization to how a table is displayed, how it behaves, and listen to UI events.
Expand Down
71 changes: 68 additions & 3 deletions plugins/ui/src/deephaven/ui/types/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -455,9 +455,6 @@ class SliderChange(TypedDict):
]
ContextMenuModeOption = Literal["CELL", "ROW_HEADER", "COLUMN_HEADER"]
ContextMenuMode = Union[ContextMenuModeOption, List[ContextMenuModeOption], None]
DataBarAxis = Literal["PROPORTIONAL", "MIDDLE", "DIRECTIONAL"]
DataBarDirection = Literal["LTR", "RTL"]
DataBarValuePlacement = Literal["BESIDE", "OVERLAP", "HIDE"]
# TODO: Fill in the list of Deephaven Colors we allow
LockType = Literal["shared", "exclusive"]
QuickFilterExpression = str
Expand Down Expand Up @@ -525,3 +522,71 @@ class DateRange(TypedDict):
"""
End value for the date range.
"""


DataBarAxis = Literal["PROPORTIONAL", "MIDDLE", "DIRECTIONAL"]
DataBarDirection = Literal["LTR", "RTL"]
DataBarValuePlacement = Literal["BESIDE", "OVERLAP", "HIDE"]


class DatabarConfig(TypedDict):
"""
Configuration for displaying a databar.
"""

column: ColumnName
"""
Name of the column to display as a databar.
"""

value_column: NotRequired[ColumnName]
"""
Name of the column to use as the value for the databar.
If not provided, the databar will use the column value.
This can be useful if you want to display a databar with
a log scale, but display the actual value in the cell.
In this case, the value_column would be the log of the actual value.
"""

min: NotRequired[Union[ColumnName, float]]
"""
Minimum value for the databar. Defaults to the minimum value in the column.
If a column name is provided, the minimum value will be the value in that column.
If a constant is providded, the minimum value will be that constant.
"""

max: NotRequired[Union[ColumnName, float]]
"""
Maximum value for the databar. Defaults to the maximum value in the column.
If a column name is provided, the maximum value will be the value in that column.
If a constant is providded, the maximum value will be that constant.
"""

axis: NotRequired[DataBarAxis]
"""
Whether the databar 0 value should be proportional to the min and max values,
in the middle of the cell, or on one side of the databar based on direction.
"""

direction: NotRequired[DataBarDirection]
"""
Direction of the databar.
"""

value_placement: NotRequired[DataBarValuePlacement]
"""
Placement of the value relative to the databar.
"""

color: NotRequired[Color]
"""
Color of the databar.
"""

opacity: NotRequired[float]
"""
Opacity of the databar fill.
"""
32 changes: 16 additions & 16 deletions plugins/ui/src/js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,23 +41,23 @@
"react-dom": "^17.0.2"
},
"dependencies": {
"@deephaven/chart": "^0.87.0",
"@deephaven/components": "^0.87.0",
"@deephaven/dashboard": "^0.86.0",
"@deephaven/dashboard-core-plugins": "^0.86.1",
"@deephaven/golden-layout": "^0.87.0",
"@deephaven/grid": "^0.87.0",
"@deephaven/icons": "^0.87.0",
"@deephaven/iris-grid": "^0.87.0",
"@deephaven/jsapi-bootstrap": "^0.87.0",
"@deephaven/jsapi-components": "^0.87.0",
"@deephaven/chart": "^0.91.0",
"@deephaven/components": "^0.91.0",
"@deephaven/dashboard": "^0.91.0",
"@deephaven/dashboard-core-plugins": "^0.91.0",
"@deephaven/golden-layout": "^0.91.0",
"@deephaven/grid": "^0.91.0",
"@deephaven/icons": "^0.91.0",
"@deephaven/iris-grid": "^0.91.0",
"@deephaven/jsapi-bootstrap": "^0.91.0",
"@deephaven/jsapi-components": "^0.91.0",
"@deephaven/jsapi-types": "^1.0.0-dev0.35.0",
"@deephaven/jsapi-utils": "^0.87.0",
"@deephaven/log": "^0.87.0",
"@deephaven/plugin": "^0.86.0",
"@deephaven/react-hooks": "^0.87.0",
"@deephaven/redux": "^0.86.0",
"@deephaven/utils": "^0.87.0",
"@deephaven/jsapi-utils": "^0.91.0",
"@deephaven/log": "^0.91.0",
"@deephaven/plugin": "^0.91.0",
"@deephaven/react-hooks": "^0.91.0",
"@deephaven/redux": "^0.91.0",
"@deephaven/utils": "^0.91.0",
"@fortawesome/react-fontawesome": "^0.2.0",
"@internationalized/date": "^3.5.5",
"classnames": "^2.5.1",
Expand Down
106 changes: 104 additions & 2 deletions plugins/ui/src/js/src/elements/UITable/JsTableProxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,23 @@ interface JsTableProxy extends dh.Table {}
* Any methods implemented in this class will be utilized over the underlying JsTable methods.
* Any methods not implemented in this class will be proxied to the table.
*/
class JsTableProxy {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
class JsTableProxy implements dh.Table {
static HIDDEN_COLUMN_SUFFIXES = ['__DATABAR_Min', '__DATABAR_Max'];

private table: dh.Table;

/**
* Keep a stable reference to all, visible, and hidden columns.
* Only update when needed.
*/
private stableColumns: {
allColumns: dh.Column[];
visibleColumns: dh.Column[];
hiddenColumns: dh.Column[];
};

layoutHints: dh.LayoutHints | null = null;

constructor({
Expand All @@ -32,6 +46,12 @@ class JsTableProxy {
}) {
this.table = table;

this.stableColumns = {
allColumns: [],
visibleColumns: [],
hiddenColumns: [],
};

const {
frontColumns = null,
frozenColumns = null,
Expand Down Expand Up @@ -87,14 +107,96 @@ class JsTableProxy {
Object.getOwnPropertyDescriptor(Object.getPrototypeOf(target), prop)
?.set != null;

if (proxyHasSetter) {
const proxyHasProp = Object.prototype.hasOwnProperty.call(target, prop);

if (proxyHasSetter || proxyHasProp) {
return Reflect.set(target, prop, value, target);
}

return Reflect.set(target.table, prop, value, target.table);
},
});
}

/**
* Update the stable columns object if needed.
* This lets us keep a stable array for columns unless the underlying table changes.
*/
private updateDisplayedColumns(): void {
if (this.stableColumns.allColumns !== this.table.columns) {
this.stableColumns.allColumns = this.table.columns;

this.stableColumns.visibleColumns = this.table.columns.filter(
column =>
!JsTableProxy.HIDDEN_COLUMN_SUFFIXES.some(suffix =>
column.name.endsWith(suffix)
)
);

this.stableColumns.hiddenColumns = this.table.columns.filter(column =>
JsTableProxy.HIDDEN_COLUMN_SUFFIXES.some(suffix =>
column.name.endsWith(suffix)
)
);
}
}

get columns(): dh.Column[] {
this.updateDisplayedColumns();
return this.stableColumns.visibleColumns;
}

get hiddenColumns(): dh.Column[] {
this.updateDisplayedColumns();
return this.stableColumns.hiddenColumns;
}

setViewport(
firstRow: number,
lastRow: number,
columns?: Array<dh.Column> | undefined | null,
updateIntervalMs?: number | undefined | null
): dh.TableViewportSubscription {
if (columns == null) {
return this.table.setViewport(
firstRow,
lastRow,
columns,
updateIntervalMs
);
}

const allColumns = columns.concat(this.hiddenColumns);
const viewportSubscription = this.table.setViewport(
firstRow,
lastRow,
allColumns,
updateIntervalMs
);
return new Proxy(viewportSubscription, {
get: (target, prop, receiver) => {
// Need to proxy setViewport on the subscription in case it is changed
// without creating an entirely new subscription
if (prop === 'setViewport') {
return (
first: number,
last: number,
cols?: dh.Column[] | null,
interval?: number | null
) => {
if (cols == null) {
return target.setViewport(first, last, cols, interval);
}

const proxyAllColumns = cols.concat(this.hiddenColumns);

return target.setViewport(first, last, proxyAllColumns, interval);
};
}
return Reflect.get(target, prop, receiver);
},
});
}
}

export default JsTableProxy;
Loading

0 comments on commit de1e40d

Please sign in to comment.