From 2e20b42f688b737e023a74467aa08224a7e25643 Mon Sep 17 00:00:00 2001 From: David Godinez Date: Mon, 27 Jan 2025 10:17:26 -0700 Subject: [PATCH 01/10] docs: update work with tables --- plugins/ui/docs/describing/work_with_tables.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/ui/docs/describing/work_with_tables.md b/plugins/ui/docs/describing/work_with_tables.md index e283d2983..d2f1757cc 100644 --- a/plugins/ui/docs/describing/work_with_tables.md +++ b/plugins/ui/docs/describing/work_with_tables.md @@ -1,8 +1,10 @@ # Work with Tables -The Deephaven table is the key abstraction that unites static and real-time data for a seamless, integrated experience. Combining tables with `deephaven.ui` components allows you to create your own powerful, data centered workflows. +`deephaven.ui` allows you to programmatically create your own custom UIs. However, the real power of `deephaven.ui` is in it's most unique feature: the ability to combine those UIs with Deephaven tables. -For more information, see [Working with Deephaven Tables](/core/docs/getting-started/quickstart/#4-working-with-deephaven-tables). +The Deephaven table is the key data structure for working with and analyzing large real time data. By combining tables with `deephaven.ui`, you can create a UI that allows you to visualize and work with data in way that best suites your own unique needs. + +For more information, see the quickstart guide on [Working with Deephaven Tables](/core/docs/getting-started/quickstart/#4-working-with-deephaven-tables). ## Display a table in a component From 41c301c9c3df3742bf38f5e72f37ac6282a84955 Mon Sep 17 00:00:00 2001 From: David Godinez Date: Mon, 27 Jan 2025 11:16:16 -0700 Subject: [PATCH 02/10] update use_table_data example --- .../ui/docs/describing/work_with_tables.md | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/plugins/ui/docs/describing/work_with_tables.md b/plugins/ui/docs/describing/work_with_tables.md index d2f1757cc..664e766fe 100644 --- a/plugins/ui/docs/describing/work_with_tables.md +++ b/plugins/ui/docs/describing/work_with_tables.md @@ -1,8 +1,8 @@ # Work with Tables -`deephaven.ui` allows you to programmatically create your own custom UIs. However, the real power of `deephaven.ui` is in it's most unique feature: the ability to combine those UIs with Deephaven tables. +`deephaven.ui` allows you to programmatically create your own custom UIs. However, the real power of `deephaven.ui` is in its most unique feature: the ability to combine those UIs with Deephaven tables. -The Deephaven table is the key data structure for working with and analyzing large real time data. By combining tables with `deephaven.ui`, you can create a UI that allows you to visualize and work with data in way that best suites your own unique needs. +The Deephaven table is the key data structure for working with and analyzing large real time data. By combining tables with `deephaven.ui`, you can create a UI that allows you to visualize and work with data in way that best suits your own unique needs. For more information, see the quickstart guide on [Working with Deephaven Tables](/core/docs/getting-started/quickstart/#4-working-with-deephaven-tables). @@ -110,7 +110,7 @@ memo_table_app = ui_memo_table_app() ## Hooks for tables -The [`use_table_data`](../hooks/use_table_data.md) hook lets you use a table's data. This is useful when you want to listen to an updating table and use the data in your component. +The [`use_table_data`](../hooks/use_table_data.md) hook lets you use a table's data. This is useful when you want to listen to an updating table and use the data in your component. This example uses the table data to populate two list views with the table data. ```python from deephaven import time_table, ui @@ -119,10 +119,20 @@ from deephaven import time_table, ui @ui.component def ui_table_data(table): table_data = ui.use_table_data(table) - return ui.heading(f"The table data is {table_data}") + return ui.flex( + table, + ui.list_view( + [ui.item(str(timestamp)) for timestamp in table_data["Timestamp"]], + selection_mode=None, + ), + ui.list_view( + [ui.item(x) for x in table_data["x"]], + selection_mode=None, + ), + ) -table_data = ui_table_data(time_table("PT1s").update("x=i").tail(5)) +table_data_example = ui_table_data(time_table("PT1s").update("x=i").tail(5)) ``` The [`use_cell_data`](../hooks/use_cell_data.md) hook lets you use the cell data of the first cell (first row in the first column) in a table. This is useful when you want to listen to an updating table and use the data in your component. From d3f63638f10b105f1eba9c7dd4499d7c65ddea68 Mon Sep 17 00:00:00 2001 From: David Godinez Date: Mon, 27 Jan 2025 11:30:41 -0700 Subject: [PATCH 03/10] conditional rendering --- plugins/ui/docs/describing/work_with_tables.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/plugins/ui/docs/describing/work_with_tables.md b/plugins/ui/docs/describing/work_with_tables.md index 664e766fe..685d3ddc1 100644 --- a/plugins/ui/docs/describing/work_with_tables.md +++ b/plugins/ui/docs/describing/work_with_tables.md @@ -135,7 +135,7 @@ def ui_table_data(table): table_data_example = ui_table_data(time_table("PT1s").update("x=i").tail(5)) ``` -The [`use_cell_data`](../hooks/use_cell_data.md) hook lets you use the cell data of the first cell (first row in the first column) in a table. This is useful when you want to listen to an updating table and use the data in your component. +The [`use_cell_data`](../hooks/use_cell_data.md) hook lets you use the cell data of the first cell (first row in the first column) in a table. This is useful when you want to listen to an updating table and use the data in your component. This value can be used for conditional rendering as shown in this example. ```python from deephaven import time_table, ui @@ -144,8 +144,14 @@ from deephaven import time_table, ui @ui.component def ui_table_first_cell(table): cell_value = ui.use_cell_data(table) - return ui.heading(f"The first cell value is {cell_value}") + is_even = cell_value % 2 == 0 + return [ + ui.heading(f"The first cell value is {cell_value}"), + ui.text(f"Is {cell_value} even?", " ✅" if is_even else " ❌"), + ] -table_first_cell = ui_table_first_cell(time_table("PT1s").tail(1)) +table_first_cell2 = ui_table_first_cell( + time_table("PT1s").update("x=i").drop_columns("Timestamp").tail(1) +) ``` From 5180ef41519eb9c1a11ba4808368691f1a7c9ab4 Mon Sep 17 00:00:00 2001 From: David Godinez Date: Mon, 27 Jan 2025 11:34:24 -0700 Subject: [PATCH 04/10] rename --- .../describing/{work_with_tables.md => ui_with_tables.md} | 4 ++-- plugins/ui/docs/sidebar.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) rename plugins/ui/docs/describing/{work_with_tables.md => ui_with_tables.md} (95%) diff --git a/plugins/ui/docs/describing/work_with_tables.md b/plugins/ui/docs/describing/ui_with_tables.md similarity index 95% rename from plugins/ui/docs/describing/work_with_tables.md rename to plugins/ui/docs/describing/ui_with_tables.md index 685d3ddc1..627396f0e 100644 --- a/plugins/ui/docs/describing/work_with_tables.md +++ b/plugins/ui/docs/describing/ui_with_tables.md @@ -1,4 +1,4 @@ -# Work with Tables +# UI with Tables `deephaven.ui` allows you to programmatically create your own custom UIs. However, the real power of `deephaven.ui` is in its most unique feature: the ability to combine those UIs with Deephaven tables. @@ -135,7 +135,7 @@ def ui_table_data(table): table_data_example = ui_table_data(time_table("PT1s").update("x=i").tail(5)) ``` -The [`use_cell_data`](../hooks/use_cell_data.md) hook lets you use the cell data of the first cell (first row in the first column) in a table. This is useful when you want to listen to an updating table and use the data in your component. This value can be used for conditional rendering as shown in this example. +The [`use_cell_data`](../hooks/use_cell_data.md) hook lets you use the cell data of the first cell (first row in the first column) in a table. This value can be used for conditional rendering as shown in this example. ```python from deephaven import time_table, ui diff --git a/plugins/ui/docs/sidebar.json b/plugins/ui/docs/sidebar.json index 0254f9e3a..6ab7fd250 100644 --- a/plugins/ui/docs/sidebar.json +++ b/plugins/ui/docs/sidebar.json @@ -47,8 +47,8 @@ "path": "describing/use_hooks.md" }, { - "label": "Working with Tables", - "path": "describing/work_with_tables.md" + "label": "UI with Tables", + "path": "describing/ui_with_tables.md" }, { "label": "Conditional Rendering", From 63a77e1a2d063ecfe3759f8136cc4a473657480a Mon Sep 17 00:00:00 2001 From: David Godinez Date: Mon, 27 Jan 2025 11:57:42 -0700 Subject: [PATCH 05/10] use directly --- plugins/ui/docs/describing/ui_with_tables.md | 48 ++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/plugins/ui/docs/describing/ui_with_tables.md b/plugins/ui/docs/describing/ui_with_tables.md index 627396f0e..df6c0448d 100644 --- a/plugins/ui/docs/describing/ui_with_tables.md +++ b/plugins/ui/docs/describing/ui_with_tables.md @@ -155,3 +155,51 @@ table_first_cell2 = ui_table_first_cell( time_table("PT1s").update("x=i").drop_columns("Timestamp").tail(1) ) ``` + +## Use tables directly with components + +Some `deephaven.ui` components support the use of tables directly or through a `item_table_source`. + +This example shows a [`list_view`](../components/list_view.md) populated directly from a table. + +```python +from deephaven import ui, new_table +from deephaven.column import string_col + +_colors = new_table( + [ + string_col("Colors", ["Red", "Blue", "Green"]), + ] +) + + +@ui.component +def ui_list_view_table(): + return ui.list_view(_colors) + + +list_view_table_example = ui_list_view_table() +``` + +In this example, an `item_table_source` is used to create complex items from a table (ie., defining which columns are the keys/labels of the data). These complex items are displayed in a `picker`. + +```python +from deephaven import ui, empty_table + +icon_names = ["vsAccount"] +columns = [ + "Key=new Integer(i)", + "Label=new String(`Display `+i)", + "Icon=(String) icon_names[0]", +] +_column_types = empty_table(20).update(columns) + +item_table_source = ui.item_table_source( + _column_types, + key_column="Key", + label_column="Label", + icon_column="Icon", +) + +picker_item_table_source_example = ui.picker(item_table_source, label="User Picker") +``` From fd1bae9adefe6b7420150310fce0599efe3be3b1 Mon Sep 17 00:00:00 2001 From: David Godinez Date: Mon, 27 Jan 2025 12:17:41 -0700 Subject: [PATCH 06/10] update tables and plots --- plugins/ui/docs/describing/ui_with_tables.md | 41 ++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/plugins/ui/docs/describing/ui_with_tables.md b/plugins/ui/docs/describing/ui_with_tables.md index df6c0448d..f6056760b 100644 --- a/plugins/ui/docs/describing/ui_with_tables.md +++ b/plugins/ui/docs/describing/ui_with_tables.md @@ -203,3 +203,44 @@ item_table_source = ui.item_table_source( picker_item_table_source_example = ui.picker(item_table_source, label="User Picker") ``` + +## Update tables and plots from user input + +Tables and plots can update in response to user input. The following examples allows a user to pick two dates on a [`date_range_picker](../components/date_range_picker.md). This updates a state variable which causes the component to re-render with a filtered table and plot. + +```python +from deephaven.time import dh_now +from deephaven import time_table, ui +import deephaven.plot.express as dx + + +@ui.component +def date_table_filter(table, start_date, end_date, time_col="Timestamp"): + dates, set_dates = ui.use_state({"start": start_date, "end": end_date}) + + def filter_by_dates(): + start = dates["start"] + end = dates["end"] + return table.where(f"{time_col} >= start && {time_col} < end") + + filtered_table = ui.use_memo(filter_by_dates, [table, dates]) + plot = ui.use_memo( + lambda: dx.line(filtered_table, x="Timestamp", y="Row"), [filtered_table] + ) + + return [ + ui.date_range_picker( + label="Dates", value=dates, on_change=set_dates, max_visible_months=2 + ), + filtered_table, + plot, + ] + + +SECONDS_IN_DAY = 86400 +today = dh_now() +_table = time_table("PT1s").update_view( + ["Timestamp=today.plusSeconds(SECONDS_IN_DAY*i)", "Row=i"] +) +date_filter = date_table_filter(_table, today, today.plusSeconds(SECONDS_IN_DAY * 10)) +``` From 38cb760a1cde13c227a847af7c4d1a57f56a56b2 Mon Sep 17 00:00:00 2001 From: dgodinez-dh <77981300+dgodinez-dh@users.noreply.github.com> Date: Tue, 28 Jan 2025 06:12:43 -0700 Subject: [PATCH 07/10] Apply suggestions from code review Co-authored-by: margaretkennedy <82049573+margaretkennedy@users.noreply.github.com> Co-authored-by: Mike Bender --- plugins/ui/docs/describing/ui_with_tables.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/plugins/ui/docs/describing/ui_with_tables.md b/plugins/ui/docs/describing/ui_with_tables.md index f6056760b..2852a628e 100644 --- a/plugins/ui/docs/describing/ui_with_tables.md +++ b/plugins/ui/docs/describing/ui_with_tables.md @@ -2,7 +2,7 @@ `deephaven.ui` allows you to programmatically create your own custom UIs. However, the real power of `deephaven.ui` is in its most unique feature: the ability to combine those UIs with Deephaven tables. -The Deephaven table is the key data structure for working with and analyzing large real time data. By combining tables with `deephaven.ui`, you can create a UI that allows you to visualize and work with data in way that best suits your own unique needs. +The Deephaven table is the key data structure for working with and analyzing large real-time data. By combining tables with `deephaven.ui`, you can create a UI that allows you to visualize and work with data in a way that best suits your own unique needs. For more information, see the quickstart guide on [Working with Deephaven Tables](/core/docs/getting-started/quickstart/#4-working-with-deephaven-tables). @@ -10,10 +10,10 @@ For more information, see the quickstart guide on [Working with Deephaven Tables You can display a Deephaven table in a component by doing one of the following: -- return a table directly from a component -- return a table as part of a `list` or `tuple` -- add a table to a container such as a `flex` or `panel` -- [use ui.table](#use-ui.table) +- Return a table directly from a component. +- Return a table as part of a `list` or `tuple`. +- Add a table to a container such as a `flex` or `panel`. +- [Use `ui.table`](#use-ui.table). ```python from deephaven import new_table, ui @@ -69,7 +69,7 @@ t = ui.table( ## Memoize table operations -If you are working with a table, memoize the table operation. This stores the result in a memoized value and prevents the table from being re-computed on every render. This can be done with the [use_memo](../hooks/use_memo.md) hook. +If you are working with a table, memoize the table operation. This stores the result in a memoized value and prevents the table from being re-computed on every render. This can be done with the [`use_memo`](../hooks/use_memo.md) hook. ```python from deephaven import time_table, ui @@ -110,7 +110,7 @@ memo_table_app = ui_memo_table_app() ## Hooks for tables -The [`use_table_data`](../hooks/use_table_data.md) hook lets you use a table's data. This is useful when you want to listen to an updating table and use the data in your component. This example uses the table data to populate two list views with the table data. +The [`use_table_data`](../hooks/use_table_data.md) hook lets you use a table's data. This is useful when you want to listen to an updating table and use the data in your component. This example uses the table data to populate two list views. ```python from deephaven import time_table, ui @@ -158,7 +158,7 @@ table_first_cell2 = ui_table_first_cell( ## Use tables directly with components -Some `deephaven.ui` components support the use of tables directly or through a `item_table_source`. +Some `deephaven.ui` components support the use of tables directly or through an `item_table_source`. This example shows a [`list_view`](../components/list_view.md) populated directly from a table. @@ -181,7 +181,7 @@ def ui_list_view_table(): list_view_table_example = ui_list_view_table() ``` -In this example, an `item_table_source` is used to create complex items from a table (ie., defining which columns are the keys/labels of the data). These complex items are displayed in a `picker`. +In this example, an `item_table_source` is used to create complex items from a table (i.e., defining which columns are the data's keys/labels). These complex items are displayed in a `picker`. ```python from deephaven import ui, empty_table From d4e1503cd7fd3ec5252e027bda3174f45242e004 Mon Sep 17 00:00:00 2001 From: David Godinez Date: Tue, 28 Jan 2025 07:52:26 -0700 Subject: [PATCH 08/10] use row data --- plugins/ui/docs/describing/ui_with_tables.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/plugins/ui/docs/describing/ui_with_tables.md b/plugins/ui/docs/describing/ui_with_tables.md index 2852a628e..3fca72947 100644 --- a/plugins/ui/docs/describing/ui_with_tables.md +++ b/plugins/ui/docs/describing/ui_with_tables.md @@ -135,6 +135,25 @@ def ui_table_data(table): table_data_example = ui_table_data(time_table("PT1s").update("x=i").tail(5)) ``` +The [`use_row_data`](../hooks/use_row_data.md) hook lets you use the first row of table data a dictionary. This example displays the latest row of data in a ticking time table. + +```python +from deephaven import time_table, ui + + +@ui.component +def ui_table_first_cell(table): + row_data = ui.use_row_data(table) + return [ + ui.heading("Latest data"), + ui.text(f"Timestamp: {row_data['Timestamp']}"), + ui.text(f"x: {row_data['x']}"), + ] + + +table_first_cell2 = ui_table_first_cell(time_table("PT1s").update("x=i").reverse()) +``` + The [`use_cell_data`](../hooks/use_cell_data.md) hook lets you use the cell data of the first cell (first row in the first column) in a table. This value can be used for conditional rendering as shown in this example. ```python From f4ab1224bfea34937f2e6fac3dd7a888eb937896 Mon Sep 17 00:00:00 2001 From: dgodinez-dh <77981300+dgodinez-dh@users.noreply.github.com> Date: Tue, 28 Jan 2025 08:02:52 -0700 Subject: [PATCH 09/10] Update plugins/ui/docs/describing/ui_with_tables.md Co-authored-by: margaretkennedy <82049573+margaretkennedy@users.noreply.github.com> --- plugins/ui/docs/describing/ui_with_tables.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/ui/docs/describing/ui_with_tables.md b/plugins/ui/docs/describing/ui_with_tables.md index 3fca72947..3f2ffd378 100644 --- a/plugins/ui/docs/describing/ui_with_tables.md +++ b/plugins/ui/docs/describing/ui_with_tables.md @@ -135,7 +135,7 @@ def ui_table_data(table): table_data_example = ui_table_data(time_table("PT1s").update("x=i").tail(5)) ``` -The [`use_row_data`](../hooks/use_row_data.md) hook lets you use the first row of table data a dictionary. This example displays the latest row of data in a ticking time table. +The [`use_row_data`](../hooks/use_row_data.md) hook lets you use the first row of table data as a dictionary. This example displays the latest row of data in a ticking time table. ```python from deephaven import time_table, ui From 7c79708a4db2919327cb6c2c3530724ee2462672 Mon Sep 17 00:00:00 2001 From: David Godinez Date: Tue, 28 Jan 2025 09:44:16 -0700 Subject: [PATCH 10/10] use table listener --- plugins/ui/docs/describing/ui_with_tables.md | 21 ++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/plugins/ui/docs/describing/ui_with_tables.md b/plugins/ui/docs/describing/ui_with_tables.md index 3f2ffd378..10bfa32e4 100644 --- a/plugins/ui/docs/describing/ui_with_tables.md +++ b/plugins/ui/docs/describing/ui_with_tables.md @@ -175,6 +175,27 @@ table_first_cell2 = ui_table_first_cell( ) ``` +If the previous hooks do not fit your use case, you can use the [`use_table_listener`](../hooks/use_table_listener.md) hook. This allows you to listen to the raw updates from a table and perform a custom action when the table updates. The update is a dictionary containing dictionaries for data that is `added`, `removed`, or `modified`. Additionally, there is flag indicating if the data is a [replay](core/docs/how-to-guides/replay-data/). + +```python +from deephaven import time_table, ui +from deephaven.table import Table + +_source = time_table("PT1s").update("X = i") + + +@ui.component +def ui_table_monitor(t: Table): + def listener_function(update, is_replay): + print(f"Table updated: {update}, is_replay: {is_replay}") + + ui.use_table_listener(t, listener_function, []) + return t + + +table_monitor = ui_table_monitor(_source) +``` + ## Use tables directly with components Some `deephaven.ui` components support the use of tables directly or through an `item_table_source`.